From fijal at codespeak.net Wed Nov 1 10:34:06 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 1 Nov 2006 10:34:06 +0100 (CET) Subject: [pypy-svn] r33995 - pypy/dist/pypy/translator/stackless Message-ID: <20061101093406.C18C010070@code0.codespeak.net> Author: fijal Date: Wed Nov 1 10:34:02 2006 New Revision: 33995 Modified: pypy/dist/pypy/translator/stackless/transform.py Log: Fixed imports. Modified: pypy/dist/pypy/translator/stackless/transform.py ============================================================================== --- pypy/dist/pypy/translator/stackless/transform.py (original) +++ pypy/dist/pypy/translator/stackless/transform.py Wed Nov 1 10:34:02 2006 @@ -1,6 +1,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS -from pypy.rlib import rarithmetic, rclass, rmodel +from pypy.rlib import rarithmetic +from pypy.rpython import rclass, rmodel from pypy.translator.backendopt import support from pypy.objspace.flow import model from pypy.translator import unsimplify, simplify From ale at codespeak.net Wed Nov 1 10:39:03 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Wed, 1 Nov 2006 10:39:03 +0100 (CET) Subject: [pypy-svn] r33996 - pypy/dist/pypy/lib/pyontology Message-ID: <20061101093903.BB80410070@code0.codespeak.net> Author: ale Date: Wed Nov 1 10:39:02 2006 New Revision: 33996 Modified: pypy/dist/pypy/lib/pyontology/pyontology.py Log: Tryingto optimise SPARQL queries Modified: pypy/dist/pypy/lib/pyontology/pyontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/pyontology.py (original) +++ pypy/dist/pypy/lib/pyontology/pyontology.py Wed Nov 1 10:39:02 2006 @@ -603,7 +603,7 @@ prop.setValues(list(self.variables['rdf_Property'].getValues())) # Get all properties by looking at 'rdf_Property' # add a constraint trip[0] in domains[prop] and trip[2] in domains[prop].getValuesPrKey(trip[0]) - self.constraints.append(PropertyConstrain(prop_name, indi, obj)) + query_constr.append(PropertyConstrain(prop_name, indi, obj)) elif case == 3: # search for s in p @@ -630,7 +630,7 @@ obj = self.variables[self.mangle_name(trip[2])] else: obj = trip[2] - self.constraints.append(PropertyConstrain2(prop_name, sub_name, obj)) + query_constr.append(PropertyConstrain2(prop_name, sub_name, obj)) elif case == 5: # return the values of p prop = self.make_var(Property, URIRef(trip[1])) @@ -658,17 +658,17 @@ obj = self.make_var(Thing, trip[2]) self.variables[obj].setValues(things) con = Expression([sub,prop,obj], "%s[0] == %s and %s[1] == %s" %(prop, sub, prop, obj)) - self.constraints.append(con) + query_constr.append(con) # call finish on the variables in the query for v in vars: - query_dom, query_constr = self.variables[self.mangle_name(v)].finish(self.variables, self.constraints) #query_dom, query_constr) + query_dom, _ = self.variables[self.mangle_name(v)].finish(self.variables, query_constr) #query_dom, query_constr) # Build a repository with the variables in the query - #dom = dict([(self.mangle_name(v),self.variables[self.mangle_name(v)) - # for v in vars]) + dom = dict([(self.mangle_name(v),self.variables[self.mangle_name(v)]) + for v in vars]) # solve the repository and return the solution -# rep = Repository(query_dom.keys(), query_dom, query_constr) -# return Solver().solve(rep) - res_s = self.solve() + rep = Repository(dom.keys(), dom, query_constr) + res_s = Solver().solve(rep) + #res_s = self.solve() res = [] for d in res_s: for k,v in d.items(): From cfbolz at codespeak.net Wed Nov 1 10:40:41 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 10:40:41 +0100 (CET) Subject: [pypy-svn] r33997 - pypy/extradoc/sprintinfo/ddorf2006b Message-ID: <20061101094041.EEC6010072@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 10:40:37 2006 New Revision: 33997 Modified: pypy/extradoc/sprintinfo/ddorf2006b/planning.txt Log: planning for today Modified: pypy/extradoc/sprintinfo/ddorf2006b/planning.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2006b/planning.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2006b/planning.txt Wed Nov 1 10:40:37 2006 @@ -13,28 +13,36 @@ Tasks ===== - - javascript interpreter (leonardo, maciek and armin around) + - javascript interpreter (leonardo, stephan) addition of numbers, strings (with proper, twisted semantics) works integration of the narcissus parser + nested scopes, variable declarations, functions without parameters - - jvm backend (niko, anto) + - jvm backend (niko, ) sharing code between gencli and genjvm + first tests running! + number manipulations, field access - - transparent proxies + - transparent proxies (maciek, guido, samuele around) - - apigen tool (guido, maciek around) + - apigen tool + changes to instance variables after calls to functions - build tool it's now actually building pypy, sending the usession directory back - - .net integration + - .net integration, fixing pypy.net (anto, carl friedrich) + quick hack, but pypy.net is broken :-( - jit code generation (eric, michael) lots of documentation about the jit-backend interface, fighting with ppc code generation + some refactorings + looking at whether it's possible to use the llvm code generation - jit front end (samuele, arre) IN-PROGRESS + fixed the last known bug, experimentation needed - running tests on the translated pypy-cs (related to py.test refactoring?) @@ -42,7 +50,10 @@ - lists of integers - - adding the microbenchmark results to the benchmark page (eric) - MAYBE DONE + - adding the microbenchmark results to the benchmark page + DONE - trying the jit efforts on a regex engine (richard, armin around) + kind of worked + +- fixing pypy on windows, adding some more os functions (christian) From stephan at codespeak.net Wed Nov 1 11:03:21 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Wed, 1 Nov 2006 11:03:21 +0100 (CET) Subject: [pypy-svn] r33998 - pypy/dist/pypy/module/_stackless/test Message-ID: <20061101100321.D78E310063@code0.codespeak.net> Author: stephan Date: Wed Nov 1 11:03:19 2006 New Revision: 33998 Modified: pypy/dist/pypy/module/_stackless/test/test_stackless.py Log: test Modified: pypy/dist/pypy/module/_stackless/test/test_stackless.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_stackless.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_stackless.py Wed Nov 1 11:03:19 2006 @@ -394,3 +394,4 @@ schedule() assert output == [('a', x) for x in "ABCDE"] + From ericvrp at codespeak.net Wed Nov 1 12:33:13 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 1 Nov 2006 12:33:13 +0100 (CET) Subject: [pypy-svn] r34000 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061101113313.CE10510060@code0.codespeak.net> Author: ericvrp Date: Wed Nov 1 12:33:10 2006 New Revision: 34000 Added: pypy/dist/pypy/jit/codegen/llvm/README.txt (contents, props changed) pypy/dist/pypy/jit/codegen/llvm/lib/ pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (contents, props changed) pypy/dist/pypy/jit/codegen/llvm/setup.py (contents, props changed) pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (contents, props changed) Modified: pypy/dist/pypy/jit/codegen/llvm/jitcode.py Log: (mwh, ericvrp) starting minimal llvm c-api library and ctypes wrapper Added: pypy/dist/pypy/jit/codegen/llvm/README.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/README.txt Wed Nov 1 12:33:10 2006 @@ -0,0 +1,4 @@ +Create llvm c api library by running "python setup.py build_ext -i" here + +note: This library building should maybe not be done with distutils at all! + It should probably be done with the regular: ./configure;make;make install Modified: pypy/dist/pypy/jit/codegen/llvm/jitcode.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/jitcode.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/jitcode.py Wed Nov 1 12:33:10 2006 @@ -1,4 +1,7 @@ """ +This code is not used anymore and it's tests are skipped. +Keeping it around for a while... + All code for using LLVM's JIT in one place """ Added: pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp Wed Nov 1 12:33:10 2006 @@ -0,0 +1,5 @@ +//implementation for using the LLVM JIT + +int testme(int n) { + return n * 2; +} Added: pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.h ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.h Wed Nov 1 12:33:10 2006 @@ -0,0 +1,11 @@ +//for using the LLVM C++ API + +#ifdef __cplusplus +extern "C" { +#endif + +int testme(int n); + +#ifdef __cplusplus +} +#endif Added: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Wed Nov 1 12:33:10 2006 @@ -0,0 +1,9 @@ +''' + Another go at using the LLVM JIT as a codegenerator for PyPy. + + For now we use the LLVM C++ API as little as possible! + In future we might talk directly to the LLVM C++ API. + + This file contains the ctypes specification to use the llvmjit library! +''' + Added: pypy/dist/pypy/jit/codegen/llvm/setup.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/setup.py Wed Nov 1 12:33:10 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='llvmjit', + sources=['lib/llvmjit.cpp'], + libraries=[], + include_dirs =["include"] + [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]) Added: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== From cfbolz at codespeak.net Wed Nov 1 12:49:51 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 12:49:51 +0100 (CET) Subject: [pypy-svn] r34001 - in pypy/dist/pypy: annotation annotation/test interpreter interpreter/pyparser jit/codegen jit/codegen/i386 jit/codegen/i386/test jit/codegen/llgraph jit/codegen/ppc jit/codegen/test jit/hintannotator/test jit/llabstractinterp/test jit/timeshifter/test jit/tl lang/automata lang/automata/test module/__builtin__ module/_pickle_support module/_stackless module/_weakref module/rsocket objspace/cclp objspace/cclp/constraint objspace/cpy objspace/flow objspace/std rlib rlib/test rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory rpython/memory/test rpython/ootypesystem rpython/ootypesystem/test rpython/test translator/backendopt/test translator/c translator/c/test translator/cli translator/cli/test translator/js translator/js/test translator/llvm translator/llvm/test translator/stackless translator/test Message-ID: <20061101114951.70FAC10060@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 12:49:34 2006 New Revision: 34001 Added: pypy/dist/pypy/rlib/objectmodel.py - copied unchanged from r33974, pypy/dist/pypy/rpython/objectmodel.py pypy/dist/pypy/rlib/test/test_objectmodel.py - copied, changed from r33974, pypy/dist/pypy/rpython/test/test_objectmodel.py Removed: pypy/dist/pypy/rpython/objectmodel.py pypy/dist/pypy/rpython/test/test_objectmodel.py Modified: pypy/dist/pypy/annotation/bookkeeper.py pypy/dist/pypy/annotation/builtin.py pypy/dist/pypy/annotation/test/test_annrpython.py pypy/dist/pypy/interpreter/error.py pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/interpreter/pyparser/ebnflexer.py pypy/dist/pypy/interpreter/typedef.py pypy/dist/pypy/jit/codegen/i386/rgenop.py pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py pypy/dist/pypy/jit/codegen/i386/test/test_operation.py pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py pypy/dist/pypy/jit/codegen/llgraph/rgenop.py pypy/dist/pypy/jit/codegen/model.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/test/rgenop_tests.py pypy/dist/pypy/jit/hintannotator/test/test_annotator.py pypy/dist/pypy/jit/llabstractinterp/test/test_llabstractinterp.py pypy/dist/pypy/jit/llabstractinterp/test/test_vlist.py pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/jit/timeshifter/test/test_promotion.py pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py pypy/dist/pypy/jit/tl/tl.py pypy/dist/pypy/jit/tl/tlc.py pypy/dist/pypy/jit/tl/tlr.py pypy/dist/pypy/lang/automata/dfa.py pypy/dist/pypy/lang/automata/test/test_dfa.py pypy/dist/pypy/module/__builtin__/special.py pypy/dist/pypy/module/_pickle_support/maker.py pypy/dist/pypy/module/_stackless/clonable.py pypy/dist/pypy/module/_stackless/interp_clonable.py pypy/dist/pypy/module/_stackless/interp_coroutine.py pypy/dist/pypy/module/_weakref/interp__weakref.py pypy/dist/pypy/module/rsocket/rsocket.py pypy/dist/pypy/objspace/cclp/constraint/constraint.py pypy/dist/pypy/objspace/cclp/misc.py pypy/dist/pypy/objspace/cclp/scheduler.py pypy/dist/pypy/objspace/cclp/space.py pypy/dist/pypy/objspace/cclp/thread.py pypy/dist/pypy/objspace/cclp/thunk.py pypy/dist/pypy/objspace/cclp/variable.py pypy/dist/pypy/objspace/cpy/objspace.py pypy/dist/pypy/objspace/cpy/typedef.py pypy/dist/pypy/objspace/flow/framestate.py pypy/dist/pypy/objspace/std/dictmultiobject.py pypy/dist/pypy/objspace/std/dictobject.py pypy/dist/pypy/objspace/std/dictstrobject.py pypy/dist/pypy/objspace/std/objspace.py pypy/dist/pypy/objspace/std/setobject.py pypy/dist/pypy/objspace/std/smallintobject.py pypy/dist/pypy/objspace/std/stringobject.py pypy/dist/pypy/rlib/rarithmetic.py pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/lltypesystem/llmemory.py pypy/dist/pypy/rpython/lltypesystem/lltype.py pypy/dist/pypy/rpython/lltypesystem/opimpl.py pypy/dist/pypy/rpython/lltypesystem/rbuiltin.py pypy/dist/pypy/rpython/lltypesystem/rclass.py pypy/dist/pypy/rpython/lltypesystem/rdict.py pypy/dist/pypy/rpython/lltypesystem/rstr.py pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py pypy/dist/pypy/rpython/lltypesystem/test/test_rtagged.py pypy/dist/pypy/rpython/memory/gc.py pypy/dist/pypy/rpython/memory/lladdress.py pypy/dist/pypy/rpython/memory/support.py pypy/dist/pypy/rpython/memory/test/test_gc.py pypy/dist/pypy/rpython/memory/test/test_support.py pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py pypy/dist/pypy/rpython/normalizecalls.py pypy/dist/pypy/rpython/ootypesystem/ootype.py pypy/dist/pypy/rpython/ootypesystem/rbuiltin.py pypy/dist/pypy/rpython/ootypesystem/rdict.py pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py pypy/dist/pypy/rpython/raddress.py pypy/dist/pypy/rpython/rbuiltin.py pypy/dist/pypy/rpython/rcpy.py pypy/dist/pypy/rpython/rdict.py pypy/dist/pypy/rpython/rint.py pypy/dist/pypy/rpython/rlist.py pypy/dist/pypy/rpython/test/test_nongc.py pypy/dist/pypy/rpython/test/test_rbuiltin.py pypy/dist/pypy/rpython/test/test_rconstantdict.py pypy/dist/pypy/rpython/test/test_rpbc.py pypy/dist/pypy/translator/backendopt/test/test_canraise.py pypy/dist/pypy/translator/backendopt/test/test_constfold.py pypy/dist/pypy/translator/backendopt/test/test_escape.py pypy/dist/pypy/translator/backendopt/test/test_malloc.py pypy/dist/pypy/translator/c/gc.py pypy/dist/pypy/translator/c/primitive.py pypy/dist/pypy/translator/c/test/test_backendoptimized.py pypy/dist/pypy/translator/c/test/test_boehm.py pypy/dist/pypy/translator/c/test/test_genc.py pypy/dist/pypy/translator/c/test/test_lladdresses.py pypy/dist/pypy/translator/c/test/test_newgc.py pypy/dist/pypy/translator/c/test/test_rtagged.py pypy/dist/pypy/translator/c/test/test_symbolic.py pypy/dist/pypy/translator/c/test/test_typed.py pypy/dist/pypy/translator/cli/database.py pypy/dist/pypy/translator/cli/test/test_constant.py pypy/dist/pypy/translator/cli/test/test_objectmodel.py pypy/dist/pypy/translator/js/jts.py pypy/dist/pypy/translator/js/test/test_genllvm.py pypy/dist/pypy/translator/llvm/database.py pypy/dist/pypy/translator/llvm/test/test_lladdresses.py pypy/dist/pypy/translator/llvm/test/test_symbolic.py pypy/dist/pypy/translator/stackless/transform.py pypy/dist/pypy/translator/test/test_simplify.py Log: move objectmodel Modified: pypy/dist/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/dist/pypy/annotation/bookkeeper.py Wed Nov 1 12:49:34 2006 @@ -19,7 +19,7 @@ from pypy.interpreter.argument import Arguments, ArgErr from pypy.rlib.rarithmetic import r_int, r_uint, r_ulonglong, r_longlong from pypy.rlib.rarithmetic import base_int -from pypy.rpython.objectmodel import r_dict, Symbolic +from pypy.rlib.objectmodel import r_dict, Symbolic from pypy.tool.algo.unionfind import UnionFind from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.ootypesystem import ootype Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Wed Nov 1 12:49:34 2006 @@ -16,7 +16,7 @@ from pypy.annotation import description from pypy.objspace.flow.model import Constant import pypy.rlib.rarithmetic -import pypy.rpython.objectmodel +import pypy.rlib.objectmodel import pypy.rlib.rstack # convenience only! @@ -356,13 +356,13 @@ ##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck] = rarith_ovfcheck ##BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.ovfcheck_lshift] = rarith_ovfcheck_lshift BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask -BUILTIN_ANALYZERS[pypy.rpython.objectmodel.instantiate] = robjmodel_instantiate -BUILTIN_ANALYZERS[pypy.rpython.objectmodel.we_are_translated] = ( +BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate +BUILTIN_ANALYZERS[pypy.rlib.objectmodel.we_are_translated] = ( robjmodel_we_are_translated) -BUILTIN_ANALYZERS[pypy.rpython.objectmodel.r_dict] = robjmodel_r_dict -BUILTIN_ANALYZERS[pypy.rpython.objectmodel.hlinvoke] = robjmodel_hlinvoke -BUILTIN_ANALYZERS[pypy.rpython.objectmodel.keepalive_until_here] = robjmodel_keepalive_until_here -BUILTIN_ANALYZERS[pypy.rpython.objectmodel.hint] = robjmodel_hint +BUILTIN_ANALYZERS[pypy.rlib.objectmodel.r_dict] = robjmodel_r_dict +BUILTIN_ANALYZERS[pypy.rlib.objectmodel.hlinvoke] = robjmodel_hlinvoke +BUILTIN_ANALYZERS[pypy.rlib.objectmodel.keepalive_until_here] = robjmodel_keepalive_until_here +BUILTIN_ANALYZERS[pypy.rlib.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 @@ -549,7 +549,7 @@ def robjmodel_free_non_gc_object(obj): pass -BUILTIN_ANALYZERS[pypy.rpython.objectmodel.free_non_gc_object] = ( +BUILTIN_ANALYZERS[pypy.rlib.objectmodel.free_non_gc_object] = ( robjmodel_free_non_gc_object) #_________________________________ Modified: pypy/dist/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_annrpython.py (original) +++ pypy/dist/pypy/annotation/test/test_annrpython.py Wed Nov 1 12:49:34 2006 @@ -11,7 +11,7 @@ from pypy.annotation.dictdef import DictDef from pypy.objspace.flow.model import * from pypy.rlib.rarithmetic import r_uint, base_int, r_longlong, r_ulonglong -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.objspace.flow import FlowObjSpace from pypy.translator.test import snippet Modified: pypy/dist/pypy/interpreter/error.py ============================================================================== --- pypy/dist/pypy/interpreter/error.py (original) +++ pypy/dist/pypy/interpreter/error.py Wed Nov 1 12:49:34 2006 @@ -1,5 +1,5 @@ import os, sys -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated AUTO_DEBUG = os.getenv('PYPY_DEBUG') RECORD_INTERPLEVEL_TRACEBACK = True Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Wed Nov 1 12:49:34 2006 @@ -7,7 +7,7 @@ from pypy.interpreter import pytraceback from pypy.rlib.rarithmetic import r_uint, intmask import opcode -from pypy.rpython.objectmodel import we_are_translated, instantiate +from pypy.rlib.objectmodel import we_are_translated, instantiate from pypy.rlib import rstack # for resume points @@ -633,7 +633,7 @@ def emptystack(self, frame): # propagate the exception to the caller - from pypy.rpython.objectmodel import we_are_translated + from pypy.rlib.objectmodel import we_are_translated if we_are_translated(): raise self.operr else: Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Wed Nov 1 12:49:34 2006 @@ -13,7 +13,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.opcodeorder import opcodeorder from pypy.tool.sourcetools import func_with_new_name -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.rarithmetic import intmask from pypy.tool import stdlib_opcode as pythonopcode from pypy.rlib import rstack # for resume points Modified: pypy/dist/pypy/interpreter/pyparser/ebnflexer.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/ebnflexer.py (original) +++ pypy/dist/pypy/interpreter/pyparser/ebnflexer.py Wed Nov 1 12:49:34 2006 @@ -22,7 +22,7 @@ EOF: end of file SYMDEF: a symbol definition e.g. "file_input:" STRING: a simple string "'xxx'" - SYMBOL: a rule symbol usually appeary right of a SYMDEF + SYMBOL: a rule symbol usually appearing right of a SYMDEF tokens: '[', ']', '(' ,')', '*', '+', '|' """ def __init__(self, inpstring ): Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Wed Nov 1 12:49:34 2006 @@ -8,7 +8,7 @@ from pypy.interpreter.baseobjspace import Wrappable, W_Root, ObjSpace from pypy.interpreter.error import OperationError from pypy.tool.sourcetools import compile2, func_with_new_name -from pypy.rpython.objectmodel import instantiate +from pypy.rlib.objectmodel import instantiate from pypy.rlib.rarithmetic import intmask class TypeDef: Modified: pypy/dist/pypy/jit/codegen/i386/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/i386/rgenop.py Wed Nov 1 12:49:34 2006 @@ -1,11 +1,11 @@ import sys -from pypy.rpython.objectmodel import specialize +from pypy.rlib.objectmodel import specialize from pypy.rpython.lltypesystem import lltype, llmemory from pypy.jit.codegen.i386.ri386 import * from pypy.jit.codegen.i386.codebuf import InMemoryCodeBuilder, CodeBlockOverflow from pypy.jit.codegen.model import AbstractRGenOp, GenLabel, GenBuilder from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.rpython.annlowlevel import llhelper WORD = 4 Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py (original) +++ pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ import os, sys from pypy.annotation import model as annmodel from pypy.annotation.listdef import s_list_of_strings -from pypy.rpython.objectmodel import keepalive_until_here +from pypy.rlib.objectmodel import keepalive_until_here from pypy.jit.timeshifter.test import test_timeshift from pypy.translator.c.genc import CStandaloneBuilder from pypy.rlib.unroll import unrolling_iterable Modified: pypy/dist/pypy/jit/codegen/i386/test/test_operation.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/test/test_operation.py (original) +++ pypy/dist/pypy/jit/codegen/i386/test/test_operation.py Wed Nov 1 12:49:34 2006 @@ -1,5 +1,5 @@ import py -from pypy.rpython.objectmodel import specialize +from pypy.rlib.objectmodel import specialize from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem import lltype from pypy.translator.translator import TranslationContext, graphof Modified: pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py Wed Nov 1 12:49:34 2006 @@ -1,6 +1,6 @@ from pypy.rpython.lltypesystem import lltype from pypy.rpython.llinterp import LLInterpreter -from pypy.rpython.objectmodel import keepalive_until_here +from pypy.rlib.objectmodel import keepalive_until_here from pypy.rpython.annlowlevel import MixLevelAnnotatorPolicy from pypy.translator.c.test import test_boehm from pypy.jit.codegen.i386.rgenop import RI386GenOp Modified: pypy/dist/pypy/jit/codegen/llgraph/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llgraph/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/llgraph/rgenop.py Wed Nov 1 12:49:34 2006 @@ -1,4 +1,4 @@ -from pypy.rpython.objectmodel import specialize +from pypy.rlib.objectmodel import specialize from pypy.rpython.lltypesystem import lltype from pypy.jit.codegen.model import AbstractRGenOp, GenLabel, GenBuilder from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch Modified: pypy/dist/pypy/jit/codegen/model.py ============================================================================== --- pypy/dist/pypy/jit/codegen/model.py (original) +++ pypy/dist/pypy/jit/codegen/model.py Wed Nov 1 12:49:34 2006 @@ -1,4 +1,4 @@ -from pypy.rpython.objectmodel import specialize +from pypy.rlib.objectmodel import specialize class NotConstant(Exception): Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ from pypy.jit.codegen.model import AbstractRGenOp, GenLabel, GenBuilder from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.rpython.objectmodel import specialize, we_are_translated +from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.codegen.ppc.conftest import option class Register(object): Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py ============================================================================== --- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py (original) +++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Wed Nov 1 12:49:34 2006 @@ -1,5 +1,5 @@ from pypy.rpython.annlowlevel import MixLevelAnnotatorPolicy -from pypy.rpython.objectmodel import keepalive_until_here +from pypy.rlib.objectmodel import keepalive_until_here from pypy.rpython.lltypesystem import lltype from pypy.translator.c.test import test_boehm from ctypes import c_void_p, cast, CFUNCTYPE, c_int Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Wed Nov 1 12:49:34 2006 @@ -4,7 +4,7 @@ from pypy.jit.hintannotator.bookkeeper import HintBookkeeper from pypy.jit.hintannotator.model import * from pypy.rpython.lltypesystem import lltype -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint from pypy.annotation import model as annmodel from pypy.objspace.flow import model as flowmodel from pypy.annotation.policy import AnnotatorPolicy @@ -350,7 +350,7 @@ assert hs1.contentdef.degenerated def test_degenerated_merge_cross_substructure(): - from pypy.rpython import objectmodel + from pypy.rlib import objectmodel S = lltype.Struct('S', ('n', lltype.Signed)) T = lltype.GcStruct('T', ('s', S), ('s1', S), ('n', lltype.Float)) Modified: pypy/dist/pypy/jit/llabstractinterp/test/test_llabstractinterp.py ============================================================================== --- pypy/dist/pypy/jit/llabstractinterp/test/test_llabstractinterp.py (original) +++ pypy/dist/pypy/jit/llabstractinterp/test/test_llabstractinterp.py Wed Nov 1 12:49:34 2006 @@ -7,7 +7,7 @@ from pypy.annotation import model as annmodel from pypy.jit.llabstractinterp.llabstractinterp import LLAbstractInterp, Policy from pypy.objspace.flow import model as flowmodel -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel # one day maybe py.test.skip("XXX need to be ported to the newer rgenop interface") @@ -424,7 +424,7 @@ assert insns == {'int_lt': 1, 'int_add': 1, 'int_mul': 1} def test_hint(): - from pypy.rpython.objectmodel import hint + from pypy.rlib.objectmodel import hint A = lltype.GcArray(lltype.Char, hints={'immutable': True}) def ll_interp(code): accum = 0 @@ -449,7 +449,7 @@ assert insns == {'int_add': 4, 'int_lt': 1} def test_hint_across_call(): - from pypy.rpython.objectmodel import hint + from pypy.rlib.objectmodel import hint A = lltype.GcArray(lltype.Char, hints={'immutable': True}) def ll_length(a): return len(a) @@ -478,7 +478,7 @@ assert insns == {'int_add': 4, 'int_lt': 1} def test_conditional_origin(): - from pypy.rpython.objectmodel import hint + from pypy.rlib.objectmodel import hint def ll_function(x, y, variable): result = 0 i = 0 Modified: pypy/dist/pypy/jit/llabstractinterp/test/test_vlist.py ============================================================================== --- pypy/dist/pypy/jit/llabstractinterp/test/test_vlist.py (original) +++ pypy/dist/pypy/jit/llabstractinterp/test/test_vlist.py Wed Nov 1 12:49:34 2006 @@ -4,7 +4,7 @@ from pypy.jit.llabstractinterp.test.test_llabstractinterp import summary from pypy.rpython.llinterp import LLInterpreter from pypy.rpython.lltypesystem.rstr import string_repr -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint policy = Policy(inlining=True, const_propagate=True, concrete_args=False, oopspec=True) Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Wed Nov 1 12:49:34 2006 @@ -5,9 +5,9 @@ from pypy.jit.timeshifter.test.test_timeshift import P_NOVIRTUAL from pypy.rpython.llinterp import LLInterpreter from pypy.objspace.flow.model import checkgraph, summary -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint import py.test Modified: pypy/dist/pypy/jit/timeshifter/test/test_promotion.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_promotion.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_promotion.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.timeshifter.test.test_timeshift import TimeshiftingTests from pypy.jit.timeshifter.test.test_timeshift import P_NOVIRTUAL -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint class TestPromotion(TimeshiftingTests): Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Wed Nov 1 12:49:34 2006 @@ -7,7 +7,7 @@ from pypy.jit.timeshifter import rtimeshift, rvalue from pypy.objspace.flow.model import summary from pypy.rpython.lltypesystem import lltype, llmemory, rstr -from pypy.rpython.objectmodel import hint, keepalive_until_here +from pypy.rlib.objectmodel import hint, keepalive_until_here from pypy.rlib.unroll import unrolling_iterable from pypy.rpython.annlowlevel import PseudoHighLevelCallable from pypy.rpython.module.support import LLSupport Modified: pypy/dist/pypy/jit/tl/tl.py ============================================================================== --- pypy/dist/pypy/jit/tl/tl.py (original) +++ pypy/dist/pypy/jit/tl/tl.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ import py from pypy.jit.tl.opcode import * -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint def char2int(c): t = ord(c) Modified: pypy/dist/pypy/jit/tl/tlc.py ============================================================================== --- pypy/dist/pypy/jit/tl/tlc.py (original) +++ pypy/dist/pypy/jit/tl/tlc.py Wed Nov 1 12:49:34 2006 @@ -3,7 +3,7 @@ import py from pypy.jit.tl.opcode import * from pypy.jit.tl import opcode as tlopcode -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint class Obj(object): Modified: pypy/dist/pypy/jit/tl/tlr.py ============================================================================== --- pypy/dist/pypy/jit/tl/tlr.py (original) +++ pypy/dist/pypy/jit/tl/tlr.py Wed Nov 1 12:49:34 2006 @@ -1,4 +1,4 @@ -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint MOV_A_R = 1 Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Wed Nov 1 12:49:34 2006 @@ -1,6 +1,6 @@ " a very stripped down versio of cfbolz's algorithm/automaton module " -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint from pypy.rpython.lltypesystem.lltype import GcArray, Signed, malloc class LexerError(Exception): Modified: pypy/dist/pypy/lang/automata/test/test_dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/test/test_dfa.py (original) +++ pypy/dist/pypy/lang/automata/test/test_dfa.py Wed Nov 1 12:49:34 2006 @@ -8,7 +8,7 @@ from pypy.jit.timeshifter.test.test_timeshift import P_NOVIRTUAL from pypy.rpython.llinterp import LLInterpreter from pypy.objspace.flow.model import checkgraph -from pypy.rpython.objectmodel import hint +from pypy.rlib.objectmodel import hint from pypy.lang.automata.dfa import * Modified: pypy/dist/pypy/module/__builtin__/special.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/special.py (original) +++ pypy/dist/pypy/module/__builtin__/special.py Wed Nov 1 12:49:34 2006 @@ -26,7 +26,7 @@ def _pdb(space): """Run an interp-level pdb. This is not available in translated versions of PyPy.""" - from pypy.rpython.objectmodel import we_are_translated + from pypy.rlib.objectmodel import we_are_translated if we_are_translated(): raise OperationError(space.w_NotImplementedError, space.wrap("Cannot use interp-level pdb in translated pypy")) Modified: pypy/dist/pypy/module/_pickle_support/maker.py ============================================================================== --- pypy/dist/pypy/module/_pickle_support/maker.py (original) +++ pypy/dist/pypy/module/_pickle_support/maker.py Wed Nov 1 12:49:34 2006 @@ -5,7 +5,7 @@ from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pytraceback import PyTraceback from pypy.interpreter.generator import GeneratorIterator -from pypy.rpython.objectmodel import instantiate +from pypy.rlib.objectmodel import instantiate from pypy.interpreter.argument import Arguments from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.objspace.std.dicttype import dictiter_typedef Modified: pypy/dist/pypy/module/_stackless/clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/clonable.py (original) +++ pypy/dist/pypy/module/_stackless/clonable.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, BaseCoState, Coroutine from pypy.module._stackless.interp_clonable import InterpClonableCoroutine -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.rlib.rgc import gc_swap_pool, gc_clone from pypy.module._stackless.stackless_flags import StacklessFlags Modified: pypy/dist/pypy/module/_stackless/interp_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/interp_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/interp_clonable.py Wed Nov 1 12:49:34 2006 @@ -1,6 +1,6 @@ from pypy.module._stackless.interp_coroutine import AbstractThunk, BaseCoState, Coroutine from pypy.rlib.rgc import gc_swap_pool, gc_clone -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.interpreter.error import OperationError 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 Wed Nov 1 12:49:34 2006 @@ -31,7 +31,7 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.rlib.rstack import yield_current_frame_to_caller, resume_point -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated try: from py.magic import greenlet Modified: pypy/dist/pypy/module/_weakref/interp__weakref.py ============================================================================== --- pypy/dist/pypy/module/_weakref/interp__weakref.py (original) +++ pypy/dist/pypy/module/_weakref/interp__weakref.py Wed Nov 1 12:49:34 2006 @@ -4,7 +4,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import GetSetProperty, TypeDef from pypy.interpreter.gateway import interp2app, ObjSpace -from pypy.rpython.objectmodel import cast_weakgcaddress_to_object, cast_object_to_weakgcaddress +from pypy.rlib.objectmodel import cast_weakgcaddress_to_object, cast_object_to_weakgcaddress from pypy.rpython.lltypesystem.llmemory import WEAKNULL Modified: pypy/dist/pypy/module/rsocket/rsocket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/rsocket.py (original) +++ pypy/dist/pypy/module/rsocket/rsocket.py Wed Nov 1 12:49:34 2006 @@ -11,7 +11,7 @@ # - methods makefile(), # - SSL -from pypy.rpython.objectmodel import instantiate +from pypy.rlib.objectmodel import instantiate from pypy.module.rsocket import ctypes_socket as _c from ctypes import cast, POINTER, c_char, c_char_p, pointer, byref, c_void_p from ctypes import create_string_buffer, sizeof Modified: pypy/dist/pypy/objspace/cclp/constraint/constraint.py ============================================================================== --- pypy/dist/pypy/objspace/cclp/constraint/constraint.py (original) +++ pypy/dist/pypy/objspace/cclp/constraint/constraint.py Wed Nov 1 12:49:34 2006 @@ -1,4 +1,4 @@ -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter import baseobjspace, typedef, gateway Modified: pypy/dist/pypy/objspace/cclp/misc.py ============================================================================== --- pypy/dist/pypy/objspace/cclp/misc.py (original) +++ pypy/dist/pypy/objspace/cclp/misc.py Wed Nov 1 12:49:34 2006 @@ -1,5 +1,5 @@ from pypy.interpreter import gateway, baseobjspace -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated # commonly imported there, used from types, variable, thread from pypy.module._stackless.clonable import ClonableCoroutine Modified: pypy/dist/pypy/objspace/cclp/scheduler.py ============================================================================== --- pypy/dist/pypy/objspace/cclp/scheduler.py (original) +++ pypy/dist/pypy/objspace/cclp/scheduler.py Wed Nov 1 12:49:34 2006 @@ -1,4 +1,4 @@ -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.interpreter.error import OperationError from pypy.interpreter import gateway, baseobjspace from pypy.objspace.std.listobject import W_ListObject Modified: pypy/dist/pypy/objspace/cclp/space.py ============================================================================== --- pypy/dist/pypy/objspace/cclp/space.py (original) +++ pypy/dist/pypy/objspace/cclp/space.py Wed Nov 1 12:49:34 2006 @@ -1,4 +1,4 @@ -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.interpreter import baseobjspace, gateway, argument, typedef from pypy.interpreter.function import Function from pypy.interpreter.pycode import PyCode Modified: pypy/dist/pypy/objspace/cclp/thread.py ============================================================================== --- pypy/dist/pypy/objspace/cclp/thread.py (original) +++ pypy/dist/pypy/objspace/cclp/thread.py Wed Nov 1 12:49:34 2006 @@ -1,5 +1,5 @@ from pypy.interpreter import gateway, baseobjspace, argument -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.objspace.cclp.types import W_Var, W_Future, W_FailedValue from pypy.objspace.cclp.misc import w, v, AppCoroutine, get_current_cspace Modified: pypy/dist/pypy/objspace/cclp/thunk.py ============================================================================== --- pypy/dist/pypy/objspace/cclp/thunk.py (original) +++ pypy/dist/pypy/objspace/cclp/thunk.py Wed Nov 1 12:49:34 2006 @@ -10,7 +10,7 @@ from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.listobject import W_TupleObject -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated def logic_args(args): "returns logic vars found in unpacked normalized args" Modified: pypy/dist/pypy/objspace/cclp/variable.py ============================================================================== --- pypy/dist/pypy/objspace/cclp/variable.py (original) +++ pypy/dist/pypy/objspace/cclp/variable.py Wed Nov 1 12:49:34 2006 @@ -9,7 +9,7 @@ from pypy.objspace.cclp.global_state import sched from pypy.objspace.cclp.types import deref, W_Var, W_CVar, W_Future, W_FailedValue -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated W_Root = baseobjspace.W_Root all_mms = {} Modified: pypy/dist/pypy/objspace/cpy/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/cpy/objspace.py (original) +++ pypy/dist/pypy/objspace/cpy/objspace.py Wed Nov 1 12:49:34 2006 @@ -8,7 +8,7 @@ from pypy.interpreter.function import Function from pypy.interpreter.typedef import GetSetProperty from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong -from pypy.rpython.objectmodel import we_are_translated, instantiate +from pypy.rlib.objectmodel import we_are_translated, instantiate class CPyObjSpace(baseobjspace.ObjSpace): Modified: pypy/dist/pypy/objspace/cpy/typedef.py ============================================================================== --- pypy/dist/pypy/objspace/cpy/typedef.py (original) +++ pypy/dist/pypy/objspace/cpy/typedef.py Wed Nov 1 12:49:34 2006 @@ -8,7 +8,7 @@ from pypy.interpreter.baseobjspace import Wrappable, SpaceCache from pypy.interpreter.function import Function from pypy.interpreter.typedef import GetSetProperty -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.rpython.rcpy import CPyTypeInterface, cpy_export, cpy_import from pypy.rpython.rcpy import cpy_typeobject, rpython_object, cpy_allocate from pypy.rpython.rcpy import init_rpython_data, get_rpython_data Modified: pypy/dist/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/dist/pypy/objspace/flow/framestate.py (original) +++ pypy/dist/pypy/objspace/flow/framestate.py Wed Nov 1 12:49:34 2006 @@ -1,6 +1,6 @@ from pypy.interpreter.pyframe import PyFrame, SuspendedUnroller from pypy.interpreter.error import OperationError -from pypy.rpython.objectmodel import instantiate +from pypy.rlib.objectmodel import instantiate from pypy.rlib.unroll import SpecTag from pypy.objspace.flow.model import * Modified: pypy/dist/pypy/objspace/std/dictmultiobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/dictmultiobject.py (original) +++ pypy/dist/pypy/objspace/std/dictmultiobject.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ from pypy.objspace.std.objspace import * from pypy.interpreter import gateway -from pypy.rpython.objectmodel import r_dict, we_are_translated +from pypy.rlib.objectmodel import r_dict, we_are_translated def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) Modified: pypy/dist/pypy/objspace/std/dictobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/dictobject.py (original) +++ pypy/dist/pypy/objspace/std/dictobject.py Wed Nov 1 12:49:34 2006 @@ -8,7 +8,7 @@ from pypy.objspace.std.objspace import * from pypy.interpreter import gateway -from pypy.rpython.objectmodel import r_dict +from pypy.rlib.objectmodel import r_dict class W_DictObject(W_Object): Modified: pypy/dist/pypy/objspace/std/dictstrobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/dictstrobject.py (original) +++ pypy/dist/pypy/objspace/std/dictstrobject.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ from pypy.objspace.std.objspace import * from pypy.interpreter import gateway -from pypy.rpython.objectmodel import r_dict +from pypy.rlib.objectmodel import r_dict class W_DictStrObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ from pypy.interpreter.baseobjspace import ObjSpace, Wrappable from pypy.interpreter.error import OperationError, debug_print from pypy.interpreter.typedef import get_unique_interplevel_subclass -from pypy.rpython.objectmodel import instantiate +from pypy.rlib.objectmodel import instantiate from pypy.interpreter.gateway import PyPyCacheDir from pypy.tool.cache import Cache from pypy.tool.sourcetools import func_with_new_name Modified: pypy/dist/pypy/objspace/std/setobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/setobject.py (original) +++ pypy/dist/pypy/objspace/std/setobject.py Wed Nov 1 12:49:34 2006 @@ -1,6 +1,6 @@ from pypy.objspace.std.objspace import W_Object, OperationError from pypy.objspace.std.objspace import registerimplementation, register_all -from pypy.rpython.objectmodel import r_dict +from pypy.rlib.objectmodel import r_dict from pypy.rlib.rarithmetic import intmask, r_uint from pypy.interpreter import gateway Modified: pypy/dist/pypy/objspace/std/smallintobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/smallintobject.py (original) +++ pypy/dist/pypy/objspace/std/smallintobject.py Wed Nov 1 12:49:34 2006 @@ -7,7 +7,7 @@ from pypy.rlib.rarithmetic import ovfcheck, ovfcheck_lshift, LONG_BIT, r_uint from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.intobject import W_IntObject -from pypy.rpython.objectmodel import UnboxedValue +from pypy.rlib.objectmodel import UnboxedValue # XXX this is a complete copy of intobject.py. Find a better but still # XXX annotator-friendly way to share code... Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Wed Nov 1 12:49:34 2006 @@ -3,7 +3,7 @@ from pypy.objspace.std.objspace import * from pypy.interpreter import gateway from pypy.rlib.rarithmetic import ovfcheck, _hash_string -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject from pypy.objspace.std import slicetype Modified: pypy/dist/pypy/rlib/rarithmetic.py ============================================================================== --- pypy/dist/pypy/rlib/rarithmetic.py (original) +++ pypy/dist/pypy/rlib/rarithmetic.py Wed Nov 1 12:49:34 2006 @@ -29,8 +29,9 @@ """ import math -from pypy.rpython import extregistry, objectmodel +from pypy.rpython import extregistry +from pypy.rlib import objectmodel # set up of machine internals _bits = 0 _itest = 1 Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Wed Nov 1 12:49:34 2006 @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory, lloperation, llheap from pypy.rpython.lltypesystem import rclass from pypy.rpython.ootypesystem import ootype -from pypy.rpython.objectmodel import ComputedIntSymbolic +from pypy.rlib.objectmodel import ComputedIntSymbolic import sys, os import math Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/llmemory.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/llmemory.py Wed Nov 1 12:49:34 2006 @@ -4,7 +4,7 @@ # sizeof, offsetof -from pypy.rpython.objectmodel import Symbolic +from pypy.rlib.objectmodel import Symbolic from pypy.rpython.lltypesystem import lltype class AddressOffset(Symbolic): Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ from pypy.rlib.rarithmetic import r_int, r_uint, intmask from pypy.rlib.rarithmetic import r_ulonglong, r_longlong, base_int from pypy.rlib.rarithmetic import normalizedinttype -from pypy.rpython.objectmodel import Symbolic +from pypy.rlib.objectmodel import Symbolic from pypy.tool.uid import Hashable from pypy.tool.tls import tlsobject from pypy.tool.picklesupport import getstate_with_slots, setstate_with_slots, pickleable_weakref Modified: pypy/dist/pypy/rpython/lltypesystem/opimpl.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/opimpl.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/opimpl.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem.lloperation import opimpls -from pypy.rpython.objectmodel import CDefinedIntSymbolic +from pypy.rlib.objectmodel import CDefinedIntSymbolic # ____________________________________________________________ # Implementation of the 'canfold' operations Modified: pypy/dist/pypy/rpython/lltypesystem/rbuiltin.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rbuiltin.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rbuiltin.py Wed Nov 1 12:49:34 2006 @@ -3,7 +3,7 @@ from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem import rclass from pypy.rpython.lltypesystem.rdict import rtype_r_dict -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.rpython.rmodel import TyperError, Constant from pypy.rpython.robject import pyobj_repr from pypy.rpython.rbool import bool_repr Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Wed Nov 1 12:49:34 2006 @@ -19,7 +19,7 @@ from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rpython.extregistry import ExtRegistryEntry from pypy.annotation import model as annmodel -from pypy.rpython.objectmodel import UnboxedValue +from pypy.rlib.objectmodel import UnboxedValue from pypy.rlib.rarithmetic import intmask # Modified: pypy/dist/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rdict.py Wed Nov 1 12:49:34 2006 @@ -5,9 +5,9 @@ rtype_newdict, dum_variant, dum_keys, dum_values, dum_items from pypy.rpython.lltypesystem import lltype from pypy.rlib.rarithmetic import r_uint -from pypy.rpython.objectmodel import hlinvoke +from pypy.rlib.objectmodel import hlinvoke from pypy.rpython import robject -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.rpython import rmodel # ____________________________________________________________ Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rstr.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ from weakref import WeakValueDictionary from pypy.annotation.pairtype import pairtype from pypy.rpython.error import TyperError -from pypy.rpython.objectmodel import malloc_zero_filled, we_are_translated +from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rlib.rarithmetic import _hash_string from pypy.rpython.rmodel import inputconst, IntegerRepr 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 Wed Nov 1 12:49:34 2006 @@ -525,8 +525,8 @@ class TestWeakAddressLLinterp(object): def test_null(self): - from pypy.rpython.objectmodel import cast_weakgcaddress_to_object - from pypy.rpython.objectmodel import cast_object_to_weakgcaddress + from pypy.rlib.objectmodel import cast_weakgcaddress_to_object + from pypy.rlib.objectmodel import cast_object_to_weakgcaddress class A: pass def f(): @@ -534,8 +534,8 @@ assert interpret(f, []) def test_attribute(object): - from pypy.rpython.objectmodel import cast_weakgcaddress_to_object - from pypy.rpython.objectmodel import cast_object_to_weakgcaddress + from pypy.rlib.objectmodel import cast_weakgcaddress_to_object + from pypy.rlib.objectmodel import cast_object_to_weakgcaddress class A: pass class B: Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rtagged.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/test/test_rtagged.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/test/test_rtagged.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ import sys from pypy.rpython.test.test_llinterp import interpret, get_interpreter from pypy.rpython.lltypesystem import lltype -from pypy.rpython.objectmodel import UnboxedValue +from pypy.rlib.objectmodel import UnboxedValue from pypy.translator.translator import graphof from pypy.objspace.flow.model import summary from pypy.translator.backendopt.all import backend_optimizations Modified: pypy/dist/pypy/rpython/memory/gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gc.py (original) +++ pypy/dist/pypy/rpython/memory/gc.py Wed Nov 1 12:49:34 2006 @@ -4,7 +4,7 @@ from pypy.rpython.memory.gcheader import GCHeaderBuilder from pypy.rpython.memory import lltypesimulation from pypy.rpython.lltypesystem import lltype, llmemory -from pypy.rpython.objectmodel import free_non_gc_object +from pypy.rlib.objectmodel import free_non_gc_object from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib.rarithmetic import ovfcheck Modified: pypy/dist/pypy/rpython/memory/lladdress.py ============================================================================== --- pypy/dist/pypy/rpython/memory/lladdress.py (original) +++ pypy/dist/pypy/rpython/memory/lladdress.py Wed Nov 1 12:49:34 2006 @@ -4,7 +4,7 @@ from pypy.rpython.lltypesystem import llmemory from pypy.rpython.lltypesystem import lltype from pypy.rpython.memory.lltypelayout import convert_offset_to_int -from pypy.rpython.objectmodel import ComputedIntSymbolic +from pypy.rlib.objectmodel import ComputedIntSymbolic NULL = llmemory.NULL Modified: pypy/dist/pypy/rpython/memory/support.py ============================================================================== --- pypy/dist/pypy/rpython/memory/support.py (original) +++ pypy/dist/pypy/rpython/memory/support.py Wed Nov 1 12:49:34 2006 @@ -1,6 +1,6 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.memory.lltypelayout import sizeof -from pypy.rpython.objectmodel import free_non_gc_object +from pypy.rlib.objectmodel import free_non_gc_object INT_SIZE = sizeof(lltype.Signed) 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 Wed Nov 1 12:49:34 2006 @@ -13,7 +13,7 @@ from pypy.rpython.memory import gclltype from pypy.rpython.memory.test.test_llinterpsim import interpret from pypy.rpython.memory.lladdress import simulator -from pypy.rpython.objectmodel import free_non_gc_object +from pypy.rlib.objectmodel import free_non_gc_object def setup_module(mod): def stdout_ignore_ll_functions(msg): 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 Wed Nov 1 12:49:34 2006 @@ -1,4 +1,4 @@ -from pypy.rpython.objectmodel import free_non_gc_object +from pypy.rlib.objectmodel import free_non_gc_object from pypy.rpython.memory.support import get_address_linked_list from pypy.rpython.test.test_llinterp import interpret Modified: pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py (original) +++ pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py Wed Nov 1 12:49:34 2006 @@ -12,7 +12,7 @@ ## from pypy.rpython.memory import gclltype ## from pypy.rpython.memory.test.test_llinterpsim import interpret ## from pypy.rpython.memory.lladdress import simulator -## from pypy.rpython.objectmodel import free_non_gc_object +## from pypy.rlib.objectmodel import free_non_gc_object ## def setup_module(mod): ## def stdout_ignore_ll_functions(msg): Modified: pypy/dist/pypy/rpython/normalizecalls.py ============================================================================== --- pypy/dist/pypy/rpython/normalizecalls.py (original) +++ pypy/dist/pypy/rpython/normalizecalls.py Wed Nov 1 12:49:34 2006 @@ -9,7 +9,7 @@ from pypy.tool.sourcetools import func_with_new_name from pypy.rpython.error import TyperError from pypy.rpython.rmodel import getgcflavor -from pypy.rpython.objectmodel import instantiate, ComputedIntSymbolic +from pypy.rlib.objectmodel import instantiate, ComputedIntSymbolic def normalize_call_familes(annotator): for callfamily in annotator.bookkeeper.pbc_maximal_call_families.infos(): Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Wed Nov 1 12:49:34 2006 @@ -3,7 +3,7 @@ Primitive, isCompatibleType, enforce, saferecursive, SignedLongLong, UnsignedLongLong from pypy.rpython.lltypesystem.lltype import frozendict, isCompatibleType from pypy.rlib.rarithmetic import intmask -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.tool.uid import uid try: Modified: pypy/dist/pypy/rpython/ootypesystem/rbuiltin.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rbuiltin.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rbuiltin.py Wed Nov 1 12:49:34 2006 @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem import rclass from pypy.rpython.ootypesystem.rdict import rtype_r_dict from pypy.objspace.flow.model import Constant -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.rpython.error import TyperError def rtype_new(hop): Modified: pypy/dist/pypy/rpython/ootypesystem/rdict.py ============================================================================== --- pypy/dist/pypy/rpython/ootypesystem/rdict.py (original) +++ pypy/dist/pypy/rpython/ootypesystem/rdict.py Wed Nov 1 12:49:34 2006 @@ -9,9 +9,9 @@ from pypy.rpython.ootypesystem import ootype from pypy.rpython.ootypesystem.rlist import ll_newlist from pypy.rlib.rarithmetic import r_uint -from pypy.rpython.objectmodel import hlinvoke +from pypy.rlib.objectmodel import hlinvoke from pypy.rpython import robject -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.rpython import rmodel from pypy.rpython import llinterp 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 Nov 1 12:49:34 2006 @@ -7,7 +7,7 @@ from pypy.objspace.flow import FlowObjSpace from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.test.test_llinterp import interpret -from pypy.rpython.objectmodel import r_dict +from pypy.rlib.objectmodel import r_dict from pypy.rpython.ootypesystem import ooregistry # side effects def gengraph(f, args=[], viewBefore=False, viewAfter=False): Modified: pypy/dist/pypy/rpython/raddress.py ============================================================================== --- pypy/dist/pypy/rpython/raddress.py (original) +++ pypy/dist/pypy/rpython/raddress.py Wed Nov 1 12:49:34 2006 @@ -145,7 +145,7 @@ def convert_const(self, value): from pypy.rpython.lltypesystem import llmemory - from pypy.rpython.objectmodel import cast_object_to_weakgcaddress + from pypy.rlib.objectmodel import cast_object_to_weakgcaddress from pypy.objspace.flow.model import Constant assert isinstance(value, llmemory.fakeweakaddress) if value.ref is None: Modified: pypy/dist/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/dist/pypy/rpython/rbuiltin.py (original) +++ pypy/dist/pypy/rpython/rbuiltin.py Wed Nov 1 12:49:34 2006 @@ -2,8 +2,8 @@ from pypy.annotation import model as annmodel from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem import lltype, rclass, llmemory -from pypy.rpython import objectmodel, rint, raddress -from pypy.rlib import rarithmetic, rstack +from pypy.rpython import rint, raddress +from pypy.rlib import rarithmetic, rstack, objectmodel from pypy.rpython.error import TyperError from pypy.rpython.rmodel import Repr, IntegerRepr, inputconst from pypy.rpython.rrange import rtype_builtin_range, rtype_builtin_xrange Modified: pypy/dist/pypy/rpython/rcpy.py ============================================================================== --- pypy/dist/pypy/rpython/rcpy.py (original) +++ pypy/dist/pypy/rpython/rcpy.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ from pypy.rpython.extregistry import ExtRegistryEntry from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rpython.objectmodel import CDefinedIntSymbolic +from pypy.rlib.objectmodel import CDefinedIntSymbolic from pypy.objspace.flow.model import Constant, Variable from pypy.objspace.flow.model import FunctionGraph, Block, Link Modified: pypy/dist/pypy/rpython/rdict.py ============================================================================== --- pypy/dist/pypy/rpython/rdict.py (original) +++ pypy/dist/pypy/rpython/rdict.py Wed Nov 1 12:49:34 2006 @@ -3,9 +3,9 @@ from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem import lltype from pypy.rlib.rarithmetic import r_uint -from pypy.rpython.objectmodel import hlinvoke +from pypy.rlib.objectmodel import hlinvoke from pypy.rpython import robject -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.rpython import rmodel def dum_keys(): pass Modified: pypy/dist/pypy/rpython/rint.py ============================================================================== --- pypy/dist/pypy/rpython/rint.py (original) +++ pypy/dist/pypy/rpython/rint.py Wed Nov 1 12:49:34 2006 @@ -10,7 +10,7 @@ from pypy.rlib.rarithmetic import intmask, r_int, r_uint, r_ulonglong, r_longlong from pypy.rpython.error import TyperError from pypy.rpython.rmodel import log -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel _integer_reprs = {} def getintegerrepr(lltype, prefix=None): Modified: pypy/dist/pypy/rpython/rlist.py ============================================================================== --- pypy/dist/pypy/rpython/rlist.py (original) +++ pypy/dist/pypy/rpython/rlist.py Wed Nov 1 12:49:34 2006 @@ -7,7 +7,7 @@ from pypy.rpython.lltypesystem.lltype import typeOf, Ptr, Void, Signed, Bool from pypy.rpython.lltypesystem.lltype import nullptr, Char, UniChar from pypy.rpython import robject -from pypy.rpython.objectmodel import malloc_zero_filled +from pypy.rlib.objectmodel import malloc_zero_filled from pypy.rpython.annlowlevel import ADTInterface ADTIFixedList = ADTInterface(None, { Modified: pypy/dist/pypy/rpython/test/test_nongc.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_nongc.py (original) +++ pypy/dist/pypy/rpython/test/test_nongc.py Wed Nov 1 12:49:34 2006 @@ -3,7 +3,7 @@ from pypy.annotation import model as annmodel from pypy.annotation.annrpython import RPythonAnnotator from pypy.rpython.rtyper import RPythonTyper -from pypy.rpython.objectmodel import free_non_gc_object +from pypy.rlib.objectmodel import free_non_gc_object from pypy.rpython.test.test_llinterp import interpret def test_free_non_gc_object(): Modified: pypy/dist/pypy/rpython/test/test_rbuiltin.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rbuiltin.py (original) +++ pypy/dist/pypy/rpython/test/test_rbuiltin.py Wed Nov 1 12:49:34 2006 @@ -1,6 +1,6 @@ from pypy.translator.translator import graphof from pypy.rpython.test import test_llinterp -from pypy.rpython.objectmodel import instantiate, we_are_translated +from pypy.rlib.objectmodel import instantiate, we_are_translated from pypy.rpython.lltypesystem import lltype from pypy.tool import udir from pypy.rlib.rarithmetic import r_uint, intmask Modified: pypy/dist/pypy/rpython/test/test_rconstantdict.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rconstantdict.py (original) +++ pypy/dist/pypy/rpython/test/test_rconstantdict.py Wed Nov 1 12:49:34 2006 @@ -1,5 +1,5 @@ import py -from pypy.rpython.objectmodel import r_dict +from pypy.rlib.objectmodel import r_dict from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin class BaseTestRconstantdict(BaseRtypingTest): 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 Nov 1 12:49:34 2006 @@ -1456,7 +1456,7 @@ rt.specialize() def ll_h(R, f, x): - from pypy.rpython.objectmodel import hlinvoke + from pypy.rlib.objectmodel import hlinvoke return hlinvoke(R, f, x, 2) from pypy.rpython import annlowlevel @@ -1500,7 +1500,7 @@ rt.specialize() def ll_h(R, f, x): - from pypy.rpython.objectmodel import hlinvoke + from pypy.rlib.objectmodel import hlinvoke return hlinvoke(R, f, x, 2) from pypy.rpython import annlowlevel @@ -1549,7 +1549,7 @@ rt.specialize() def ll_h(R, f, a): - from pypy.rpython.objectmodel import hlinvoke + from pypy.rlib.objectmodel import hlinvoke return hlinvoke(R, f, a) from pypy.rpython import annlowlevel @@ -1599,7 +1599,7 @@ rt.specialize() def ll_h(R, f, a): - from pypy.rpython.objectmodel import hlinvoke + from pypy.rlib.objectmodel import hlinvoke return hlinvoke(R, f, a) from pypy.rpython import annlowlevel @@ -1660,7 +1660,7 @@ rt.specialize() def ll_h(R, f, a): - from pypy.rpython.objectmodel import hlinvoke + from pypy.rlib.objectmodel import hlinvoke return hlinvoke(R, f, a) from pypy.rpython import annlowlevel 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 Wed Nov 1 12:49:34 2006 @@ -74,7 +74,7 @@ assert result def test_instantiate(): - from pypy.rpython.objectmodel import instantiate + from pypy.rlib.objectmodel import instantiate class A: pass class B(A): Modified: pypy/dist/pypy/translator/backendopt/test/test_constfold.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_constfold.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_constfold.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.llinterp import LLInterpreter from pypy.rpython.lltypesystem import lltype -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.translator.backendopt.constfold import constant_fold_graph from pypy import conftest Modified: pypy/dist/pypy/translator/backendopt/test/test_escape.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_escape.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_escape.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ from pypy.translator.backendopt.escape import AbstractDataFlowInterpreter, malloc_to_stack from pypy.translator.backendopt.support import find_backedges, find_loop_blocks from pypy.rpython.llinterp import LLInterpreter -from pypy.rpython.objectmodel import instantiate +from pypy.rlib.objectmodel import instantiate def build_adi(function, types): t = TranslationContext() 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 Wed Nov 1 12:49:34 2006 @@ -119,7 +119,7 @@ check(fn6, [int], [1], 12, must_be_removed=False) def test_with_keepalive(): - from pypy.rpython.objectmodel import keepalive_until_here + from pypy.rlib.objectmodel import keepalive_until_here def fn1(x, y): if x > 0: t = x+y, x-y Modified: pypy/dist/pypy/translator/c/gc.py ============================================================================== --- pypy/dist/pypy/translator/c/gc.py (original) +++ pypy/dist/pypy/translator/c/gc.py Wed Nov 1 12:49:34 2006 @@ -62,7 +62,7 @@ class RefcountingInfo: static_deallocator = None -from pypy.rpython.objectmodel import CDefinedIntSymbolic +from pypy.rlib.objectmodel import CDefinedIntSymbolic class RefcountingGcPolicy(BasicGcPolicy): transformerclass = refcounting.RefcountingGCTransformer Modified: pypy/dist/pypy/translator/c/primitive.py ============================================================================== --- pypy/dist/pypy/translator/c/primitive.py (original) +++ pypy/dist/pypy/translator/c/primitive.py Wed Nov 1 12:49:34 2006 @@ -1,6 +1,6 @@ import sys -from pypy.rpython.objectmodel import Symbolic, ComputedIntSymbolic -from pypy.rpython.objectmodel import CDefinedIntSymbolic +from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic +from pypy.rlib.objectmodel import CDefinedIntSymbolic from pypy.rpython.lltypesystem.lltype import * from pypy.rpython.lltypesystem.llmemory import Address, fakeaddress, \ AddressOffset, ItemOffset, ArrayItemsOffset, FieldOffset, \ Modified: pypy/dist/pypy/translator/c/test/test_backendoptimized.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_backendoptimized.py (original) +++ pypy/dist/pypy/translator/c/test/test_backendoptimized.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ import py from pypy.translator.c.test.test_typed import TestTypedTestCase as _TestTypedTestCase from pypy.translator.backendopt.all import backend_optimizations -from pypy.rpython import objectmodel +from pypy.rlib import objectmodel from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong from pypy import conftest 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 Wed Nov 1 12:49:34 2006 @@ -99,7 +99,7 @@ def test_weakgcaddress_is_weak(self): from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython.lltypesystem import lltype - from pypy.rpython.objectmodel import cast_object_to_weakgcaddress + from pypy.rlib.objectmodel import cast_object_to_weakgcaddress class State: pass s = State() 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 Wed Nov 1 12:49:34 2006 @@ -275,7 +275,7 @@ def test_keepalive(): - from pypy.rpython import objectmodel + from pypy.rlib import objectmodel def f(): x = [1] y = ['b'] Modified: pypy/dist/pypy/translator/c/test/test_lladdresses.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_lladdresses.py (original) +++ pypy/dist/pypy/translator/c/test/test_lladdresses.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ from pypy.rpython.memory.lladdress import * from pypy.annotation.model import SomeAddress, SomeChar from pypy.translator.c.test.test_genc import compile -from pypy.rpython.objectmodel import free_non_gc_object +from pypy.rlib.objectmodel import free_non_gc_object def test_null(): def f(): @@ -122,8 +122,8 @@ assert fn(1) == 2 def test_weakaddress(): - from pypy.rpython.objectmodel import cast_object_to_weakgcaddress - from pypy.rpython.objectmodel import cast_weakgcaddress_to_object + from pypy.rlib.objectmodel import cast_object_to_weakgcaddress + from pypy.rlib.objectmodel import cast_weakgcaddress_to_object from pypy.rpython.lltypesystem.lloperation import llop class A(object): pass @@ -139,8 +139,8 @@ assert fn(10) def test_constant_weakaddress(): - from pypy.rpython.objectmodel import cast_object_to_weakgcaddress - from pypy.rpython.objectmodel import cast_weakgcaddress_to_object + from pypy.rlib.objectmodel import cast_object_to_weakgcaddress + from pypy.rlib.objectmodel import cast_weakgcaddress_to_object from pypy.rpython.lltypesystem.lloperation import llop class A(object): 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 Nov 1 12:49:34 2006 @@ -8,7 +8,7 @@ from pypy.translator.c import genc, gc from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.lltypesystem.lloperation import llop -from pypy.rpython.objectmodel import cast_weakgcaddress_to_object, cast_object_to_weakgcaddress +from pypy.rlib.objectmodel import cast_weakgcaddress_to_object, cast_object_to_weakgcaddress from pypy.config.config import Config from pypy.config.pypyoption import pypy_optiondescription from pypy import conftest Modified: pypy/dist/pypy/translator/c/test/test_rtagged.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_rtagged.py (original) +++ pypy/dist/pypy/translator/c/test/test_rtagged.py Wed Nov 1 12:49:34 2006 @@ -1,5 +1,5 @@ import sys, os -from pypy.rpython.objectmodel import UnboxedValue +from pypy.rlib.objectmodel import UnboxedValue class A(object): Modified: pypy/dist/pypy/translator/c/test/test_symbolic.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_symbolic.py (original) +++ pypy/dist/pypy/translator/c/test/test_symbolic.py Wed Nov 1 12:49:34 2006 @@ -2,7 +2,7 @@ from pypy import conftest from pypy.rpython.lltypesystem import llmemory, lltype from pypy.rpython.memory import lladdress -from pypy.rpython.objectmodel import ComputedIntSymbolic +from pypy.rlib.objectmodel import ComputedIntSymbolic def getcompiled(f, args): t = Translation(f) 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 Wed Nov 1 12:49:34 2006 @@ -711,7 +711,7 @@ assert fn(1) == 42 def test_r_dict_exceptions(self): - from pypy.rpython.objectmodel import r_dict + from pypy.rlib.objectmodel import r_dict def raising_hash(obj): if obj.startswith("bla"): Modified: pypy/dist/pypy/translator/cli/database.py ============================================================================== --- pypy/dist/pypy/translator/cli/database.py (original) +++ pypy/dist/pypy/translator/cli/database.py Wed Nov 1 12:49:34 2006 @@ -15,7 +15,7 @@ from pypy.rpython.lltypesystem import llmemory from pypy.translator.cli.opcodes import opcodes from pypy.translator.cli import dotnet -from pypy.rpython.objectmodel import CDefinedIntSymbolic +from pypy.rlib.objectmodel import CDefinedIntSymbolic try: set Modified: pypy/dist/pypy/translator/cli/test/test_constant.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_constant.py (original) +++ pypy/dist/pypy/translator/cli/test/test_constant.py Wed Nov 1 12:49:34 2006 @@ -100,7 +100,7 @@ assert self.interpret(fn2, [1]) == True def test_customdict_circular(self): - from pypy.rpython.objectmodel import r_dict + from pypy.rlib.objectmodel import r_dict def key_eq(a, b): return a.x[0] == b.x[0] def key_hash(a): Modified: pypy/dist/pypy/translator/cli/test/test_objectmodel.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_objectmodel.py (original) +++ pypy/dist/pypy/translator/cli/test/test_objectmodel.py Wed Nov 1 12:49:34 2006 @@ -1,8 +1,8 @@ import py from pypy.translator.cli.test.runtest import CliTest -from pypy.rpython.test.test_objectmodel import BaseTestObjectModel +from pypy.rlib.test.test_objectmodel import BaseTestObjectModel -from pypy.rpython.objectmodel import cast_object_to_weakgcaddress,\ +from pypy.rlib.objectmodel import cast_object_to_weakgcaddress,\ cast_weakgcaddress_to_object def skip_r_dict(self): @@ -12,7 +12,7 @@ test_rtype_r_dict_bm = skip_r_dict def test_rdict_of_void_copy(self): - from pypy.rpython.test.test_objectmodel import r_dict, strange_key_eq, strange_key_hash + from pypy.rlib.test.test_objectmodel import r_dict, strange_key_eq, strange_key_hash def fn(): d = r_dict(strange_key_eq, strange_key_hash) d['hello'] = None @@ -22,7 +22,7 @@ assert self.interpret(fn, []) == 2 # this test is copied from TestLLtype in - # rpython/test_objectmodel.py. It is not in TestOOtype because at + # rlib/test_objectmodel.py. It is not in TestOOtype because at # the moment llinterpret can't handle cast_*weakadr* def test_cast_to_and_from_weakaddress(self): class A(object): Modified: pypy/dist/pypy/translator/js/jts.py ============================================================================== --- pypy/dist/pypy/translator/js/jts.py (original) +++ pypy/dist/pypy/translator/js/jts.py Wed Nov 1 12:49:34 2006 @@ -9,7 +9,7 @@ from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong, Primitive from pypy.rpython.lltypesystem.lltype import Char, UniChar from pypy.rpython.ootypesystem.ootype import String, _string, List, StaticMethod -from pypy.rpython.objectmodel import Symbolic +from pypy.rlib.objectmodel import Symbolic from pypy.translator.js.log import log Modified: pypy/dist/pypy/translator/js/test/test_genllvm.py ============================================================================== --- pypy/dist/pypy/translator/js/test/test_genllvm.py (original) +++ pypy/dist/pypy/translator/js/test/test_genllvm.py Wed Nov 1 12:49:34 2006 @@ -436,7 +436,7 @@ assert fn() == some_test() def test_symbolic(): - from pypy.rpython.objectmodel import malloc_zero_filled + from pypy.rlib.objectmodel import malloc_zero_filled def symbolic1(): if malloc_zero_filled: Modified: pypy/dist/pypy/translator/llvm/database.py ============================================================================== --- pypy/dist/pypy/translator/llvm/database.py (original) +++ pypy/dist/pypy/translator/llvm/database.py Wed Nov 1 12:49:34 2006 @@ -14,8 +14,8 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.objspace.flow.model import Constant, Variable from pypy.rpython.memory.lladdress import NULL -from pypy.rpython.objectmodel import Symbolic, ComputedIntSymbolic -from pypy.rpython.objectmodel import CDefinedIntSymbolic +from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic +from pypy.rlib.objectmodel import CDefinedIntSymbolic log = log.database Modified: pypy/dist/pypy/translator/llvm/test/test_lladdresses.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/test_lladdresses.py (original) +++ pypy/dist/pypy/translator/llvm/test/test_lladdresses.py Wed Nov 1 12:49:34 2006 @@ -1,7 +1,7 @@ import py from pypy.rpython.memory.lladdress import * from pypy.annotation.model import SomeAddress, SomeChar -from pypy.rpython.objectmodel import free_non_gc_object +from pypy.rlib.objectmodel import free_non_gc_object from pypy.translator.llvm.test.runtest import * @@ -171,8 +171,8 @@ assert f() == 579 def test_weakaddress(): - from pypy.rpython.objectmodel import cast_object_to_weakgcaddress - from pypy.rpython.objectmodel import cast_weakgcaddress_to_object + from pypy.rlib.objectmodel import cast_object_to_weakgcaddress + from pypy.rlib.objectmodel import cast_weakgcaddress_to_object from pypy.rpython.lltypesystem.lloperation import llop class A(object): pass Modified: pypy/dist/pypy/translator/llvm/test/test_symbolic.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/test_symbolic.py (original) +++ pypy/dist/pypy/translator/llvm/test/test_symbolic.py Wed Nov 1 12:49:34 2006 @@ -3,7 +3,7 @@ from pypy import conftest from pypy.rpython.lltypesystem import llmemory, lltype from pypy.rpython.memory import lladdress -from pypy.rpython.objectmodel import ComputedIntSymbolic +from pypy.rlib.objectmodel import ComputedIntSymbolic from pypy.translator.llvm.test.runtest import * Modified: pypy/dist/pypy/translator/stackless/transform.py ============================================================================== --- pypy/dist/pypy/translator/stackless/transform.py (original) +++ pypy/dist/pypy/translator/stackless/transform.py Wed Nov 1 12:49:34 2006 @@ -13,7 +13,7 @@ from pypy.rpython.rbuiltin import gen_cast from pypy.rpython.rtyper import LowLevelOpList from pypy.rpython.module import ll_stackless, ll_stack -from pypy.rpython.objectmodel import ComputedIntSymbolic +from pypy.rlib.objectmodel import ComputedIntSymbolic from pypy.translator.backendopt import graphanalyze from pypy.translator.stackless.frame import SAVED_REFERENCE, STORAGE_TYPES 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 Wed Nov 1 12:49:34 2006 @@ -76,7 +76,7 @@ def test_remove_pointless_keepalive(): - from pypy.rpython import objectmodel + from pypy.rlib import objectmodel class C: y = None z1 = None From fijal at codespeak.net Wed Nov 1 12:51:08 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 1 Nov 2006 12:51:08 +0100 (CET) Subject: [pypy-svn] r34002 - pypy/branch/transparent-proxy Message-ID: <20061101115108.089D610060@code0.codespeak.net> Author: fijal Date: Wed Nov 1 12:51:07 2006 New Revision: 34002 Added: pypy/branch/transparent-proxy/ - copied from r34001, pypy/dist/ Log: Branch for work on transparent proxy objspace. From cfbolz at codespeak.net Wed Nov 1 12:52:09 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 12:52:09 +0100 (CET) Subject: [pypy-svn] r34003 - pypy/dist/pypy/lang/automata/test Message-ID: <20061101115209.3067010060@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 12:52:08 2006 New Revision: 34003 Modified: pypy/dist/pypy/lang/automata/test/test_dfa.py Log: fix whitespace, docstring Modified: pypy/dist/pypy/lang/automata/test/test_dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/test/test_dfa.py (original) +++ pypy/dist/pypy/lang/automata/test/test_dfa.py Wed Nov 1 12:52:08 2006 @@ -1,10 +1,10 @@ import py from pypy import conftest -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret from pypy.translator.translator import graphof from pypy.jit.timeshifter.test.test_timeshift import hannotate -from pypy.jit.timeshifter.rtyper import HintRTyper +from pypy.jit.timeshifter.hrtyper import HintRTyper from pypy.jit.timeshifter.test.test_timeshift import P_NOVIRTUAL from pypy.rpython.llinterp import LLInterpreter from pypy.objspace.flow.model import checkgraph From ericvrp at codespeak.net Wed Nov 1 12:59:21 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 1 Nov 2006 12:59:21 +0100 (CET) Subject: [pypy-svn] r34006 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061101115921.9566910060@code0.codespeak.net> Author: ericvrp Date: Wed Nov 1 12:59:19 2006 New Revision: 34006 Modified: pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/setup.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: (mwh, ericvrp) called a simple function from the library with test and proper skip Modified: pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp Wed Nov 1 12:59:19 2006 @@ -1,5 +1,7 @@ //implementation for using the LLVM JIT +#include "llvmjit.h" + int testme(int n) { return n * 2; } Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Wed Nov 1 12:59:19 2006 @@ -7,3 +7,11 @@ This file contains the ctypes specification to use the llvmjit library! ''' +import ctypes +import os + +path = os.path.join(os.path.dirname(__file__), 'llvmjit_.so') +llvmjit = ctypes.cdll.LoadLibrary(os.path.abspath(path)) + +def testme(n): + return llvmjit.testme(n) Modified: pypy/dist/pypy/jit/codegen/llvm/setup.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/setup.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/setup.py Wed Nov 1 12:59:19 2006 @@ -6,7 +6,7 @@ ldflags = popen('llvm-config --ldflags').readline().split() libs = popen('llvm-config --libs all').readline().split() -opts = dict(name='llvmjit', +opts = dict(name='llvmjit_', sources=['lib/llvmjit.cpp'], libraries=[], include_dirs =["include"] + [f[2:] for f in cxxflags if f.startswith('-I')], Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Wed Nov 1 12:59:19 2006 @@ -0,0 +1,9 @@ +import py + +try: + from pypy.jit.codegen.llvm import llvmjit +except OSError: + py.test.skip("llvmjit library not found (see ../README.TXT)") + +def test_testme(): + assert llvmjit.testme(10) == 20 From ale at codespeak.net Wed Nov 1 13:06:39 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Wed, 1 Nov 2006 13:06:39 +0100 (CET) Subject: [pypy-svn] r34007 - pypy/dist/pypy/lib/pyontology Message-ID: <20061101120639.5D21110068@code0.codespeak.net> Author: ale Date: Wed Nov 1 13:06:38 2006 New Revision: 34007 Modified: pypy/dist/pypy/lib/pyontology/pyontology.py Log: Made the optimisation work for more cases Modified: pypy/dist/pypy/lib/pyontology/pyontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/pyontology.py (original) +++ pypy/dist/pypy/lib/pyontology/pyontology.py Wed Nov 1 13:06:38 2006 @@ -600,8 +600,11 @@ else: obj = trip[2] prop = self.variables[prop_name] - prop.setValues(list(self.variables['rdf_Property'].getValues())) # Get all properties by looking at 'rdf_Property' + props = list(self.variables['rdf_Property'].getValues()) + prop.setValues(props) + for p in props: + query_dom[p] = self.variables[p] # add a constraint trip[0] in domains[prop] and trip[2] in domains[prop].getValuesPrKey(trip[0]) query_constr.append(PropertyConstrain(prop_name, indi, obj)) @@ -624,7 +627,10 @@ sub = self.variables[sub_name] sub.setValues(list(self.variables['owl_Thing'].getValues())) prop = self.variables[prop_name] - prop.setValues(list(self.variables['rdf_Property'].getValues())) + props = list(self.variables['rdf_Property'].getValues()) + prop.setValues(props) + for p in props: + query_dom[p] = self.variables[p] obj_name = self.mangle_name(trip[2]) if obj_name in self.variables: obj = self.variables[self.mangle_name(trip[2])] @@ -661,10 +667,12 @@ query_constr.append(con) # call finish on the variables in the query for v in vars: - query_dom, _ = self.variables[self.mangle_name(v)].finish(self.variables, query_constr) #query_dom, query_constr) + _dom, _ = self.variables[self.mangle_name(v)].finish(self.variables, query_constr) #query_dom, query_constr) + query_dom.update(_dom) # Build a repository with the variables in the query dom = dict([(self.mangle_name(v),self.variables[self.mangle_name(v)]) for v in vars]) + dom.update(query_dom) # solve the repository and return the solution rep = Repository(dom.keys(), dom, query_constr) res_s = Solver().solve(rep) From rxe at codespeak.net Wed Nov 1 13:09:56 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Nov 2006 13:09:56 +0100 (CET) Subject: [pypy-svn] r34008 - pypy/dist/pypy/jit/llabstractinterp Message-ID: <20061101120956.A71F110068@code0.codespeak.net> Author: rxe Date: Wed Nov 1 13:09:56 2006 New Revision: 34008 Removed: pypy/dist/pypy/jit/llabstractinterp/ Log: kill some dead code - help people reading the jit code for the first time From ac at codespeak.net Wed Nov 1 13:13:24 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 1 Nov 2006 13:13:24 +0100 (CET) Subject: [pypy-svn] r34009 - pypy/dist/pypy/jit/timeshifter/test Message-ID: <20061101121324.D70A21006E@code0.codespeak.net> Author: ac Date: Wed Nov 1 13:13:23 2006 New Revision: 34009 Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/jit/timeshifter/test/test_promotion.py pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Log: Move a test using the _dont_cache_ hack to use a portal and remove the hack. Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Wed Nov 1 13:13:23 2006 @@ -130,3 +130,42 @@ res = self.timeshift_from_portal(main, recognizetable, [0], policy=P_NOVIRTUAL) assert res >= 0 + + def test_method_call_promote(self): + class Base(object): + pass + class Int(Base): + def __init__(self, n): + self.n = n + def double(self): + return Int(self.n * 2) + def get(self): + return self.n + class Str(Base): + def __init__(self, s): + self.s = s + def double(self): + return Str(self.s + self.s) + def get(self): + return ord(self.s[4]) + + def ll_make(n): + if n > 0: + return Int(n) + else: + return Str('123') + + def ll_function(n): + hint(None, global_merge_point=True) + o = ll_make(n) + hint(o.__class__, promote=True) + return o.double().get() + + res = self.timeshift_from_portal(ll_function, ll_function, [5], policy=P_NOVIRTUAL) + assert res == 10 + self.check_insns(indirect_call=0) + + res = self.timeshift_from_portal(ll_function, ll_function, [0], policy=P_NOVIRTUAL) + assert res == ord('2') + self.check_insns(indirect_call=0) + Modified: pypy/dist/pypy/jit/timeshifter/test/test_promotion.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_promotion.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_promotion.py Wed Nov 1 13:13:23 2006 @@ -223,45 +223,6 @@ self.check_insns(indirect_call=2) - def test_method_call_promote(self): - class Base(object): - pass - class Int(Base): - def __init__(self, n): - self.n = n - def double(self): - return Int(self.n * 2) - def get(self): - return self.n - class Str(Base): - def __init__(self, s): - self.s = s - def double(self): - return Str(self.s + self.s) - def get(self): - return ord(self.s[4]) - - def ll_make(n): - if n > 0: - return Int(n) - else: - return Str('123') - - def ll_function(n): - hint(None, global_merge_point=True) - o = ll_make(n) - hint(o.__class__, promote=True) - return o.double().get() - ll_function._dont_cache_ = True - - res = self.timeshift(ll_function, [5], [], policy=P_NOVIRTUAL) - assert res == 10 - self.check_insns(indirect_call=0) - - res = self.timeshift(ll_function, [0], [], policy=P_NOVIRTUAL) - assert res == ord('2') - self.check_insns(indirect_call=0) - def test_mixed_merges(self): def ll_function(x, y, z, k): if x: Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Wed Nov 1 13:13:23 2006 @@ -222,14 +222,9 @@ from pypy.translator.tool.graphpage import FlowGraphPage FlowGraphPage(t, ha.translator.graphs).display() - if getattr(ll_function, '_dont_cache_', False): - # XXX TEMPORARY: for now, caching doesn't work in the presence - # of global caches - pass - else: - cache = self.__dict__.copy() - self._cache[key] = cache, getargtypes(rtyper.annotator, values) - self._cache_order.append(key) + cache = self.__dict__.copy() + self._cache[key] = cache, getargtypes(rtyper.annotator, values) + self._cache_order.append(key) return values def annotate_interface_functions(self): From cfbolz at codespeak.net Wed Nov 1 13:24:12 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 13:24:12 +0100 (CET) Subject: [pypy-svn] r34010 - in pypy/dist/pypy/config: . test Message-ID: <20061101122412.9001A10077@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 13:24:11 2006 New Revision: 34010 Modified: pypy/dist/pypy/config/config.py pypy/dist/pypy/config/test/test_config.py Log: (cfbolz, pedronis and arigo discussing) add copy method Modified: pypy/dist/pypy/config/config.py ============================================================================== --- pypy/dist/pypy/config/config.py (original) +++ pypy/dist/pypy/config/config.py Wed Nov 1 13:24:11 2006 @@ -31,6 +31,25 @@ homeconfig, name = self._cfgimpl_get_home_by_path(name) homeconfig.setoption(name, value, 'default') + def copy(self, as_default=False, parent=None): + result = Config.__new__(self.__class__) + result._cfgimpl_descr = self._cfgimpl_descr + result._cfgimpl_value_owners = owners = {} + result._cfgimpl_parent = parent + result._cfgimpl_values = v = {} + for child in self._cfgimpl_descr._children: + if isinstance(child, Option): + v[child._name] = self._cfgimpl_values[child._name] + if as_default: + owners[child._name] = 'default' + else: + owners[child._name] = ( + self._cfgimpl_value_owners[child._name]) + elif isinstance(child, OptionDescription): + v[child._name] = self._cfgimpl_values[child._name].copy( + as_default, parent=result) + return result + def __setattr__(self, name, value): if self._cfgimpl_frozen and getattr(self, name) != value: raise TypeError("trying to change a frozen option object") Modified: pypy/dist/pypy/config/test/test_config.py ============================================================================== --- pypy/dist/pypy/config/test/test_config.py (original) +++ pypy/dist/pypy/config/test/test_config.py Wed Nov 1 13:24:11 2006 @@ -424,3 +424,23 @@ d = make_dict(config) assert d == {"s1.a": True, "int": 43} +def test_copy(): + descr = OptionDescription("opt", "", [ + OptionDescription("s1", "", [ + BoolOption("a", "", default=False)]), + IntOption("int", "", default=42)]) + c1 = Config(descr) + c1.int = 43 + c2 = c1.copy() + assert c2.int == 43 + assert not c2.s1.a + c2.s1.a = True + assert c2.s1.a + py.test.raises(ValueError, "c2.int = 44") + c2 = c1.copy(as_default=True) + assert c2.int == 43 + assert not c2.s1.a + c2.s1.a = True + assert c2.s1.a + c2.int = 44 # does not crash + From arigo at codespeak.net Wed Nov 1 13:30:28 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 1 Nov 2006 13:30:28 +0100 (CET) Subject: [pypy-svn] r34011 - pypy/dist/pypy/lang/js/js Message-ID: <20061101123028.BF19410079@code0.codespeak.net> Author: arigo Date: Wed Nov 1 13:30:27 2006 New Revision: 34011 Modified: pypy/dist/pypy/lang/js/js/jsparse.js Log: (fijal, arigo) Hate hate hate JavaScript. Modified: pypy/dist/pypy/lang/js/js/jsparse.js ============================================================================== --- pypy/dist/pypy/lang/js/js/jsparse.js (original) +++ pypy/dist/pypy/lang/js/js/jsparse.js Wed Nov 1 13:30:27 2006 @@ -284,7 +284,7 @@ var s = "{\n" + INDENTATION.repeat(n) + "'type': '" + tokenstr(this.type) + "'"; for (i = 0; i < a.length; i++) { val = a[i].value + ""; - if (val.search("},{") != -1) { + if (val.search("\\},\\{") != -1) { s += ",\n" + INDENTATION.repeat(n) + "'" + a[i].id + "': [" + val + "]"; } else { if (val.search("\n") != -1) { From ericvrp at codespeak.net Wed Nov 1 13:41:40 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 1 Nov 2006 13:41:40 +0100 (CET) Subject: [pypy-svn] r34012 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061101124140.16B2D10079@code0.codespeak.net> Author: ericvrp Date: Wed Nov 1 13:41:39 2006 New Revision: 34012 Added: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp - copied, changed from r34006, pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h - copied unchanged from r34000, pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.h Removed: pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/llvmjit.h Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/setup.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: (mwh, ericvrp) translation of the c-api lib works Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Wed Nov 1 13:41:39 2006 @@ -6,12 +6,20 @@ This file contains the ctypes specification to use the llvmjit library! ''' +from pypy.rpython.rctypes import implementation import ctypes import os -path = os.path.join(os.path.dirname(__file__), 'llvmjit_.so') +path = os.path.join(os.path.dirname(__file__), 'libllvmjit.so') llvmjit = ctypes.cdll.LoadLibrary(os.path.abspath(path)) +class _FuncPtr(ctypes._CFuncPtr): + _flags_ = ctypes._FUNCFLAG_CDECL + # aaarghdistutilsunixaaargh (may need something different for standalone builds...) + libraries = (os.path.join(os.path.dirname(path), 'llvmjit'),) +llvmjit._FuncPtr = _FuncPtr -def testme(n): - return llvmjit.testme(n) +#impls +testme = llvmjit.testme +testme.restype = ctypes.c_int +testme.argtypes = [ctypes.c_int] Modified: pypy/dist/pypy/jit/codegen/llvm/setup.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/setup.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/setup.py Wed Nov 1 13:41:39 2006 @@ -2,12 +2,14 @@ from distutils.extension import Extension from os import popen +#Create llvm c api library by running "python setup.py build_ext -i" here + 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='llvmjit_', - sources=['lib/llvmjit.cpp'], +opts = dict(name='libllvmjit', + sources=['lib/libllvmjit.cpp'], libraries=[], include_dirs =["include"] + [f[2:] for f in cxxflags if f.startswith('-I')], library_dirs =[f[2:] for f in ldflags if f.startswith('-L')], Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Wed Nov 1 13:41:39 2006 @@ -1,4 +1,5 @@ import py +from pypy.translator.c.test.test_genc import compile try: from pypy.jit.codegen.llvm import llvmjit @@ -7,3 +8,10 @@ def test_testme(): assert llvmjit.testme(10) == 20 + +def test_testme_compile(): + def f(x): + return llvmjit.testme(20+x) + fn = compile(f, [int]) + res = fn(1) + assert res == 42 From rxe at codespeak.net Wed Nov 1 13:42:03 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Nov 2006 13:42:03 +0100 (CET) Subject: [pypy-svn] r34014 - in pypy/dist/pypy/lang/automata: . test Message-ID: <20061101124203.006291007D@code0.codespeak.net> Author: rxe Date: Wed Nov 1 13:42:03 2006 New Revision: 34014 Modified: pypy/dist/pypy/lang/automata/dfa.py pypy/dist/pypy/lang/automata/test/test_dfa.py Log: simplify, cleanup and add final states check on recognizetable() Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Wed Nov 1 13:42:03 2006 @@ -1,43 +1,19 @@ -" a very stripped down versio of cfbolz's algorithm/automaton module " +" a very stripped down version of cfbolz's algorithm/automaton module " from pypy.rlib.objectmodel import hint from pypy.rpython.lltypesystem.lltype import GcArray, Signed, malloc -class LexerError(Exception): - def __init__(self, input, state, index): - self.input = input - self.state = state - self.index = index - self.args = (input, state, index) - class DFA(object): - def __init__(self, num_states=0, transitions=None, final_states=None, - names=None): + def __init__(self, num_states=0, transitions=None, final_states=None): self.num_states = 0 - if transitions is None: - transitions = {} - if final_states is None: - final_states = {} - if names is None: - names = [] - self.transitions = transitions - self.final_states = final_states - self.names = names - - def __repr__(self): - from pprint import pformat - return "DFA%s" % (pformat(( - self.num_states, self.transitions, self.final_states, - self.names)), ) + self.transitions = {} + self.final_states = {} - def add_state(self, name=None, final=False): + def add_state(self, final=False): state = self.num_states self.num_states += 1 if final: self.final_states[state] = None - if name is None: - name = str(state) - self.names.append(name) return self.num_states - 1 def add_transition(self, state, input, next_state): @@ -46,22 +22,21 @@ def get_transition(self, state, input): return self.transitions[state, input] - def contains(self, (state, input)): - return (state, input) in self.transitions - - def get_all_chars(self): + def get_language(self): all_chars = {} for state, input in self.transitions: - all_chars.add(input) + all_chars[input] = None return all_chars - def get_runner(self): - return DFARunner(self) + def __repr__(self): + from pprint import pformat + return "DFA%s" % (pformat( + self.num_states, self.transitions, self.final_states)) def getautomaton(): - # simple example of handcrafted dfa + " simple example of handcrafted dfa " a = DFA() - s0 = a.add_state("start") + s0 = a.add_state() s1 = a.add_state() s2 = a.add_state(final=True) a.add_transition(s0, "a", s0) @@ -71,6 +46,7 @@ return a def recognize(automaton, s): + " a simple recognizer " state = 0 try: for char in s: @@ -80,53 +56,20 @@ return state in automaton.final_states -#________________________________________________________________________________ - -# lower level version - more amenable to JIT - -# an earlier version to keep around, based of GcArray - -# A = GcArray(Signed, hints={'immutable': True}) -# def convertdfa(automaton): -# automaton.transitions -# size = automaton.num_states * 256 -# dfatable = malloc(A, size) -# for ii in range(size): -# dfatable[ii] = -1 -# for (s, c), r in automaton.transitions.items(): -# dfatable[s * 256 + ord(c)] = r -# return dfatable - -# def recognizetable(dfatable, s): -# state = 0 -# indx = 0 -# while True: -# hint(None, global_merge_point=True) -# if indx >= len(s): -# break -# c = s[indx] -# c = hint(c, promote=True) -# state = dfatable[state * 256 + ord(c)] -# hint(state, concrete=True) -# if state < 0: -# break -# indx += 1 -# return hint(state, variable=True) - -#________________________________________________________________________________ - -# another lower level version - more amenable to JIT, this time converts -# nice automata class to a table, represented as a big string - def convertdfa(automaton): - automaton.transitions + """ converts the dfa transitions into a table, represented as a big string. + this is just to make the code more amenable to current state of the JIT. Returns + a two tuple of dfa as table, and final states""" + size = automaton.num_states * 256 dfatable = [chr(255)] * size for (s, c), r in automaton.transitions.items(): dfatable[s * 256 + ord(c)] = chr(r) - return "".join(dfatable) + dfatable = "".join(dfatable) + final_states = "".join([chr(fs) for fs in automaton.final_states]) + return dfatable, final_states -def recognizetable(dfatable, s): +def recognizetable(dfatable, s, finalstates): state = 0 indx = 0 while True: @@ -140,4 +83,10 @@ if state == 255: break indx += 1 - return hint(state, variable=True) + state = hint(state, variable=True) + + # more strange code for now - check final state? + for fs in finalstates: + if state == ord(fs): + return 1 + return 0 Modified: pypy/dist/pypy/lang/automata/test/test_dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/test/test_dfa.py (original) +++ pypy/dist/pypy/lang/automata/test/test_dfa.py Wed Nov 1 13:42:03 2006 @@ -14,11 +14,17 @@ def rundfa(): a = getautomaton() + assert 'a' in a.get_language() + assert 'b' in a.get_language() + assert 'c' in a.get_language() + assert 'd' not in a.get_language() + assert recognize(a, "aaaaaaaaaab") assert recognize(a, "b") + assert recognize(a, "aaaacb") + assert not recognize(a, "a") assert not recognize(a, "xyza") - assert recognize(a, "aaaacb") def test_dfa_simple(): rundfa() @@ -29,65 +35,9 @@ def test_dfa_compiledummy(): def main(gets): a = getautomaton() - dfatable = convertdfa(a) + dfatable, final_states = convertdfa(a) s = ["aaaaaaaaaab", "aaaa"][gets] - return recognizetable(dfatable, s) - - interpret(main, [0]) + return recognizetable(dfatable, s, final_states) + assert interpret(main, [0]) + assert not interpret(main, [1]) -# class TestWithPortal(object): -# from pypy.jit.codegen.llgraph.rgenop import RGenOp - -# def setup_class(cls): -# cls._cache = {} -# cls._cache_order = [] - -# def teardown_class(cls): -# del cls._cache -# del cls._cache_order - -# def timeshift_from_portal(self, main, portal, main_args, -# inline=None, policy=None, -# backendoptimize=False): - -# key = main, portal, inline, policy, backendoptimize -# try: -# maingraph, rtyper = self._cache[key] -# except KeyError: -# if len(self._cache_order) >= 3: -# del self._cache[self._cache_order.pop(0)] - -# hs, ha, rtyper = hannotate(main, main_args, portal=portal, -# policy=policy, inline=inline, -# backendoptimize=backendoptimize) - -# t = rtyper.annotator.translator -# maingraph = graphof(t, main) -# # make the timeshifted graphs -# hrtyper = HintRTyper(ha, rtyper, self.RGenOp) -# origportalgraph = graphof(t, portal) -# hrtyper.specialize(origportalgraph=origportalgraph, -# view = conftest.option.view) - -# for graph in ha.translator.graphs: -# checkgraph(graph) -# t.graphs.append(graph) - -# if conftest.option.view: -# t.view() - -# self._cache[key] = maingraph, rtyper -# self._cache_order.append(key) - -# llinterp = LLInterpreter(rtyper) -# return llinterp.eval_graph(maingraph, main_args) - -# def test_dfa_compile(self): -# def main(gets): -# a = getautomaton() -# dfatable = convertdfa(a) -# s = ["aaaaaaaaaab", "aaaa"][gets] -# return recognizetable(dfatable, s) - -# res = self.timeshift_from_portal(main, recognizetable, [0], policy=P_NOVIRTUAL) -# assert res >= 0 From cfbolz at codespeak.net Wed Nov 1 13:42:07 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 13:42:07 +0100 (CET) Subject: [pypy-svn] r34013 - pypy/dist/pypy/translator/oosupport/test_template Message-ID: <20061101124207.443051007D@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 13:42:00 2006 New Revision: 34013 Modified: pypy/dist/pypy/translator/oosupport/test_template/ (props changed) pypy/dist/pypy/translator/oosupport/test_template/snippets.py (props changed) Log: fixeol From cfbolz at codespeak.net Wed Nov 1 13:43:38 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 13:43:38 +0100 (CET) Subject: [pypy-svn] r34015 - in pypy/dist/pypy/translator: . backendopt backendopt/test c/test llvm Message-ID: <20061101124338.F24AF1007B@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 13:43:37 2006 New Revision: 34015 Modified: pypy/dist/pypy/translator/backendopt/all.py pypy/dist/pypy/translator/backendopt/test/test_all.py pypy/dist/pypy/translator/backendopt/test/test_merge_if_blocks.py pypy/dist/pypy/translator/backendopt/test/test_removenoops.py pypy/dist/pypy/translator/c/test/test_backendoptimized.py pypy/dist/pypy/translator/driver.py pypy/dist/pypy/translator/llvm/genllvm.py Log: (cfbolz, arigo and pedronis discussing) fix failing backend optimization tests Modified: pypy/dist/pypy/translator/backendopt/all.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/all.py (original) +++ pypy/dist/pypy/translator/backendopt/all.py Wed Nov 1 13:43:37 2006 @@ -11,25 +11,14 @@ from pypy.translator.backendopt.support import log from pypy.objspace.flow.model import checkgraph -def backend_optimizations(translator, graphs=None, - raisingop2direct_call_all=False, - inline_threshold=1, - mallocs=True, - merge_if_blocks_to_switch=True, - constfold=True, - heap2stack=False, - clever_malloc_removal=False): - - config = translator.config.translation.backendopt - # ZZZ the arguments here should disappear - raisingop2direct_call_all = (config.raisingop2direct_call or - raisingop2direct_call_all) - mallocs = config.mallocs or mallocs - merge_if_blocks_to_switch = (config.merge_if_blocks or - merge_if_blocks_to_switch) - constfold = config.constfold or constfold - heap2stack = config.heap2stack or heap2stack - clever_malloc_removal = config.clever_malloc_removal or clever_malloc_removal +def backend_optimizations(translator, graphs=None, **kwds): + # sensible keywords are + # raisingop2direct_call, inline_threshold, mallocs + # merge_if_blocks, constfold, heap2stack + # clever_malloc_removal + + config = translator.config.translation.backendopt.copy() + config.set(**kwds) if graphs is None: graphs = translator.graphs @@ -38,7 +27,7 @@ print "before optimizations:" print_statistics(translator.graphs[0], translator, "per-graph.txt") - if raisingop2direct_call_all: + if config.raisingop2direct_call: raisingop2direct_call(translator, graphs) # remove obvious no-ops @@ -52,11 +41,11 @@ print "after no-op removal:" print_statistics(translator.graphs[0], translator) - if not clever_malloc_removal: + if not config.clever_malloc_removal: # inline functions in each other - if inline_threshold: + if config.inline_threshold: callgraph = inline.inlinable_static_callers(graphs) - inline.auto_inlining(translator, inline_threshold, + inline.auto_inlining(translator, config.inline_threshold, callgraph=callgraph) for graph in graphs: removenoops.remove_superfluous_keep_alive(graph) @@ -67,7 +56,7 @@ print_statistics(translator.graphs[0], translator) # vaporize mallocs - if mallocs: + if config.mallocs: tot = 0 for graph in graphs: count = remove_simple_mallocs(graph) @@ -90,15 +79,15 @@ print "after clever inlining and malloc removal" print_statistics(translator.graphs[0], translator) - if constfold: + if config.constfold: for graph in graphs: constant_fold_graph(graph) - if heap2stack: + if config.heap2stack: assert graphs is translator.graphs # XXX for now malloc_to_stack(translator) - if merge_if_blocks_to_switch: + if config.merge_if_blocks: for graph in graphs: merge_if_blocks(graph) Modified: pypy/dist/pypy/translator/backendopt/test/test_all.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_all.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_all.py Wed Nov 1 13:43:37 2006 @@ -139,7 +139,7 @@ c = [i for i in range(n2)] return 33 + big() + g(10) - t = translateopt(idempotent, [int, int], raisingop2direct_call_all=True, + t = translateopt(idempotent, [int, int], raisingop2direct_call=True, constfold=False) digest1 = md5digest(t) @@ -148,7 +148,7 @@ #XXX Inlining and constfold are currently non-idempotent. # Maybe they just renames variables but the graph changes in some way. - backend_optimizations(t, raisingop2direct_call_all=True, + backend_optimizations(t, raisingop2direct_call=True, inline_threshold=0, constfold=False) digest3 = md5digest(t) assert digest1 == digest3 @@ -184,7 +184,7 @@ for i in r: res = res * 51 + i return res - t = translateopt(fn, [int, int, int], merge_if_blocks_to_switch=True) + t = translateopt(fn, [int, int, int], merge_if_blocks=True) interp = LLInterpreter(t.rtyper) for args in [2, 7, 0], [7, 2, 0], [10, 50, 7], [50, -10, -3]: assert interp.eval_graph(graphof(t, fn), args) == intmask(fn(*args)) Modified: pypy/dist/pypy/translator/backendopt/test/test_merge_if_blocks.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_merge_if_blocks.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_merge_if_blocks.py Wed Nov 1 13:43:37 2006 @@ -154,7 +154,7 @@ a.build_types(fn, []) rtyper = t.buildrtyper() rtyper.specialize() - backend_optimizations(t, merge_if_blocks_to_switch=True) + backend_optimizations(t, merge_if_blocks=True) graph = tgraphof(t, fn) blocknum = len(list(graph.iterblocks())) merge_if_blocks(graph) @@ -174,7 +174,7 @@ a.build_types(fn, [int]) rtyper = t.buildrtyper() rtyper.specialize() - backend_optimizations(t, merge_if_blocks_to_switch=True) + backend_optimizations(t, merge_if_blocks=True) graph = tgraphof(t, fn) assert len(graph.startblock.exits) == 2 interp = LLInterpreter(rtyper) Modified: pypy/dist/pypy/translator/backendopt/test/test_removenoops.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_removenoops.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_removenoops.py Wed Nov 1 13:43:37 2006 @@ -21,7 +21,7 @@ if all_opts: backend_optimizations(t, inline_threshold=inline_threshold, constfold=False, - raisingop2direct_call_all=False) + raisingop2direct_call=False) graph = graphof(t, fn) if conftest.option.view: t.view() Modified: pypy/dist/pypy/translator/c/test/test_backendoptimized.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_backendoptimized.py (original) +++ pypy/dist/pypy/translator/c/test/test_backendoptimized.py Wed Nov 1 13:43:37 2006 @@ -10,7 +10,7 @@ def process(self, t): _TestTypedTestCase.process(self, t) self.t = t - backend_optimizations(t, merge_if_blocks_to_switch=False) + backend_optimizations(t, merge_if_blocks=False) if conftest.option.view: t.view() @@ -89,7 +89,7 @@ def process(self, t): _TestTypedTestCase.process(self, t) self.t = t - backend_optimizations(t, merge_if_blocks_to_switch=True) + backend_optimizations(t, merge_if_blocks=True) def test_int_switch(self): def f(x): @@ -186,7 +186,7 @@ def process(self, t): _TestTypedTestCase.process(self, t) self.t = t - backend_optimizations(t, raisingop2direct_call_all=True) + backend_optimizations(t, raisingop2direct_call=True) def test_int_floordiv_zer(self): def f(x): Modified: pypy/dist/pypy/translator/driver.py ============================================================================== --- pypy/dist/pypy/translator/driver.py (original) +++ pypy/dist/pypy/translator/driver.py Wed Nov 1 13:43:37 2006 @@ -277,10 +277,10 @@ def task_backendopt_ootype(self): from pypy.translator.backendopt.all import backend_optimizations backend_optimizations(self.translator, - raisingop2direct_call_all=False, + raisingop2direct_call=False, inline_threshold=0, mallocs=False, - merge_if_blocks_to_switch=False, + merge_if_blocks=False, propagate=False, constfold=True, heap2stack=False, Modified: pypy/dist/pypy/translator/llvm/genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/genllvm.py Wed Nov 1 13:43:37 2006 @@ -335,13 +335,13 @@ # use backend optimizations? if optimize: - backend_optimizations(translator, raisingop2direct_call_all=True) + backend_optimizations(translator, raisingop2direct_call=True) else: backend_optimizations(translator, - raisingop2direct_call_all=True, + raisingop2direct_call=True, inline_threshold=0, mallocs=False, - merge_if_blocks_to_switch=False, + merge_if_blocks=False, constfold=False) # note: this is without stackless and policy transforms From rxe at codespeak.net Wed Nov 1 13:44:50 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Nov 2006 13:44:50 +0100 (CET) Subject: [pypy-svn] r34016 - pypy/dist/pypy/jit/timeshifter/test Message-ID: <20061101124450.1EDDF1007E@code0.codespeak.net> Author: rxe Date: Wed Nov 1 13:44:49 2006 New Revision: 34016 Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py Log: broken dfa test again - after adding some logic for testing for final state Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Wed Nov 1 13:44:49 2006 @@ -121,15 +121,19 @@ self.check_insns(int_floordiv=1, int_mul=0) def test_dfa_compile(self): + py.test.skip("we've gone yellow") from pypy.lang.automata.dfa import getautomaton, convertdfa, recognizetable def main(gets): a = getautomaton() - dfatable = convertdfa(a) + dfatable, final_states = convertdfa(a) s = ["aaaaaaaaaab", "aaaa"][gets] - return recognizetable(dfatable, s) + return recognizetable(dfatable, s, final_states) res = self.timeshift_from_portal(main, recognizetable, [0], policy=P_NOVIRTUAL) - assert res >= 0 + assert res + + res = self.timeshift_from_portal(main, recognizetable, [1], policy=P_NOVIRTUAL) + assert not res def test_method_call_promote(self): class Base(object): @@ -168,4 +172,3 @@ res = self.timeshift_from_portal(ll_function, ll_function, [0], policy=P_NOVIRTUAL) assert res == ord('2') self.check_insns(indirect_call=0) - From fijal at codespeak.net Wed Nov 1 13:51:13 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 1 Nov 2006 13:51:13 +0100 (CET) Subject: [pypy-svn] r34017 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061101125113.02A3310071@code0.codespeak.net> Author: fijal Date: Wed Nov 1 13:51:12 2006 New Revision: 34017 Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py (contents, props changed) pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (contents, props changed) pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (contents, props changed) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py Log: (pedronis, guido, fijal) - First operation on transparent list. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/model.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/model.py Wed Nov 1 13:51:12 2006 @@ -66,6 +66,7 @@ from pypy.objspace.std import stringobject from pypy.objspace.std import strsliceobject from pypy.objspace.std import strjoinobject + from pypy.objspace.std import tlistobject from pypy.objspace.std import typeobject from pypy.objspace.std import sliceobject from pypy.objspace.std import longobject @@ -119,6 +120,9 @@ else: imported_but_not_registered[implcls] = True + # xxx config + self.typeorder[tlistobject.W_TransparentList] = [] + if config.objspace.std.withstrdict: del self.typeorder[dictobject.W_DictObject] del self.typeorder[dictobject.W_DictIterObject] @@ -137,6 +141,7 @@ # register the order in which types are converted into each others # when trying to dispatch multimethods. # XXX build these lists a bit more automatically later + if config.objspace.std.withsmallint: self.typeorder[boolobject.W_BoolObject] += [ (smallintobject.W_SmallIntObject, boolobject.delegate_Bool2SmallInt), Modified: pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py Wed Nov 1 13:51:12 2006 @@ -135,6 +135,11 @@ # final setup self.setup_builtin_modules() + # Adding transparent proxy call + from pypy.objspace.std.transparent import app_proxy + + self.setitem(self.builtin.w_dict, self.wrap('proxy'), + self.wrap(app_proxy)) def enable_old_style_classes_as_default_metaclass(self): self.setitem(self.builtin.w_dict, self.wrap('__metaclass__'), self.w_classobj) Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Wed Nov 1 13:51:12 2006 @@ -0,0 +1,31 @@ + +""" test transparent proxy features +""" + +class AppTestProxy(object): + def test_proxy(self): + lst = proxy(list, lambda : None) + assert type(lst) is list + + def test_proxy_repr(self): + def controller(name, *args): + lst = [1,2,3] + if name == '__repr__': + return repr(lst) + + lst = proxy(list, controller) + assert repr(lst) == repr([1,2,3]) + + def test_proxy_append(self): + class Controller(object): + def __init__(self, obj): + self.obj = obj + + def perform(self, name, *args): + return getattr(self.obj, name)(*args) + + c = Controller([]) + lst = proxy(list, c.perform) + lst.append(1) + lst.append(2) + assert repr(lst) == repr([1,2]) Added: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Wed Nov 1 13:51:12 2006 @@ -0,0 +1,27 @@ + +""" transparent list implementation +""" + +from pypy.objspace.std.objspace import * + +class W_TransparentList(W_Object): + from pypy.objspace.std.listtype import list_typedef as typedef + + def __init__(self, w_controller): + self.controller = w_controller + +registerimplementation(W_TransparentList) + +def repr__TransparentList(space, w_transparent_list): + return space.call_function(w_transparent_list.controller, space.wrap("__repr__")) + +def list_append__TransparentList_ANY(space, w_transparent_list, w_any): + space.call_function(w_transparent_list.controller, space.wrap("append"), w_any) + return space.w_None + +def list_extend__TransparentList_ANY(space, w_list, w_any): + space.call_function(w_transparent_list.controller, space.wrap("extend"), w_any) + return space.w_None + +from pypy.objspace.std import listtype +register_all(vars(), listtype) Added: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Wed Nov 1 13:51:12 2006 @@ -0,0 +1,18 @@ + +""" transparent.py - Several transparent proxy helpers +""" + +from pypy.objspace.std.tlistobject import W_TransparentList +from pypy.interpreter import gateway +from pypy.interpreter.function import Function +from pypy.interpreter.error import OperationError + +def proxy(space, w_type, w_controller): + if not space.is_true(space.callable(w_controller)): + raise OperationError(space.w_TypeError, space.wrap("controller should be function")) + if not space.is_w(w_type, space.w_list): + raise OperationError(space.w_TypeError, space.wrap("type of object wrapped should be list")) + return W_TransparentList(w_controller) + +app_proxy = gateway.interp2app(proxy, unwrap_spec=[gateway.ObjSpace, gateway.W_Root, \ + gateway.W_Root]) From stephan at codespeak.net Wed Nov 1 14:20:20 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Wed, 1 Nov 2006 14:20:20 +0100 (CET) Subject: [pypy-svn] r34018 - pypy/dist/pypy/lang/js Message-ID: <20061101132020.9796C10072@code0.codespeak.net> Author: stephan Date: Wed Nov 1 14:20:17 2006 New Revision: 34018 Modified: pypy/dist/pypy/lang/js/parser.py Log: (stephan, santagada) fixed compatability for Windows and some cleanups Modified: pypy/dist/pypy/lang/js/parser.py ============================================================================== --- pypy/dist/pypy/lang/js/parser.py (original) +++ pypy/dist/pypy/lang/js/parser.py Wed Nov 1 14:20:17 2006 @@ -4,6 +4,7 @@ # 1st attempt - exec the code +import os import py import re from subprocess import Popen, PIPE, STDOUT @@ -27,26 +28,12 @@ def parse(code_string): read_code = read_js_output(code_string) - #print read_code - #for line in read_code.split("\n"): - #m = re.search('^(\s*)(\w+): +(.*?)(,)?$', line) - #if m and (m.group(3) != '{' or m.group(4)): - # output.append("%s'%s': '%s'," % (m.group(1), m.group(2), m.group(3))) - #else: - # m = re.search('^(\s*)(\w+):(.*)$', line) - # if m: - # output.append("%s'%s': %s" % (m.group(1), m.group(2), m.group(3))) - # else: - # output.append(line) - - #print "\n".join(output) - output = read_code.split("\n") - d = {} + output = read_code.split(os.linesep) try: - exec "code =" + "\n".join(output) in d + code = eval("\n".join(output)) except (SyntaxError, NameError): for num, line in enumerate(output): print "%d: %s" % (num + 1, line) open("/tmp/out", "w").write("\n".join(output)) raise - return d['code'] + return code From cfbolz at codespeak.net Wed Nov 1 14:32:00 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 14:32:00 +0100 (CET) Subject: [pypy-svn] r34019 - pypy/dist/pypy/translator/goal Message-ID: <20061101133200.44F731006E@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 14:31:59 2006 New Revision: 34019 Modified: pypy/dist/pypy/translator/goal/translate.py Log: fix logic for disabled goals Modified: pypy/dist/pypy/translator/goal/translate.py ============================================================================== --- pypy/dist/pypy/translator/goal/translate.py (original) +++ pypy/dist/pypy/translator/goal/translate.py Wed Nov 1 14:31:59 2006 @@ -117,12 +117,16 @@ options, args = opt_parser.parse_args() # set goals and skipped_goals + reset = False for name, _, _, _ in GOALS: if getattr(translateconfig.goal_options, name): if name not in translateconfig.goals: translateconfig.goals.append(name) if getattr(translateconfig.goal_options, 'no_'+name): if name not in translateconfig.skipped_goals: + if not reset: + translateconfig.skipped_goals[:] = [] + reset = True translateconfig.skipped_goals.append(name) if args: From cfbolz at codespeak.net Wed Nov 1 14:32:57 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 14:32:57 +0100 (CET) Subject: [pypy-svn] r34020 - pypy/dist/pypy/translator Message-ID: <20061101133257.3B5A41006E@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 14:32:56 2006 New Revision: 34020 Modified: pypy/dist/pypy/translator/driver.py Log: make backendopt optional for cli. propagate does not longer exist Modified: pypy/dist/pypy/translator/driver.py ============================================================================== --- pypy/dist/pypy/translator/driver.py (original) +++ pypy/dist/pypy/translator/driver.py Wed Nov 1 14:32:56 2006 @@ -281,7 +281,6 @@ inline_threshold=0, mallocs=False, merge_if_blocks=False, - propagate=False, constfold=True, heap2stack=False, clever_malloc_removal=False) @@ -500,7 +499,7 @@ config=self.config) filename = self.gen.generate_source() self.log.info("Wrote %s" % (filename,)) - task_source_cli = taskdef(task_source_cli, [OOBACKENDOPT, OOTYPE], + task_source_cli = taskdef(task_source_cli, ["?" + OOBACKENDOPT, OOTYPE], 'Generating CLI source') def task_compile_cli(self): From fijal at codespeak.net Wed Nov 1 14:53:13 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 1 Nov 2006 14:53:13 +0100 (CET) Subject: [pypy-svn] r34022 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061101135313.842401006E@code0.codespeak.net> Author: fijal Date: Wed Nov 1 14:53:12 2006 New Revision: 34022 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Log: (arigo, fijal, guido, pedronis) - List >= TransparentList and friends. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py Wed Nov 1 14:53:12 2006 @@ -123,12 +123,10 @@ return a return b -def lt__List_List(space, w_list1, w_list2): +def lessthan_unwrappeditems(space, items1_w, items2_w): # needs to be safe against eq_w() mutating the w_lists behind our back # Search for the first index where items are different i = 0 - items1_w = w_list1.wrappeditems - items2_w = w_list2.wrappeditems while i < len(items1_w) and i < len(items2_w): w_item1 = items1_w[i] w_item2 = items2_w[i] @@ -138,13 +136,11 @@ # No more items to compare -- compare sizes return space.newbool(len(items1_w) < len(items2_w)) -def gt__List_List(space, w_list1, w_list2): +def greaterthan_unwrappeditems(space, items1_w, items2_w): # needs to be safe against eq_w() mutating the w_lists behind our back # Search for the first index where items are different i = 0 - items1_w = w_list1.wrappeditems - items2_w = w_list2.wrappeditems - while i < len(w_list1.wrappeditems) and i < len(w_list2.wrappeditems): + while i < len(items1_w) and i < len(items2_w): w_item1 = items1_w[i] w_item2 = items2_w[i] if not space.eq_w(w_item1, w_item2): @@ -153,6 +149,29 @@ # No more items to compare -- compare sizes return space.newbool(len(items1_w) > len(items2_w)) +def lt__List_List(space, w_list1, w_list2): + return lessthan_unwrappeditems(space, w_list1.wrappeditems, + w_list2.wrappeditems) + +def lt__List_ANY(space, w_list1, w_any): + # XXX: Implement it not unpacking all the elements + if space.is_true(space.isinstance(w_any, space.w_list)): + items1_w = w_list1.wrappeditems + items2_w = space.unpackiterable(w_any) + return lessthan_unwrappeditems(space, items1_w, items2_w) + raise FailedToImplement + +def gt__List_List(space, w_list1, w_list2): + return greaterthan_unwrappeditems(space, w_list1.wrappeditems, + w_list2.wrappeditems) + +def gt__List_ANY(space, w_list1, w_any): + # XXX: Implement it not unpacking all the elements + if space.is_true(space.isinstance(w_any, space.w_list)): + items1_w = w_list1.wrappeditems + items2_w = space.unpackiterable(w_any) + return greaterthan_unwrappeditems(space, items1_w, items2_w) + raise FailedToImplement def delitem__List_ANY(space, w_list, w_idx): idx = space.int_w(w_idx) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Wed Nov 1 14:53:12 2006 @@ -3,6 +3,17 @@ """ class AppTestProxy(object): + def setup_method(self, meth): + self.w_Controller = self.space.appexec([], """(): + class Controller(object): + def __init__(self, obj): + self.obj = obj + + def perform(self, name, *args): + return getattr(self.obj, name)(*args) + return Controller + """) + def test_proxy(self): lst = proxy(list, lambda : None) assert type(lst) is list @@ -17,15 +28,19 @@ assert repr(lst) == repr([1,2,3]) def test_proxy_append(self): - class Controller(object): - def __init__(self, obj): - self.obj = obj - - def perform(self, name, *args): - return getattr(self.obj, name)(*args) - - c = Controller([]) + c = self.Controller([]) lst = proxy(list, c.perform) lst.append(1) lst.append(2) assert repr(lst) == repr([1,2]) + + def test_gt_lt_list(self): + c = self.Controller([]) + lst = proxy(list, c.perform) + lst.append(1) + lst.append(2) + assert lst < [1,2,3] + assert [1,2,3] > lst + #assert not ([2,3] < lst) + assert [2,3] >= lst + assert lst <= [1,2] Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Wed Nov 1 14:53:12 2006 @@ -23,5 +23,14 @@ space.call_function(w_transparent_list.controller, space.wrap("extend"), w_any) return space.w_None +def lt__TransparentList_ANY(space, w_transparent_list, w_list): + return space.call_function(w_transparent_list.controller, space.wrap("__lt__"), w_list) + +def gt__TransparentList_ANY(space, w_transparent_list, w_list): + return space.call_function(w_transparent_list.controller, space.wrap("__gt__"), w_list) + +def iter__TransparentList(space, w_transparent_list): + return space.call_function(w_transparent_list.controller, space.wrap("__iter__")) + from pypy.objspace.std import listtype register_all(vars(), listtype) From niko at codespeak.net Wed Nov 1 14:57:44 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Wed, 1 Nov 2006 14:57:44 +0100 (CET) Subject: [pypy-svn] r34023 - in pypy/dist/pypy/translator: cli js jvm jvm/src jvm/test oosupport Message-ID: <20061101135744.5DC6E10071@code0.codespeak.net> Author: niko Date: Wed Nov 1 14:57:43 2006 New Revision: 34023 Modified: pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/js/function.py pypy/dist/pypy/translator/jvm/conftest.py pypy/dist/pypy/translator/jvm/database.py pypy/dist/pypy/translator/jvm/generator.py pypy/dist/pypy/translator/jvm/node.py pypy/dist/pypy/translator/jvm/opcodes.py pypy/dist/pypy/translator/jvm/option.py pypy/dist/pypy/translator/jvm/src/PyPy.java pypy/dist/pypy/translator/jvm/test/ (props changed) pypy/dist/pypy/translator/jvm/test/runtest.py pypy/dist/pypy/translator/jvm/typesystem.py pypy/dist/pypy/translator/oosupport/function.py pypy/dist/pypy/translator/oosupport/metavm.py Log: Update JVM handling of class objects. Add support for casts, new, etc. Some minor refactoring into oosupport as well. Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Wed Nov 1 14:57:43 2006 @@ -99,6 +99,10 @@ # Generator interface + + def add_comment(self, text): + pass + def function_signature(self, graph, func_name=None): return self.cts.graph_to_signature(graph, False, func_name) @@ -138,9 +142,13 @@ signature, virtual = self.cts.method_signature(obj, name) self.ilasm.call_method(signature, virtual) - def downcast(self, type): + def downcast(self, TYPE): + type = self.cts.lltype_to_cts(TYPE) return self.ilasm.opcode('castclass', type) + def instantiate(self): + self.call_signature('object [pypylib]pypy.runtime.Utils::RuntimeNew(class [mscorlib]System.Type)') + def load(self, v): if isinstance(v, flowmodel.Variable): if v.name in self.argset: Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Wed Nov 1 14:57:43 2006 @@ -1,8 +1,8 @@ -from pypy.translator.cli.metavm import Call, CallMethod, RuntimeNew, \ +from pypy.translator.cli.metavm import Call, CallMethod, \ IndirectCall, GetField, SetField, CastTo, OOString, DownCast, NewCustomDict,\ CastWeakAdrToPtr, MapException, Box, Unbox, GetArrayElem from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\ - New + New, RuntimeNew from pypy.translator.cli.cts import WEAKREF # some useful instruction patterns Modified: pypy/dist/pypy/translator/js/function.py ============================================================================== --- pypy/dist/pypy/translator/js/function.py (original) +++ pypy/dist/pypy/translator/js/function.py Wed Nov 1 14:57:43 2006 @@ -368,6 +368,9 @@ # following methods belongs to the Generator interface + def add_comment(self, text): + pass + def function_signature(self, graph): return self.cts.graph_to_signature(graph, False) Modified: pypy/dist/pypy/translator/jvm/conftest.py ============================================================================== --- pypy/dist/pypy/translator/jvm/conftest.py (original) +++ pypy/dist/pypy/translator/jvm/conftest.py Wed Nov 1 14:57:43 2006 @@ -14,5 +14,7 @@ Option('--noassemble', action='store_true', dest="noasm", default=False, help="don't assemble jasmin files"), Option('--package', action='store', dest='package', default='pypy', - help='Package to output generated classes into') + help='Package to output generated classes into'), + Option('--trace', action='store_true', dest='trace', default=False, + help='Trace execution of generated code') ) Modified: pypy/dist/pypy/translator/jvm/database.py ============================================================================== --- pypy/dist/pypy/translator/jvm/database.py (original) +++ pypy/dist/pypy/translator/jvm/database.py Wed Nov 1 14:57:43 2006 @@ -18,7 +18,8 @@ self.genoo = genoo # Private attributes: - self._classes = {} # Maps ootype class objects to node.Class objects + self._classes = {} # Maps ootype class objects to node.Class objects, + # and JvmType objects as well self._counter = 0 # Used to create unique names self._functions = {} # graph -> jvmgen.Method @@ -61,14 +62,26 @@ # Create class object if it does not already exist: if OOCLASS in self._classes: return self._classes[OOCLASS] + + # Resolve super class first + if OOCLASS._superclass: + superclsnm = self.lltype_to_cts(OOCLASS._superclass).class_name() + else: + superclsobj = "java.lang.Object" #? + # TODO --- make package of java class reflect the package of the # OO class? clsnm = self._pkg( self._uniq(OOCLASS._name.replace('.','_'))) - clsobj = node.Class(clsnm) + clsobj = node.Class(clsnm, superclsnm) - # TODO --- mangle field and method names? Must be deterministic or - # use hashtable to avoid conflicts between classes? + # Store the class object for future calls + self._classes[OOCLASS] = clsobj + self._classes[clsobj.jvm_type()] = clsobj + + # TODO --- mangle field and method names? Must be + # deterministic, or use hashtable to avoid conflicts between + # classes? # Add fields: for fieldnm, (FIELDOOTY, fielddef) in OOCLASS._fields.iteritems(): @@ -86,17 +99,24 @@ # this class it means that this method this method is # not really used by the class: don't render it, else # there would be a type mismatch. - args = m_meth.graph.getargs() + args = mimpl.graph.getargs() SELF = args[0].concretetype if not ootype.isSubclass(OOCLASS, SELF): continue mobj = self._function_for_graph( - clsobj, mimpl.name, False, mimpl.graph) + clsobj, mname, False, mimpl.graph) clsobj.add_method(mobj) - self._classes[OOCLASS] = clsobj + # currently, we always include a special "dump" method for debugging + # purposes + dump_method = node.TestDumpMethod(self, OOCLASS, clsobj) + clsobj.add_dump_method(dump_method) + self.pending_node(clsobj) return clsobj + def class_obj_for_jvm_type(self, jvmtype): + return self._classes[jvmtype] + def pending_function(self, graph): """ This is invoked when a standalone function is to be compiled. @@ -108,7 +128,7 @@ if graph in self._functions: return self._functions[graph] classnm = self._pkg(self._uniq(graph.name)) - classobj = node.Class(classnm) + classobj = node.Class(classnm, 'java.lang.Object') funcobj = self._function_for_graph(classobj, "invoke", True, graph) classobj.add_method(funcobj) self.pending_node(classobj) @@ -147,8 +167,23 @@ # For NOW, we create a new class PER constant. # Clearly this is probably undesirable in the long # term. - print "TYPE=" + repr(TYPE) - return jvmgen.VoidConst() # TODO + return jvmgen.WarnNullConst() # TODO + + # Other + + _type_printing_methods = { + ootype.Signed:jvmgen.PYPYDUMPINT, + ootype.Unsigned:jvmgen.PYPYDUMPUINT, + ootype.SignedLongLong:jvmgen.PYPYDUMPLONG, + ootype.Float:jvmgen.PYPYDUMPDOUBLE, + ootype.Bool:jvmgen.PYPYDUMPBOOLEAN, + ootype.Class:jvmgen.PYPYDUMPOBJECT, + } + + def generate_dump_method_for_ootype(self, OOTYPE): + if OOTYPE in self._type_printing_methods: + return self._type_printing_methods[OOTYPE] + return self.pending_class(OOTYPE).dump_method.method() # Type translation functions Modified: pypy/dist/pypy/translator/jvm/generator.py ============================================================================== --- pypy/dist/pypy/translator/jvm/generator.py (original) +++ pypy/dist/pypy/translator/jvm/generator.py Wed Nov 1 14:57:43 2006 @@ -1,7 +1,8 @@ import os # from pypy.objspace.flow import model as flowmodel from pypy.translator.oosupport.metavm import Generator -from pypy.translator.jvm.typesystem import JvmType +from pypy.translator.jvm.typesystem import \ + JvmType, jObject, jPrintStream, jvm_for_class, jVoid from pypy.rpython.ootypesystem import ootype # ___________________________________________________________________________ @@ -46,6 +47,8 @@ return self.jvmstr + "_m1", () elif args[0] >= 0 and args[0] <= 5: return self.jvmstr + "_" + str(args[0]), () + else: + return "ldc", args # HACK if self.flags & CONST3: assert len(args) == 1 @@ -132,6 +135,7 @@ # Method invocation INVOKESTATIC = Opcode(INVOKE, 'invokestatic') +INVOKEVIRTUAL = Opcode(INVOKE, 'invokevirtual') INVOKESPECIAL = Opcode(INVOKE, 'invokespecial') # Other opcodes @@ -148,7 +152,7 @@ PUTFIELD = Opcode(FIELD, 'putfield') GETSTATIC = Opcode(FIELD, 'getstatic') PUTSTATIC = Opcode(FIELD, 'putstatic') -CHECKCAST = Opcode(NOFLAGS, 'checkcast') +CHECKCAST = Opcode(CLASSINM, 'checkcast') INEG = Opcode(NOFLAGS, 'ineg') IXOR = Opcode(NOFLAGS, 'ixor') IADD = Opcode(NOFLAGS, 'iadd') @@ -190,6 +194,7 @@ NEW = Opcode(CLASSINM, 'new') DUP = Opcode(NOFLAGS, 'dup') POP = Opcode(NOFLAGS, 'pop') +INSTANCEOF= Opcode(CLASSINM, 'instanceof') # Loading/storing local variables LOAD = OpcodeFamily(CONST3, "load") STORE = OpcodeFamily(CONST3, "store") @@ -231,6 +236,8 @@ MATHLABS = Method('java.lang.Math', 'abs', '(L)L') MATHDABS = Method('java.lang.Math', 'abs', '(D)D') MATHFLOOR = Method('java.lang.Math', 'floor', '(D)D') +PRINTSTREAMPRINTSTR = Method('java.io.PrintStream', 'print', + '(Ljava/lang/String;)V', opcode=INVOKEVIRTUAL) PYPYUINTCMP = Method('pypy.PyPy', 'uint_cmp', '(II)I') PYPYULONGCMP = Method('pypy.PyPy', 'ulong', '(LL)I') PYPYUINTTODOUBLE = Method('pypy.PyPy', 'uint_to_double', '(I)D') @@ -252,12 +259,19 @@ '(Ljava/lang/String;)D') PYPYSTRTOCHAR = Method('pypy.PyPy', 'str_to_char', '(Ljava/lang/String;)C') -PYPYDUMPINT = Method('pypy.PyPy', 'dump_int', '(I)V') -PYPYDUMPUINT = Method('pypy.PyPy', 'dump_uint', '(I)V') -PYPYDUMPLONG = Method('pypy.PyPy', 'dump_long', '(L)V') -PYPYDUMPDOUBLE = Method('pypy.PyPy', 'dump_double', '(D)V') -PYPYDUMPSTRING = Method('pypy.PyPy', 'dump_string', '([B)V') -PYPYDUMPBOOLEAN = Method('pypy.PyPy', 'dump_boolean', '(Z)V') +PYPYDUMPINDENTED = Method('pypy.PyPy', 'dump_indented', + '(ILjava/lang/String;)V') +PYPYDUMPINT = Method('pypy.PyPy', 'dump_int', '(II)V') +PYPYDUMPUINT = Method('pypy.PyPy', 'dump_uint', '(II)V') +PYPYDUMPLONG = Method('pypy.PyPy', 'dump_long', '(LI)V') +PYPYDUMPDOUBLE = Method('pypy.PyPy', 'dump_double', '(DI)V') +PYPYDUMPSTRING = Method('pypy.PyPy', 'dump_string', '([BI)V') +PYPYDUMPBOOLEAN = Method('pypy.PyPy', 'dump_boolean', '(ZI)V') +PYPYDUMPOBJECT = Method('pypy.PyPy', 'dump_object', + '(Ljava/lang/Object;I)V') +PYPYRUNTIMENEW = Method('pypy.PyPy', 'RuntimeNew', + '(Ljava/lang/Class;)Ljava/lang/Object;') + # ___________________________________________________________________________ # Fields @@ -285,6 +299,9 @@ return "%s/%s %s" % ( self.class_name.replace('.','/'), self.field_name, self.jtype) +SYSTEMOUT = Field('java.lang.System', 'out', jPrintStream, True) +SYSTEMERR = Field('java.lang.System', 'err', jPrintStream, True) + # ___________________________________________________________________________ # Constants # @@ -305,6 +322,15 @@ def load(self, gen): pass +class NullConst(object): + def load(self, gen): + gen.emit(ACONST_NULL) + +class WarnNullConst(NullConst): + def load(self, gen): + gen.add_comment(" substituting NULL") + NullConst.load(self, gen) + class SignedIntConst(Const): def __init__(self, value): self.value = value @@ -372,7 +398,13 @@ self.value = value def load(self, gen): assert isinstance(self.value, unicode) - res = '"' + self.value.encode('utf-8').replace('"', r'\"') + '"' + def escape(char): + if char == '"': return r'\"' + if char == '\n': return r'\n' + return char + res = ('"' + + "".join(escape(c) for c in self.value.encode('utf-8')) + + '"') gen.emit(LDC, res) class ComplexConst(Const): @@ -396,6 +428,40 @@ gen.emit(self.methodinfo) # ___________________________________________________________________________ +# Generator State + +class ClassState(object): + """ When you invoked begin_class(), one of these objects is allocated + and tracks the state as we go through the definition process. """ + def __init__(self, classnm, superclassnm): + self.class_name = classnm + self.superclass_name = superclassnm + def out(self, arg): + self.file.write(arg) + +class FunctionState(object): + """ When you invoked begin_function(), one of these objects is allocated + and tracks the state as we go through the definition process. """ + def __init__(self): + self.next_offset = 0 + self.local_vars = {} + self.instr_counter = 0 + def add_var(self, jvar, jtype): + """ Adds new entry for variable 'jvar', of java type 'jtype' """ + idx = self.next_offset + self.next_offset += jtype.type_width() + if jvar: + assert jvar not in self.local_vars # never been added before + self.local_vars[jvar] = idx + return idx + def var_offset(self, jvar, jtype): + """ Returns offset for variable 'jvar', of java type 'jtype' """ + if jvar in self.local_vars: + return self.local_vars[jvar] + return self.add_var(jvar, jtype) + + +# ___________________________________________________________________________ # Generator class JVMGenerator(Generator): @@ -410,6 +476,8 @@ def __init__(self, db): self.db = db self.label_counter = 0 + self.curclass = None + self.curfunc = None # __________________________________________________________________ # JVM specific methods to be overloaded by a subclass @@ -417,14 +485,38 @@ # If the name does not begin with '_', it will be called from # outside the generator. - def begin_class(self, classnm): + def begin_class(self, classnm, superclsnm): """ + Begins a class declaration. Overall flow of class declaration + looks like: + + begin_class() + [add_field()] + emit_constructor() + [begin_function()...end_function()] + end_class() + + Where items in brackets may appear anywhere from 0 to inf times. + classnm --- full Java name of the class (i.e., "java.lang.String") + superclassnm --- full Java name of the super class """ - unimplemented + assert not self.curclass + self.curclass = ClassState(classnm, superclsnm) + self._begin_class() def end_class(self): - unimplemented + self._end_class() + self.curclass = None + self.curfunc = None + + def _begin_class(self): + """ Main implementation of begin_class """ + raise NotImplementedError + + def _end_class(self): + """ Main implementation of end_class """ + raise NotImplementedError def add_field(self, fobj): """ @@ -432,13 +524,29 @@ """ unimplemented + def emit_constructor(self): + """ + Emits the constructor for this class, which merely invokes the + parent constructor. + + superclsnm --- same Java name of super class as from begin_class + """ + jtype = jvm_for_class(self.curclass.class_name) + self.begin_function("", [], [jtype], jVoid) + self.load_jvm_var(jtype, 0) + jmethod = Method(self.curclass.superclass_name, "", "()V", + opcode=INVOKESPECIAL) + jmethod.invoke(self) + self.return_val(jVoid) + self.end_function() + def begin_function(self, funcname, argvars, argtypes, rettype, static=False): """ funcname --- name of the function argvars --- list of objects passed to load() that represent arguments; should be in order, or () if load() will not be used - argtypes --- JvmType for each argument + argtypes --- JvmType for each argument [INCLUDING this] rettype --- JvmType for the return value static --- keyword, if true then a static func is generated @@ -448,13 +556,12 @@ # Compute the indicates of each argument in the local variables # for the function. Note that some arguments take up two slots # depending on their type [this is compute by type_width()] - self.next_offset = 0 - self.local_vars = {} + assert not self.curfunc + self.curfunc = FunctionState() for idx, ty in enumerate(argtypes): - if idx < len(argvars): - var = argvars[idx] - self.local_vars[var] = self.next_offset - self.next_offset += ty.type_width() + if idx < len(argvars): var = argvars[idx] + else: var = None + self.curfunc.add_var(var, ty) # Prepare a map for the local variable indices we will add # Let the subclass do the rest of the work; note that it does # not need to know the argvars parameter, so don't pass it @@ -469,8 +576,7 @@ def end_function(self): self._end_function() - del self.next_offset - del self.local_vars + self.curfunc = None def _end_function(self): unimplemented @@ -488,17 +594,24 @@ """ Returns a value from top of stack of the JvmType 'vartype' """ self._instr(RETURN.for_type(vartype)) + def load_string(self, str): + uni = str.decode('utf-8') + UnicodeConst(uni).load(self) + def load_jvm_var(self, vartype, varidx): """ Loads from jvm slot #varidx, which is expected to hold a value of type vartype """ + assert varidx < self.curfunc.next_offset opc = LOAD.for_type(vartype) - print "load_jvm_jar: vartype=%s varidx=%s opc=%s" % ( - repr(vartype), repr(varidx), repr(opc)) + self.add_comment(" load_jvm_jar: vartype=%s varidx=%s" % ( + repr(vartype), repr(varidx))) self._instr(opc, varidx) def store_jvm_var(self, vartype, varidx): """ Loads from jvm slot #varidx, which is expected to hold a value of type vartype """ + self.add_comment(" store_jvm_jar: vartype=%s varidx=%s" % ( + repr(vartype), repr(varidx))) self._instr(STORE.for_type(vartype), varidx) def load_from_array(self, elemtype): @@ -531,6 +644,11 @@ if mark: self.mark(res) return res + + def load_this_ptr(self): + """ Convenience method. Be sure you only call it from a + virtual method, not static methods. """ + self.load_jvm_var(jObject, 0) # __________________________________________________________________ # Exception Handling @@ -604,17 +722,11 @@ jty = self.db.lltype_to_cts(v.concretetype) # Determine index in stack frame slots: # note that arguments and locals can be treated the same here - if v in self.local_vars: - idx = self.local_vars[v] - else: - idx = self.local_vars[v] = self.next_offset - self.next_offset += jty.type_width() - return jty, idx + return jty, self.curfunc.var_offset(v, jty) def load(self, value): if isinstance(value, flowmodel.Variable): jty, idx = self._var_data(value) - print "load_jvm_var: jty=%s idx=%s" % (repr(jty), repr(idx)) return self.load_jvm_var(jty, idx) if isinstance(value, flowmodel.Constant): @@ -624,6 +736,10 @@ repr(value.concretetype) + " v=" + repr(value)) def store(self, v): + # Ignore Void values + if v.concretetype is ootype.Void: + return + if isinstance(v, flowmodel.Variable): jty, idx = self._var_data(v) return self.store_jvm_var(jty, idx) @@ -631,6 +747,9 @@ def set_field(self, CONCRETETYPE, fieldname): if fieldname == "meta": + # temporary hack + self.add_comment(" WARNING: emulating meta for now") + self.emit(POP) self.emit(POP) else: clsobj = self.db.pending_class(CONCRETETYPE) @@ -639,6 +758,7 @@ def get_field(self, CONCRETETYPE, fieldname): if fieldname == 'meta': + self.add_comment(" WARNING: emulating meta for now") self.emit(POP) self.emit(ACONST_NULL) else: @@ -646,8 +766,13 @@ fieldobj = clsobj.lookup_field(fieldname) fieldobj.load(self) - def downcast(self, type): - self._instr(CHECKCAST, type) + def downcast(self, TYPE): + jtype = self.db.lltype_to_cts(TYPE) + self._instr(CHECKCAST, jtype) + + def instanceof(self, TYPE): + jtype = self.db.lltype_to_cts(TYPE) + self._instr(INSTANCEOF, jtype) def branch_unconditionally(self, target_label): self._instr(GOTO, target_label) @@ -662,6 +787,11 @@ mthd = self.db.pending_function(graph) mthd.invoke(self) + def call_method(self, OOCLASS, method_name): + clsobj = self.db.pending_class(OOCLASS) + mthd = clsobj.lookup_method(method_name) + mthd.invoke(self) + def call_primitive(self, graph): raise NotImplementedError @@ -671,6 +801,9 @@ self.emit(NEW, clsobj.jvm_type()) self.emit(DUP) self.emit(ctor) + + def instantiate(self): + self.emit(PYPYRUNTIMENEW) # __________________________________________________________________ # Methods invoked directly by strings in jvm/opcode.py @@ -713,6 +846,9 @@ self._instr(ICONST, 1) self.mark(endlbl) + is_null = lambda self: self._compare_op(IFNULL) + is_not_null = lambda self: self._compare_op(IFNOTNULL) + logical_not = lambda self: self._compare_op(IFEQ) equals_zero = logical_not not_equals_zero = lambda self: self._compare_op(IFNE) @@ -774,74 +910,60 @@ JVMGenerator.__init__(self, db) self.outdir = outdir - def add_comment(self, comment): - self.out.write(" ; %s\n" % comment) - - def begin_class(self, classnm): + def _begin_class(self): """ classnm --- full Java name of the class (i.e., "java.lang.String") """ + + iclassnm = self.curclass.class_name.replace('.', '/') + isuper = self.curclass.superclass_name.replace('.', '/') - iclassnm = classnm.replace('.', '/') jfile = "%s/%s.j" % (self.outdir, iclassnm) try: jdir = jfile[:jfile.rindex('/')] os.makedirs(jdir) except OSError: pass - self.out = open(jfile, 'w') + self.curclass.file = open(jfile, 'w') # Write the JasminXT header - #self.out.write(".bytecode XX\n") - #self.out.write(".source \n") - self.out.write(".class public %s\n" % iclassnm) - - # FIX: custom super class - self.out.write(".super java/lang/Object\n") - self.constructor_emitted = False + self.curclass.out(".class public %s\n" % iclassnm) + self.curclass.out(".super %s\n" % isuper) - def end_class(self): - self._emit_constructor() - self.out.close() - self.out = None + def _end_class(self): + self.curclass.file.close() def close(self): - assert self.out is None, "Unended class" + assert self.curclass is None + + def add_comment(self, comment): + self.curclass.out(" ; %s\n" % comment) def add_field(self, fobj): - self.out.write('.field public %s %s\n' % ( + self.curclass.out('.field public %s %s\n' % ( fobj.field_name, fobj.jtype)) - def _emit_constructor(self): - if not self.constructor_emitted: - self.out.write(".method public ()V\n") - self.out.write(" aload_0\n") - self.out.write(" invokespecial java/lang/Object/()V\n") - self.out.write(" return\n") - self.out.write(".end method\n") - self.constructor_emitted = True - def _begin_function(self, funcname, argtypes, rettype, static): - self._emit_constructor() + if not static: argtypes = argtypes[1:] # Throws clause? Only use RuntimeExceptions? kw = ['public'] if static: kw.append('static') - self.out.write('.method %s %s(%s)%s\n' % ( + self.curclass.out('.method %s %s(%s)%s\n' % ( " ".join(kw), funcname, "".join(argtypes), rettype)) def _end_function(self): - self.out.write('.limit stack 100\n') # HACK, track max offset - self.out.write('.limit locals %d\n' % self.next_offset) - self.out.write('.end method\n') + self.curclass.out('.limit stack 100\n') # HACK, track max offset + self.curclass.out('.limit locals %d\n' % self.curfunc.next_offset) + self.curclass.out('.end method\n') def mark(self, lbl): """ Marks the point that a label indicates. """ _, lblnum, lbldesc = lbl assert _ == "Label" - self.out.write(' %s_%s:\n' % (lbldesc, lblnum)) + self.curclass.out(' %s_%s:\n' % (lbldesc, lblnum)) def _instr(self, opcode, *args): jvmstr, args = opcode.specialize_opcode(args) @@ -853,10 +975,12 @@ if opcode.flags & (INVOKE|FIELD): assert len(args) == 1 args = (args[0].jasmin_syntax(),) - self.out.write(' %s %s\n' % ( - jvmstr, " ".join([str(s) for s in args]))) + instr_text = ' %s %s' % (jvmstr, " ".join([str(s) for s in args])) + self.curclass.out(' %-60s ; %d\n' % ( + instr_text, self.curfunc.instr_counter)) + self.curfunc.instr_counter+=1 def try_catch_region(self, excclsty, trystartlbl, tryendlbl, catchlbl): - self.out.write(' .catch %s from %s to %s using %s\n' % ( + self.curclass.out(' .catch %s from %s to %s using %s\n' % ( excclsty.int_class_name(), trystartlbl, tryendlbl, catchlbl)) Modified: pypy/dist/pypy/translator/jvm/node.py ============================================================================== --- pypy/dist/pypy/translator/jvm/node.py (original) +++ pypy/dist/pypy/translator/jvm/node.py Wed Nov 1 14:57:43 2006 @@ -8,8 +8,9 @@ from pypy.rpython.ootypesystem import ootype from pypy.translator.jvm.typesystem import \ jString, jStringArray, jVoid, jThrowable -from pypy.translator.jvm.typesystem import jvm_for_class, jvm_method_desc +from pypy.translator.jvm.typesystem import jvm_for_class, jvm_method_desc, jInt from pypy.translator.jvm.opcodes import opcodes +from pypy.translator.jvm.option import getoption from pypy.translator.oosupport.function import Function as OOFunction import pypy.translator.jvm.generator as jvmgen @@ -60,16 +61,8 @@ ootype.Char:jvmgen.PYPYSTRTOCHAR } - _type_printing_methods = { - ootype.Signed:jvmgen.PYPYDUMPINT, - ootype.Unsigned:jvmgen.PYPYDUMPUINT, - ootype.SignedLongLong:jvmgen.PYPYDUMPLONG, - ootype.Float:jvmgen.PYPYDUMPDOUBLE, - ootype.Bool:jvmgen.PYPYDUMPBOOLEAN, - } - def render(self, gen): - gen.begin_class('pypy.Main') + gen.begin_class('pypy.Main', 'java.lang.Object') gen.begin_function( 'main', (), [jStringArray], jVoid, static=True) @@ -97,10 +90,10 @@ # Print result? if self.print_result: - resootype = self.graph.getreturnvar().concretetype - resjtype = self.db.lltype_to_cts(resootype) - meth = self._type_printing_methods[resootype] - gen.emit(meth) + gen.emit(jvmgen.ICONST, 0) + RESOOTYPE = self.graph.getreturnvar().concretetype + dumpmethod = self.db.generate_dump_method_for_ootype(RESOOTYPE) + dumpmethod.invoke(gen) # And finish up gen.return_val(jVoid) @@ -131,9 +124,13 @@ def method(self): """ Returns a jvmgen.Method that can invoke this function """ - if not self.is_method: opcode = jvmgen.INVOKESTATIC - else: opcode = jvmgen.INVOKEVIRTUAL - mdesc = jvm_method_desc(self.jargtypes, self.jrettype) + if not self.is_method: + opcode = jvmgen.INVOKESTATIC + startidx = 0 + else: + opcode = jvmgen.INVOKEVIRTUAL + startidx = 1 + mdesc = jvm_method_desc(self.jargtypes[startidx:], self.jrettype) return jvmgen.Method(self.classnm, self.name, mdesc, opcode=opcode) def begin_render(self): @@ -196,15 +193,14 @@ self.ilasm.load(exc) self.ilasm.throw() - 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 ootype.Void: - self.ilasm.load(to_load) - self.ilasm.store(to_store) - def _render_op(self, op): self.generator.add_comment(str(op)) + + if getoption('trace'): + jvmgen.SYSTEMERR.load(self.generator) + self.generator.load_string(str(op) + "\n") + jvmgen.PRINTSTREAMPRINTSTR.invoke(self.generator) + OOFunction._render_op(self, op) class Class(Node): @@ -212,15 +208,16 @@ """ Represents a class to be emitted. Note that currently, classes are emitted all in one shot, not piecemeal. """ - def __init__(self, name): + def __init__(self, name, supername): """ - 'name' should be a fully qualified Java class name like + 'name' and 'super_name' should be fully qualified Java class names like "java.lang.String" """ - self.name = name # public attribute - self.fields = [] - self.methods = [] + self.name = name # public attribute + self.super_name = supername # public attribute + self.fields = {} self.rendered = False + self.methods = {} def jvm_type(self): return jvm_for_class(self.name) @@ -229,29 +226,104 @@ """ Creates a new field accessed via the jvmgen.Field descriptor 'fieldobj'. Must be called before render().""" assert not self.rendered and isinstance(fieldobj, jvmgen.Field) - self.fields.append(fieldobj) + self.fields[fieldobj.field_name] = fieldobj def lookup_field(self, fieldnm): - for f in self.fields: - if f.field_name == fieldnm: return f - assert False, "No field named '%s' found" % fieldnm + """ Given a field name, returns a jvmgen.Field object """ + return self.fields[fieldnm] + + def lookup_method(self, methodnm): + """ Given the method name, returns a jvmgen.Method object """ + return self.methods[methodnm].method() def add_method(self, func): """ Creates a new method in this class, represented by the Function object 'func'. Must be called before render(); intended to be invoked by the database. Note that some of these 'methods' may actually represent static functions. """ - self.methods.append(func) + self.methods[func.name] = func + def add_dump_method(self, dm): + self.dump_method = dm # public attribute for reading + self.add_method(dm) + def render(self, gen): self.rendered = True - gen.begin_class(self.name) + gen.begin_class(self.name, self.super_name) - for field in self.fields: + for field in self.fields.values(): gen.add_field(field) - for method in self.methods: + gen.emit_constructor() + + for method in self.methods.values(): method.render(gen) gen.end_class() +class TestDumpMethod(object): + + def __init__(self, db, OOCLASS, clsobj): + self.db = db + self.OOCLASS = OOCLASS + self.clsobj = clsobj + self.name = "_pypy_dump" + self.jargtypes = [clsobj.jvm_type(), jInt] + self.jrettype = jVoid + + def method(self): + """ Returns a jvmgen.Method that can invoke this function """ + mdesc = jvm_method_desc(self.jargtypes[1:], self.jrettype) + return jvmgen.Method(self.clsobj.name, self.name, mdesc, + opcode=jvmgen.INVOKEVIRTUAL) + + def render(self, gen): + clsobj = self.clsobj + + gen.begin_function( + self.name, (), self.jargtypes, self.jrettype, static=False) + + def genprint(str, unoffset=0): + gen.load_jvm_var(jInt, 1) + if unoffset: + gen.emit(jvmgen.ICONST, unoffset) + gen.emit(jvmgen.ISUB) + gen.load_string(str) + jvmgen.PYPYDUMPINDENTED.invoke(gen) + + # Start the dump + genprint("InstanceWrapper([") + + # Increment the indent + gen.load_jvm_var(jInt, 1) + gen.emit(jvmgen.ICONST, 2) + gen.emit(jvmgen.IADD) + gen.store_jvm_var(jInt, 1) + + for fieldnm, (FIELDOOTY, fielddef) in self.OOCLASS._fields.iteritems(): + + if FIELDOOTY is ootype.Void: continue + + genprint("(") + genprint(fieldnm+",") + + print "fieldnm=%r fieldty=%r" % (fieldnm, FIELDOOTY) + + # Print the value of the field: + gen.load_this_ptr() + fieldobj = clsobj.lookup_field(fieldnm) + fieldobj.load(gen) + gen.load_jvm_var(jInt, 1) + dumpmethod = self.db.generate_dump_method_for_ootype(FIELDOOTY) + gen.emit(dumpmethod) + + genprint(")") + + # Decrement indent and dump close + genprint("])", 2) + + gen.emit(jvmgen.RETURN.for_type(jVoid)) + + gen.end_function() + + Modified: pypy/dist/pypy/translator/jvm/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/jvm/opcodes.py (original) +++ pypy/dist/pypy/translator/jvm/opcodes.py Wed Nov 1 14:57:43 2006 @@ -7,7 +7,7 @@ from pypy.translator.oosupport.metavm import \ PushArg, PushAllArgs, StoreResult, InstructionList, New, DoNothing, Call,\ - SetField, GetField + SetField, GetField, CallMethod, DownCast, RuntimeNew import pypy.translator.jvm.generator as jvmgen def _check_zer(op): @@ -23,14 +23,14 @@ opcodes = { # __________ object oriented operations __________ 'new': [New, StoreResult], - #'runtimenew': [RuntimeNew], + 'runtimenew': [RuntimeNew, StoreResult], 'oosetfield': [SetField], 'oogetfield': [GetField, StoreResult], - #'oosend': [CallMethod], - #'ooupcast': DoNothing, - #'oodowncast': [DownCast], - #'oois': 'ceq', - #'oononnull': [PushAllArgs, 'ldnull', 'ceq']+Not, + 'oosend': [CallMethod, StoreResult], + 'ooupcast': DoNothing, + 'oodowncast': [DownCast,StoreResult], + 'oois': 'is_null', + 'oononnull': 'is_not_null', #'instanceof': [CastTo, 'ldnull', 'cgt.un'], #'subclassof': [PushAllArgs, 'call bool [pypylib]pypy.runtime.Utils::SubclassOf(class [mscorlib]System.Type, class[mscorlib]System.Type)'], #'ooidentityhash': [PushAllArgs, 'callvirt instance int32 object::GetHashCode()'], @@ -41,7 +41,7 @@ # 'same_as': DoNothing, #'hint': [PushArg(0), StoreResult], - 'direct_call': [Call], + 'direct_call': [Call, StoreResult], #'indirect_call': [IndirectCall], # #'cast_ptr_to_weakadr': [PushAllArgs, 'newobj instance void class %s::.ctor(object)' % WEAKREF], Modified: pypy/dist/pypy/translator/jvm/option.py ============================================================================== --- pypy/dist/pypy/translator/jvm/option.py (original) +++ pypy/dist/pypy/translator/jvm/option.py Wed Nov 1 14:57:43 2006 @@ -8,7 +8,8 @@ 'noasm':False, 'package':'pypy', 'wd':False, - 'norun':False + 'norun':False, + 'trace':False } def getoption(name): Modified: pypy/dist/pypy/translator/jvm/src/PyPy.java ============================================================================== --- pypy/dist/pypy/translator/jvm/src/PyPy.java (original) +++ pypy/dist/pypy/translator/jvm/src/PyPy.java Wed Nov 1 14:57:43 2006 @@ -185,45 +185,69 @@ // Used in testing: - public static void dump_int(int i) { - System.out.println(i); + public static void dump_indented(int indent, String text) { + for (int i = 0; i < indent; i++) + System.out.print(" "); + System.out.println(text); } - public static void dump_uint(int i) { + public static void dump_int(int i, int indent) { + dump_indented(indent, Integer.toString(i)); + } + + public static void dump_uint(int i, int indent) { if (i >= 0) - System.out.println(i); + dump_indented(indent, Integer.toString(i)); else { int loword = i & 0xFFFF; int hiword = i >>> 16; long res = loword + (hiword*0xFFFF); - System.out.println(res); + dump_indented(indent, Long.toString(res)); } } - public static void dump_boolean(boolean l) { + public static void dump_boolean(boolean l, int indent) { if (l) - System.out.println("True"); + dump_indented(indent, "True"); else - System.out.println("False"); + dump_indented(indent, "False"); } - public static void dump_long(long l) { - System.out.println(l); + public static void dump_long(long l, int indent) { + dump_indented(indent, Long.toString(l)); } - public static void dump_double(double d) { - System.out.println(d); + public static void dump_double(double d, int indent) { + dump_indented(indent, Double.toString(d)); } - public static void dump_string(char[] b) { - System.out.print('"'); + public static void dump_string(char[] b, int indent) { + StringBuffer sb = new StringBuffer(); + sb.append('"'); for (char c : b) { if (c == '"') - System.out.print("\\\""); - System.out.print(c); + sb.append("\\\""); + else + sb.append(c); + } + sb.append('"'); + dump_indented(indent, sb.toString()); + } + + public static void dump_object(Object o, int indent) { + dump_indented(indent, o.toString()); + } + + // ---------------------------------------------------------------------- + // Type Manipulation Routines + + public static Object RuntimeNew(Class c) { + // all classes in our system have constructors w/ no arguments + try { + return c.getConstructor().newInstance(); + } catch (Exception exc) { + throw new RuntimeException("Unexpected", exc); } - System.out.print('"'); - System.out.println(); } // ---------------------------------------------------------------------- Modified: pypy/dist/pypy/translator/jvm/test/runtest.py ============================================================================== --- pypy/dist/pypy/translator/jvm/test/runtest.py (original) +++ pypy/dist/pypy/translator/jvm/test/runtest.py Wed Nov 1 14:57:43 2006 @@ -40,6 +40,14 @@ def __repr__(self): return 'ExceptionWrapper(%s)' % repr(self.class_name) +class InstanceWrapper: + def __init__(self, fields): + # fields is a list of (name, value) tuples + self.fields = fields + + def __repr__(self): + return 'InstanceWrapper(%s)' % repr(self.fields) + # CLI could-be duplicate class JvmGeneratedSourceWrapper(object): def __init__(self, gensrc): Modified: pypy/dist/pypy/translator/jvm/typesystem.py ============================================================================== --- pypy/dist/pypy/translator/jvm/typesystem.py (original) +++ pypy/dist/pypy/translator/jvm/typesystem.py Wed Nov 1 14:57:43 2006 @@ -48,9 +48,13 @@ return not self.is_scalar() def is_array(self): return self[0] == '[' + def class_name(self): + """ Converts a descriptor like Ljava/lang/Object; to + full class name java.lang.Object """ + return self.int_class_name().replace('/','.') def int_class_name(self): """ Converts a descriptor like Ljava/lang/Object; to - java/lang/Object """ + internal class name java/lang/Object """ assert self[0] == 'L' and self[-1] == ';' return self[1:-1] def type_width(self): @@ -93,6 +97,7 @@ jIterator = jvm_for_class('java.util.Iterator') jClass = jvm_for_class('java.lang.Class') jStringBuilder = jvm_for_class('java.lang.StringBuilder') +jPrintStream = jvm_for_class('java.io.PrintStream') # Map from OOType to an internal JVM type descriptor # only handles the simple cases Modified: pypy/dist/pypy/translator/oosupport/function.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/function.py (original) +++ pypy/dist/pypy/translator/oosupport/function.py Wed Nov 1 14:57:43 2006 @@ -158,9 +158,12 @@ self.generator.branch_conditionally(link.exitcase, target_label) def _setup_link(self, link): + self.generator.add_comment("Setup link") target = link.target for to_load, to_store in zip(link.args, target.inputargs): if to_load.concretetype is not Void: + self.generator.add_comment(" to_load=%r to_store=%r" % ( + to_load, to_store)) self.generator.load(to_load) self.generator.store(to_store) Modified: pypy/dist/pypy/translator/oosupport/metavm.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/metavm.py (original) +++ pypy/dist/pypy/translator/oosupport/metavm.py Wed Nov 1 14:57:43 2006 @@ -15,6 +15,19 @@ from pypy.rpython.ootypesystem.bltregistry import ExternalType class Generator(object): + + def add_comment(self, text): + """ + Called w/in a function w/ a text string that could be + usefully added to the output. + """ + pass + + def dup(self, TYPE): + """ Duplicates the top of the stack, which is of the given TYPE. + + Stack: val, ... -> val, val, ...""" + raise NotImplementedError def emit(self, instr, *args): """ @@ -49,7 +62,7 @@ Stack: value, item, ... -> ... """ - pass + raise NotImplementedError def get_field(self, CONCRETETYPE, fieldname): """ @@ -60,15 +73,35 @@ Stack: item, ... -> ... """ - pass + raise NotImplementedError - def downcast(self, type): + def downcast(self, TYPE): """ Casts the object on the top of the stack to be of the specified - type. Assumed to raise an exception on failure. + ootype. Assumed to raise an exception on failure. Stack: obj, ... -> obj, ... """ + raise NotImplementedError + + + def instantiate(self): + """ + Instantiates an instance of the Class object that is on top of + the stack. Class objects refers to an object representing a + class. Used to implement RuntimeNew. + + Stack: class_obj, ... -> instance_obj, ... + """ + raise NotImplementedError + + def instanceof(self, TYPE): + """ + Determines whether the object on the top of the stack is an + instance of TYPE (an ootype). + + Stack: obj, ... -> boolean, ... + """ pass def branch_unconditionally(self, target_label): @@ -85,13 +118,20 @@ raise NotImplementedError def call_graph(self, graph): - """ Invokes the method corresponding to the given graph. The + """ Invokes the function corresponding to the given graph. The arguments to the graph have already been pushed in order (i.e., first argument pushed first, etc). Pushes the return value. Stack: argN...arg2, arg1, arg0, ... -> ret, ... """ - raise NotImplementedError + raise NotImplementedError + + def call_method(self, OOCLASS, method_name): + """ Invokes the given method on the object on the stack. The + this ptr and all arguments have already been pushed. + + Stack: argN, arg2, arg1, this, ... -> ret, ... """ + raise NotImplementedError def call_primitive(self, graph): """ Like call_graph, but it has been suggested that the method be @@ -106,6 +146,9 @@ Stack: ... -> newobj, ... """ raise NotImplementedError + def push_null(self): + raise NotImplementedError + class InstructionList(list): def render(self, generator, op): for instr in self: @@ -182,9 +225,16 @@ result on top of the stack. """ def render(self, generator, op): RESULTTYPE = op.result.concretetype - resulttype = generator.cts.lltype_to_cts(RESULTTYPE) generator.load(op.args[0]) - generator.downcast(resulttype) + generator.downcast(RESULTTYPE) + +class _InstanceOf(MicroInstruction): + """ Push the argument op.args[0] and cast it to the desired type, leaving + result on top of the stack. """ + def render(self, generator, op): + RESULTTYPE = op.result.concretetype + generator.load(op.args[0]) + generator.instanceof(RESULTTYPE) # There are three distinct possibilities where we need to map call differently: # 1. Object is marked with rpython_hints as a builtin, so every attribut access @@ -292,37 +342,23 @@ else: generator.call_graph(graph) else: - self._render_method(generator, method_name, op.args[1:]) - - def _render_method(self, generator, method_name, args): - this = args[0] - for arg in args: # push parameters - generator.load(arg) - - # XXX: very hackish, need refactoring - if this.concretetype is ootype.String: - # special case for string: don't use methods, but plain functions - METH = this.concretetype._METHODS[method_name] - cts = generator.cts - ret_type = cts.lltype_to_cts(METH.RESULT) - arg_types = [cts.lltype_to_cts(arg) for arg in METH.ARGS if arg is not ootype.Void] - arg_types.insert(0, cts.lltype_to_cts(ootype.String)) - arg_list = ', '.join(arg_types) - signature = '%s %s::%s(%s)' % (ret_type, STRING_HELPER_CLASS, method_name, arg_list) - generator.call_signature(signature) - else: + this = op.args[1] generator.call_method(this.concretetype, method_name) - # special case: DictItemsIterator(XXX, - # Void).ll_current_value needs to return an int32 because - # we can't use 'void' as a parameter of a Generic. This - # means that after the call to ll_current_value there will - # be a value on the stack, and we need to explicitly pop - # it. - if isinstance(this.concretetype, ootype.DictItemsIterator) and \ - this.concretetype._VALUETYPE is ootype.Void and \ - method_name == 'll_current_value': - generator.ilasm.pop() +class _CallMethod(MicroInstruction): + def render(self, generator, op): + method = op.args[0] # a FlowConstant string... + this = op.args[1] + for arg in op.args[1:]: + generator.load(arg) + generator.call_method(this.concretetype, method.value) + +class _RuntimeNew(MicroInstruction): + def render(self, generator, op): + generator.load(op.args[0]) + generator.instantiate() + generator.downcast(op.result.concretetype) + New = _New() @@ -333,3 +369,5 @@ DownCast = _DownCast() DoNothing = _DoNothing() Call = _Call() +CallMethod = _CallMethod() +RuntimeNew = _RuntimeNew() From rxe at codespeak.net Wed Nov 1 15:01:37 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 1 Nov 2006 15:01:37 +0100 (CET) Subject: [pypy-svn] r34024 - in pypy/dist/pypy: jit/timeshifter/test lang/automata Message-ID: <20061101140137.7B5B810071@code0.codespeak.net> Author: rxe Date: Wed Nov 1 15:01:33 2006 New Revision: 34024 Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/lang/automata/dfa.py Log: fix up final states (thanks samuele) Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Wed Nov 1 15:01:33 2006 @@ -7,8 +7,6 @@ from pypy.objspace.flow.model import checkgraph, summary from pypy.rlib.objectmodel import hint -from pypy.rlib.objectmodel import hint - import py.test class TestPortal(object): @@ -121,11 +119,10 @@ self.check_insns(int_floordiv=1, int_mul=0) def test_dfa_compile(self): - py.test.skip("we've gone yellow") from pypy.lang.automata.dfa import getautomaton, convertdfa, recognizetable + a = getautomaton() + dfatable, final_states = convertdfa(a) def main(gets): - a = getautomaton() - dfatable, final_states = convertdfa(a) s = ["aaaaaaaaaab", "aaaa"][gets] return recognizetable(dfatable, s, final_states) Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Wed Nov 1 15:01:33 2006 @@ -59,7 +59,7 @@ def convertdfa(automaton): """ converts the dfa transitions into a table, represented as a big string. this is just to make the code more amenable to current state of the JIT. Returns - a two tuple of dfa as table, and final states""" + a two tuple of dfa as table, and final states""" size = automaton.num_states * 256 dfatable = [chr(255)] * size @@ -83,10 +83,18 @@ if state == 255: break indx += 1 - state = hint(state, variable=True) # more strange code for now - check final state? - for fs in finalstates: - if state == ord(fs): - return 1 - return 0 + res = 0 + indx = 0 + while True: + if indx >= len(finalstates): + break + fs = ord(finalstates[indx]) + fs = hint(fs, concrete=True) + if state == fs: + res = 1 + break + indx += 1 + res = hint(res, variable=True) + return res From niko at codespeak.net Wed Nov 1 15:01:59 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Wed, 1 Nov 2006 15:01:59 +0100 (CET) Subject: [pypy-svn] r34025 - in pypy/dist/pypy/translator/jvm: . test Message-ID: <20061101140159.70F4910077@code0.codespeak.net> Author: niko Date: Wed Nov 1 15:01:58 2006 New Revision: 34025 Modified: pypy/dist/pypy/translator/jvm/genjvm.py pypy/dist/pypy/translator/jvm/test/test_bool.py Log: change stderr for executing generated code so that it is not hidden Modified: pypy/dist/pypy/translator/jvm/genjvm.py ============================================================================== --- pypy/dist/pypy/translator/jvm/genjvm.py (original) +++ pypy/dist/pypy/translator/jvm/genjvm.py Wed Nov 1 15:01:58 2006 @@ -86,7 +86,7 @@ res = subp.wait() if res or (not allow_stderr and stderr): raise JvmSubprogramError(res, args, stdout, stderr) - return stdout + return stdout, stderr def compile(self): """ @@ -125,7 +125,9 @@ '-cp', str(self.javadir), self.package+".Main"] + strargs - return self._invoke(cmd, True) + stdout, stderr = self._invoke(cmd, True) + sys.stderr.write(stderr) + return stdout def generate_source_for_function(func, annotation): Modified: pypy/dist/pypy/translator/jvm/test/test_bool.py ============================================================================== --- pypy/dist/pypy/translator/jvm/test/test_bool.py (original) +++ pypy/dist/pypy/translator/jvm/test/test_bool.py Wed Nov 1 15:01:58 2006 @@ -2,6 +2,6 @@ from pypy.translator.jvm.test.runtest import JvmTest from pypy.rpython.test.test_rbool import BaseTestRbool -#class TestJvmBool(JvmTest, BaseTestRbool): -# pass +class TestJvmBool(JvmTest, BaseTestRbool): + pass From ericvrp at codespeak.net Wed Nov 1 15:28:49 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 1 Nov 2006 15:28:49 +0100 (CET) Subject: [pypy-svn] r34027 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061101142849.3FB0210071@code0.codespeak.net> Author: ericvrp Date: Wed Nov 1 15:28:48 2006 New Revision: 34027 Added: pypy/dist/pypy/jit/codegen/llvm/test/square.ll Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: (mwh, ericvrp) added libllvmjit functions compile&execute. Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Wed Nov 1 15:28:48 2006 @@ -2,6 +2,57 @@ #include "libllvmjit.h" +#include "llvm/Module.h" +#include "llvm/Assembly/Parser.h" +#include "llvm/Bytecode/Writer.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/System/Signals.h" +#include "llvm/ModuleProvider.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/ExecutionEngine/Interpreter.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include +#include +#include + +using namespace llvm; + + int testme(int n) { return n * 2; } + + +void* compile(const char* filename) { + std::string inputfile(filename); + + //from llvm-as.cpp + Module* module(ParseAssemblyFile(inputfile + ".ll")); + if (!module) return NULL; + + std::ostream *Out = new std::ofstream((inputfile + ".bc").c_str(), + std::ios::out | std::ios::trunc | std::ios::binary); + WriteBytecodeToFile(module, *Out); //XXX what to do with the 3rd param (NoCompress)? + + return module; +} + + +int execute(void* compiled, const char* funcname, int param) { //currently compiled=Module + Module* module = (Module*)compiled; + if (!module) { + std::cerr << "Error: can not execute " << funcname << " in a non existing module\n" << std::flush; + return -1; + } + + ExistingModuleProvider* module_provider = new ExistingModuleProvider(module); + ExecutionEngine* EE = ExecutionEngine::create(module_provider, false); + + std::vector args; + args.push_back((void*)param); + GenericValue gv = EE->runFunction(module->getNamedFunction(funcname), args); + + return gv.IntVal; +} Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h Wed Nov 1 15:28:48 2006 @@ -5,6 +5,8 @@ #endif int testme(int n); +void* compile(const char* filename); +int execute(void* compiled, const char* funcname, int param); #ifdef __cplusplus } Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Wed Nov 1 15:28:48 2006 @@ -8,18 +8,27 @@ ''' from pypy.rpython.rctypes import implementation -import ctypes +from ctypes import _CFuncPtr, _FUNCFLAG_CDECL +from ctypes import * import os path = os.path.join(os.path.dirname(__file__), 'libllvmjit.so') -llvmjit = ctypes.cdll.LoadLibrary(os.path.abspath(path)) -class _FuncPtr(ctypes._CFuncPtr): - _flags_ = ctypes._FUNCFLAG_CDECL +llvmjit = cdll.LoadLibrary(os.path.abspath(path)) +class _FuncPtr(_CFuncPtr): + _flags_ = _FUNCFLAG_CDECL # aaarghdistutilsunixaaargh (may need something different for standalone builds...) libraries = (os.path.join(os.path.dirname(path), 'llvmjit'),) llvmjit._FuncPtr = _FuncPtr -#impls +#exposed functions... testme = llvmjit.testme -testme.restype = ctypes.c_int -testme.argtypes = [ctypes.c_int] +testme.restype = c_int +testme.argtypes = [c_int] + +compile = llvmjit.compile +compile.restype = c_void_p +compile.argtypes = [c_char_p] + +execute = llvmjit.execute +execute.restype = c_int +execute.argtypes = [c_void_p, c_char_p, c_int] Added: pypy/dist/pypy/jit/codegen/llvm/test/square.ll ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/test/square.ll Wed Nov 1 15:28:48 2006 @@ -0,0 +1,5 @@ +int %square(int %n) { +block0: + %n2 = mul int %n, %n + ret int %n2 +} Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Wed Nov 1 15:28:48 2006 @@ -1,10 +1,14 @@ import py +from os.path import dirname, join from pypy.translator.c.test.test_genc import compile try: from pypy.jit.codegen.llvm import llvmjit except OSError: - py.test.skip("llvmjit library not found (see ../README.TXT)") + py.test.skip("libllvmjit not found (see ../README.TXT)") + +curdir = dirname(__file__) +square = join(curdir, 'square') def test_testme(): assert llvmjit.testme(10) == 20 @@ -15,3 +19,11 @@ fn = compile(f, [int]) res = fn(1) assert res == 42 + +def test_compile(): + assert llvmjit.compile(square) + +def test_compiled(): + compiled = llvmjit.compile(square) + assert llvmjit.execute(compiled, 'square', 4) == 4 * 4 + From cfbolz at codespeak.net Wed Nov 1 15:49:15 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 15:49:15 +0100 (CET) Subject: [pypy-svn] r34033 - pypy/dist/pypy/translator/microbench/pybench Message-ID: <20061101144915.3526410063@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 15:49:14 2006 New Revision: 34033 Added: pypy/dist/pypy/translator/microbench/pybench/autopath.py - copied unchanged from r34003, pypy/dist/pypy/translator/autopath.py Log: adding missing autopath (pybench.py contains an import of it) From cfbolz at codespeak.net Wed Nov 1 15:52:52 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 15:52:52 +0100 (CET) Subject: [pypy-svn] r34034 - in pypy/dist/pypy/rlib: . test Message-ID: <20061101145252.F01C610077@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 15:52:52 2006 New Revision: 34034 Added: pypy/dist/pypy/rlib/autopath.py - copied unchanged from r34003, pypy/dist/pypy/bin/autopath.py pypy/dist/pypy/rlib/test/autopath.py - copied unchanged from r34003, pypy/dist/pypy/bin/autopath.py Log: more missing autopaths From arigo at codespeak.net Wed Nov 1 15:58:11 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 1 Nov 2006 15:58:11 +0100 (CET) Subject: [pypy-svn] r34035 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20061101145811.8739C10079@code0.codespeak.net> Author: arigo Date: Wed Nov 1 15:58:10 2006 New Revision: 34035 Modified: pypy/dist/pypy/objspace/std/stdtypedef.py pypy/dist/pypy/objspace/std/test/test_stdobjspace.py Log: (pedronis, arigo) A hack to enumerate the multimethods that a given W_XxxObject class implements. Modified: pypy/dist/pypy/objspace/std/stdtypedef.py ============================================================================== --- pypy/dist/pypy/objspace/std/stdtypedef.py (original) +++ pypy/dist/pypy/objspace/std/stdtypedef.py Wed Nov 1 15:58:10 2006 @@ -309,3 +309,16 @@ for multimethod in typedef.local_multimethods: slicemultimethod(space, multimethod, typedef, result, local=True) return result + +def multimethods_defined_on(cls): + """NOT_RPYTHON: enumerate the (multimethod, local_flag) for all the + multimethods that have an implementation whose first typed argument + is 'cls'. + """ + from pypy.objspace.std.objspace import StdObjSpace # XXX for now + typedef = cls.typedef + for multimethod in hack_out_multimethods(StdObjSpace.MM.__dict__): + if cls in multimethod.dispatch_tree: + yield multimethod, False + for multimethod in typedef.local_multimethods: + yield multimethod, True Modified: pypy/dist/pypy/objspace/std/test/test_stdobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_stdobjspace.py (original) +++ pypy/dist/pypy/objspace/std/test/test_stdobjspace.py Wed Nov 1 15:58:10 2006 @@ -22,7 +22,15 @@ raises(OperationError,self.space.uint_w,self.space.wrap(None)) raises(OperationError,self.space.uint_w,self.space.wrap("")) - - def hopeful_test_exceptions(self): - self.apptest("self.failUnless(issubclass(ArithmeticError, Exception))") - self.apptest("self.failIf(issubclass(ArithmeticError, KeyError))") + def test_multimethods_defined_on(self): + from pypy.objspace.std.stdtypedef import multimethods_defined_on + from pypy.objspace.std.listobject import W_ListObject + res = multimethods_defined_on(W_ListObject) + res = [(m.name, local) for (m, local) in res] + assert ('add', False) in res + assert ('lt', False) in res + assert ('setitem', False) in res + assert ('mod', False) not in res + assert ('pop', True) in res + assert ('reverse', True) in res + assert ('popitem', True) not in res From cfbolz at codespeak.net Wed Nov 1 16:02:54 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 16:02:54 +0100 (CET) Subject: [pypy-svn] r34036 - in pypy/dist/pypy: objspace/std objspace/std/test rlib rlib/test Message-ID: <20061101150254.0D58010071@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 16:02:51 2006 New Revision: 34036 Added: pypy/dist/pypy/rlib/listsort.py - copied, changed from r34003, pypy/dist/pypy/objspace/std/listsort.py pypy/dist/pypy/rlib/test/test_listsort.py - copied, changed from r34003, pypy/dist/pypy/objspace/std/test/test_listsort.py Removed: pypy/dist/pypy/objspace/std/listsort.py pypy/dist/pypy/objspace/std/test/test_listsort.py Modified: pypy/dist/pypy/objspace/std/listobject.py Log: move timsort to rlib Modified: pypy/dist/pypy/objspace/std/listobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/listobject.py (original) +++ pypy/dist/pypy/objspace/std/listobject.py Wed Nov 1 16:02:51 2006 @@ -5,7 +5,7 @@ from pypy.objspace.std import slicetype from pypy.interpreter import gateway, baseobjspace -from pypy.objspace.std.listsort import TimSort +from pypy.rlib.listsort import TimSort class W_ListObject(W_Object): From stephan at codespeak.net Wed Nov 1 16:16:11 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Wed, 1 Nov 2006 16:16:11 +0100 (CET) Subject: [pypy-svn] r34037 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061101151611.4736410071@code0.codespeak.net> Author: stephan Date: Wed Nov 1 16:16:10 2006 New Revision: 34037 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/jsobj.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) Basic function parameters working Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Wed Nov 1 16:16:10 2006 @@ -135,7 +135,7 @@ elif tp == 'FUNCTION': scope = scope_manager.enter_scope() body = from_dict(d['body']) - f = Function(d['params'], body, scope) + f = Function(d['params'].split(','), body, scope) scope_manager.leave_scope() return f elif tp == 'RETURN': Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Wed Nov 1 16:16:10 2006 @@ -17,6 +17,61 @@ scope_manager.set_variable(self.identifier.name, val) return val +class __extend__(Call): + def call(self, context=None): + name = self.identifier.get_literal() + if name == 'print': + writer(",".join([i.ToString() for i in self.arglist.call(context)])) + else: + # #import pdb;pdb.set_trace() + +# # +# retval = self.body.call() +# #scope_manager.current_scope = backup_scope +# return retval + backup_scope = scope_manager.current_scope + w_obj = scope_manager.get_variable(name) + scope_manager.current_scope = w_obj.function.scope + + retval = w_obj.Call(context=context, args=[i for i in self.arglist.call(context)]) + scope_manager.current_scope = backup_scope + return retval + +class __extend__(Dot): + def call(self, context=None): + w_obj = self.left.call(context).GetValue().ToObject() + name = self.right.get_literal() + return w_obj.Get(name) + +class __extend__(Function): + def call(self, context=None): + w_obj = W_Object({}, function=self) + return w_obj + +class __extend__(Identifier): + def call(self, context=None): + if self.initialiser is not None: + scope_manager.set_variable(self.name, self.initialiser.call(context)) + try: + return context.access(self.name) + except NameError: + return scope_manager.get_variable(self.name) + + def get_literal(self): + return self.name + +class __extend__(Index): + def call(self, context=None): + w_obj = self.left.call(context).GetValue() + w_member = self.expr.call(context).GetValue() + w_obj = w_obj.ToObject() + name = w_member.ToString() + return w_obj.Get(name) + +class __extend__(List): + def call(self, context=None): + return [node.call(context) for node in self.nodes] + class __extend__(Number): def call(self, context): return W_Number(self.num) @@ -25,20 +80,17 @@ # XXX Think about a shortcut later return str(W_Number(self.num)) -class __extend__(Dot): +class __extend__(ObjectInit): def call(self, context=None): - w_obj = self.left.call(context).GetValue().ToObject() - name = self.right.get_literal() - return w_obj.Get(name) - -#class __extend__(Function): -# def call(self, context=None): -# #import pdb;pdb.set_trace() -# #backup_scope = scope_manager.current_scope -# #scope_manager.current_scope = self.scope -# retval = self.body.call() -# #scope_manager.current_scope = backup_scope -# return retval + w_obj = W_Object({}) + for property in self.properties: + name = property.name.get_literal() + w_expr = property.value.call(context).GetValue() + w_obj.Put(name, w_expr) + return w_obj + #dict_w = {} + #for property in self.properties: + # dict_w[property.name class __extend__(Plus): def call(self, context=None): @@ -58,51 +110,28 @@ return W_Number(num_left + num_right) #return self.left.call(context).add(self.right.call(context)) -class __extend__(Semicolon): - def call(self, context=None): - self.expr.call(context) - -class __extend__(Identifier): - def call(self, context=None): - if self.initialiser is not None: - scope_manager.set_variable(self.name, self.initialiser.call(context)) - return scope_manager.get_variable(self.name) - - def get_literal(self): - return self.name - class __extend__(Script): - def call(self, context=None): - new_context = ExecutionContext(context) + def call(self, context=None, args=None, this=None, params=None): + if params == None: + params = [] + ncontext = ExecutionContext(context) + for i, item in enumerate(params): + try: + temp = args[i] + except IndexError: + temp = w_Undefined + ncontext.assign(item, temp) + try: for node in self.nodes: - node.call(new_context) + node.call(ncontext) except ExecutionReturned, e: return e.value return w_Undefined -class __extend__(Call): - def call(self, context=None): - name = self.identifier.get_literal() - if name == 'print': - writer(",".join([i.ToString() for i in self.arglist.call(context)])) - else: - # #import pdb;pdb.set_trace() - -# # -# retval = self.body.call() -# #scope_manager.current_scope = backup_scope -# return retval - backup_scope = scope_manager.current_scope - w_obj = scope_manager.get_variable(name) - scope_manager.current_scope = w_obj.function.scope - retval = w_obj.Call() - scope_manager.current_scope = backup_scope - return retval - -class __extend__(List): +class __extend__(Semicolon): def call(self, context=None): - return [node.call(context) for node in self.nodes] + self.expr.call(context) class __extend__(String): def call(self, context=None): @@ -111,31 +140,6 @@ def get_literal(self): return self.strval -class __extend__(ObjectInit): - def call(self, context=None): - w_obj = W_Object({}) - for property in self.properties: - name = property.name.get_literal() - w_expr = property.value.call(context).GetValue() - w_obj.Put(name, w_expr) - return w_obj - #dict_w = {} - #for property in self.properties: - # dict_w[property.name - -class __extend__(Index): - def call(self, context=None): - w_obj = self.left.call(context).GetValue() - w_member = self.expr.call(context).GetValue() - w_obj = w_obj.ToObject() - name = w_member.ToString() - return w_obj.Get(name) - -class __extend__(Function): - def call(self, context=None): - w_obj = W_Object({}, function=self) - return w_obj - class __extend__(Return): def call(self, context=None): raise ExecutionReturned(self.expr.call(context)) Modified: pypy/dist/pypy/lang/js/jsobj.py ============================================================================== --- pypy/dist/pypy/lang/js/jsobj.py (original) +++ pypy/dist/pypy/lang/js/jsobj.py Wed Nov 1 16:16:10 2006 @@ -2,6 +2,9 @@ class SeePage(NotImplementedError): pass +INFDEF = 1e300 * 1e300 +NaN = INFDEF/INFDEF + class W_Root(object): def GetValue(self): return self @@ -27,7 +30,7 @@ def ToNumber(self): # XXX make NaN - return 0 + return NaN class W_Null(W_Root): def __str__(self): @@ -65,6 +68,9 @@ def __str__(self): # XXX: more attention + # cough, cough + if str(self.floatval) == str(NaN): + return 'NaN' if float(int(self.floatval)) == self.floatval: return str(int(self.floatval)) return str(self.floatval) @@ -90,9 +96,11 @@ self.function = function #self.class_ = None - def Call(self, this=None): + def Call(self, context=None, args=None, this=None): if self.function: - return self.function.body.call() + return self.function.body.call(context=context, + args=args, this=this, + params= self.function.params) else: raise SeePage(33) Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Wed Nov 1 16:16:10 2006 @@ -76,3 +76,39 @@ var z = 2; print(x(), y, p); """), ["5,3,0"]) + + def test_function_args(self): + self.assert_prints(parse_d(""" + x = function (t,r) { + return t+r; + }; + print(x(2,3)); + """), ["5"]) + + def test_function_less_args(self): + self.assert_prints(parse_d(""" + x = function (t, r) { + return t + r; + }; + print(x(2)); + """), ["NaN"]) + + def test_function_more_args(self): + self.assert_prints(parse_d(""" + x = function (t, r) { + return t + r; + }; + print(x(2,3,4)); + """), ["5"]) + + def test_function_arguments(self): + self.assert_prints(parse_d(""" + x = function () { + var r = arguments[0]; + var t = arguments[1]; + return t + r; + }; + print(x(2,3)); + """), ["5"]) + + From niko at codespeak.net Wed Nov 1 16:27:12 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Wed, 1 Nov 2006 16:27:12 +0100 (CET) Subject: [pypy-svn] r34038 - pypy/dist/pypy/translator/jvm Message-ID: <20061101152712.25EBA10071@code0.codespeak.net> Author: niko Date: Wed Nov 1 16:27:11 2006 New Revision: 34038 Modified: pypy/dist/pypy/translator/jvm/generator.py Log: fix generator.py so that it uses lltype_to_cs instead of pending_class Modified: pypy/dist/pypy/translator/jvm/generator.py ============================================================================== --- pypy/dist/pypy/translator/jvm/generator.py (original) +++ pypy/dist/pypy/translator/jvm/generator.py Wed Nov 1 16:27:11 2006 @@ -796,9 +796,9 @@ raise NotImplementedError def new(self, TYPE): - clsobj = self.db.pending_class(TYPE) - ctor = Method(clsobj.name, "", "()V", opcode=INVOKESPECIAL) - self.emit(NEW, clsobj.jvm_type()) + jtype = self.db.lltype_to_cts(TYPE) + ctor = Method(jtype.class_name(), "", "()V", opcode=INVOKESPECIAL) + self.emit(NEW, jtype) self.emit(DUP) self.emit(ctor) From ericvrp at codespeak.net Wed Nov 1 16:35:36 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 1 Nov 2006 16:35:36 +0100 (CET) Subject: [pypy-svn] r34039 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061101153536.ADFC71006E@code0.codespeak.net> Author: ericvrp Date: Wed Nov 1 16:35:35 2006 New Revision: 34039 Added: pypy/dist/pypy/jit/codegen/llvm/test/mul2.ll Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: (ericvrp, mwh around) support for multiple modules in execution engine Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Wed Nov 1 16:35:35 2006 @@ -20,39 +20,51 @@ using namespace llvm; -int testme(int n) { - return n * 2; -} +ExecutionEngine* g_execution_engine; -void* compile(const char* filename) { +int compile(const char* filename) { std::string inputfile(filename); //from llvm-as.cpp Module* module(ParseAssemblyFile(inputfile + ".ll")); - if (!module) return NULL; + if (!module) { + std::cerr << "Error: can not parse " << inputfile << ".ll\n" << std::flush; + return false; + } std::ostream *Out = new std::ofstream((inputfile + ".bc").c_str(), std::ios::out | std::ios::trunc | std::ios::binary); WriteBytecodeToFile(module, *Out); //XXX what to do with the 3rd param (NoCompress)? - return module; + ModuleProvider* module_provider = new ExistingModuleProvider(module); + if (!g_execution_engine) { + g_execution_engine = ExecutionEngine::create(module_provider, false); + } else { + g_execution_engine->addModuleProvider(module_provider); + } + + return true; } -int execute(void* compiled, const char* funcname, int param) { //currently compiled=Module - Module* module = (Module*)compiled; - if (!module) { - std::cerr << "Error: can not execute " << funcname << " in a non existing module\n" << std::flush; - return -1; - } +int execute(const char* funcname, int param) { //currently compiled=Module + int err = -1; - ExistingModuleProvider* module_provider = new ExistingModuleProvider(module); - ExecutionEngine* EE = ExecutionEngine::create(module_provider, false); + if (!g_execution_engine) { + std::cerr << "Error: no llvm code compiled yet!\n" << std::flush; + return err; + } std::vector args; args.push_back((void*)param); - GenericValue gv = EE->runFunction(module->getNamedFunction(funcname), args); + Function* func = g_execution_engine->FindFunctionNamed(funcname); + if (!func) { + std::cerr << "Error: can not find function " << funcname << "\n" << std::flush; + return err; + } + + GenericValue gv = g_execution_engine->runFunction(func, args); return gv.IntVal; } Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h Wed Nov 1 16:35:35 2006 @@ -4,9 +4,8 @@ extern "C" { #endif -int testme(int n); -void* compile(const char* filename); -int execute(void* compiled, const char* funcname, int param); +int compile(const char* filename); +int execute(const char* funcname, int param); #ifdef __cplusplus } Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Wed Nov 1 16:35:35 2006 @@ -21,14 +21,10 @@ llvmjit._FuncPtr = _FuncPtr #exposed functions... -testme = llvmjit.testme -testme.restype = c_int -testme.argtypes = [c_int] - compile = llvmjit.compile -compile.restype = c_void_p +compile.restype = c_int compile.argtypes = [c_char_p] execute = llvmjit.execute execute.restype = c_int -execute.argtypes = [c_void_p, c_char_p, c_int] +execute.argtypes = [c_char_p, c_int] Added: pypy/dist/pypy/jit/codegen/llvm/test/mul2.ll ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/test/mul2.ll Wed Nov 1 16:35:35 2006 @@ -0,0 +1,5 @@ +int %mul2(int %n) { +block0: + %n2 = mul int %n, 2 + ret int %n2 +} Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Wed Nov 1 16:35:35 2006 @@ -9,21 +9,31 @@ curdir = dirname(__file__) square = join(curdir, 'square') +mul2 = join(curdir, 'mul2') -def test_testme(): - assert llvmjit.testme(10) == 20 +def execute(filename, funcname, param): + assert llvmjit.compile(filename) + return llvmjit.execute(funcname, param) -def test_testme_compile(): +def test_execute_compile(): def f(x): - return llvmjit.testme(20+x) + return execute(square, 'square', x + 5) fn = compile(f, [int]) res = fn(1) - assert res == 42 + assert res == 36 def test_compile(): assert llvmjit.compile(square) def test_compiled(): - compiled = llvmjit.compile(square) - assert llvmjit.execute(compiled, 'square', 4) == 4 * 4 + assert execute(square, 'square', 4) == 4 * 4 +def test_compiled2(): + llvmjit.compile(square) + llvmjit.compile(mul2) + for i in range(5): + assert llvmjit.execute('square', i) == i * i + assert llvmjit.execute('mul2', i) == i * 2 + +def DONTtest_execute_accross_module(): + pass From xoraxax at codespeak.net Wed Nov 1 16:47:17 2006 From: xoraxax at codespeak.net (xoraxax at codespeak.net) Date: Wed, 1 Nov 2006 16:47:17 +0100 (CET) Subject: [pypy-svn] r34040 - in pypy/dist/pypy/translator/jvm: . src Message-ID: <20061101154717.C6BE110072@code0.codespeak.net> Author: xoraxax Date: Wed Nov 1 16:47:16 2006 New Revision: 34040 Modified: pypy/dist/pypy/translator/jvm/database.py pypy/dist/pypy/translator/jvm/generator.py pypy/dist/pypy/translator/jvm/opcodes.py pypy/dist/pypy/translator/jvm/src/PyPy.java Log: Fixed IF_ICMPGE, added oostring operation. Modified: pypy/dist/pypy/translator/jvm/database.py ============================================================================== --- pypy/dist/pypy/translator/jvm/database.py (original) +++ pypy/dist/pypy/translator/jvm/database.py Wed Nov 1 16:47:16 2006 @@ -178,6 +178,7 @@ ootype.Float:jvmgen.PYPYDUMPDOUBLE, ootype.Bool:jvmgen.PYPYDUMPBOOLEAN, ootype.Class:jvmgen.PYPYDUMPOBJECT, + ootype.String:jvmgen.PYPYDUMPSTRING, } def generate_dump_method_for_ootype(self, OOTYPE): Modified: pypy/dist/pypy/translator/jvm/generator.py ============================================================================== --- pypy/dist/pypy/translator/jvm/generator.py (original) +++ pypy/dist/pypy/translator/jvm/generator.py Wed Nov 1 16:47:16 2006 @@ -2,7 +2,8 @@ from pypy.objspace.flow import model as flowmodel from pypy.translator.oosupport.metavm import Generator from pypy.translator.jvm.typesystem import \ - JvmType, jObject, jPrintStream, jvm_for_class, jVoid + JvmType, jObject, jPrintStream, jvm_for_class, jVoid, jvm_method_desc, \ + jInt, jByteArray from pypy.rpython.ootypesystem import ootype # ___________________________________________________________________________ @@ -739,7 +740,7 @@ # Ignore Void values if v.concretetype is ootype.Void: return - + if isinstance(v, flowmodel.Variable): jty, idx = self._var_data(v) return self.store_jvm_var(jty, idx) @@ -795,6 +796,11 @@ def call_primitive(self, graph): raise NotImplementedError + def call_oostring(self, OOTYPE): + cts_type = self.db.lltype_to_cts(OOTYPE) + mthd = Method('pypy.PyPy', 'oostring', jvm_method_desc([cts_type, jInt], jByteArray)) + self.emit(mthd) + def new(self, TYPE): jtype = self.db.lltype_to_cts(TYPE) ctor = Method(jtype.class_name(), "", "()V", opcode=INVOKESPECIAL) @@ -857,7 +863,7 @@ less_than = lambda self: self._compare_op(IF_ICMPLT) greater_than = lambda self: self._compare_op(IF_ICMPGT) less_equals = lambda self: self._compare_op(IF_ICMPLT) - greater_equals = lambda self: self._compare_op(IF_ICMPGT) + greater_equals = lambda self: self._compare_op(IF_ICMPGE) def _uint_compare_op(self, cmpopcode): PYPYUINTCMP.invoke(self) Modified: pypy/dist/pypy/translator/jvm/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/jvm/opcodes.py (original) +++ pypy/dist/pypy/translator/jvm/opcodes.py Wed Nov 1 16:47:16 2006 @@ -7,7 +7,7 @@ from pypy.translator.oosupport.metavm import \ PushArg, PushAllArgs, StoreResult, InstructionList, New, DoNothing, Call,\ - SetField, GetField, CallMethod, DownCast, RuntimeNew + SetField, GetField, CallMethod, DownCast, RuntimeNew, OOString import pypy.translator.jvm.generator as jvmgen def _check_zer(op): @@ -28,14 +28,14 @@ 'oogetfield': [GetField, StoreResult], 'oosend': [CallMethod, StoreResult], 'ooupcast': DoNothing, - 'oodowncast': [DownCast,StoreResult], + 'oodowncast': [DownCast, StoreResult], 'oois': 'is_null', 'oononnull': 'is_not_null', #'instanceof': [CastTo, 'ldnull', 'cgt.un'], #'subclassof': [PushAllArgs, 'call bool [pypylib]pypy.runtime.Utils::SubclassOf(class [mscorlib]System.Type, class[mscorlib]System.Type)'], #'ooidentityhash': [PushAllArgs, 'callvirt instance int32 object::GetHashCode()'], #'oohash': [PushAllArgs, 'callvirt instance int32 object::GetHashCode()'], - #'oostring': [OOString], + 'oostring': [OOString, StoreResult], #'ooparse_int': [PushAllArgs, 'call int32 [pypylib]pypy.runtime.Utils::OOParseInt(string, int32)'], #'oonewcustomdict': [NewCustomDict], # Modified: pypy/dist/pypy/translator/jvm/src/PyPy.java ============================================================================== --- pypy/dist/pypy/translator/jvm/src/PyPy.java (original) +++ pypy/dist/pypy/translator/jvm/src/PyPy.java Wed Nov 1 16:47:16 2006 @@ -251,6 +251,50 @@ } // ---------------------------------------------------------------------- + // Helpers + + public static byte[] string2bytes(String s) { + return s.getBytes(); + } + + // ---------------------------------------------------------------------- + // OOString support + + public static byte[] oostring(int n, int base_) { + // XXX needs special case for unsigned ints + if (base_ == -1) + base_ = 10; + if (n < 0 && base_ != 10) + return string2bytes("-" + Integer.toString(-n, base_)); + else + return string2bytes(Integer.toString(n, base_)); + } + + public static byte[] oostring(double d, int base_) { + return string2bytes(new Double(d).toString()); + } + + public static byte[] oostring(Object obj, int base_) + { + return string2bytes(String.format("<%s object>", new Object[] { obj.getClass().getName() })); + } + + public static byte[] oostring(char ch, int base_) + { + return string2bytes(new Character(ch).toString()); + } + + public static byte[] oostring(byte[] s, int base_) + { + return s; + } + + public static byte[] OOString(boolean b, int base_) + { + return string2bytes(new Boolean(b).toString()); + } + + // ---------------------------------------------------------------------- // Self Test public static int __counter = 0, __failures = 0; From ericvrp at codespeak.net Wed Nov 1 16:57:17 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 1 Nov 2006 16:57:17 +0100 (CET) Subject: [pypy-svn] r34041 - pypy/dist/pypy/jit/codegen/llvm/test Message-ID: <20061101155717.B6BDF10063@code0.codespeak.net> Author: ericvrp Date: Wed Nov 1 16:57:15 2006 New Revision: 34041 Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: (ericvrp, mwh around) add testcase(names) as a kind of todo list Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Wed Nov 1 16:57:15 2006 @@ -37,3 +37,25 @@ def DONTtest_execute_accross_module(): pass + +def DONTtest_modify_global_data(): + pass + +def DONTtest_call_back_to_parent(): #call JIT-compiler again for it to add case(s) to flexswitch + pass + +def DONTtest_delete_function(): + pass + +def DONTtest_functions_with_different_signatures(): + pass + +def DONTtest_llvm_transformations(): + pass + +def DONTtest_layers_of_codegenerators(): #e.g. i386 code until function stabilizes then llvm + pass + +def DONTtest_inmemory_ll_and_bc_files(): + pass + From fijal at codespeak.net Wed Nov 1 17:12:46 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 1 Nov 2006 17:12:46 +0100 (CET) Subject: [pypy-svn] r34042 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061101161246.B9E0110077@code0.codespeak.net> Author: fijal Date: Wed Nov 1 17:12:44 2006 New Revision: 34042 Added: pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py (contents, props changed) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py pypy/branch/transparent-proxy/pypy/objspace/std/stdtypedef.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_stdobjspace.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (fijal, guido, arigo, samuele) - Added generic way of overriding multimethods, so we've got (almost) working list implementation. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py Wed Nov 1 17:12:44 2006 @@ -78,6 +78,13 @@ def add__List_List(space, w_list1, w_list2): return W_ListObject(w_list1.wrappeditems + w_list2.wrappeditems) +def add__List_ANY(space, w_list, w_any): + if space.is_true(space.isinstance(w_any, space.w_list)): + items1_w = w_list.wrappeditems + items2_w = space.unpackiterable(w_any) + return W_ListObject(items1_w + items2_w) + raise FailedToImplement + def inplace_add__List_ANY(space, w_list1, w_iterable2): list_extend__List_ANY(space, w_list1, w_iterable2) return w_list1 @@ -109,14 +116,27 @@ def eq__List_List(space, w_list1, w_list2): # needs to be safe against eq_w() mutating the w_lists behind our back - if len(w_list1.wrappeditems) != len(w_list2.wrappeditems): + items1_w = w_list1.wrappeditems + items2_w = w_list2.wrappeditems + return equal_wrappeditems(space, items1_w, items2_w) + +def equal_wrappeditems(space, items1_w, items2_w): + if len(items1_w) != len(items2_w): return space.w_False i = 0 - while i < len(w_list1.wrappeditems) and i < len(w_list2.wrappeditems): - if not space.eq_w(w_list1.wrappeditems[i], w_list2.wrappeditems[i]): + while i < len(items1_w) and i < len(items2_w): + if not space.eq_w(items1_w[i], items2_w[i]): return space.w_False i += 1 - return space.newbool(len(w_list1.wrappeditems) == len(w_list2.wrappeditems)) + return space.w_True + #return space.newbool(len(w_list1.wrappeditems) == len(w_list2.wrappeditems)) + +def eq__List_ANY(space, w_list1, w_any): + if space.is_true(space.isinstance(w_any, space.w_list)): + items1_w = w_list1.wrappeditems + items2_w = space.unpackiterable(w_any) + return equal_wrappeditems(space, items1_w, items2_w) + raise FailedToImplement def _min(a, b): if a < b: Added: pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py Wed Nov 1 17:12:44 2006 @@ -0,0 +1,32 @@ + +""" Some transparent helpers, put here because +of cyclic imports +""" + +from pypy.objspace.std.model import W_ANY + +def create_mm_names(classname, mm, is_local): + s = "" + if is_local: + s += "list_" + s += mm.name + "__" + s += "_".join([classname] + ["ANY"] * (mm.arity - 1)) + if '__' + mm.name + '__' in mm.specialnames: + return s, '__' + mm.name + '__' + return s, mm.name + +def install_mm_trampoline(type_, mm, is_local): + classname = type_.__name__[2:] + mm_name, op_name = create_mm_names(classname, mm, is_local) + def function(space, w_transparent_list, *args_w): + return space.call_function(w_transparent_list.controller, space.wrap\ + (op_name), *args_w) + function.func_name = mm_name + mm.register(function, type_, *([W_ANY] * (mm.arity - 1))) + +def register_type(type_): + from pypy.objspace.std.stdtypedef import multimethods_defined_on + + for mm, is_local in multimethods_defined_on(type_.original): + if not mm.name.startswith('__'): + install_mm_trampoline(type_, mm, is_local) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/stdtypedef.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/stdtypedef.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/stdtypedef.py Wed Nov 1 17:12:44 2006 @@ -309,3 +309,16 @@ for multimethod in typedef.local_multimethods: slicemultimethod(space, multimethod, typedef, result, local=True) return result + +def multimethods_defined_on(cls): + """NOT_RPYTHON: enumerate the (multimethod, local_flag) for all the + multimethods that have an implementation whose first typed argument + is 'cls'. + """ + from pypy.objspace.std.objspace import StdObjSpace # XXX for now + typedef = cls.typedef + for multimethod in hack_out_multimethods(StdObjSpace.MM.__dict__): + if cls in multimethod.dispatch_tree: + yield multimethod, False + for multimethod in typedef.local_multimethods: + yield multimethod, True Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Wed Nov 1 17:12:44 2006 @@ -35,12 +35,29 @@ assert repr(lst) == repr([1,2]) def test_gt_lt_list(self): + skip("FAILS RANDOMLY (~73% works)") c = self.Controller([]) lst = proxy(list, c.perform) lst.append(1) lst.append(2) - assert lst < [1,2,3] - assert [1,2,3] > lst - #assert not ([2,3] < lst) + #assert lst < [1,2,3] + #assert [1,2,3] > lst + #assert lst == [1,2] + #assert [1,2] == lst + assert [2,3] >= list(iter(lst)) + assert lst < [2,3] assert [2,3] >= lst assert lst <= [1,2] + + def test_add_list(self): + c = self.Controller([]) + lst = proxy(list, c.perform) + lst.append(1) + assert lst + lst == [1,1] + + def test_list_getitem(self): + c = self.Controller([1,2,3]) + lst = proxy(list, c.perform) + assert lst[2] == 3 + lst[1] = 0 + assert lst[0] + lst[1] == 1 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_stdobjspace.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_stdobjspace.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_stdobjspace.py Wed Nov 1 17:12:44 2006 @@ -22,7 +22,15 @@ raises(OperationError,self.space.uint_w,self.space.wrap(None)) raises(OperationError,self.space.uint_w,self.space.wrap("")) - - def hopeful_test_exceptions(self): - self.apptest("self.failUnless(issubclass(ArithmeticError, Exception))") - self.apptest("self.failIf(issubclass(ArithmeticError, KeyError))") + def test_multimethods_defined_on(self): + from pypy.objspace.std.stdtypedef import multimethods_defined_on + from pypy.objspace.std.listobject import W_ListObject + res = multimethods_defined_on(W_ListObject) + res = [(m.name, local) for (m, local) in res] + assert ('add', False) in res + assert ('lt', False) in res + assert ('setitem', False) in res + assert ('mod', False) not in res + assert ('pop', True) in res + assert ('reverse', True) in res + assert ('popitem', True) not in res Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Wed Nov 1 17:12:44 2006 @@ -3,8 +3,10 @@ """ from pypy.objspace.std.objspace import * +from pypy.objspace.std.proxy_helpers import register_type class W_TransparentList(W_Object): + from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef def __init__(self, w_controller): @@ -12,25 +14,4 @@ registerimplementation(W_TransparentList) -def repr__TransparentList(space, w_transparent_list): - return space.call_function(w_transparent_list.controller, space.wrap("__repr__")) - -def list_append__TransparentList_ANY(space, w_transparent_list, w_any): - space.call_function(w_transparent_list.controller, space.wrap("append"), w_any) - return space.w_None - -def list_extend__TransparentList_ANY(space, w_list, w_any): - space.call_function(w_transparent_list.controller, space.wrap("extend"), w_any) - return space.w_None - -def lt__TransparentList_ANY(space, w_transparent_list, w_list): - return space.call_function(w_transparent_list.controller, space.wrap("__lt__"), w_list) - -def gt__TransparentList_ANY(space, w_transparent_list, w_list): - return space.call_function(w_transparent_list.controller, space.wrap("__gt__"), w_list) - -def iter__TransparentList(space, w_transparent_list): - return space.call_function(w_transparent_list.controller, space.wrap("__iter__")) - -from pypy.objspace.std import listtype -register_all(vars(), listtype) +register_type(W_TransparentList) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Wed Nov 1 17:12:44 2006 @@ -2,16 +2,17 @@ """ transparent.py - Several transparent proxy helpers """ -from pypy.objspace.std.tlistobject import W_TransparentList from pypy.interpreter import gateway from pypy.interpreter.function import Function from pypy.interpreter.error import OperationError +from pypy.objspace.std.tlistobject import W_TransparentList def proxy(space, w_type, w_controller): if not space.is_true(space.callable(w_controller)): raise OperationError(space.w_TypeError, space.wrap("controller should be function")) - if not space.is_w(w_type, space.w_list): + if not space.is_true(space.issubtype(w_type, space.w_list)): raise OperationError(space.w_TypeError, space.wrap("type of object wrapped should be list")) + return W_TransparentList(w_controller) app_proxy = gateway.interp2app(proxy, unwrap_spec=[gateway.ObjSpace, gateway.W_Root, \ From stephan at codespeak.net Wed Nov 1 17:14:09 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Wed, 1 Nov 2006 17:14:09 +0100 (CET) Subject: [pypy-svn] r34043 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061101161409.0536310076@code0.codespeak.net> Author: stephan Date: Wed Nov 1 17:14:08 2006 New Revision: 34043 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/context.py pypy/dist/pypy/lang/js/parser.py pypy/dist/pypy/lang/js/test/test_interp.py pypy/dist/pypy/lang/js/test/test_parser.py Log: (stephan, santagada) fixed single quote problem with js parser. fixed some context things (globals vs. locals) Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Wed Nov 1 17:14:08 2006 @@ -101,6 +101,9 @@ output = [from_dict(d[str(i)]) for i in range(lgt)] return output +def build_interpreter(d): + return from_dict(d) + def from_dict(d): if d is None: return d Modified: pypy/dist/pypy/lang/js/context.py ============================================================================== --- pypy/dist/pypy/lang/js/context.py (original) +++ pypy/dist/pypy/lang/js/context.py Wed Nov 1 17:14:08 2006 @@ -1,22 +1,22 @@ class ExecutionContext(object): - globals = {} - def __init__(self, parent=None): - pass - -## def __init__(self, parent = None): -## self.parent = parent -## if parent is None: -## self.globals = {} -## else: -## self.globals = parent.globals -## #self.locals = {} + def __init__(self, parent = None): + self.parent = parent + self.locals = {} + if parent is None: + self.globals = {} + else: + self.globals = parent.globals + #self.locals = {} def assign(self, name, value): - self.globals[name] = value + self.locals[name] = value + #self.globals[name] = value def access(self, name): - if name in self.globals: + if name in self.locals: + return self.locals[name] + elif name in self.globals: return self.globals[name] raise NameError("%s is not declared" % name) Modified: pypy/dist/pypy/lang/js/parser.py ============================================================================== --- pypy/dist/pypy/lang/js/parser.py (original) +++ pypy/dist/pypy/lang/js/parser.py Wed Nov 1 17:14:08 2006 @@ -19,6 +19,7 @@ jsparse = jsdir.join("jsparse.js").read() pipe = Popen("js", stdin=PIPE, stdout=PIPE, stderr=STDOUT) pipe.stdin.write(jsdefs + jsparse + "\n") + stripped_code = stripped_code.replace("'",r"\'") pipe.stdin.write("print(parse('%s'));\n" % stripped_code) pipe.stdin.close() retval = pipe.stdout.read() @@ -29,6 +30,7 @@ def parse(code_string): read_code = read_js_output(code_string) output = read_code.split(os.linesep) + print '\n'.join(output) try: code = eval("\n".join(output)) except (SyntaxError, NameError): Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Wed Nov 1 17:14:08 2006 @@ -2,12 +2,13 @@ from pypy.lang.js.astgen import * from pypy.lang.js import interpreter from pypy.lang.js.parser import parse +import py.test import sys from StringIO import StringIO def parse_d(code): - return from_dict(parse(code)) + return build_interpreter(parse(code)) class TestInterp(object): def test_simple(self): @@ -101,14 +102,30 @@ print(x(2,3,4)); """), ["5"]) + def test_function_has_var(self): + self.assert_prints(parse_d(""" + x = function () { + var t = 'test'; + return t; + }; + print(x()); + """), ["test"]) + def test_function_arguments(self): + #py.test.skip('not ready yet') self.assert_prints(parse_d(""" x = function () { - var r = arguments[0]; - var t = arguments[1]; + r = arguments[0]; + t = arguments[1]; return t + r; }; print(x(2,3)); """), ["5"]) + def test_index(self): + self.assert_prints(parse_d(""" + x = {1:"test"}; + print(x[1]); + """), ["test"]) + Modified: pypy/dist/pypy/lang/js/test/test_parser.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_parser.py (original) +++ pypy/dist/pypy/lang/js/test/test_parser.py Wed Nov 1 17:14:08 2006 @@ -19,3 +19,8 @@ assert data['0']['body']['0']['value']['value'] == '1' assert sorted(data.keys()) == ['0', 'funDecls', 'length', 'lineno', \ 'tokenizer', 'type', 'varDecls'] + +def test_single_quote(): + "test if parser eats single quotes" + data = parse("x = '2'") + assert data['type'] == 'SCRIPT' From xoraxax at codespeak.net Wed Nov 1 17:14:52 2006 From: xoraxax at codespeak.net (xoraxax at codespeak.net) Date: Wed, 1 Nov 2006 17:14:52 +0100 (CET) Subject: [pypy-svn] r34044 - pypy/dist/pypy/translator/oosupport Message-ID: <20061101161452.8039210076@code0.codespeak.net> Author: xoraxax Date: Wed Nov 1 17:14:52 2006 New Revision: 34044 Modified: pypy/dist/pypy/translator/oosupport/metavm.py Log: Oops, forgot to check this in. Modified: pypy/dist/pypy/translator/oosupport/metavm.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/metavm.py (original) +++ pypy/dist/pypy/translator/oosupport/metavm.py Wed Nov 1 17:14:52 2006 @@ -359,6 +359,13 @@ generator.instantiate() generator.downcast(op.result.concretetype) +class _OOString(MicroInstruction): + def render(self, generator, op): + ARGTYPE = op.args[0].concretetype + generator.load(op.args[0]) + generator.load(op.args[1]) + generator.call_oostring(ARGTYPE) + New = _New() @@ -371,3 +378,4 @@ Call = _Call() CallMethod = _CallMethod() RuntimeNew = _RuntimeNew() +OOString = _OOString() From fijal at codespeak.net Wed Nov 1 17:37:59 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 1 Nov 2006 17:37:59 +0100 (CET) Subject: [pypy-svn] r34045 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061101163759.9E41410072@code0.codespeak.net> Author: fijal Date: Wed Nov 1 17:37:57 2006 New Revision: 34045 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (fijal, guido, arigo, pedronis) - Naively added dictionary Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/model.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/model.py Wed Nov 1 17:37:57 2006 @@ -122,6 +122,7 @@ # xxx config self.typeorder[tlistobject.W_TransparentList] = [] + self.typeorder[tlistobject.W_TransparentDict] = [] if config.objspace.std.withstrdict: del self.typeorder[dictobject.W_DictObject] Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Wed Nov 1 17:37:57 2006 @@ -61,3 +61,13 @@ assert lst[2] == 3 lst[1] = 0 assert lst[0] + lst[1] == 1 + + def test_dict(self): + c = self.Controller({"xx":1}) + d = proxy(dict, c.perform) + assert d['xx'] == 1 + assert 'yy' not in d + #d2 = {'yy':3} + #d.update(d2) + #assert sorted(d.keys()) == ['xx', 'yy'] + #assert sorted(d.values()) == [1, 3] Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Wed Nov 1 17:37:57 2006 @@ -5,13 +5,21 @@ from pypy.objspace.std.objspace import * from pypy.objspace.std.proxy_helpers import register_type -class W_TransparentList(W_Object): - from pypy.objspace.std.listobject import W_ListObject as original - from pypy.objspace.std.listtype import list_typedef as typedef - +class W_Transparent(W_Object): def __init__(self, w_controller): self.controller = w_controller +class W_TransparentList(W_Transparent): + from pypy.objspace.std.listobject import W_ListObject as original + from pypy.objspace.std.listtype import list_typedef as typedef + +class W_TransparentDict(W_Transparent): + from pypy.objspace.std.dictobject import W_DictObject as original + from pypy.objspace.std.dicttype import dict_typedef as typedef + registerimplementation(W_TransparentList) +registerimplementation(W_TransparentDict) + register_type(W_TransparentList) +register_type(W_TransparentDict) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Wed Nov 1 17:37:57 2006 @@ -5,15 +5,17 @@ from pypy.interpreter import gateway from pypy.interpreter.function import Function from pypy.interpreter.error import OperationError -from pypy.objspace.std.tlistobject import W_TransparentList +from pypy.objspace.std.tlistobject import W_TransparentList, W_TransparentDict def proxy(space, w_type, w_controller): if not space.is_true(space.callable(w_controller)): raise OperationError(space.w_TypeError, space.wrap("controller should be function")) - if not space.is_true(space.issubtype(w_type, space.w_list)): - raise OperationError(space.w_TypeError, space.wrap("type of object wrapped should be list")) - - return W_TransparentList(w_controller) + + if space.is_true(space.issubtype(w_type, space.w_list)): + return W_TransparentList(w_controller) + if space.is_true(space.issubtype(w_type, space.w_dict)): + return W_TransparentDict(w_controller) + raise OperationError(space.w_TypeError, space.wrap("type of object wrapped should be list or int")) app_proxy = gateway.interp2app(proxy, unwrap_spec=[gateway.ObjSpace, gateway.W_Root, \ gateway.W_Root]) From ac at codespeak.net Wed Nov 1 17:40:14 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 1 Nov 2006 17:40:14 +0100 (CET) Subject: [pypy-svn] r34046 - in pypy/dist/pypy/jit: codegen/i386/test timeshifter/test Message-ID: <20061101164014.64F6810072@code0.codespeak.net> Author: ac Date: Wed Nov 1 17:40:13 2006 New Revision: 34046 Added: pypy/dist/pypy/jit/codegen/i386/test/test_genc_portal.py (contents, props changed) Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py Log: Port the portal tests to codegen/i386. Added: pypy/dist/pypy/jit/codegen/i386/test/test_genc_portal.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/i386/test/test_genc_portal.py Wed Nov 1 17:40:13 2006 @@ -0,0 +1,76 @@ +import py, os +from pypy.annotation import model as annmodel +from pypy.annotation.listdef import s_list_of_strings +from pypy.rlib.unroll import unrolling_iterable +from pypy.translator.c.genc import CStandaloneBuilder +from pypy.jit.timeshifter.test import test_portal +from pypy.jit.codegen.i386.rgenop import RI386GenOp +from pypy.rpython.annlowlevel import PseudoHighLevelCallable + +class I386PortalTestMixin(object): + RGenOp = RI386GenOp + + def postprocess_timeshifting(self): + annhelper = self.hrtyper.annhelper + convert_result = getattr(self.main, 'convert_result', str) + annotator = self.rtyper.annotator + args_s = [annotator.binding(v) for v in self.maingraph.getargs()] + s_result = self.rtyper.annotator.binding(self.maingraph.getreturnvar()) + main_fnptr = self.rtyper.type_system.getcallable(self.maingraph) + main = PseudoHighLevelCallable(main_fnptr, args_s, s_result) + + if hasattr(self.main, 'convert_arguments'): + decoders = self.main.convert_arguments + assert len(decoders) == len(args_s) + else: + decoders = [int] * len(args_s) + decoders = unrolling_iterable(decoders) + def ll_main(argv): + args = () + i = 1 + for decoder in decoders: + args += (decoder(argv[i]),) + i = i + 1 + try: + res = main(*args) + except Exception, e: + os.write(1, 'EXCEPTION: %s\n' % (e,)) + return 0 + os.write(1, convert_result(res) + '\n') + return 0 + + annhelper.getgraph(ll_main, [s_list_of_strings], + annmodel.SomeInteger()) + annhelper.finish() + t = self.rtyper.annotator.translator + t.config.translation.gc = 'boehm' + self.cbuilder = CStandaloneBuilder(t, ll_main) + self.cbuilder.generate_source() + self.cbuilder.compile() + + def timeshift_from_portal(self, main, portal, main_args, + inline=None, policy=None, + backendoptimize=False): + self.main = main + self._timeshift_from_portal(main, portal, main_args, + inline=inline, policy=policy, + backendoptimize=backendoptimize) + cmdargs = ' '.join([str(arg) for arg in main_args]) + output = self.cbuilder.cmdexec(cmdargs) + lines = output.split() + lastline = lines[-1] + assert not lastline.startswith('EXCEPTION:') + if hasattr(main, 'convert_result'): + return lastline + else: + return int(lastline) # assume an int + + def check_insns(self, expected=None, **counts): + "Cannot check instructions in the generated assembler." + +class TestPromotion(I386PortalTestMixin, + test_portal.TestPortal): + + # for the individual tests see + # ====> ../../../timeshifter/test/test_promotion.py + pass Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Wed Nov 1 17:40:13 2006 @@ -1,6 +1,6 @@ from pypy import conftest from pypy.translator.translator import graphof -from pypy.jit.timeshifter.test.test_timeshift import hannotate +from pypy.jit.timeshifter.test.test_timeshift import hannotate, getargtypes from pypy.jit.timeshifter.hrtyper import HintRTyper from pypy.jit.timeshifter.test.test_timeshift import P_NOVIRTUAL from pypy.rpython.llinterp import LLInterpreter @@ -20,45 +20,66 @@ del cls._cache del cls._cache_order - def timeshift_from_portal(self, main, portal, main_args, + def postprocess_timeshifting(self): + self.readportalgraph = self.hrtyper.readportalgraph + + def _timeshift_from_portal(self, main, portal, main_args, inline=None, policy=None, backendoptimize=False): - + # decode the 'values' if they are specified as strings + if hasattr(main, 'convert_arguments'): + assert len(main.convert_arguments) == len(values) + main_args = [decoder(value) for decoder, value in zip( + main.convert_arguments, + main_args)] key = main, portal, inline, policy, backendoptimize try: - maingraph, readportalgraph, rtyper = self._cache[key] + cache, argtypes = self._cache[key] except KeyError: - if len(self._cache_order) >= 3: - del self._cache[self._cache_order.pop(0)] - - hs, ha, rtyper = hannotate(main, main_args, portal=portal, - policy=policy, inline=inline, - backendoptimize=backendoptimize) - - t = rtyper.annotator.translator - maingraph = graphof(t, main) - # make the timeshifted graphs - hrtyper = HintRTyper(ha, rtyper, self.RGenOp) - origportalgraph = graphof(t, portal) - hrtyper.specialize(origportalgraph=origportalgraph, - view = conftest.option.view) - - for graph in ha.translator.graphs: - checkgraph(graph) - t.graphs.append(graph) - - if conftest.option.view: - t.view() - - readportalgraph = hrtyper.readportalgraph - self._cache[key] = maingraph, readportalgraph, rtyper - self._cache_order.append(key) + pass + else: + self.__dict__.update(cache) + assert argtypes == getargtypes(self.rtyper.annotator, main_args) + return + + hs, ha, self.rtyper = hannotate(main, main_args, portal=portal, + policy=policy, inline=inline, + backendoptimize=backendoptimize) + + t = self.rtyper.annotator.translator + self.maingraph = graphof(t, main) + # make the timeshifted graphs + self.hrtyper = HintRTyper(ha, self.rtyper, self.RGenOp) + origportalgraph = graphof(t, portal) + self.hrtyper.specialize(origportalgraph=origportalgraph, + view = conftest.option.view) + + for graph in ha.translator.graphs: + checkgraph(graph) + t.graphs.append(graph) + + if conftest.option.view: + t.view() + self.postprocess_timeshifting() + self.readportalgraph = self.hrtyper.readportalgraph + + # Populate the cache + if len(self._cache_order) >= 3: + del self._cache[self._cache_order.pop(0)] + cache = self.__dict__.copy() + self._cache[key] = cache, getargtypes(self.rtyper.annotator, main_args) + self._cache_order.append(key) - self.readportalgraph = readportalgraph + + def timeshift_from_portal(self, main, portal, main_args, + inline=None, policy=None, + backendoptimize=False): + self._timeshift_from_portal(main, portal, main_args, + inline=inline, policy=policy, + backendoptimize=backendoptimize) self.main_args = main_args - self.rtyper = rtyper - llinterp = LLInterpreter(rtyper) - res = llinterp.eval_graph(maingraph, main_args) + llinterp = LLInterpreter(self.rtyper) + res = llinterp.eval_graph(self.maingraph, main_args) return res def check_insns(self, expected=None, **counts): From cfbolz at codespeak.net Wed Nov 1 17:40:40 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 1 Nov 2006 17:40:40 +0100 (CET) Subject: [pypy-svn] r34047 - in pypy/dist/pypy/rlib: . test Message-ID: <20061101164040.206C71007E@code0.codespeak.net> Author: cfbolz Date: Wed Nov 1 17:40:38 2006 New Revision: 34047 Added: pypy/dist/pypy/rlib/streamio.py - copied, changed from r34003, pypy/dist/pypy/lib/_sio.py pypy/dist/pypy/rlib/test/test_streamio.py - copied, changed from r34003, pypy/dist/pypy/lib/test2/test_sio.py Log: (antocuni, cfbolz) some steps in the direction of making streamio rpython From stephan at codespeak.net Wed Nov 1 17:42:37 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Wed, 1 Nov 2006 17:42:37 +0100 (CET) Subject: [pypy-svn] r34048 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061101164237.0C2621006F@code0.codespeak.net> Author: stephan Date: Wed Nov 1 17:42:36 2006 New Revision: 34048 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/jsobj.py pypy/dist/pypy/lang/js/parser.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) making progress with 'arguments' Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Wed Nov 1 17:42:36 2006 @@ -16,6 +16,10 @@ # getlist = staticmethod(getlist) +class Array(Node): + def __init__(self, items=()): + self.items = items + class Assign(Node): def __init__(self, identifier, expr): self.identifier = identifier @@ -111,6 +115,8 @@ if tp == 'SCRIPT': # XXX: Cannot parse it right now return Script(getlist(d), [], []) + elif tp == 'ARRAY_INIT': + return Array(getlist(d)) elif tp == 'SEMICOLON': return Semicolon(from_dict(d['expression'])) elif tp == 'NUMBER': Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Wed Nov 1 17:42:36 2006 @@ -11,6 +11,11 @@ def __init__(self, value): self.value = value +class __extend__(Array): + def call(self, context): + d = dict(enumerate(self.items)) + return W_Array(d) + class __extend__(Assign): def call(self, context): val = self.expr.call(context) @@ -148,3 +153,4 @@ def call(self, context=None): for var in self.nodes: var.call(context) + Modified: pypy/dist/pypy/lang/js/jsobj.py ============================================================================== --- pypy/dist/pypy/lang/js/jsobj.py (original) +++ pypy/dist/pypy/lang/js/jsobj.py Wed Nov 1 17:42:36 2006 @@ -24,6 +24,10 @@ def __repr__(self): return "<%s(%s)>" % (self.__class__.__name__, str(self)) +class W_Array(W_Root): + # TODO to be continued :-) + pass + class W_Undefined(W_Root): def __str__(self): return "" Modified: pypy/dist/pypy/lang/js/parser.py ============================================================================== --- pypy/dist/pypy/lang/js/parser.py (original) +++ pypy/dist/pypy/lang/js/parser.py Wed Nov 1 17:42:36 2006 @@ -30,7 +30,7 @@ def parse(code_string): read_code = read_js_output(code_string) output = read_code.split(os.linesep) - print '\n'.join(output) + #print '\n'.join(output) try: code = eval("\n".join(output)) except (SyntaxError, NameError): Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Wed Nov 1 17:42:36 2006 @@ -129,3 +129,10 @@ print(x[1]); """), ["test"]) + def test_array_initializer(self): + py.test.skip('not ready yet') + self.assert_prints(parse_d(""" + x = []; + print(x); + """), ["[]"]) + From niko at codespeak.net Wed Nov 1 23:24:15 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Wed, 1 Nov 2006 23:24:15 +0100 (CET) Subject: [pypy-svn] r34050 - in pypy/dist/pypy/translator/jvm: . src Message-ID: <20061101222415.B863510063@code0.codespeak.net> Author: niko Date: Wed Nov 1 23:24:14 2006 New Revision: 34050 Modified: pypy/dist/pypy/translator/jvm/database.py pypy/dist/pypy/translator/jvm/src/PyPy.java Log: add some introspection for BuiltInTypes so that we can invoke methods on them... test_bool *almost* works now... Modified: pypy/dist/pypy/translator/jvm/database.py ============================================================================== --- pypy/dist/pypy/translator/jvm/database.py (original) +++ pypy/dist/pypy/translator/jvm/database.py Wed Nov 1 23:24:14 2006 @@ -12,6 +12,66 @@ import pypy.translator.jvm.generator as jvmgen import pypy.translator.jvm.typesystem as jvmtypes +class BuiltInClassNode(object): + + """ + This is a fake node that is returned instead of a node.Class object + when pending_class is invoked on a built-in type. It allows other + code to query the fields and methods. + """ + + def __init__(self, db, OOTYPE): + self.db = db + self.OOTYPE = OOTYPE + self.jvmtype = db.lltype_to_cts(OOTYPE) + + # Create a generic mapping. Other than SELFTYPE_T, we map each + # generic argument to ootype.ROOT. We use a hack here where + # we assume that the only generic parameters are named + # SELFTYPE_T, ITEMTYPE_T, KEYTYPE_T, or VALUETYPE_T. + + self.generics = {} + + if hasattr(self.OOTYPE, 'SELFTYPE_T'): + self.generics[self.OOTYPE.SELFTYPE_T] = self.OOTYPE + + for param in ('ITEMTYPE_T', 'KEYTYPE_T', 'VALUETYPE_T'): + if hasattr(self.OOTYPE, param): + self.generics[getattr(self.OOTYPE, param)] = ootype.ROOT + + def jvm_type(self): + return self.jvmtype + + def lookup_field(self, fieldnm): + """ Given a field name, returns a jvmgen.Field object """ + _, FIELDTY = self.OOTYPE._lookup_field(fieldnm) + jfieldty = self.db.lltype_to_cts(FIELDTY) + return jvmgen.Field( + self.jvmtype.class_name(), fieldnm, jfieldty, False) + + def _map(self, ARG): + """ Maps ootype ARG to a java type. If arg is one of our + generic arguments, substitutes the appropriate type before + performing the mapping. """ + return self.db.lltype_to_cts(self.generics.get(ARG,ARG)) + + def lookup_method(self, methodnm): + """ Given the method name, returns a jvmgen.Method object """ + + # Lookup the generic method by name. + GENMETH = self.OOTYPE._GENERIC_METHODS[methodnm] + + # Create an array with the Java version of each type in the + # argument list and return type. + jargtypes = [self._map(P) for P in GENMETH.ARGS] + jrettype = self._map(GENMETH.RESULT) + return jvmgen.Method( + self.jvmtype.class_name(), + methodnm, + jvm_method_desc(jargtypes, jrettype), + opcode=jvmgen.INVOKEVIRTUAL) + + class Database: def __init__(self, genoo): # Public attributes: @@ -57,7 +117,8 @@ self._pending_nodes.add(node) def pending_class(self, OOCLASS): - assert isinstance(OOCLASS, ootype.Instance) + if not isinstance(OOCLASS, ootype.Instance): + return BuiltInClassNode(self, OOCLASS) # Create class object if it does not already exist: if OOCLASS in self._classes: @@ -179,12 +240,15 @@ ootype.Bool:jvmgen.PYPYDUMPBOOLEAN, ootype.Class:jvmgen.PYPYDUMPOBJECT, ootype.String:jvmgen.PYPYDUMPSTRING, + ootype.StringBuilder:jvmgen.PYPYDUMPOBJECT, } def generate_dump_method_for_ootype(self, OOTYPE): if OOTYPE in self._type_printing_methods: return self._type_printing_methods[OOTYPE] - return self.pending_class(OOTYPE).dump_method.method() + pclass = self.pending_class(OOTYPE) + assert hasattr(pclass, 'dump_method'), "No dump_method for "+OOTYPE + return pclass.dump_method.method() # Type translation functions Modified: pypy/dist/pypy/translator/jvm/src/PyPy.java ============================================================================== --- pypy/dist/pypy/translator/jvm/src/PyPy.java (original) +++ pypy/dist/pypy/translator/jvm/src/PyPy.java Wed Nov 1 23:24:14 2006 @@ -7,7 +7,6 @@ * Class with a number of utility routines. */ public class PyPy { - /** * Compares two unsigned integers (value1 and value2) and returns * a value greater than, equal to, or less than zero if value 1 is @@ -221,10 +220,11 @@ dump_indented(indent, Double.toString(d)); } - public static void dump_string(char[] b, int indent) { + public static void dump_string(byte[] b, int indent) { StringBuffer sb = new StringBuffer(); sb.append('"'); - for (char c : b) { + for (byte _c : b) { + char c = (char)_c; if (c == '"') sb.append("\\\""); else @@ -256,7 +256,7 @@ public static byte[] string2bytes(String s) { return s.getBytes(); } - + // ---------------------------------------------------------------------- // OOString support @@ -289,9 +289,14 @@ return s; } - public static byte[] OOString(boolean b, int base_) + public static final byte[] trueString = new byte[] { + (byte)'T', (byte)'r', (byte)'u', (byte)'e' }; + public static final byte[] falseString = new byte[] { + (byte)'F', (byte)'a', (byte)'l', (byte)'s', (byte)'e' }; + public static byte[] oostring(boolean b, int base_) { - return string2bytes(new Boolean(b).toString()); + if (b) return trueString; + return falseString; } // ---------------------------------------------------------------------- From niko at codespeak.net Thu Nov 2 00:23:26 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Thu, 2 Nov 2006 00:23:26 +0100 (CET) Subject: [pypy-svn] r34051 - in pypy/dist/pypy/translator/jvm: . src Message-ID: <20061101232326.7DD891006E@code0.codespeak.net> Author: niko Date: Thu Nov 2 00:23:25 2006 New Revision: 34051 Modified: pypy/dist/pypy/translator/jvm/conftest.py pypy/dist/pypy/translator/jvm/database.py pypy/dist/pypy/translator/jvm/generator.py pypy/dist/pypy/translator/jvm/option.py pypy/dist/pypy/translator/jvm/src/PyPy.java pypy/dist/pypy/translator/jvm/typesystem.py Log: Because I can't seem to sleep... 1. Add an option to choose between native strings and byte arrays 2. Add ability to rename built-in methods like ll_append_char etc, so that string builders work. As a result, so does test_bool Modified: pypy/dist/pypy/translator/jvm/conftest.py ============================================================================== --- pypy/dist/pypy/translator/jvm/conftest.py (original) +++ pypy/dist/pypy/translator/jvm/conftest.py Thu Nov 2 00:23:25 2006 @@ -16,5 +16,7 @@ Option('--package', action='store', dest='package', default='pypy', help='Package to output generated classes into'), Option('--trace', action='store_true', dest='trace', default=False, - help='Trace execution of generated code') + help='Trace execution of generated code'), + Option('--byte-arrays', action='store_true', dest='byte-arrays', + default=False, help='Use byte arrays rather than native strings'), ) Modified: pypy/dist/pypy/translator/jvm/database.py ============================================================================== --- pypy/dist/pypy/translator/jvm/database.py (original) +++ pypy/dist/pypy/translator/jvm/database.py Thu Nov 2 00:23:25 2006 @@ -10,7 +10,40 @@ from pypy.translator.jvm import node from pypy.translator.jvm.option import getoption import pypy.translator.jvm.generator as jvmgen -import pypy.translator.jvm.typesystem as jvmtypes +from pypy.translator.jvm.typesystem import \ + jStringBuilder, jInt, jVoid, jString, jOOString, jChar + +# When we lookup a method on a BuiltInClassNode, we first check +# the 'built_in_methods' table. This allows us to redirect to other +# methods if we like. + +def _ll_build_method(): + # Choose an appropriate ll_build depending on what representation + # we are using for ootype.String: + if jOOString == jString: + return jvmgen.Method.v( + jStringBuilder.class_name(), "toString", (),jString) + return jvmgen.Method.s( + jvmgen.PYPYJAVA, "ll_build", (jStringBuilder,), jOOString) + +built_in_methods = { + (ootype.StringBuilder.__class__, "ll_allocate"): + jvmgen.Method.v(jStringBuilder.class_name(), "ensureCapacity", + (jInt,), jVoid), + + (ootype.StringBuilder.__class__, "ll_append_char"): + jvmgen.Method.s(jvmgen.PYPYJAVA, "ll_append_char", + (jStringBuilder, jChar), jVoid), + + (ootype.StringBuilder.__class__, "ll_append"): + jvmgen.Method.s(jvmgen.PYPYJAVA, "ll_append", + (jStringBuilder, jOOString), jVoid), + + # XXX will not work with --byte-arrays + (ootype.StringBuilder.__class__, "ll_build"): + _ll_build_method() + + } class BuiltInClassNode(object): @@ -58,6 +91,14 @@ def lookup_method(self, methodnm): """ Given the method name, returns a jvmgen.Method object """ + # Look for a shortcut method + try: + key = (self.OOTYPE.__class__, methodnm) + print "key=%r" % (key,) + print "hash=%r" % (built_in_methods,) + return built_in_methods[key] + except KeyError: pass + # Lookup the generic method by name. GENMETH = self.OOTYPE._GENERIC_METHODS[methodnm] Modified: pypy/dist/pypy/translator/jvm/generator.py ============================================================================== --- pypy/dist/pypy/translator/jvm/generator.py (original) +++ pypy/dist/pypy/translator/jvm/generator.py Thu Nov 2 00:23:25 2006 @@ -3,10 +3,15 @@ from pypy.translator.oosupport.metavm import Generator from pypy.translator.jvm.typesystem import \ JvmType, jObject, jPrintStream, jvm_for_class, jVoid, jvm_method_desc, \ - jInt, jByteArray + jInt, jByteArray, jOOString, jString, jStringBuilder from pypy.rpython.ootypesystem import ootype # ___________________________________________________________________________ +# Helper class string constants + +PYPYJAVA = "pypy.PyPy" + +# ___________________________________________________________________________ # JVM Opcode Flags: # # Indicates certain properties of each opcode. Used mainly for debugging @@ -221,6 +226,16 @@ # methobj is its Method instance. class Method(object): + + def v(classnm, methnm, argtypes, rettype): + return Method(classnm, methnm, jvm_method_desc(argtypes, rettype), + opcode=INVOKEVIRTUAL) + v = staticmethod(v) + + def s(classnm, methnm, argtypes, rettype): + return Method(classnm, methnm, jvm_method_desc(argtypes, rettype)) + s = staticmethod(s) + def __init__(self, classnm, methnm, desc, opcode=INVOKESTATIC): self.opcode = opcode self.class_name = classnm # String, ie. "java.lang.Math" @@ -239,39 +254,42 @@ MATHFLOOR = Method('java.lang.Math', 'floor', '(D)D') PRINTSTREAMPRINTSTR = Method('java.io.PrintStream', 'print', '(Ljava/lang/String;)V', opcode=INVOKEVIRTUAL) -PYPYUINTCMP = Method('pypy.PyPy', 'uint_cmp', '(II)I') -PYPYULONGCMP = Method('pypy.PyPy', 'ulong', '(LL)I') -PYPYUINTTODOUBLE = Method('pypy.PyPy', 'uint_to_double', '(I)D') -PYPYDOUBLETOUINT = Method('pypy.PyPy', 'double_to_uint', '(D)I') -PYPYLONGBITWISENEGATE = Method('pypy.PyPy', 'long_bitwise_negate', '(L)L') -PYPYARRAYTOLIST = Method('pypy.PyPy', 'array_to_list', +PYPYUINTCMP = Method(PYPYJAVA, 'uint_cmp', '(II)I') +PYPYULONGCMP = Method(PYPYJAVA, 'ulong', '(LL)I') +PYPYUINTTODOUBLE = Method(PYPYJAVA, 'uint_to_double', '(I)D') +PYPYDOUBLETOUINT = Method(PYPYJAVA, 'double_to_uint', '(D)I') +PYPYLONGBITWISENEGATE = Method(PYPYJAVA, 'long_bitwise_negate', '(L)L') +PYPYARRAYTOLIST = Method(PYPYJAVA, 'array_to_list', '([Ljava/lang/Object;)Ljava/util/List;') -PYPYSTRTOINT = Method('pypy.PyPy', 'str_to_int', +PYPYSTRTOINT = Method(PYPYJAVA, 'str_to_int', '(Ljava/lang/String;)I') -PYPYSTRTOUINT = Method('pypy.PyPy', 'str_to_uint', +PYPYSTRTOUINT = Method(PYPYJAVA, 'str_to_uint', '(Ljava/lang/String;)I') -PYPYSTRTOLONG = Method('pypy.PyPy', 'str_to_long', +PYPYSTRTOLONG = Method(PYPYJAVA, 'str_to_long', '(Ljava/lang/String;)J') -PYPYSTRTOULONG = Method('pypy.PyPy', 'str_to_ulong', +PYPYSTRTOULONG = Method(PYPYJAVA, 'str_to_ulong', '(Ljava/lang/String;)J') -PYPYSTRTOBOOL = Method('pypy.PyPy', 'str_to_bool', +PYPYSTRTOBOOL = Method(PYPYJAVA, 'str_to_bool', '(Ljava/lang/String;)Z') -PYPYSTRTODOUBLE = Method('pypy.PyPy', 'str_to_double', +PYPYSTRTODOUBLE = Method(PYPYJAVA, 'str_to_double', '(Ljava/lang/String;)D') -PYPYSTRTOCHAR = Method('pypy.PyPy', 'str_to_char', +PYPYSTRTOCHAR = Method(PYPYJAVA, 'str_to_char', '(Ljava/lang/String;)C') -PYPYDUMPINDENTED = Method('pypy.PyPy', 'dump_indented', +PYPYDUMPINDENTED = Method(PYPYJAVA, 'dump_indented', '(ILjava/lang/String;)V') -PYPYDUMPINT = Method('pypy.PyPy', 'dump_int', '(II)V') -PYPYDUMPUINT = Method('pypy.PyPy', 'dump_uint', '(II)V') -PYPYDUMPLONG = Method('pypy.PyPy', 'dump_long', '(LI)V') -PYPYDUMPDOUBLE = Method('pypy.PyPy', 'dump_double', '(DI)V') -PYPYDUMPSTRING = Method('pypy.PyPy', 'dump_string', '([BI)V') -PYPYDUMPBOOLEAN = Method('pypy.PyPy', 'dump_boolean', '(ZI)V') -PYPYDUMPOBJECT = Method('pypy.PyPy', 'dump_object', +PYPYDUMPINT = Method(PYPYJAVA, 'dump_int', '(II)V') +PYPYDUMPUINT = Method(PYPYJAVA, 'dump_uint', '(II)V') +PYPYDUMPLONG = Method(PYPYJAVA, 'dump_long', '(LI)V') +PYPYDUMPDOUBLE = Method(PYPYJAVA, 'dump_double', '(DI)V') +PYPYDUMPSTRING = Method(PYPYJAVA, 'dump_string', + jvm_method_desc((jOOString,jInt),jVoid)) +PYPYDUMPBOOLEAN = Method(PYPYJAVA, 'dump_boolean', '(ZI)V') +PYPYDUMPOBJECT = Method(PYPYJAVA, 'dump_object', '(Ljava/lang/Object;I)V') -PYPYRUNTIMENEW = Method('pypy.PyPy', 'RuntimeNew', +PYPYRUNTIMENEW = Method(PYPYJAVA, 'RuntimeNew', '(Ljava/lang/Class;)Ljava/lang/Object;') +PYPYSTRING2BYTES = Method(PYPYJAVA, 'string2bytes', + jvm_method_desc((jString),jByteArray)) # ___________________________________________________________________________ @@ -798,8 +816,14 @@ def call_oostring(self, OOTYPE): cts_type = self.db.lltype_to_cts(OOTYPE) - mthd = Method('pypy.PyPy', 'oostring', jvm_method_desc([cts_type, jInt], jByteArray)) - self.emit(mthd) + if cts_type != jByteArray: + mthd = Method.s(PYPYJAVA, 'oostring', [cts_type, jInt], jString) + self.emit(mthd) + if jOOString == jByteArray: + self.emit(PYPYSTRING2BYTES) + else: + mthd = Method.s(PYPYJAVA, 'oostring', + [jByteArray, jInt], jByteArray) def new(self, TYPE): jtype = self.db.lltype_to_cts(TYPE) Modified: pypy/dist/pypy/translator/jvm/option.py ============================================================================== --- pypy/dist/pypy/translator/jvm/option.py (original) +++ pypy/dist/pypy/translator/jvm/option.py Thu Nov 2 00:23:25 2006 @@ -9,7 +9,8 @@ 'package':'pypy', 'wd':False, 'norun':False, - 'trace':False + 'trace':False, + 'byte-arrays':False } def getoption(name): Modified: pypy/dist/pypy/translator/jvm/src/PyPy.java ============================================================================== --- pypy/dist/pypy/translator/jvm/src/PyPy.java (original) +++ pypy/dist/pypy/translator/jvm/src/PyPy.java Thu Nov 2 00:23:25 2006 @@ -5,6 +5,10 @@ /** * Class with a number of utility routines. + * + * I apologize for the Python-esque naming conventions, but it seems + * I can't switch my mind to camelCase when working so closely with + * Python mere minutes before. */ public class PyPy { /** @@ -220,15 +224,30 @@ dump_indented(indent, Double.toString(d)); } + public static void _append_char(StringBuffer sb, char c) { + if (c == '"') + sb.append("\\\""); + else + sb.append(c); + } + public static void dump_string(byte[] b, int indent) { StringBuffer sb = new StringBuffer(); sb.append('"'); for (byte _c : b) { char c = (char)_c; - if (c == '"') - sb.append("\\\""); - else - sb.append(c); + _append_char(sb, c); + } + sb.append('"'); + dump_indented(indent, sb.toString()); + } + + public static void dump_string(String b, int indent) { + StringBuffer sb = new StringBuffer(); + sb.append('"'); + for (int i = 0; i < b.length(); i++) { + char c = b.charAt(i); + _append_char(sb, c); } sb.append('"'); dump_indented(indent, sb.toString()); @@ -239,6 +258,37 @@ } // ---------------------------------------------------------------------- + // StringBuffer + + public static void ll_append_char(StringBuilder sb, char c) { + // annoyingly, the actual return code is StringBuilder, so I have + // to make this wrapper to ignore the return value + sb.append(c); + } + + public static void ll_append(StringBuilder sb, String s) { + // annoyingly, the actual return code is StringBuilder, so I have + // to make this wrapper to ignore the return value + sb.append(s); + } + + public static void ll_append(StringBuilder sb, byte[] s) { + // This is only used when we are using byte arrays instead of + // strings. We should really replace StringBuilder with some + // kind of ByteBuilder in that case... + for (byte b : s) { + sb.append((char)b); + } + } + + public static byte[] ll_build(StringBuilder sb) { + // This is only used when we are using byte arrays instead of + // strings. We should really replace StringBuilder with some + // kind of ByteBuilder in that case... + return string2bytes(sb.toString()); + } + + // ---------------------------------------------------------------------- // Type Manipulation Routines public static Object RuntimeNew(Class c) { @@ -260,28 +310,28 @@ // ---------------------------------------------------------------------- // OOString support - public static byte[] oostring(int n, int base_) { + public static String oostring(int n, int base_) { // XXX needs special case for unsigned ints if (base_ == -1) base_ = 10; if (n < 0 && base_ != 10) - return string2bytes("-" + Integer.toString(-n, base_)); + return "-" + Integer.toString(-n, base_); else - return string2bytes(Integer.toString(n, base_)); + return Integer.toString(n, base_); } - public static byte[] oostring(double d, int base_) { - return string2bytes(new Double(d).toString()); + public static String oostring(double d, int base_) { + return new Double(d).toString(); } - public static byte[] oostring(Object obj, int base_) + public static String oostring(Object obj, int base_) { - return string2bytes(String.format("<%s object>", new Object[] { obj.getClass().getName() })); + return String.format("<%s object>", new Object[] { obj.getClass().getName() }); } - public static byte[] oostring(char ch, int base_) + public static String oostring(char ch, int base_) { - return string2bytes(new Character(ch).toString()); + return new Character(ch).toString(); } public static byte[] oostring(byte[] s, int base_) @@ -289,14 +339,15 @@ return s; } - public static final byte[] trueString = new byte[] { - (byte)'T', (byte)'r', (byte)'u', (byte)'e' }; - public static final byte[] falseString = new byte[] { - (byte)'F', (byte)'a', (byte)'l', (byte)'s', (byte)'e' }; - public static byte[] oostring(boolean b, int base_) + public static String oostring(String s, int base_) + { + return s; + } + + public static String oostring(boolean b, int base_) { - if (b) return trueString; - return falseString; + if (b) return "True"; + return "False"; } // ---------------------------------------------------------------------- Modified: pypy/dist/pypy/translator/jvm/typesystem.py ============================================================================== --- pypy/dist/pypy/translator/jvm/typesystem.py (original) +++ pypy/dist/pypy/translator/jvm/typesystem.py Thu Nov 2 00:23:25 2006 @@ -111,7 +111,7 @@ ootype.Float: jDouble, ootype.Char: jByte, ootype.UniChar: jChar, - ootype.String: jByteArray, + ootype.String: jString, ootype.ROOT: jObject, # We may want to use PyPy wrappers here later: @@ -123,6 +123,11 @@ ootype.DictItemsIterator:jIterator } +# Determine which class we will use to represent strings: +if getoption('byte-arrays'): + ootype_to_jvm[ootype.String] = jByteArray +jOOString = ootype_to_jvm[ootype.String] + # Method descriptor construction def jvm_method_desc(argtypes, rettype): """ A Java method has a descriptor, which is a string specified From ericvrp at codespeak.net Thu Nov 2 10:59:24 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Thu, 2 Nov 2006 10:59:24 +0100 (CET) Subject: [pypy-svn] r34053 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061102095924.B383410063@code0.codespeak.net> Author: ericvrp Date: Thu Nov 2 10:59:21 2006 New Revision: 34053 Removed: pypy/dist/pypy/jit/codegen/llvm/jitcode.py pypy/dist/pypy/jit/codegen/llvm/test/test_rgenop.py Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Log: * don not write the .bc file to disc after parsing the .ll file. * remove old llvm jit interface Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Thu Nov 2 10:59:21 2006 @@ -33,9 +33,9 @@ return false; } - std::ostream *Out = new std::ofstream((inputfile + ".bc").c_str(), - std::ios::out | std::ios::trunc | std::ios::binary); - WriteBytecodeToFile(module, *Out); //XXX what to do with the 3rd param (NoCompress)? + //std::ostream *Out = new std::ofstream((inputfile + ".bc").c_str(), + // std::ios::out | std::ios::trunc | std::ios::binary); + //WriteBytecodeToFile(module, *Out); //XXX what to do with the 3rd param (NoCompress)? ModuleProvider* module_provider = new ExistingModuleProvider(module); if (!g_execution_engine) { From ericvrp at codespeak.net Thu Nov 2 11:38:28 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Thu, 2 Nov 2006 11:38:28 +0100 (CET) Subject: [pypy-svn] r34054 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061102103828.71FB410060@code0.codespeak.net> Author: ericvrp Date: Thu Nov 2 11:38:26 2006 New Revision: 34054 Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: Add inmemory parsing of llvm sourcecode. next: remove the parsing of code from disc. Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Thu Nov 2 11:38:26 2006 @@ -23,16 +23,13 @@ ExecutionEngine* g_execution_engine; -int compile(const char* filename) { - std::string inputfile(filename); +void restart() { + delete g_execution_engine; + g_execution_engine = NULL; +} - //from llvm-as.cpp - Module* module(ParseAssemblyFile(inputfile + ".ll")); - if (!module) { - std::cerr << "Error: can not parse " << inputfile << ".ll\n" << std::flush; - return false; - } +int add_module_to_execution_engine(Module* module) { //std::ostream *Out = new std::ofstream((inputfile + ".bc").c_str(), // std::ios::out | std::ios::trunc | std::ios::binary); //WriteBytecodeToFile(module, *Out); //XXX what to do with the 3rd param (NoCompress)? @@ -48,6 +45,30 @@ } +int compile(const char* filename) { + std::string inputfile(filename); + + Module* module(ParseAssemblyFile(inputfile + ".ll")); + if (!module) { + std::cerr << "Error: can not parse " << inputfile << ".ll\n" << std::flush; + return false; + } + + return add_module_to_execution_engine(module); +} + + +int compile_src(const char* src) { + Module* module = ParseAssemblyString(src, new Module("llvmjit")); + if (!module) { + std::cerr << "Error: can not parse " << src << "\n" << std::flush; + return false; + } + + return add_module_to_execution_engine(module); +} + + int execute(const char* funcname, int param) { //currently compiled=Module int err = -1; @@ -68,3 +89,4 @@ GenericValue gv = g_execution_engine->runFunction(func, args); return gv.IntVal; } + Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h Thu Nov 2 11:38:26 2006 @@ -4,8 +4,10 @@ extern "C" { #endif -int compile(const char* filename); -int execute(const char* funcname, int param); +void restart(); +int compile(const char* filename); +int compile_src(const char* src); +int execute(const char* funcname, int param); #ifdef __cplusplus } Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Thu Nov 2 11:38:26 2006 @@ -21,10 +21,16 @@ llvmjit._FuncPtr = _FuncPtr #exposed functions... +restart = llvmjit.restart + compile = llvmjit.compile compile.restype = c_int compile.argtypes = [c_char_p] +compile_src = llvmjit.compile_src +compile_src.restype = c_int +compile_src.argtypes = [c_char_p] + execute = llvmjit.execute execute.restype = c_int execute.argtypes = [c_char_p, c_int] Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Thu Nov 2 11:38:26 2006 @@ -7,15 +7,38 @@ except OSError: py.test.skip("libllvmjit not found (see ../README.TXT)") +#helper data curdir = dirname(__file__) square = join(curdir, 'square') mul2 = join(curdir, 'mul2') +square_src = '''int %square(int %n) { +block0: + %n2 = mul int %n, %n + ret int %n2 +}''' + +mul2_src = '''int %mul2(int %n) { +block0: + %n2 = mul int %n, 2 + ret int %n2 +}''' + +#helpers def execute(filename, funcname, param): assert llvmjit.compile(filename) return llvmjit.execute(funcname, param) -def test_execute_compile(): +def execute_src(src, funcname, param): + assert llvmjit.compile_src(src) + return llvmjit.execute(funcname, param) + +#tests... +def test_restart(): + llvmjit.restart() + +def test_execute_translation(): + llvmjit.restart() def f(x): return execute(square, 'square', x + 5) fn = compile(f, [int]) @@ -23,18 +46,37 @@ assert res == 36 def test_compile(): + llvmjit.restart() assert llvmjit.compile(square) -def test_compiled(): +def test_execute(): + llvmjit.restart() assert execute(square, 'square', 4) == 4 * 4 -def test_compiled2(): +def test_execute_multiple(): + llvmjit.restart() llvmjit.compile(square) llvmjit.compile(mul2) for i in range(5): assert llvmjit.execute('square', i) == i * i assert llvmjit.execute('mul2', i) == i * 2 +def test_compile_src(): + llvmjit.restart() + assert llvmjit.compile_src(square_src) + +def test_execute_src(): + llvmjit.restart() + assert execute_src(square_src, 'square', 4) == 4 * 4 + +def test_execute_multiple_src(): + llvmjit.restart() + llvmjit.compile_src(square_src) + llvmjit.compile_src(mul2_src) + for i in range(5): + assert llvmjit.execute('square', i) == i * i + assert llvmjit.execute('mul2', i) == i * 2 + def DONTtest_execute_accross_module(): pass @@ -56,6 +98,3 @@ def DONTtest_layers_of_codegenerators(): #e.g. i386 code until function stabilizes then llvm pass -def DONTtest_inmemory_ll_and_bc_files(): - pass - From ericvrp at codespeak.net Thu Nov 2 12:12:26 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Thu, 2 Nov 2006 12:12:26 +0100 (CET) Subject: [pypy-svn] r34055 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061102111226.E1FC010063@code0.codespeak.net> Author: ericvrp Date: Thu Nov 2 12:12:22 2006 New Revision: 34055 Removed: pypy/dist/pypy/jit/codegen/llvm/test/mul2.ll pypy/dist/pypy/jit/codegen/llvm/test/square.ll Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: * depricated llvm parsing/compiling from disc (inmemory only from now on) * remove .ll sourcefiles * added tests for llvmjit.restart and llvmjit.find_function Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Thu Nov 2 12:12:22 2006 @@ -23,14 +23,20 @@ ExecutionEngine* g_execution_engine; -void restart() { - delete g_execution_engine; +void restart() { + delete g_execution_engine; //XXX test if this correctly cleans up including generated code g_execution_engine = NULL; } -int add_module_to_execution_engine(Module* module) { - //std::ostream *Out = new std::ofstream((inputfile + ".bc").c_str(), +int compile(const char* llsource) { + Module* module = ParseAssemblyString(llsource, new Module("llvmjit")); + if (!module) { + std::cerr << "Error: can not parse " << llsource << "\n" << std::flush; + return false; + } + + //std::ostream *Out = new std::ofstream("temp-libllvmjit.bc", // std::ios::out | std::ios::trunc | std::ios::binary); //WriteBytecodeToFile(module, *Out); //XXX what to do with the 3rd param (NoCompress)? @@ -45,48 +51,28 @@ } -int compile(const char* filename) { - std::string inputfile(filename); - - Module* module(ParseAssemblyFile(inputfile + ".ll")); - if (!module) { - std::cerr << "Error: can not parse " << inputfile << ".ll\n" << std::flush; - return false; - } - - return add_module_to_execution_engine(module); -} - - -int compile_src(const char* src) { - Module* module = ParseAssemblyString(src, new Module("llvmjit")); - if (!module) { - std::cerr << "Error: can not parse " << src << "\n" << std::flush; - return false; - } +void* find_function(const char* name) { + if (!g_execution_engine) return NULL; //note: decided not to be treated as an error - return add_module_to_execution_engine(module); + return g_execution_engine->FindFunctionNamed(name); //note: can be NULL } -int execute(const char* funcname, int param) { //currently compiled=Module - int err = -1; - +int execute(const void* function, int param) { //XXX allow different function signatures if (!g_execution_engine) { std::cerr << "Error: no llvm code compiled yet!\n" << std::flush; - return err; + return -1; + } + + if (!function) { + std::cerr << "Error: no function supplied to libllvmjit.execute(...)\n" << std::flush; + return -1; } std::vector args; args.push_back((void*)param); - Function* func = g_execution_engine->FindFunctionNamed(funcname); - if (!func) { - std::cerr << "Error: can not find function " << funcname << "\n" << std::flush; - return err; - } - - GenericValue gv = g_execution_engine->runFunction(func, args); + GenericValue gv = g_execution_engine->runFunction((Function*)function, args); return gv.IntVal; } Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h Thu Nov 2 12:12:22 2006 @@ -5,9 +5,9 @@ #endif void restart(); -int compile(const char* filename); -int compile_src(const char* src); -int execute(const char* funcname, int param); +int compile(const char* llsource); +void* find_function(const char* funcname); +int execute(const void* function, int param); #ifdef __cplusplus } Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Thu Nov 2 12:12:22 2006 @@ -27,10 +27,10 @@ compile.restype = c_int compile.argtypes = [c_char_p] -compile_src = llvmjit.compile_src -compile_src.restype = c_int -compile_src.argtypes = [c_char_p] +find_function = llvmjit.find_function +find_function.restype = c_void_p +find_function.argtypes = [c_char_p] execute = llvmjit.execute execute.restype = c_int -execute.argtypes = [c_char_p, c_int] +execute.argtypes = [c_void_p, c_int] Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Thu Nov 2 12:12:22 2006 @@ -12,70 +12,67 @@ square = join(curdir, 'square') mul2 = join(curdir, 'mul2') -square_src = '''int %square(int %n) { +llsquare = '''int %square(int %n) { block0: %n2 = mul int %n, %n ret int %n2 }''' -mul2_src = '''int %mul2(int %n) { +llmul2 = '''int %mul2(int %n) { block0: %n2 = mul int %n, 2 ret int %n2 }''' #helpers -def execute(filename, funcname, param): - assert llvmjit.compile(filename) - return llvmjit.execute(funcname, param) - -def execute_src(src, funcname, param): - assert llvmjit.compile_src(src) - return llvmjit.execute(funcname, param) +def execute(llsource, function_name, param): + assert llvmjit.compile(llsource) + function = llvmjit.find_function(function_name) + assert function + return llvmjit.execute(function, param) #tests... def test_restart(): - llvmjit.restart() + for i in range(3): + llvmjit.restart() + assert not llvmjit.find_function('square') + assert llvmjit.compile(llsquare) + assert llvmjit.find_function('square') + +def test_find_function(): + for i in range(3): + llvmjit.restart() + assert not llvmjit.find_function('square') + assert not llvmjit.find_function('square') + assert llvmjit.compile(llsquare) + assert llvmjit.find_function('square') + assert llvmjit.find_function('square') def test_execute_translation(): llvmjit.restart() def f(x): - return execute(square, 'square', x + 5) + return execute(llsquare, 'square', x + 5) fn = compile(f, [int]) res = fn(1) assert res == 36 def test_compile(): llvmjit.restart() - assert llvmjit.compile(square) + assert llvmjit.compile(llsquare) def test_execute(): llvmjit.restart() - assert execute(square, 'square', 4) == 4 * 4 + assert execute(llsquare, 'square', 4) == 4 * 4 def test_execute_multiple(): llvmjit.restart() - llvmjit.compile(square) - llvmjit.compile(mul2) - for i in range(5): - assert llvmjit.execute('square', i) == i * i - assert llvmjit.execute('mul2', i) == i * 2 - -def test_compile_src(): - llvmjit.restart() - assert llvmjit.compile_src(square_src) - -def test_execute_src(): - llvmjit.restart() - assert execute_src(square_src, 'square', 4) == 4 * 4 - -def test_execute_multiple_src(): - llvmjit.restart() - llvmjit.compile_src(square_src) - llvmjit.compile_src(mul2_src) + llvmjit.compile(llsquare) + llvmjit.compile(llmul2) + square = llvmjit.find_function('square') + mul2 = llvmjit.find_function('mul2') for i in range(5): - assert llvmjit.execute('square', i) == i * i - assert llvmjit.execute('mul2', i) == i * 2 + assert llvmjit.execute(square, i) == i * i + assert llvmjit.execute(mul2 , i) == i * 2 def DONTtest_execute_accross_module(): pass @@ -97,4 +94,3 @@ def DONTtest_layers_of_codegenerators(): #e.g. i386 code until function stabilizes then llvm pass - From ericvrp at codespeak.net Thu Nov 2 12:30:48 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Thu, 2 Nov 2006 12:30:48 +0100 (CET) Subject: [pypy-svn] r34056 - in pypy/dist/pypy/jit/codegen/llvm: . test Message-ID: <20061102113048.2C30D10063@code0.codespeak.net> Author: ericvrp Date: Thu Nov 2 12:30:47 2006 New Revision: 34056 Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: attempt to add a nice helper (for calling jit-ed functions) which is not translatable. Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Thu Nov 2 12:30:47 2006 @@ -34,3 +34,12 @@ execute = llvmjit.execute execute.restype = c_int execute.argtypes = [c_void_p, c_int] + +#helpers... +class FindFunction(object): + def __init__(self, function_name): + self.function = find_function(function_name) + + def __call__(self, param): #XXX this does not seem to translate, how to do it instead? + return execute(self.function, param) + Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Thu Nov 2 12:30:47 2006 @@ -27,9 +27,10 @@ #helpers def execute(llsource, function_name, param): assert llvmjit.compile(llsource) - function = llvmjit.find_function(function_name) - assert function - return llvmjit.execute(function, param) + f = llvmjit.FindFunction(function_name) + assert f.function + return llvmjit.execute(f.function, param) + #return function(param) #XXX this does not seem to translate, how to do it instead? #tests... def test_restart(): @@ -48,14 +49,6 @@ assert llvmjit.find_function('square') assert llvmjit.find_function('square') -def test_execute_translation(): - llvmjit.restart() - def f(x): - return execute(llsquare, 'square', x + 5) - fn = compile(f, [int]) - res = fn(1) - assert res == 36 - def test_compile(): llvmjit.restart() assert llvmjit.compile(llsquare) @@ -74,6 +67,16 @@ assert llvmjit.execute(square, i) == i * i assert llvmjit.execute(mul2 , i) == i * 2 +def test_call_found_function(): + llvmjit.restart() + llvmjit.compile(llsquare) + llvmjit.compile(llmul2) + square = llvmjit.FindFunction('square') + mul2 = llvmjit.FindFunction('mul2') + for i in range(5): + assert square(i) == i * i + assert mul2(i) == i * 2 + def DONTtest_execute_accross_module(): pass @@ -94,3 +97,11 @@ def DONTtest_layers_of_codegenerators(): #e.g. i386 code until function stabilizes then llvm pass + +def test_execute_translation(): #put this one last because it takes the most time + llvmjit.restart() + def f(x): + return execute(llsquare, 'square', x + 5) + fn = compile(f, [int]) + res = fn(1) + assert res == 36 From fijal at codespeak.net Thu Nov 2 16:11:57 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 2 Nov 2006 16:11:57 +0100 (CET) Subject: [pypy-svn] r34063 - in pypy/dist/pypy/translator/js: . examples test tools Message-ID: <20061102151157.955E31007B@code0.codespeak.net> Author: fijal Date: Thu Nov 2 16:11:54 2006 New Revision: 34063 Added: pypy/dist/pypy/translator/js/examples/ - copied from r34035, pypy/dist/pypy/translator/js/tools/ pypy/dist/pypy/translator/js/examples/serialise.py (contents, props changed) Removed: pypy/dist/pypy/translator/js/tools/ Modified: pypy/dist/pypy/translator/js/main.py pypy/dist/pypy/translator/js/test/test_typed.py Log: Moved tools to examples. Added simple example of function serialiser. Added: pypy/dist/pypy/translator/js/examples/serialise.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/js/examples/serialise.py Thu Nov 2 16:11:54 2006 @@ -0,0 +1,15 @@ + +""" example of (very simple) serialiser +""" + +def serialise(obj): + if isinstance(obj, str): + return "S" + obj + elif isinstance(obj, int): + return "I" + str(obj) + return "?" + +serialise._annspecialcase_ = "specialize:argtype(0)" + +def serialisetest(): + return serialise("aaa") + serialise(3) + serialise(None) Modified: pypy/dist/pypy/translator/js/main.py ============================================================================== --- pypy/dist/pypy/translator/js/main.py (original) +++ pypy/dist/pypy/translator/js/main.py Thu Nov 2 16:11:54 2006 @@ -40,7 +40,7 @@ [:func_data.func_code.co_argcount]) def rpython2javascript_main(argv, opts): - if len(argv) < 1: + if len(argv) < 2: print "usage: module " import sys sys.exit(0) @@ -114,8 +114,12 @@ if func_name not in mod.__dict__: raise FunctionNotFound("function %r was not found in module %r" % (func_name, module_name)) func_code = mod.__dict__[func_name] + if func_code.func_defaults: + lgt = len(func_code.func_defaults) + else: + lgt = 0 if func_code.func_code.co_argcount > 0 and func_code.func_code. \ - co_argcount != len(func_code.func_defaults): + co_argcount != lgt: raise BadSignature("Function %s does not have default arguments" % func_name) source_ssf = get_source_ssf(mod, module_name, function_names, opts.debug_transform) exec(source_ssf) in globals() Modified: pypy/dist/pypy/translator/js/test/test_typed.py ============================================================================== --- pypy/dist/pypy/translator/js/test/test_typed.py (original) +++ pypy/dist/pypy/translator/js/test/test_typed.py Thu Nov 2 16:11:54 2006 @@ -14,7 +14,7 @@ return res == expected fn = compile_function(wrapper, []) result = fn() - assert result + assert result == 0 def test_get_set_del_slice(): def get_set_del_nonneg_slice(): # no neg slices for now! From fijal at codespeak.net Thu Nov 2 16:32:58 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 2 Nov 2006 16:32:58 +0100 (CET) Subject: [pypy-svn] r34064 - pypy/dist/pypy/translator/js/modules Message-ID: <20061102153258.77A9C1006E@code0.codespeak.net> Author: fijal Date: Thu Nov 2 16:32:55 2006 New Revision: 34064 Modified: pypy/dist/pypy/translator/js/modules/mochikit.py Log: Specialise mochikit function. Modified: pypy/dist/pypy/translator/js/modules/mochikit.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/mochikit.py (original) +++ pypy/dist/pypy/translator/js/modules/mochikit.py Thu Nov 2 16:32:55 2006 @@ -9,19 +9,25 @@ def log(data): pass log.suggested_primitive = True +log._annspecialcase_ = "specialize:argtype(0)" def logDebug(data): pass logDebug.suggested_primitive = True +logDebug._annspecialcase_ = "specialize:argtype(0)" def logWarning(data): pass logWarning.suggested_primitive = True +logWarning._annspecialcase_ = "specialize:argtype(0)" + def logError(data): pass logError.suggested_primitive = True +logError._annspecialcase_ = "specialize:argtype(0)" def logFatal(data): pass logFatal.suggested_primitive = True +logFatal._annspecialcase_ = "specialize:argtype(0)" From arigo at codespeak.net Thu Nov 2 17:49:06 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 2 Nov 2006 17:49:06 +0100 (CET) Subject: [pypy-svn] r34068 - in pypy/dist/pypy: interpreter interpreter/test module/thread Message-ID: <20061102164906.197D21006E@code0.codespeak.net> Author: arigo Date: Thu Nov 2 17:49:02 2006 New Revision: 34068 Added: pypy/dist/pypy/interpreter/test/test_executioncontext.py (contents, props changed) Modified: pypy/dist/pypy/interpreter/baseobjspace.py pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/miscutils.py pypy/dist/pypy/module/thread/__init__.py pypy/dist/pypy/module/thread/gil.py pypy/dist/pypy/module/thread/threadlocals.py Log: Add generic support for global or per-thread "actions" in the interpreter, executed every sys.setcheckinterval() bytecode instructions. Adapted the GIL-releasing code to use such an "action". Should be usable for things like soft preemptive threading (for the logic object space), and maybe for signal handlers (e.g. Ctrl-C => KeyboardInterrupt). Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Thu Nov 2 17:49:02 2006 @@ -148,6 +148,7 @@ config = Config(pypy_optiondescription) self.config = config self.interned_strings = {} + self.pending_actions = [] self.setoptions(**kw) if self.config.objspace.logbytecodes: Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Nov 2 17:49:02 2006 @@ -1,5 +1,5 @@ import sys -from pypy.interpreter.miscutils import Stack +from pypy.interpreter.miscutils import Stack, Action from pypy.interpreter.error import OperationError def new_framestack(): @@ -16,6 +16,7 @@ self.w_profilefunc = None self.is_tracing = 0 self.ticker = 0 + self.pending_actions = [] self.compiler = space.createcompiler() def enter(self, frame): @@ -106,7 +107,8 @@ # as selected by sys.setcheckinterval() ticker = self.ticker if ticker <= 0: - self.space.threadlocals.yield_thread() + Action.perform_actions(self.pending_actions) + Action.perform_actions(self.space.pending_actions) ticker = self.space.sys.checkinterval self.ticker = ticker - 1 if frame.w_f_trace is None or self.is_tracing: @@ -254,3 +256,6 @@ frame.last_exception = last_exception self.is_tracing -= 1 + def add_pending_action(self, action): + self.pending_actions.append(action) + self.ticker = 0 Modified: pypy/dist/pypy/interpreter/miscutils.py ============================================================================== --- pypy/dist/pypy/interpreter/miscutils.py (original) +++ pypy/dist/pypy/interpreter/miscutils.py Thu Nov 2 17:49:02 2006 @@ -165,9 +165,28 @@ def setvalue(self, value): self._value = value - def yield_thread(self): - """Called from time to time between the interpretation of bytecodes. - Hook for threading models that require it.""" - def getGIL(self): return None # XXX temporary hack! + + +class Action(object): + """Abstract base class for actions that must be performed regularly, + every Nth bytecode (as selected by sys.setcheckinterval()).""" + + # set repeat to True for actions that must be kept around and + # re-performed regularly + repeat = False + + def perform(self): + """To be overridden.""" + + def perform_actions(actionlist): + i = 0 + while i < len(actionlist): + a = actionlist[i] + if a.repeat: + i += 1 # keep action + else: + del actionlist[i] + a.perform() + perform_actions = staticmethod(perform_actions) Added: pypy/dist/pypy/interpreter/test/test_executioncontext.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/interpreter/test/test_executioncontext.py Thu Nov 2 17:49:02 2006 @@ -0,0 +1,36 @@ +import py +from pypy.interpreter import miscutils + + +class TestExecutionContext: + + def test_action(self): + class Finished(Exception): + pass + + class DemoAction(miscutils.Action): + def __init__(self, repeat): + self.repeat = repeat + self.counter = 0 + def perform(self): + self.counter += 1 + if self.counter == 10: + raise Finished + + a1 = DemoAction(False) + a2 = DemoAction(True) + a3 = DemoAction(False) + + space = self.space + space.pending_actions.append(a1) + space.getexecutioncontext().add_pending_action(a2) + space.getexecutioncontext().add_pending_action(a3) + + py.test.raises(Finished, space.appexec, [], """(): + n = 50000 + while n > 0: + n -= 1 + """) + assert a1.counter == 1 + assert a2.counter == 10 + assert a3.counter == 1 Modified: pypy/dist/pypy/module/thread/__init__.py ============================================================================== --- pypy/dist/pypy/module/thread/__init__.py (original) +++ pypy/dist/pypy/module/thread/__init__.py Thu Nov 2 17:49:02 2006 @@ -27,6 +27,8 @@ space.threadlocals = gil.GILThreadLocals() space.threadlocals.setvalue(prev) space.threadlocals.enter_thread(space) # setup the main thread + # add the GIL-releasing callback as an action on the space + space.pending_actions.append(gil.GILReleaseAction(space.threadlocals)) def setup_after_space_initialization(self): # the import lock is in imp.py. Import it after the space is fully Modified: pypy/dist/pypy/module/thread/gil.py ============================================================================== --- pypy/dist/pypy/module/thread/gil.py (original) +++ pypy/dist/pypy/module/thread/gil.py Thu Nov 2 17:49:02 2006 @@ -8,6 +8,7 @@ # from time to time, using the executioncontext's XXX import thread +from pypy.interpreter.miscutils import Action from pypy.module.thread.threadlocals import OSThreadLocals @@ -39,3 +40,16 @@ def getGIL(self): return self.GIL # XXX temporary hack! + + +class GILReleaseAction(Action): + """An action called when the current thread is between two bytecodes + (so that it's a good time to yield some time to other threads). + """ + repeat = True + + def __init__(self, threadlocals): + self.threadlocals = threadlocals + + def perform(self): + self.threadlocals.yield_thread() Modified: pypy/dist/pypy/module/thread/threadlocals.py ============================================================================== --- pypy/dist/pypy/module/thread/threadlocals.py (original) +++ pypy/dist/pypy/module/thread/threadlocals.py Thu Nov 2 17:49:02 2006 @@ -40,10 +40,6 @@ except KeyError: pass - def yield_thread(self): - """Notification that the current thread is between two bytecodes - (so that it's a good time to yield some time to other threads).""" - def atthreadexit(self, space, exit_func, w_obj): ec = space.getexecutioncontext() ec.thread_exit_funcs.append((exit_func, w_obj)) From arigo at codespeak.net Thu Nov 2 19:06:49 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 2 Nov 2006 19:06:49 +0100 (CET) Subject: [pypy-svn] r34072 - in pypy/dist/pypy: interpreter module/signal module/signal/test module/thread translator/goal Message-ID: <20061102180649.D063B10072@code0.codespeak.net> Author: arigo Date: Thu Nov 2 19:06:46 2006 New Revision: 34072 Added: pypy/dist/pypy/module/signal/ (props changed) pypy/dist/pypy/module/signal/__init__.py (contents, props changed) pypy/dist/pypy/module/signal/ctypes_signal.py (contents, props changed) pypy/dist/pypy/module/signal/interp_signal.py (contents, props changed) pypy/dist/pypy/module/signal/test/ (props changed) pypy/dist/pypy/module/signal/test/test_signal.py (contents, props changed) Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/miscutils.py pypy/dist/pypy/module/thread/threadlocals.py pypy/dist/pypy/translator/goal/app_main.py Log: Rough sketch of the 'signal' module. Work in progress. When pypy-c finds it, i.e. when translated --withmod-signal, it should install a handler for Ctrl-C. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Nov 2 19:06:46 2006 @@ -107,8 +107,8 @@ # as selected by sys.setcheckinterval() ticker = self.ticker if ticker <= 0: - Action.perform_actions(self.pending_actions) Action.perform_actions(self.space.pending_actions) + Action.perform_actions(self.pending_actions) ticker = self.space.sys.checkinterval self.ticker = ticker - 1 if frame.w_f_trace is None or self.is_tracing: Modified: pypy/dist/pypy/interpreter/miscutils.py ============================================================================== --- pypy/dist/pypy/interpreter/miscutils.py (original) +++ pypy/dist/pypy/interpreter/miscutils.py Thu Nov 2 19:06:46 2006 @@ -165,6 +165,9 @@ def setvalue(self, value): self._value = value + def getmainthreadvalue(self): + return self._value + def getGIL(self): return None # XXX temporary hack! Added: pypy/dist/pypy/module/signal/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/signal/__init__.py Thu Nov 2 19:06:46 2006 @@ -0,0 +1,26 @@ + +from pypy.interpreter.mixedmodule import MixedModule + +class Module(MixedModule): + interpleveldefs = { + 'signal': 'interp_signal.signal', + } + + appleveldefs = { + } + + def buildloaders(cls): + from pypy.module.signal import ctypes_signal + for name in ctypes_signal.signal_names: + signum = getattr(ctypes_signal, name) + if signum is not None: + Module.interpleveldefs[name] = 'space.wrap(%d)' % (signum,) + super(Module, cls).buildloaders() + buildloaders = classmethod(buildloaders) + + def __init__(self, space, *args): + "NOT_RPYTHON" + from pypy.module.signal.interp_signal import CheckSignalAction + MixedModule.__init__(self, space, *args) + # add the signal-checking callback as an action on the space + space.pending_actions.append(CheckSignalAction(space)) Added: pypy/dist/pypy/module/signal/ctypes_signal.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/signal/ctypes_signal.py Thu Nov 2 19:06:46 2006 @@ -0,0 +1,33 @@ +from pypy.rpython.rctypes.tool import ctypes_platform +from pypy.rpython.rctypes.tool.libc import libc +from ctypes import * + + +signal_names = ['SIGINT', 'SIGTERM', 'SIGKILL', + # ... + ] + + +sighandler_t = CFUNCTYPE(None, c_int) + +signal = libc.signal +signal.restype = sighandler_t +signal.argtypes = [c_int, sighandler_t] + + +class CConfig: + _includes_ = ('signal.h',) + +## struct_sigaction = ctypes_platform.Struct('struct sigaction', +## [('sa_handler', sighandler_t)]) + +for name in signal_names: + setattr(CConfig, name, ctypes_platform.DefinedConstantInteger(name)) + +globals().update(ctypes_platform.configure(CConfig)) + + +##sigaction = libc.sigaction +##sigaction.restype = c_int +##sigaction.argtypes = [c_int, POINTER(struct_sigaction), +## POINTER(struct_sigaction)] Added: pypy/dist/pypy/module/signal/interp_signal.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/signal/interp_signal.py Thu Nov 2 19:06:46 2006 @@ -0,0 +1,105 @@ +from pypy.interpreter.baseobjspace import W_Root, ObjSpace +from pypy.interpreter.miscutils import Action +from pypy.module.signal import ctypes_signal + + +class CheckSignalAction(Action): + """A repeatitive action at the space level, checking if the + signal_occurred flag is set and if so, scheduling ReportSignal actions. + """ + repeat = True + + def __init__(self, space): + self.space = space + + def perform(self): + if flag_queue.signal_occurred: + flag_queue.signal_occurred = 0 + node = flag_queue.head + signum = 0 + while node is not None: + if node.flag: + node.flag = 0 + main_ec = self.space.threadlocals.getmainthreadvalue() + main_ec.add_pending_action(ReportSignal(self.space, + node, signum)) + node = node.next + signum += 1 + + +class ReportSignal(Action): + """A one-shot action for the main thread's execution context.""" + + def __init__(self, space, node, signum): + self.space = space + self.node = node + self.signum = signum + + def perform(self): + w_handler = self.node.w_handler + if w_handler is not None: + space = self.space + ec = space.getexecutioncontext() + try: + w_frame = ec.framestack.top() + except IndexError: + w_frame = space.w_None + space.call_function(w_handler, space.wrap(self.signum), w_frame) + + +# ____________________________________________________________ +# Global flags set by the signal handler + +# XXX some of these data structures may need to +# use the "volatile" keyword in the generated C code + +class FlagQueueNode(object): + def __init__(self): + self.flag = 0 + self.next = None + self.w_handler = None + +class FlagQueue(object): + signal_occurred = 0 + head = FlagQueueNode() + +flag_queue = FlagQueue() + +def get_flag_queue_signum(signum): + node = flag_queue.head + while signum > 0: + if node.next is None: + node.next = FlagQueueNode() + node = node.next + signum -= 1 + return node + +def generic_signal_handler(signum): + node = flag_queue.head + index = 0 + while index < signum: + node = node.next + index += 1 + node.flag = 1 + flag_queue.signal_occurred = 1 + # XXX may need to set the handler again, in case the OS clears it + +def os_setsig(signum, handler): + return ctypes_signal.signal(signum, handler) + +# ____________________________________________________________ + +def signal(space, signum, w_handler): + ec = space.getexecutioncontext() + main_ec = space.threadlocals.getmainthreadvalue() + if ec is not main_ec: + raise OperationError(space.w_ValueError, + space.wrap("signal() must be called from the " + "main thread")) + node = get_flag_queue_signum(signum) + node.w_handler = w_handler + # XXX special values SIG_IGN, SIG_DFL + handler = ctypes_signal.sighandler_t(generic_signal_handler) + os_setsig(signum, handler) + # XXX return value +signal.unwrap_spec = [ObjSpace, int, W_Root] Added: pypy/dist/pypy/module/signal/test/test_signal.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/signal/test/test_signal.py Thu Nov 2 19:06:46 2006 @@ -0,0 +1,13 @@ + +##import signal + +##def ya(*args): +## print "ya", args + +##signal.signal(signal.SIGINT, ya) + +##i = 0 +##while 1: +## i += 1 +## if i%1000 == 0: +## print i Modified: pypy/dist/pypy/module/thread/threadlocals.py ============================================================================== --- pypy/dist/pypy/module/thread/threadlocals.py (original) +++ pypy/dist/pypy/module/thread/threadlocals.py Thu Nov 2 19:06:46 2006 @@ -12,6 +12,7 @@ def __init__(self): self._valuedict = {} # {thread_ident: ExecutionContext()} + self._mainthreadident = 0 def getvalue(self): ident = thread.get_ident() @@ -19,7 +20,19 @@ def setvalue(self, value): ident = thread.get_ident() - self._valuedict[ident] = value + if value is not None: + if len(self._valuedict) == 0: + self._mainthreadident = ident + self._valuedict[ident] = value + else: + try: + del self._valuedict[ident] + except KeyError: + pass + + def getmainthreadvalue(self): + ident = self._mainthreadident + return self._valuedict.get(ident, None) def enter_thread(self, space): "Notification that the current thread is just starting." Modified: pypy/dist/pypy/translator/goal/app_main.py ============================================================================== --- pypy/dist/pypy/translator/goal/app_main.py (original) +++ pypy/dist/pypy/translator/goal/app_main.py Thu Nov 2 19:06:46 2006 @@ -198,6 +198,17 @@ mainmodule = type(sys)('__main__') sys.modules['__main__'] = mainmodule + # set up the Ctrl-C => KeyboardInterrupt signal handler, if the + # signal module is available + try: + import signal + except ImportError: + pass + else: + def keyboard_interrupt_handler(*args): + raise KeyboardInterrupt + signal.signal(signal.SIGINT, keyboard_interrupt_handler) + try: if sys.argv: if sys.argv[0] == '-c': From arigo at codespeak.net Thu Nov 2 19:15:05 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 2 Nov 2006 19:15:05 +0100 (CET) Subject: [pypy-svn] r34074 - pypy/dist/pypy/module/signal Message-ID: <20061102181505.BF0D81007A@code0.codespeak.net> Author: arigo Date: Thu Nov 2 19:15:04 2006 New Revision: 34074 Modified: pypy/dist/pypy/module/signal/interp_signal.py Log: Missing import. Modified: pypy/dist/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/interp_signal.py (original) +++ pypy/dist/pypy/module/signal/interp_signal.py Thu Nov 2 19:15:04 2006 @@ -1,3 +1,4 @@ +from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace from pypy.interpreter.miscutils import Action from pypy.module.signal import ctypes_signal From cfbolz at codespeak.net Fri Nov 3 10:44:37 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 10:44:37 +0100 (CET) Subject: [pypy-svn] r34085 - pypy/extradoc/sprintinfo/ddorf2006b Message-ID: <20061103094437.58EF810068@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 10:44:32 2006 New Revision: 34085 Modified: pypy/extradoc/sprintinfo/ddorf2006b/planning.txt Log: (all): planning for today Modified: pypy/extradoc/sprintinfo/ddorf2006b/planning.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2006b/planning.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2006b/planning.txt Fri Nov 3 10:44:32 2006 @@ -13,17 +13,23 @@ Tasks ===== - - javascript interpreter (leonardo, stephan) + - javascript interpreter (leonardo, stephan, maciek around) addition of numbers, strings (with proper, twisted semantics) works integration of the narcissus parser nested scopes, variable declarations, functions without parameters + function arguments working, windows support, in-progress: argument attribute - - jvm backend (niko, ) + - jvm backend sharing code between gencli and genjvm first tests running! number manipulations, field access + more tests running! added support for classes, in-progress: constants - transparent proxies (maciek, guido, samuele around) + lists are working somehow, refactoring in progress + dictionaries seem to work somewhat + provide a way to implement an object that is of type list, but the behaviour + is defined at app-level - apigen tool changes to instance variables after calls to functions @@ -31,18 +37,25 @@ - build tool it's now actually building pypy, sending the usession directory back - - .net integration, fixing pypy.net (anto, carl friedrich) - quick hack, but pypy.net is broken :-( + - .net integration, fixing pypy.net + quick hack, but pypy.net is no longer broken - - jit code generation (eric, michael) + - making streams RPython (anto, carl friedrich) + in progress + + - jit code generation lots of documentation about the jit-backend interface, fighting with ppc code generation some refactorings looking at whether it's possible to use the llvm code generation + hackish way: produce strings in memory and have llvm parse them + + - jit ppc code generation (mwh, niko) - - jit front end (samuele, arre) + - jit front end (armin, arre, richard) IN-PROGRESS fixed the last known bug, experimentation needed + porting portal tests to run with the backends - running tests on the translated pypy-cs (related to py.test refactoring?) @@ -54,6 +67,8 @@ DONE - trying the jit efforts on a regex engine (richard, armin around) - kind of worked + kind of worked, some progress - fixing pypy on windows, adding some more os functions (christian) + +- general wizardry (samuele) From santagada at codespeak.net Fri Nov 3 12:02:01 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Fri, 3 Nov 2006 12:02:01 +0100 (CET) Subject: [pypy-svn] r34090 - pypy/dist/pypy/lang/js Message-ID: <20061103110201.7E5F610060@code0.codespeak.net> Author: santagada Date: Fri Nov 3 12:01:39 2006 New Revision: 34090 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/jsobj.py Log: (stephan, santagada) implemented argument list for functions Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Fri Nov 3 12:01:39 2006 @@ -15,7 +15,7 @@ # return output # getlist = staticmethod(getlist) - + class Array(Node): def __init__(self, items=()): self.items = items Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Fri Nov 3 12:01:39 2006 @@ -1,7 +1,7 @@ from pypy.lang.js.astgen import * from pypy.lang.js.context import ExecutionContext -from pypy.lang.js.jsobj import W_Number, W_String, W_Object, w_Undefined +from pypy.lang.js.jsobj import W_Number, W_String, W_Object, w_Undefined, W_Arguments from pypy.lang.js.scope import scope_manager def writer(x): @@ -15,7 +15,7 @@ def call(self, context): d = dict(enumerate(self.items)) return W_Array(d) - + class __extend__(Assign): def call(self, context): val = self.expr.call(context) @@ -116,7 +116,7 @@ #return self.left.call(context).add(self.right.call(context)) class __extend__(Script): - def call(self, context=None, args=None, this=None, params=None): + def call(self, context=None, args=(), this=None, params=None): if params == None: params = [] ncontext = ExecutionContext(context) @@ -126,7 +126,11 @@ except IndexError: temp = w_Undefined ncontext.assign(item, temp) - + + w_Arguments = W_Arguments(dict([(str(x),y) for x,y in enumerate(args)])) + print w_Arguments.dict_w + ncontext.assign('arguments', w_Arguments) + try: for node in self.nodes: node.call(ncontext) Modified: pypy/dist/pypy/lang/js/jsobj.py ============================================================================== --- pypy/dist/pypy/lang/js/jsobj.py (original) +++ pypy/dist/pypy/lang/js/jsobj.py Fri Nov 3 12:01:39 2006 @@ -24,71 +24,6 @@ def __repr__(self): return "<%s(%s)>" % (self.__class__.__name__, str(self)) -class W_Array(W_Root): - # TODO to be continued :-) - pass - -class W_Undefined(W_Root): - def __str__(self): - return "" - - def ToNumber(self): - # XXX make NaN - return NaN - -class W_Null(W_Root): - def __str__(self): - return "null" - -class W_Boolean(W_Root): - def __init__(self, boolval): - self.boolval = boolval - - def __str__(self): - if self.boolval: - return "true" - return "false" - - def ToNumber(self): - if self.boolval: - return 1 - return 0 - -class W_String(W_Root): - def __init__(self, strval): - # XXX: Should be unicode object - self.strval = strval - -# def ToString(self): -# return self.strval - - def __str__(self): - # INSANE - should be like 'str' or so - return self.strval - -class W_Number(W_Root): - def __init__(self, floatval): - self.floatval = floatval - - def __str__(self): - # XXX: more attention - # cough, cough - if str(self.floatval) == str(NaN): - return 'NaN' - if float(int(self.floatval)) == self.floatval: - return str(int(self.floatval)) - return str(self.floatval) - - def Get(self, name): - return w_Undefined - - def ToNumber(self): - return self.floatval - -class W_Reference(W_Root): - def GetValue(self): - raise NotImplementedError("W_Reference.GetValue") - class W_Object(W_Root): def __init__(self, dict_w, function=None): # string --> W_Root @@ -107,10 +42,10 @@ params= self.function.params) else: raise SeePage(33) - + def w_string(self): return W_String(str(self)) - + def DefaultValue(self, hint): #if hint == "string": tostring_meth = self.Get("toString") @@ -130,20 +65,20 @@ ## if isinstance(tostring_meth, W_Object): ## return tostring_meth.Call(this=self) return w_Undefined - + def ToPrimitive(self, hint=""): return self.DefaultValue(hint) - + def ToNumber(self): return self.ToPrimitive("number").ToNumber(hint="number") - + def ToString(self): return str(self.DefaultValue(hint="string")) - + def Get(self, name): if name in self.dict_w: return self.dict_w[name] - + return w_Undefined #def ToPrimitive(self, hint=""): @@ -151,20 +86,84 @@ #def ToString(self): # raise SeePage(42) - + def CanPut(self, name): return True - + def Put(self, name, w_obj): # INSANE - raise some exceptions in case of read only and such if not self.CanPut(name): return # AAAAAAAAAAAAaaaaaaaaaaaa self.dict_w[name] = w_obj - + def __str__(self): # INSANE return "[object Object]" +class W_Arguments(W_Object): + pass + +class W_Undefined(W_Root): + def __str__(self): + return "" + + def ToNumber(self): + # XXX make NaN + return NaN + +class W_Null(W_Root): + def __str__(self): + return "null" + +class W_Boolean(W_Root): + def __init__(self, boolval): + self.boolval = boolval + + def __str__(self): + if self.boolval: + return "true" + return "false" + + def ToNumber(self): + if self.boolval: + return 1 + return 0 + +class W_String(W_Root): + def __init__(self, strval): + # XXX: Should be unicode object + self.strval = strval + +# def ToString(self): +# return self.strval + + def __str__(self): + # INSANE - should be like 'str' or so + return self.strval + +class W_Number(W_Root): + def __init__(self, floatval): + self.floatval = floatval + + def __str__(self): + # XXX: more attention + # cough, cough + if str(self.floatval) == str(NaN): + return 'NaN' + if float(int(self.floatval)) == self.floatval: + return str(int(self.floatval)) + return str(self.floatval) + + def Get(self, name): + return w_Undefined + + def ToNumber(self): + return self.floatval + +class W_Reference(W_Root): + def GetValue(self): + raise NotImplementedError("W_Reference.GetValue") + class W_Builtin(W_Object): def __init__(self, dict_w, internalfunction): self.dict_w = {} From ericvrp at codespeak.net Fri Nov 3 12:17:54 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Fri, 3 Nov 2006 12:17:54 +0100 (CET) Subject: [pypy-svn] r34092 - pypy/dist/pypy/jit/codegen/llvm/test Message-ID: <20061103111754.2524B1007A@code0.codespeak.net> Author: ericvrp Date: Fri Nov 3 12:17:51 2006 New Revision: 34092 Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: proper skip on darwin for the llvmjit codegen translation test Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Fri Nov 3 12:17:51 2006 @@ -1,4 +1,5 @@ import py +from sys import platform from os.path import dirname, join from pypy.translator.c.test.test_genc import compile @@ -99,6 +100,9 @@ pass def test_execute_translation(): #put this one last because it takes the most time + if platform == 'darwin': + py.test.skip('dynamic vs. static library issue. see: http://www.cocoadev.com/index.pl?ApplicationLinkingIssues for more information (needs to be fixed)') + llvmjit.restart() def f(x): return execute(llsquare, 'square', x + 5) From ericvrp at codespeak.net Fri Nov 3 13:32:53 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Fri, 3 Nov 2006 13:32:53 +0100 (CET) Subject: [pypy-svn] r34094 - in pypy/dist/pypy/jit/codegen/llvm: . test Message-ID: <20061103123253.3195810077@code0.codespeak.net> Author: ericvrp Date: Fri Nov 3 13:32:51 2006 New Revision: 34094 Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: made sure that importint llvmjit causes the c-library to be updated. Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Fri Nov 3 13:32:51 2006 @@ -13,6 +13,23 @@ import os path = os.path.join(os.path.dirname(__file__), 'libllvmjit.so') + +curdir = os.getcwd() +os.chdir(os.path.dirname(__file__)) + +#With py.test --session=R the master server rsyncs the .so library too!?! +#So we always need to recompile the library if its platform (output of file libllvmjit.so) +#differs from the current (remote) platform. +#note: we can't do this in global scope because that will only be executed on the master server. +#os.system('rm -rf libllvmjit.so build') + +#We might want to generate an up-to-date version of the library always so running (tests) +#on a clean checkout will produce correct results. +os.system('python setup.py build_ext -i') + +os.chdir(curdir) + +#load the actual library llvmjit = cdll.LoadLibrary(os.path.abspath(path)) class _FuncPtr(_CFuncPtr): _flags_ = _FUNCFLAG_CDECL Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Fri Nov 3 13:32:51 2006 @@ -3,10 +3,12 @@ from os.path import dirname, join from pypy.translator.c.test.test_genc import compile +from pypy.jit.codegen.llvm import llvmjit + try: from pypy.jit.codegen.llvm import llvmjit except OSError: - py.test.skip("libllvmjit not found (see ../README.TXT)") + py.test.skip("can not load libllvmjit library (see ../README.TXT)") #helper data curdir = dirname(__file__) From ericvrp at codespeak.net Fri Nov 3 13:36:34 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Fri, 3 Nov 2006 13:36:34 +0100 (CET) Subject: [pypy-svn] r34095 - pypy/dist/pypy/jit/codegen/llvm Message-ID: <20061103123634.5A72F1007A@code0.codespeak.net> Author: ericvrp Date: Fri Nov 3 13:36:33 2006 New Revision: 34095 Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Log: This change (or probably the os.system after it) makes py.test --session=R hang. I am testing with disthosts = ['ericvrp at snake'] Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Fri Nov 3 13:36:33 2006 @@ -21,7 +21,7 @@ #So we always need to recompile the library if its platform (output of file libllvmjit.so) #differs from the current (remote) platform. #note: we can't do this in global scope because that will only be executed on the master server. -#os.system('rm -rf libllvmjit.so build') +os.system('rm -rf libllvmjit.so build') #We might want to generate an up-to-date version of the library always so running (tests) #on a clean checkout will produce correct results. From fijal at codespeak.net Fri Nov 3 13:44:10 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 13:44:10 +0100 (CET) Subject: [pypy-svn] r34096 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061103124410.B52841007B@code0.codespeak.net> Author: fijal Date: Fri Nov 3 13:44:07 2006 New Revision: 34096 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py pypy/branch/transparent-proxy/pypy/objspace/std/model.py pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py pypy/branch/transparent-proxy/pypy/objspace/std/stdtypedef.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Log: (pedronis, fijal) - Fix the list implementation by having AnyList (and AnyXxx as well) for implementing different multimethods. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/listobject.py Fri Nov 3 13:44:07 2006 @@ -78,12 +78,15 @@ def add__List_List(space, w_list1, w_list2): return W_ListObject(w_list1.wrappeditems + w_list2.wrappeditems) -def add__List_ANY(space, w_list, w_any): - if space.is_true(space.isinstance(w_any, space.w_list)): - items1_w = w_list.wrappeditems - items2_w = space.unpackiterable(w_any) - return W_ListObject(items1_w + items2_w) - raise FailedToImplement +#def radd__List_List(space, w_list1, w_list2): +# return W_ListObject(w_list2.wrappeditems + w_list1.wrappeditems) + +##def add__List_ANY(space, w_list, w_any): +## if space.is_true(space.isinstance(w_any, space.w_list)): +## items1_w = w_list.wrappeditems +## items2_w = space.unpackiterable(w_any) +## return W_ListObject(items1_w + items2_w) +## raise FailedToImplement def inplace_add__List_ANY(space, w_list1, w_iterable2): list_extend__List_ANY(space, w_list1, w_iterable2) @@ -131,12 +134,12 @@ return space.w_True #return space.newbool(len(w_list1.wrappeditems) == len(w_list2.wrappeditems)) -def eq__List_ANY(space, w_list1, w_any): - if space.is_true(space.isinstance(w_any, space.w_list)): - items1_w = w_list1.wrappeditems - items2_w = space.unpackiterable(w_any) - return equal_wrappeditems(space, items1_w, items2_w) - raise FailedToImplement +##def eq__List_ANY(space, w_list1, w_any): +## if space.is_true(space.isinstance(w_any, space.w_list)): +## items1_w = w_list1.wrappeditems +## items2_w = space.unpackiterable(w_any) +## return equal_wrappeditems(space, items1_w, items2_w) +## raise FailedToImplement def _min(a, b): if a < b: @@ -173,25 +176,25 @@ return lessthan_unwrappeditems(space, w_list1.wrappeditems, w_list2.wrappeditems) -def lt__List_ANY(space, w_list1, w_any): - # XXX: Implement it not unpacking all the elements - if space.is_true(space.isinstance(w_any, space.w_list)): - items1_w = w_list1.wrappeditems - items2_w = space.unpackiterable(w_any) - return lessthan_unwrappeditems(space, items1_w, items2_w) - raise FailedToImplement +##def lt__List_ANY(space, w_list1, w_any): +## # XXX: Implement it not unpacking all the elements +## if space.is_true(space.isinstance(w_any, space.w_list)): +## items1_w = w_list1.wrappeditems +## items2_w = space.unpackiterable(w_any) +## return lessthan_unwrappeditems(space, items1_w, items2_w) +## raise FailedToImplement def gt__List_List(space, w_list1, w_list2): return greaterthan_unwrappeditems(space, w_list1.wrappeditems, w_list2.wrappeditems) -def gt__List_ANY(space, w_list1, w_any): - # XXX: Implement it not unpacking all the elements - if space.is_true(space.isinstance(w_any, space.w_list)): - items1_w = w_list1.wrappeditems - items2_w = space.unpackiterable(w_any) - return greaterthan_unwrappeditems(space, items1_w, items2_w) - raise FailedToImplement +##def gt__List_ANY(space, w_list1, w_any): +## # XXX: Implement it not unpacking all the elements +## if space.is_true(space.isinstance(w_any, space.w_list)): +## items1_w = w_list1.wrappeditems +## items2_w = space.unpackiterable(w_any) +## return greaterthan_unwrappeditems(space, items1_w, items2_w) +## raise FailedToImplement def delitem__List_ANY(space, w_list, w_idx): idx = space.int_w(w_idx) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/model.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/model.py Fri Nov 3 13:44:07 2006 @@ -201,6 +201,9 @@ # put W_Root everywhere self.typeorder[W_Root] = [] for type in self.typeorder: + from pypy.objspace.std import stdtypedef + if type is not W_Root and isinstance(type.typedef, stdtypedef.StdTypeDef): + self.typeorder[type].append((type.typedef.any, None)) self.typeorder[type].append((W_Root, None)) # ____________________________________________________________ Modified: pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py Fri Nov 3 13:44:07 2006 @@ -554,7 +554,7 @@ w_start = space.add(w_start, space.len(w_obj)) # NB. the language ref is inconsistent with the new-style class # behavior when w_obj doesn't implement __len__(), so we just - # ignore this case. + # ignore this case.eq if space.is_w(w_stop, space.w_None): w_stop = space.wrap(slice_max) elif space.is_true(space.lt(w_stop, space.wrap(0))): Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py Fri Nov 3 13:44:07 2006 @@ -3,7 +3,8 @@ of cyclic imports """ -from pypy.objspace.std.model import W_ANY +from pypy.objspace.std.model import W_ANY, W_Object +from pypy.interpreter import baseobjspace def create_mm_names(classname, mm, is_local): s = "" @@ -18,15 +19,47 @@ def install_mm_trampoline(type_, mm, is_local): classname = type_.__name__[2:] mm_name, op_name = create_mm_names(classname, mm, is_local) + # we search here for special-cased stuff def function(space, w_transparent_list, *args_w): return space.call_function(w_transparent_list.controller, space.wrap\ (op_name), *args_w) function.func_name = mm_name mm.register(function, type_, *([W_ANY] * (mm.arity - 1))) +def is_special_doublearg(mm, type_): + """ We specialcase when we've got two argument method for which + there exist reverse operation + """ + if mm.arity != 2: + return False + + if len(mm.specialnames) != 2: + return False + + # search over the signatures + for signature in mm.signatures(): + if signature == (type_.original, type_.original): + return True + return False + +def install_mm_special(type_, mm, is_local): + classname = type_.__name__[2:] + #mm_name, op_name = create_mm_names(classname, mm, is_local) + + def function(space, w_any, w_transparent_list): + retval = space.call_function(w_transparent_list.controller, space.wrap(mm.specialnames[1]), + w_any) + return retval + + function.func_name = mm.specialnames[0] + + mm.register(function, type_.typedef.any, type_) + def register_type(type_): from pypy.objspace.std.stdtypedef import multimethods_defined_on for mm, is_local in multimethods_defined_on(type_.original): if not mm.name.startswith('__'): install_mm_trampoline(type_, mm, is_local) + if is_special_doublearg(mm, type_): + install_mm_special(type_, mm, is_local) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/stdtypedef.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/stdtypedef.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/stdtypedef.py Fri Nov 3 13:44:07 2006 @@ -20,6 +20,7 @@ def __init__(self, __name, __base=None, **rawdict): "NOT_RPYTHON: initialization-time only." TypeDef.__init__(self, __name, __base, **rawdict) + self.any = type("W_Any"+__name.title(), (baseobjspace.W_Root,), {'typedef': self}) self.local_multimethods = [] def registermethods(self, namespace): Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Fri Nov 3 13:44:07 2006 @@ -35,15 +35,14 @@ assert repr(lst) == repr([1,2]) def test_gt_lt_list(self): - skip("FAILS RANDOMLY (~73% works)") c = self.Controller([]) lst = proxy(list, c.perform) lst.append(1) lst.append(2) - #assert lst < [1,2,3] - #assert [1,2,3] > lst - #assert lst == [1,2] - #assert [1,2] == lst + assert lst < [1,2,3] + assert [1,2,3] > lst + assert lst == [1,2] + assert [1,2] == lst assert [2,3] >= list(iter(lst)) assert lst < [2,3] assert [2,3] >= lst @@ -54,6 +53,8 @@ lst = proxy(list, c.perform) lst.append(1) assert lst + lst == [1,1] + assert lst + [1] == [1,1] + assert [1] + lst == [1,1] def test_list_getitem(self): c = self.Controller([1,2,3]) From fijal at codespeak.net Fri Nov 3 14:12:52 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 14:12:52 +0100 (CET) Subject: [pypy-svn] r34098 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061103131252.4A81410075@code0.codespeak.net> Author: fijal Date: Fri Nov 3 14:12:51 2006 New Revision: 34098 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Log: (samuele, fijal) - It seems that TransparentList and TransparentDict are working quite well. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py Fri Nov 3 14:12:51 2006 @@ -5,6 +5,7 @@ from pypy.objspace.std.model import W_ANY, W_Object from pypy.interpreter import baseobjspace +from pypy.interpreter.argument import Arguments def create_mm_names(classname, mm, is_local): s = "" @@ -16,9 +17,31 @@ return s, '__' + mm.name + '__' return s, mm.name +def install_general_args_trampoline(type_, mm, is_local): + def function(space, w_transparent_list, __args__): + args = __args__.prepend(space.wrap(mm.name)) + return space.call_args(w_transparent_list.controller, args) + + function.func_name = mm.name + mm.register(function, type_) + +def install_w_args_trampoline(type_, mm, is_local): + def function(space, w_transparent_list, *args_w): + args = Arguments(space, [space.wrap(mm.name)] + list(args_w[:-1]), w_stararg=args_w[-1]) + return space.call_args(w_transparent_list.controller, args) + + function.func_name = mm.name + mm.register(function, type_, *([W_ANY] * (mm.arity - 1))) + def install_mm_trampoline(type_, mm, is_local): classname = type_.__name__[2:] mm_name, op_name = create_mm_names(classname, mm, is_local) + + if ['__args__'] == mm.argnames_after: + return install_general_args_trampoline(type_, mm, is_local) + if ['w_args'] == mm.argnames_after: + return install_w_args_trampoline(type_, mm, is_local) + assert not mm.argnames_after # we search here for special-cased stuff def function(space, w_transparent_list, *args_w): return space.call_function(w_transparent_list.controller, space.wrap\ Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Fri Nov 3 14:12:51 2006 @@ -9,8 +9,8 @@ def __init__(self, obj): self.obj = obj - def perform(self, name, *args): - return getattr(self.obj, name)(*args) + def perform(self, name, *args, **kwargs): + return getattr(self.obj, name)(*args, **kwargs) return Controller """) @@ -63,12 +63,34 @@ lst[1] = 0 assert lst[0] + lst[1] == 1 + def test_list_setitem(self): + c = self.Controller([1,2,3]) + lst = proxy(list, c.perform) + try: + lst[3] = "x" + except IndexError: + pass + else: + fail("Accessing outside a list didn't raise") + def test_dict(self): c = self.Controller({"xx":1}) d = proxy(dict, c.perform) assert d['xx'] == 1 assert 'yy' not in d - #d2 = {'yy':3} - #d.update(d2) - #assert sorted(d.keys()) == ['xx', 'yy'] - #assert sorted(d.values()) == [1, 3] + d2 = {'yy':3} + d.update(d2, x=4) + assert sorted(d.keys()) == ['x', 'xx', 'yy'] + assert sorted(d.values()) == [1, 3, 4] + + def test_dict_pop(self): + c = self.Controller({'x':1}) + d = proxy(dict, c.perform) + assert d.pop('x') == 1 + assert d.pop('x', None) is None + + def test_dict_iter(self): + c = self.Controller({'a':1, 'b':2, 'c':3}) + d = proxy(dict, c.perform) + d['z'] = 4 + assert sorted(list(d.iterkeys())) == ['a', 'b', 'c', 'z'] From niko at codespeak.net Fri Nov 3 14:13:43 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 3 Nov 2006 14:13:43 +0100 (CET) Subject: [pypy-svn] r34099 - pypy/dist/pypy/translator/asm/ppcgen Message-ID: <20061103131343.75F0B10075@code0.codespeak.net> Author: niko Date: Fri Nov 3 14:13:42 2006 New Revision: 34099 Modified: pypy/dist/pypy/translator/asm/ppcgen/ppc_assembler.py Log: (mwh, niko) Fix computation of 32bit constants on PPC... precedence error. Modified: pypy/dist/pypy/translator/asm/ppcgen/ppc_assembler.py ============================================================================== --- pypy/dist/pypy/translator/asm/ppcgen/ppc_assembler.py (original) +++ pypy/dist/pypy/translator/asm/ppcgen/ppc_assembler.py Fri Nov 3 14:13:42 2006 @@ -778,20 +778,26 @@ def ha(w): if (w >> 15) & 1: - return w >> 16 + 1 + return (w >> 16) + 1 else: return w >> 16 def lo(w): return w & 0x0000FFFF +def la(w): + v = w & 0x0000FFFF + if v & 0x8000: + return -((v ^ 0xFFFF) + 1) # "sign extend" to 32 bits + return v + class MyPPCAssembler(PPCAssembler): def load_word(self, rD, word): self.addis(rD, 0, hi(word)) self.ori(rD, rD, lo(word)) def load_from(self, rD, addr): self.addis(rD, 0, ha(addr)) - self.lwz(rD, rD, lo(addr)) + self.lwz(rD, rD, la(addr)) def b(n): r = [] From niko at codespeak.net Fri Nov 3 14:14:48 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 3 Nov 2006 14:14:48 +0100 (CET) Subject: [pypy-svn] r34100 - in pypy/dist/pypy: jit/codegen/ppc translator/asm/ppcgen translator/asm/ppcgen/test Message-ID: <20061103131448.121FA10077@code0.codespeak.net> Author: niko Date: Fri Nov 3 14:14:47 2006 New Revision: 34100 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/translator/asm/ppcgen/rassemblermaker.py pypy/dist/pypy/translator/asm/ppcgen/test/test_rassemblermaker.py Log: (mwh,niko) insert a simple prologue, uncovering an annoying annotation problem in the meantime Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Fri Nov 3 14:14:47 2006 @@ -249,6 +249,11 @@ RPPCAssembler = make_rassembler(MyPPCAssembler) +r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, \ + r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, \ + r23, r24, r25, r26, r27, r28, r29, r30, r31 = range(32) +rSP = r1 + def emit(self, value): self.mc.write(value) RPPCAssembler.emit = emit @@ -361,6 +366,12 @@ self.initial_varmapping = {} for arg in self.inputargs: self.initial_varmapping[arg] = gprs[3+len(self.initial_varmapping)] + + # Emit standard prologue + self.asm.mflr(r0) + self.asm.stw(r0,rSP,8) + self.asm.stwu(rSP,rSP,-64) + return self.inputargs def _close(self): @@ -388,7 +399,13 @@ allocator = self.emit() reg = allocator.var2reg[gv_returnvar] if reg.number != 3: - self.asm.mr(3, reg.number) + self.asm.mr(r3, reg.number) + + # Emit standard epilogue: + # TODO rewrite to handle varying size stack? + self.asm.lwz(r0,rSP,64+8) + self.asm.mtlr(r0) + self.asm.addi(rSP,rSP,64) self.asm.blr() self._close() Modified: pypy/dist/pypy/translator/asm/ppcgen/rassemblermaker.py ============================================================================== --- pypy/dist/pypy/translator/asm/ppcgen/rassemblermaker.py (original) +++ pypy/dist/pypy/translator/asm/ppcgen/rassemblermaker.py Fri Nov 3 14:14:47 2006 @@ -1,5 +1,5 @@ from pypy.tool.sourcetools import compile2 - +from pypy.rlib.rarithmetic import r_uint from pypy.translator.asm.ppcgen.form import IDesc, IDupDesc ## "opcode": ( 0, 5), @@ -32,19 +32,19 @@ if isinstance(desc, IDupDesc): for destfield, srcfield in desc.dupfields.iteritems(): fieldvalues.append((destfield, srcfield.name)) - body = ['v = 0'] + body = ['v = r_uint(0)'] assert 'v' not in sig # that wouldn't be funny #body.append('print %r'%name + ', ' + ', '.join(["'%s:', %s"%(s, s) for s in sig])) for field, value in fieldvalues: if field.name == 'spr': body.append('spr = (%s&31) << 5 | (%s >> 5 & 31)'%(value, value)) value = 'spr' - body.append('v |= (%3s & %#05x) << %d'%(value, + body.append('v |= (%3s & r_uint(%#05x)) << %d'%(value, field.mask, (32 - field.right - 1))) body.append('self.emit(v)') src = 'def %s(self, %s):\n %s'%(name, ', '.join(sig), '\n '.join(body)) - d = {} + d = {'r_uint':r_uint} #print src exec compile2(src) in d return d[name] Modified: pypy/dist/pypy/translator/asm/ppcgen/test/test_rassemblermaker.py ============================================================================== --- pypy/dist/pypy/translator/asm/ppcgen/test/test_rassemblermaker.py (original) +++ pypy/dist/pypy/translator/asm/ppcgen/test/test_rassemblermaker.py Fri Nov 3 14:14:47 2006 @@ -17,6 +17,7 @@ def f(): ra = RPPCAssembler() ra.add(3, 3, 4) + ra.lwz(1, 1, 1) # ensure that high bit doesn't produce long but r_uint return ra.insts[0] res = interpret(f, []) assert res == add_r3_r3_r4 @@ -36,4 +37,3 @@ a.mtctr(3) mrs.append(a.insts[0]) assert mrs[0].assemble() == mrs[1] - From rxe at codespeak.net Fri Nov 3 14:39:22 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 14:39:22 +0100 (CET) Subject: [pypy-svn] r34101 - in pypy/dist/pypy/jit/hintannotator: . test Message-ID: <20061103133922.3DBC01007A@code0.codespeak.net> Author: rxe Date: Fri Nov 3 14:39:20 2006 New Revision: 34101 Modified: pypy/dist/pypy/jit/hintannotator/annotator.py pypy/dist/pypy/jit/hintannotator/model.py pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Log: add deepfreeze hint and a few ops. (arigo, arre, rxe) Modified: pypy/dist/pypy/jit/hintannotator/annotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/annotator.py (original) +++ pypy/dist/pypy/jit/hintannotator/annotator.py Fri Nov 3 14:39:20 2006 @@ -14,7 +14,7 @@ self.base_translator = base_translator assert base_translator is not None # None not supported any more self.exceptiontransformer = base_translator.getexceptiontransformer() - + def build_types(self, origgraph, input_args_hs): desc = self.bookkeeper.getdesc(origgraph) flowgraph = desc.specialize(input_args_hs) @@ -28,6 +28,8 @@ vstructdef = self.bookkeeper.getvirtualcontainerdef(TYPE) return hintmodel.SomeLLAbstractContainer(vstructdef) + consider_op_zero_malloc = consider_op_malloc + def consider_op_malloc_varsize(self, hs_TYPE, hs_length): TYPE = hs_TYPE.const if getattr(self.policy, 'novirtualcontainer', False): @@ -36,6 +38,8 @@ vcontainerdef = self.bookkeeper.getvirtualcontainerdef(TYPE) return hintmodel.SomeLLAbstractContainer(vcontainerdef) + consider_op_zero_malloc_varsize = consider_op_malloc_varsize + def consider_op_zero_gc_pointers_inside(self, hs_v): pass Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Fri Nov 3 14:39:20 2006 @@ -18,11 +18,12 @@ ptr_iszero""".split() BINARY_OPERATIONS = """int_add int_sub int_mul int_mod int_and int_rshift int_floordiv - uint_add uint_sub uint_mul uint_mod uint_and uint_rshift uint_floordiv + uint_add uint_sub uint_mul uint_mod uint_and uint_lshift uint_rshift uint_floordiv char_gt char_lt char_le char_ge char_eq char_ne int_gt int_lt int_le int_ge int_eq int_ne - uint_gt uint_lt uint_le uint_ge uint_eq uint_ne + uint_gt uint_lt uint_le uint_ge uint_eq uint_ne getarrayitem + getarraysubstruct ptr_eq ptr_ne""".split() class HintError(Exception): @@ -132,7 +133,9 @@ class SomeLLAbstractConstant(SomeLLAbstractValue): - + " color: dont know yet.. " + deepfrozen = False + def __init__(self, T, origins, eager_concrete=False, myorigin=None): SomeLLAbstractValue.__init__(self, T) self.origins = origins @@ -188,6 +191,7 @@ class SomeLLAbstractVariable(SomeLLAbstractValue): + " color: hopelessly red" pass @@ -262,7 +266,7 @@ hs_concrete = SomeLLAbstractConstant(hs_v1.concretetype, {}) hs_concrete.eager_concrete = True return hs_concrete - + def getfield(hs_v1, hs_fieldname): S = hs_v1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) @@ -324,6 +328,11 @@ if hs_flags.const.get('forget', False): assert isinstance(hs_c1, SomeLLAbstractConstant) return reorigin(hs_c1) + if hs_flags.const.get('deepfreeze', False): + hs_concrete = SomeLLAbstractConstant(hs_c1.concretetype, + hs_c1.origins) + hs_concrete.deepfrozen = True + return hs_concrete return SomeLLAbstractValue.hint(hs_c1, hs_flags) def direct_call(hs_f1, *args_hs): @@ -359,12 +368,14 @@ def getfield(hs_c1, hs_fieldname): S = hs_c1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) - if S._hints.get('immutable', False): + if S._hints.get('immutable', False) or hs_c1.deepfrozen: origin = getbookkeeper().myorigin() d = setadd(hs_c1.origins, origin) - return SomeLLAbstractConstant(FIELD_TYPE, d, - eager_concrete=hs_c1.eager_concrete, - myorigin=origin) + res = SomeLLAbstractConstant(FIELD_TYPE, d, + eager_concrete=hs_c1.eager_concrete, + myorigin=origin) + res.deepfrozen = hs_c1.deepfrozen + return res else: return SomeLLAbstractVariable(FIELD_TYPE) @@ -373,8 +384,10 @@ SUB_TYPE = getattr(S, hs_fieldname.const) origin = getbookkeeper().myorigin() d = setadd(hs_c1.origins, origin) - return SomeLLAbstractConstant(lltype.Ptr(SUB_TYPE), d, myorigin=origin) - + res = SomeLLAbstractConstant(lltype.Ptr(SUB_TYPE), d, myorigin=origin) + res.deepfrozen = hs_c1.deepfrozen + return res + class __extend__(SomeLLAbstractContainer): @@ -441,15 +454,18 @@ hs_c2.eager_concrete, myorigin = myorigin) + def getarrayitem((hs_c1, hs_index)): A = hs_c1.concretetype.TO READ_TYPE = A.OF - if A._hints.get('immutable', False): + if A._hints.get('immutable', False) or hs_c1.deepfrozen: origin = getbookkeeper().myorigin() d = newset(hs_c1.origins, hs_index.origins, {origin: True}) - return SomeLLAbstractConstant(READ_TYPE, d, - eager_concrete=hs_c1.eager_concrete, - myorigin=origin) + res = SomeLLAbstractConstant(READ_TYPE, d, + eager_concrete=hs_c1.eager_concrete, + myorigin=origin) + res.deepfrozen = hs_c1.deepfrozen + return res else: return SomeLLAbstractVariable(READ_TYPE) Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Fri Nov 3 14:39:20 2006 @@ -32,6 +32,7 @@ from pypy.translator.backendopt.all import backend_optimizations backend_optimizations(t) graph1 = graphof(t, func) + # build hint annotator types hannotator = HintAnnotator(base_translator=t, policy=policy) hs = hannotator.build_types(graph1, [SomeLLAbstractConstant(v.concretetype, @@ -79,6 +80,22 @@ assert isinstance(hs, SomeLLAbstractConstant) assert hs.eager_concrete assert hs.concretetype == lltype.Signed + +def test_deepfreeze(): + + A = lltype.GcArray(lltype.Signed) + + def ll_function(a, i): + a = hint(a, deepfreeze=True) + res = a[i] + res = hint(res, concrete=True) + + res = hint(res, variable=True) + return res + + hs = hannotate(ll_function, [annmodel.SomePtr(lltype.Ptr(A)), int]) + assert type(hs) is SomeLLAbstractVariable + assert hs.concretetype == lltype.Signed def test_simple_hint_origins(): def ll_function(cond, x,y): From rxe at codespeak.net Fri Nov 3 14:40:03 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 14:40:03 +0100 (CET) Subject: [pypy-svn] r34102 - pypy/dist/pypy/lang/automata Message-ID: <20061103134003.283C71007A@code0.codespeak.net> Author: rxe Date: Fri Nov 3 14:40:02 2006 New Revision: 34102 Modified: pypy/dist/pypy/lang/automata/dfa.py Log: new goal for jit - (arigo, arre, rxe) Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Fri Nov 3 14:40:02 2006 @@ -98,3 +98,23 @@ indx += 1 res = hint(res, variable=True) return res + +def recognizeparts(trans, finals, s): + " a less simple recognizer " + trans = hint(trans, deepfreeze=True) + finals = hint(finals, deepfreeze=True) + + state = 0 + try: + hint(None, global_mp_to_follow=True) + for char in s: + char = hint(char, promote=True) + state = trans[state, char] + hint(state, concrete=True) + + except KeyError: + return False + + res = state in finals + res = hint(res, variable=True) + return res From arigo at codespeak.net Fri Nov 3 14:40:19 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 3 Nov 2006 14:40:19 +0100 (CET) Subject: [pypy-svn] r34103 - pypy/dist/pypy/jit/hintannotator Message-ID: <20061103134019.5A30C1007C@code0.codespeak.net> Author: arigo Date: Fri Nov 3 14:40:18 2006 New Revision: 34103 Modified: pypy/dist/pypy/jit/hintannotator/model.py Log: Removed unused methods. Move setarrayitem to BINARY_OPERATIONS, where getarrayitem already is. Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Fri Nov 3 14:40:18 2006 @@ -3,7 +3,7 @@ from pypy.jit.hintannotator.bookkeeper import getbookkeeper from pypy.rpython.lltypesystem import lltype, lloperation -UNARY_OPERATIONS = """same_as hint getfield setfield getsubstruct getarraysize setarrayitem +UNARY_OPERATIONS = """same_as hint getfield setfield getsubstruct getarraysize cast_pointer direct_call indirect_call @@ -22,7 +22,7 @@ char_gt char_lt char_le char_ge char_eq char_ne int_gt int_lt int_le int_ge int_eq int_ne uint_gt uint_lt uint_le uint_ge uint_eq uint_ne - getarrayitem + getarrayitem setarrayitem getarraysubstruct ptr_eq ptr_ne""".split() @@ -280,16 +280,16 @@ FIELD_TYPE = getattr(S, hs_fieldname.const) return SomeLLAbstractVariable(lltype.Ptr(FIELD_TYPE)) - def getarrayitem(hs_v1, hs_index): - ARRAY = hs_v1.concretetype.TO - return SomeLLAbstractVariable(ARRAY.OF) - - def setarrayitem(hs_v1, hs_index, hs_value): - pass - - def getarraysubstruct(hs_v1, hs_index): - ARRAY = hs_v1.concretetype.TO - return SomeLLAbstractVariable(lltype.Ptr(ARRAY.OF)) +## def getarrayitem(hs_v1, hs_index): +## ARRAY = hs_v1.concretetype.TO +## return SomeLLAbstractVariable(ARRAY.OF) + +## def setarrayitem(hs_v1, hs_index, hs_value): +## pass + +## def getarraysubstruct(hs_v1, hs_index): +## ARRAY = hs_v1.concretetype.TO +## return SomeLLAbstractVariable(lltype.Ptr(ARRAY.OF)) def indirect_call(hs_v1, *args_hs): hs_graph_list = args_hs[-1] @@ -426,6 +426,9 @@ def getarrayitem((hs_v1, hs_v2)): return SomeLLAbstractVariable(hs_v1.concretetype.TO.OF) + def setarrayitem((hs_v1, hs_v2), hs_v3): + pass + def union((hs_v1, hs_v2)): raise annmodel.UnionError("%s %s don't mix" % (hs_v1, hs_v2)) From antocuni at codespeak.net Fri Nov 3 14:44:31 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 3 Nov 2006 14:44:31 +0100 (CET) Subject: [pypy-svn] r34104 - pypy/dist/pypy/rpython/test Message-ID: <20061103134431.8A43A10077@code0.codespeak.net> Author: antocuni Date: Fri Nov 3 14:44:27 2006 New Revision: 34104 Modified: pypy/dist/pypy/rpython/test/test_rstr.py Log: (antocuni, cfbolz) failing test Modified: pypy/dist/pypy/rpython/test/test_rstr.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rstr.py (original) +++ pypy/dist/pypy/rpython/test/test_rstr.py Fri Nov 3 14:44:27 2006 @@ -378,6 +378,11 @@ res = self.interpret(fn, ()) assert self.ll_to_string(res) == 'hell' + def test_str_slice_empty_string(self): + def fn(): + return ''[1:] + 'hello'[6:] + res = self.interpret(fn, []) + assert self.ll_to_string(res) == '' def test_strformat(self): def percentS(s): From niko at codespeak.net Fri Nov 3 14:50:33 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 3 Nov 2006 14:50:33 +0100 (CET) Subject: [pypy-svn] r34105 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061103135033.8E0D51007E@code0.codespeak.net> Author: niko Date: Fri Nov 3 14:50:31 2006 New Revision: 34105 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: (mwh,niko) cleanup prologue a bit and save callee-save registers Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Fri Nov 3 14:50:31 2006 @@ -368,12 +368,24 @@ self.initial_varmapping[arg] = gprs[3+len(self.initial_varmapping)] # Emit standard prologue + # Minimum space = 24+params+lv+4*GPR+8*FPR + # GPR=19 + # Initially, we allocate only enough space for GPRs, and allow + # each basic block to ensure it has enough space to continue. + minspace = self._stack_offset(0,0) self.asm.mflr(r0) self.asm.stw(r0,rSP,8) - self.asm.stwu(rSP,rSP,-64) + self.asm.stmw(r13,rSP,-(4*20)) # save all regs from 13-31 to stack + self.asm.stwu(rSP,rSP,-minspace) return self.inputargs + def _stack_offset(self, param, lv): + """ Returns the required stack offset to store all data, assuming + that there are 'param' words of parameters for callee functions and + 'lv' words of local variable information. """ + return ((24 + param*4 + lv*4 + 4*19) & ~15)+16 + def _close(self): self.rgenop.close_mc(self.asm.mc) self.asm.mc = None @@ -402,11 +414,11 @@ self.asm.mr(r3, reg.number) # Emit standard epilogue: - # TODO rewrite to handle varying size stack? - self.asm.lwz(r0,rSP,64+8) - self.asm.mtlr(r0) - self.asm.addi(rSP,rSP,64) - self.asm.blr() + self.asm.lwz(rSP,rSP,0) # restore old SP + self.asm.lmw(r13,rSP,-4*20) # restore all GPRs + self.asm.lwz(r0,rSP,8) # load old Link Register and jump to it + self.asm.mtlr(r0) # + self.asm.blr() # self._close() def finish_and_goto(self, outputargs_gv, target): From arigo at codespeak.net Fri Nov 3 15:01:39 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 3 Nov 2006 15:01:39 +0100 (CET) Subject: [pypy-svn] r34106 - pypy/dist/pypy/rpython/lltypesystem Message-ID: <20061103140139.690B710080@code0.codespeak.net> Author: arigo Date: Fri Nov 3 15:01:37 2006 New Revision: 34106 Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py Log: Assert that operations like slicing are not producing strings of negative length. Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rstr.py Fri Nov 3 15:01:37 2006 @@ -109,7 +109,10 @@ resulttype=pyobj_repr, _callable= lambda chars, sz: pyobjectptr(''.join(chars))) +from pypy.rpython.lltypesystem.lloperation import llop + def mallocstr(length): + llop.debug_assert(Void, "%s >= 0 # negative string length", length) r = malloc(STR, length) if not we_are_translated() or not malloc_zero_filled: r.hash = 0 @@ -507,7 +510,6 @@ def ll_stringslice_minusone(s1): newlen = len(s1.chars) - 1 - assert newlen >= 0 newstr = mallocstr(newlen) j = 0 while j < newlen: From antocuni at codespeak.net Fri Nov 3 15:13:43 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 3 Nov 2006 15:13:43 +0100 (CET) Subject: [pypy-svn] r34107 - pypy/dist/pypy/rpython/test Message-ID: <20061103141343.9664010080@code0.codespeak.net> Author: antocuni Date: Fri Nov 3 15:13:42 2006 New Revision: 34107 Modified: pypy/dist/pypy/rpython/test/test_rstr.py Log: (antocuni, cfbolz, arigo around) this test is not supposed to pass, there is a slight difference between python and rpython semantics. Modified: pypy/dist/pypy/rpython/test/test_rstr.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rstr.py (original) +++ pypy/dist/pypy/rpython/test/test_rstr.py Fri Nov 3 15:13:42 2006 @@ -378,12 +378,6 @@ res = self.interpret(fn, ()) assert self.ll_to_string(res) == 'hell' - def test_str_slice_empty_string(self): - def fn(): - return ''[1:] + 'hello'[6:] - res = self.interpret(fn, []) - assert self.ll_to_string(res) == '' - def test_strformat(self): def percentS(s): return "before %s after" % (s,) From santagada at codespeak.net Fri Nov 3 15:29:58 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Fri, 3 Nov 2006 15:29:58 +0100 (CET) Subject: [pypy-svn] r34108 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061103142958.C78DA1007A@code0.codespeak.net> Author: santagada Date: Fri Nov 3 15:29:57 2006 New Revision: 34108 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) Grouping, comma operator, throwing exceptions Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Fri Nov 3 15:29:57 2006 @@ -9,13 +9,6 @@ # def __init__(self, lineno = 1): # self.lineno = lineno -# def getlist(d): -# lgt = int(d['length']) -# output = [d[str(i)] for i in range(lgt)] -# return output -# getlist = staticmethod(getlist) - - class Array(Node): def __init__(self, items=()): self.items = items @@ -30,6 +23,11 @@ self.identifier = identifier self.arglist = arglist +class Comma(Node): + def __init__(self, left, right): + self.left = left + self.right = right + class Dot(Node): def __init__(self, left, right): self.left = left @@ -42,7 +40,12 @@ self.scope = scope #w_obj = W_Object({}, function=self) #self.scope = Scope(copy(scope.dict)) - + +class Group(Node): + """The Group class.""" + def __init__(self, expr): + self.expr = expr + class Identifier(Node): def __init__(self, name, initialiser): self.name = name @@ -93,6 +96,12 @@ def __init__(self, strval): self.strval = strval +class Throw(Node): + """The Throw class.""" + def __init__(self, exception): + self.exception = exception + + class Vars(Node): def __init__(self, nodes): self.nodes = nodes @@ -149,6 +158,12 @@ return f elif tp == 'RETURN': return Return(from_dict(d['value'])) + elif tp == 'THROW': + return Throw(from_dict(d['exception'])) + elif tp == 'GROUP': + return Group(from_dict(d['0'])) + elif tp == 'COMMA': + return Comma(from_dict(d['0']),from_dict(d['1'])) elif tp == 'VAR': return Vars(getlist(d)) else: Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Fri Nov 3 15:29:57 2006 @@ -11,6 +11,11 @@ def __init__(self, value): self.value = value +class ThrowException(Exception): + def __init__(self, exception): + self.exception = exception + + class __extend__(Array): def call(self, context): d = dict(enumerate(self.items)) @@ -42,6 +47,11 @@ scope_manager.current_scope = backup_scope return retval +class __extend__(Comma): + def call(self, context=None): + self.left.call(context) + return self.right.call(context) + class __extend__(Dot): def call(self, context=None): w_obj = self.left.call(context).GetValue().ToObject() @@ -65,6 +75,11 @@ def get_literal(self): return self.name +class __extend__(Group): + """The __extend__ class.""" + def call(self, context = None): + return self.expr.call(context) + class __extend__(Index): def call(self, context=None): w_obj = self.left.call(context).GetValue() @@ -128,7 +143,6 @@ ncontext.assign(item, temp) w_Arguments = W_Arguments(dict([(str(x),y) for x,y in enumerate(args)])) - print w_Arguments.dict_w ncontext.assign('arguments', w_Arguments) try: @@ -153,6 +167,10 @@ def call(self, context=None): raise ExecutionReturned(self.expr.call(context)) +class __extend__(Throw): + def call(self, context=None): + raise ThrowException(self.exception.call(context)) + class __extend__(Vars): def call(self, context=None): for var in self.nodes: Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Fri Nov 3 15:29:57 2006 @@ -2,6 +2,7 @@ from pypy.lang.js.astgen import * from pypy.lang.js import interpreter from pypy.lang.js.parser import parse +from pypy.lang.js.interpreter import ThrowException import py.test import sys @@ -23,7 +24,10 @@ def assert_prints(self, code, assval): l = [] interpreter.writer = l.append - code.call() + try: + code.call() + except ThrowException, excpt: + l.append("uncaught exception: "+str(excpt.exception)) assert l == assval def test_interp_parse(self): @@ -112,7 +116,6 @@ """), ["test"]) def test_function_arguments(self): - #py.test.skip('not ready yet') self.assert_prints(parse_d(""" x = function () { r = arguments[0]; @@ -136,3 +139,23 @@ print(x); """), ["[]"]) + def test_throw(self): + self.assert_prints(parse_d("throw(3)"), ["uncaught exception: 3"]) + + def test_group(self): + self.assert_prints(parse_d("print((2+1))"), ["3"]) + + def test_comma(self): + self.assert_prints(parse_d("print((500,3))"), ["3"]) + + def test_try_catch(self): + py.test.skip('Under Construction') + self.assert_prints(parse_d(""" + try { + throw(3); + } + catch (x) { + print(x); + } + """), ["3"]) + \ No newline at end of file From fijal at codespeak.net Fri Nov 3 15:34:43 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 15:34:43 +0100 (CET) Subject: [pypy-svn] r34109 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061103143443.2034810075@code0.codespeak.net> Author: fijal Date: Fri Nov 3 15:34:42 2006 New Revision: 34109 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (samuele, fijal) - Progress. For use objects we've got attribute getting and setting. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Fri Nov 3 15:34:42 2006 @@ -2,7 +2,9 @@ """ test transparent proxy features """ -class AppTestProxy(object): +from pypy.conftest import gettestobjspace + +class AppProxyBasic(object): def setup_method(self, meth): self.w_Controller = self.space.appexec([], """(): class Controller(object): @@ -13,7 +15,8 @@ return getattr(self.obj, name)(*args, **kwargs) return Controller """) - + +class AppTestListProxy(AppProxyBasic): def test_proxy(self): lst = proxy(list, lambda : None) assert type(lst) is list @@ -73,6 +76,7 @@ else: fail("Accessing outside a list didn't raise") +class AppTestDictProxy(AppProxyBasic): def test_dict(self): c = self.Controller({"xx":1}) d = proxy(dict, c.perform) @@ -94,3 +98,7 @@ d = proxy(dict, c.perform) d['z'] = 4 assert sorted(list(d.iterkeys())) == ['a', 'b', 'c', 'z'] + +class AppTestDictStrProxy(AppTestDictProxy): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withstrdict": True}) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Fri Nov 3 15:34:42 2006 @@ -4,11 +4,45 @@ from pypy.objspace.std.objspace import * from pypy.objspace.std.proxy_helpers import register_type +from pypy.interpreter.error import OperationError class W_Transparent(W_Object): def __init__(self, w_controller): self.controller = w_controller +class W_TransparentObject(W_Object): + def __init__(self, w_type, w_controller): + self.w_type = w_type + self.w_controller = w_controller + + def getclass(self, space): + return self.w_type + + def setclass(self, space, w_subtype): + raise OperationError(space.w_TypeError, + space.wrap("You cannot override __class__ for transparent proxies")) + + def getdictvalue(self, space, w_attr): + try: + return space.call_function(self.w_controller, space.wrap('__getattribute__'), + w_attr) + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return None + + def setdictvalue(self, space, w_attr, w_value): + try: + space.call_function(self.w_controller, space.wrap('__setattr__'), + w_attr, w_value) + return True + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return False + + from pypy.objspace.std.objecttype import object_typedef as typedef + class W_TransparentList(W_Transparent): from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Fri Nov 3 15:34:42 2006 @@ -5,7 +5,8 @@ from pypy.interpreter import gateway from pypy.interpreter.function import Function from pypy.interpreter.error import OperationError -from pypy.objspace.std.tlistobject import W_TransparentList, W_TransparentDict +from pypy.objspace.std.tlistobject import W_TransparentList, W_TransparentDict,\ + W_TransparentObject def proxy(space, w_type, w_controller): if not space.is_true(space.callable(w_controller)): @@ -15,7 +16,13 @@ return W_TransparentList(w_controller) if space.is_true(space.issubtype(w_type, space.w_dict)): return W_TransparentDict(w_controller) - raise OperationError(space.w_TypeError, space.wrap("type of object wrapped should be list or int")) + w_bestbase = w_type.w_bestbase + if w_bestbase is not None and space.is_w(w_bestbase, space.w_object): + return W_TransparentObject(w_type, w_controller) + #return type_cache[w_type or w_type.w_bestbase] + + raise OperationError(space.w_TypeError, space.wrap("Object type %s could not"\ + "be wrapped (YET)" % w_type.getname(space, "?"))) app_proxy = gateway.interp2app(proxy, unwrap_spec=[gateway.ObjSpace, gateway.W_Root, \ gateway.W_Root]) From tismer at codespeak.net Fri Nov 3 16:01:51 2006 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 3 Nov 2006 16:01:51 +0100 (CET) Subject: [pypy-svn] r34110 - pypy/dist/pypy/translator/c/src Message-ID: <20061103150151.A35411007A@code0.codespeak.net> Author: tismer Date: Fri Nov 3 16:01:49 2006 New Revision: 34110 Modified: pypy/dist/pypy/translator/c/src/ll_os.h Log: I really felt like commenting this obscure implicit creation of a needed type. Modified: pypy/dist/pypy/translator/c/src/ll_os.h ============================================================================== --- pypy/dist/pypy/translator/c/src/ll_os.h (original) +++ pypy/dist/pypy/translator/c/src/ll_os.h Fri Nov 3 16:01:49 2006 @@ -378,6 +378,15 @@ } #endif +/* + The following code is only generated if spawnv exists and + if RPyListOfString exists. The latter is a bit tricky: + The RPyListOfString is necessary to correctly declare this function. + For this to work, the test code must be properly written in a way + that RPyListOfString is really annotated as such. + Please see the test in test_extfunc.py - creating the correct + argument string type is not obvious and error prone. + */ #if defined(HAVE_SPAWNV) && defined(HAVE_RPY_LIST_OF_STRING) long LL_os_spawnv(int mode, RPyString *path, RPyListOfString *args) { int pid, i, nargs = args->l_length; From cfbolz at codespeak.net Fri Nov 3 16:03:06 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 16:03:06 +0100 (CET) Subject: [pypy-svn] r34111 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061103150306.229271007A@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 16:03:05 2006 New Revision: 34111 Modified: pypy/dist/pypy/lib/_sio.py pypy/dist/pypy/lib/test2/test_sio.py Log: (antocuni, cfbolz): add a helpful hint Modified: pypy/dist/pypy/lib/_sio.py ============================================================================== --- pypy/dist/pypy/lib/_sio.py (original) +++ pypy/dist/pypy/lib/_sio.py Fri Nov 3 16:03:05 2006 @@ -29,6 +29,10 @@ import os + +# XXX XXX XXX XXX please don't change this file. it will go away soon +# in favour of rlib/streamio.py + # ____________________________________________________________ Modified: pypy/dist/pypy/lib/test2/test_sio.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_sio.py (original) +++ pypy/dist/pypy/lib/test2/test_sio.py Fri Nov 3 16:03:05 2006 @@ -6,6 +6,9 @@ from pypy.lib import _sio as sio +# XXX XXX XXX XXX please don't change this file. it will go away soon +# in favour of rlib/test/test_streamio.py + class TSource(object): From fijal at codespeak.net Fri Nov 3 16:03:43 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 16:03:43 +0100 (CET) Subject: [pypy-svn] r34112 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061103150343.590791007A@code0.codespeak.net> Author: fijal Date: Fri Nov 3 16:03:41 2006 New Revision: 34112 Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py (contents, props changed) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (samuele, fijal) - Added user created objects and fixed some bugs. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py Fri Nov 3 16:03:41 2006 @@ -20,7 +20,7 @@ def install_general_args_trampoline(type_, mm, is_local): def function(space, w_transparent_list, __args__): args = __args__.prepend(space.wrap(mm.name)) - return space.call_args(w_transparent_list.controller, args) + return space.call_args(w_transparent_list.w_controller, args) function.func_name = mm.name mm.register(function, type_) @@ -28,7 +28,7 @@ def install_w_args_trampoline(type_, mm, is_local): def function(space, w_transparent_list, *args_w): args = Arguments(space, [space.wrap(mm.name)] + list(args_w[:-1]), w_stararg=args_w[-1]) - return space.call_args(w_transparent_list.controller, args) + return space.call_args(w_transparent_list.w_controller, args) function.func_name = mm.name mm.register(function, type_, *([W_ANY] * (mm.arity - 1))) @@ -44,7 +44,7 @@ assert not mm.argnames_after # we search here for special-cased stuff def function(space, w_transparent_list, *args_w): - return space.call_function(w_transparent_list.controller, space.wrap\ + return space.call_function(w_transparent_list.w_controller, space.wrap\ (op_name), *args_w) function.func_name = mm_name mm.register(function, type_, *([W_ANY] * (mm.arity - 1))) @@ -70,7 +70,7 @@ #mm_name, op_name = create_mm_names(classname, mm, is_local) def function(space, w_any, w_transparent_list): - retval = space.call_function(w_transparent_list.controller, space.wrap(mm.specialnames[1]), + retval = space.call_function(w_transparent_list.w_controller, space.wrap(mm.specialnames[1]), w_any) return retval Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py Fri Nov 3 16:03:41 2006 @@ -0,0 +1,75 @@ + +""" test proxy object +""" + +from pypy.objspace.std.test.test_proxy import AppProxyBasic + +class AppTestProxyObj(AppProxyBasic): + def setup_method(self, meth): + super(AppTestProxyObj, self).setup_method(meth) + self.w_A = self.space.appexec([], """(): + class A(object): + pass + return A + """) + + def test_simple_obj(self): + class AT(self.A): + pass + + c = self.Controller(self.A()) + obj = proxy(AT, c.perform) + + assert type(obj) is AT + assert obj.__class__ is AT + + def test__class__override(self): + c = self.Controller(self.A()) + obj = proxy(self.A, c.perform) + + raises(TypeError, "obj.__class__ = self.A") + + def test_attribute_access(self): + a = self.A() + a.x = 3 + c = self.Controller(a) + obj = proxy(self.A, c.perform) + + assert obj.x == 3 + + def test_nonexistant_attribuite_access(self): + c = self.Controller(self.A()) + obj = proxy(self.A, c.perform) + raises(AttributeError, "obj.x") + + def test_setattr(self): + a = self.A() + c = self.Controller(a) + obj = proxy(self.A, c.perform) + obj.x = 1 + assert obj.x == 1 + assert a.x == 1 + + def test_delattr(self): + a = self.A() + a.f = 3 + c = self.Controller(a) + obj = proxy(self.A, c.perform) + del obj.f + raises(AttributeError, "obj.f") + +class AppTestProxyObjectList(AppTestProxyObj): + def setup_method(self, meth): + super(AppTestProxyObj, self).setup_method(meth) + self.w_A = self.space.appexec([], """(): + class A(list): + pass + return A + """) + + def test_list_append(self): + a = self.A([1,2,3]) + c = self.Controller(a) + obj = proxy(self.A, c.perform) + assert len(obj) == 3 + assert obj[1] == 2 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Fri Nov 3 16:03:41 2006 @@ -6,11 +6,11 @@ from pypy.objspace.std.proxy_helpers import register_type from pypy.interpreter.error import OperationError -class W_Transparent(W_Object): - def __init__(self, w_controller): - self.controller = w_controller +#class W_Transparent(W_Object): +# def __init__(self, w_controller): +# self.controller = w_controller -class W_TransparentObject(W_Object): +class W_Transparent(W_Object): def __init__(self, w_type, w_controller): self.w_type = w_type self.w_controller = w_controller @@ -41,6 +41,16 @@ raise return False + def deldictvalue(self, space, w_attr): + try: + space.call_function(self.w_controller, space.wrap('__delattr__'), + w_attr) + return True + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return False + from pypy.objspace.std.objecttype import object_typedef as typedef class W_TransparentList(W_Transparent): Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Fri Nov 3 16:03:41 2006 @@ -6,21 +6,19 @@ from pypy.interpreter.function import Function from pypy.interpreter.error import OperationError from pypy.objspace.std.tlistobject import W_TransparentList, W_TransparentDict,\ - W_TransparentObject + W_Transparent def proxy(space, w_type, w_controller): if not space.is_true(space.callable(w_controller)): raise OperationError(space.w_TypeError, space.wrap("controller should be function")) if space.is_true(space.issubtype(w_type, space.w_list)): - return W_TransparentList(w_controller) + return W_TransparentList(w_type, w_controller) if space.is_true(space.issubtype(w_type, space.w_dict)): - return W_TransparentDict(w_controller) - w_bestbase = w_type.w_bestbase - if w_bestbase is not None and space.is_w(w_bestbase, space.w_object): - return W_TransparentObject(w_type, w_controller) + return W_TransparentDict(w_type, w_controller) + if w_type.instancetypedef is space.w_object.instancetypedef: + return W_Transparent(w_type, w_controller) #return type_cache[w_type or w_type.w_bestbase] - raise OperationError(space.w_TypeError, space.wrap("Object type %s could not"\ "be wrapped (YET)" % w_type.getname(space, "?"))) From cfbolz at codespeak.net Fri Nov 3 16:06:01 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 16:06:01 +0100 (CET) Subject: [pypy-svn] r34113 - in pypy/dist/pypy/rlib: . test Message-ID: <20061103150601.2599910076@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 16:06:00 2006 New Revision: 34113 Modified: pypy/dist/pypy/rlib/streamio.py pypy/dist/pypy/rlib/test/test_streamio.py Log: (antocuni, cfbolz): steps in the direction of making streamio more rpython: run them on top of the llinterpreter. it turns out, that they rtype fine, but there are some subtle differences between rpython and python :-(((. very painful. Modified: pypy/dist/pypy/rlib/streamio.py ============================================================================== --- pypy/dist/pypy/rlib/streamio.py (original) +++ pypy/dist/pypy/rlib/streamio.py Fri Nov 3 16:06:00 2006 @@ -27,7 +27,7 @@ """ -import os +import os, sys # ____________________________________________________________ @@ -48,6 +48,12 @@ def replace_char_with_str(string, c, s): return s.join(string.split(c)) + +class StreamError(Exception): + def __init__(self, message): + self.message = message + + class Stream(object): """Base class for streams. Provides a default implementation of @@ -116,44 +122,28 @@ self.fd = fd def seek(self, offset, whence=0): - try: - os.lseek(self.fd, offset, whence) - except OSError, e: - raise IOError(*e.args) + os.lseek(self.fd, offset, whence) def tell(self): - try: - return os.lseek(self.fd, 0, 1) - except OSError, e: - raise IOError(*e.args) + return os.lseek(self.fd, 0, 1) def read(self, n): - try: - return os.read(self.fd, n) - except OSError, e: - raise IOError(*e.args) + return os.read(self.fd, n) def write(self, data): - try: - while data: - n = os.write(self.fd, data) - data = data[n:] - except OSError, e: - raise IOError(*e.args) + while data: + n = os.write(self.fd, data) + data = data[n:] def close(self): - try: - os.close(self.fd) - except OSError, e: - raise IOError(*e.args) + os.close(self.fd) - def truncate(self, size): - try: - os.ftruncate(self.fd, size) - except OSError, e: - raise IOError(*e.args) - except AttributeError: + if sys.platform == "win32": + def truncate(self, size): raise NotImplementedError + else: + def truncate(self, size): + os.ftruncate(self.fd, size) # next class is not RPython @@ -162,31 +152,6 @@ """Standard I/O basis stream using mmap.""" -## def __init__(self, filename, mode="r"): -## import mmap -## self.filename = filename -## self.mode = mode -## if mode == "r": -## flag = os.O_RDONLY -## self.access = mmap.ACCESS_READ -## else: -## if mode == "w": -## flag = os.O_RDWR | os.O_CREAT -## elif mode == "a": -## flag = os.O_RDWR -## else: -## raise ValueError, "mode should be 'r', 'w' or 'a'" -## self.access = mmap.ACCESS_WRITE -## if hasattr(os, "O_BINARY"): -## flag |= os.O_BINARY -## self.fd = os.open(filename, flag) -## try: -## self.mapfile() -## except: -## os.close(self.fd) -## raise -## self.pos = 0 - def __init__(self, fd, mmapaccess): """NOT_RPYTHON""" self.fd = fd @@ -214,7 +179,7 @@ elif whence == 2: self.pos = max(0, self.mm.size() + offset) else: - raise ValueError, "seek(): whence must be 0, 1 or 2" + raise StreamError("seek(): whence must be 0, 1 or 2") def readall(self): filesize = self.mm.size() # Actual file size, may be more than mapped @@ -353,12 +318,14 @@ while self.lines: line = self.lines[0] if offset <= len(line): + assert offset >= 0 self.lines[0] = line[offset:] return offset -= len(self.lines[0]) - 1 del self.lines[0] assert not self.lines if offset <= len(self.buf): + assert offset >= 0 self.buf = self.buf[offset:] return offset -= len(self.buf) @@ -395,13 +362,13 @@ del buffers[0] cutoff = total + offset if cutoff < 0: - raise TypeError, "cannot seek back" + raise StreamError("cannot seek back") if buffers: buffers[0] = buffers[0][cutoff:] self.buf = "".join(buffers) self.lines = [] return - raise ValueError, "whence should be 0, 1 or 2" + raise StreamError("whence should be 0, 1 or 2") def readall(self): self.lines.append(self.buf) @@ -418,6 +385,7 @@ return "".join(more) def read(self, n): + assert n >= 0 if self.lines: # See if this can be satisfied from self.lines[0] line = self.lines[0] @@ -434,6 +402,7 @@ lines = self.lines[:i] data = self.lines[i] cutoff = len(data) - (k-n) + assert cutoff >= 0 lines.append(data[:cutoff]) self.lines[:i+1] = [data[cutoff:]] return "\n".join(lines) @@ -445,6 +414,7 @@ lines = self.lines self.lines = [] cutoff = n - k + assert cutoff >= 0 lines.append(self.buf[:cutoff]) self.buf = self.buf[cutoff:] return "\n".join(lines) @@ -455,6 +425,8 @@ k = len(data) if k >= n: cutoff = len(data) - (k-n) + assert cutoff >= 0 + assert len(data) >= cutoff self.buf = data[cutoff:] return data[:cutoff] @@ -472,8 +444,12 @@ if not data: break cutoff = len(data) - (k-n) - self.buf = data[cutoff:] - more[-1] = data[:cutoff] + assert cutoff >= 0 + if len(data) <= cutoff: + self.buf = "" + else: + self.buf = data[cutoff:] + more[-1] = data[:cutoff] return "".join(more) def readline(self): @@ -487,7 +463,10 @@ if self.lines: return self.lines.pop(0) + "\n" - buf = self.buf and [self.buf] or [] + if self.buf: + buf = [self.buf] + else: + buf = [] while 1: self.buf = self.do_read(self.bufsize) self.lines = self.buf.split("\n") Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 16:06:00 2006 @@ -6,14 +6,16 @@ from pypy.rlib import streamio +from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin -class TSource(object): + +class TSource(streamio.Stream): def __init__(self, packets): for x in packets: assert x - self.orig_packets = list(packets) - self.packets = list(packets) + self.orig_packets = packets[:] + self.packets = packets[:] self.pos = 0 self.chunks = [] @@ -37,6 +39,7 @@ assert self.pos == offset def read(self, n): + assert n >= 0 try: data = self.packets.pop(0) except IndexError: @@ -56,7 +59,7 @@ def flush(self): pass -class TWriter(object): +class TWriter(streamio.Stream): def __init__(self, data=''): self.buf = data @@ -116,11 +119,14 @@ self.pos += n return result -class TestBufferingInputStreamTests: +class BaseTestBufferingInputStreamTests(BaseRtypingTest): packets = ["a", "b", "\n", "def", "\nxy\npq\nuv", "wx"] lines = ["ab\n", "def\n", "xy\n", "pq\n", "uvwx"] + def _freeze_(self): + return True + def makeStream(self, tell=False, seek=False, bufsize=-1): base = TSource(self.packets) self.source = base @@ -132,194 +138,317 @@ base.seek = f return streamio.BufferingInputStream(base, bufsize) - def test_readline(self): - file = self.makeStream() - assert list(iter(file.readline, "")) == self.lines - - def test_readlines_small_bufsize(self): - file = self.makeStream(bufsize=1) - assert list(iter(file.readline, "")) == self.lines + def Xtest_readline(self): + for file in [self.makeStream(), self.makeStream(bufsize=1)]: + def f(): + i = 0 + result = True + while 1: + r = file.readline() + if r == "": + break + result = result and self.lines[i] == r + i += 1 + return result + res = self.interpret(f, []) + assert res def test_readall(self): file = self.makeStream() - assert file.readall() == "".join(self.lines) + def f(): + return file.readall() == "".join(self.lines) + res = self.interpret(f, []) + assert res def test_readall_small_bufsize(self): file = self.makeStream(bufsize=1) - assert file.readall() == "".join(self.lines) + def f(): + return file.readall() == "".join(self.lines) + res = self.interpret(f, []) + assert res def test_readall_after_readline(self): file = self.makeStream() - assert file.readline() == self.lines[0] - assert file.readline() == self.lines[1] - assert file.readall() == "".join(self.lines[2:]) + def f(): + return (file.readline() == self.lines[0] and + file.readline() == self.lines[1] and + file.readall() == "".join(self.lines[2:])) + res = self.interpret(f, []) + assert res - def test_read_1_after_readline(self): + def Xtest_read_1_after_readline(self): file = self.makeStream() - assert file.readline() == "ab\n" - assert file.readline() == "def\n" - blocks = [] - while 1: - block = file.read(1) - if not block: - break - blocks.append(block) - assert file.read(0) == "" - assert blocks == list("".join(self.lines)[7:]) + def f(): + if not file.readline() == "ab\n": + return False + if not file.readline() == "def\n": + return False + os.write(1, "3\n") + blocks = [] + while 1: + block = file.read(1) + os.write(1, "XXXX" + block + "YYYY") + os.write(1, "4\n") + if not block: + break + os.write(1, "5\n") + blocks.append(block) + if not file.read(0) == "": + return False + os.write(1, "6\n") + return "".join(blocks) == "".join(self.lines)[7:] + res = self.interpret(f, []) + assert res def test_read_1(self): file = self.makeStream() - blocks = [] - while 1: - block = file.read(1) - if not block: - break - blocks.append(block) - assert file.read(0) == "" - assert blocks == list("".join(self.lines)) + def f(): + blocks = [] + while 1: + block = file.read(1) + if not block: + break + blocks.append(block) + if not file.read(0) == "": + return False + return "".join(blocks) == "".join(self.lines) + res = self.interpret(f, []) + assert res def test_read_2(self): file = self.makeStream() - blocks = [] - while 1: - block = file.read(2) - if not block: - break - blocks.append(block) - assert file.read(0) == "" - assert blocks == ["ab", "\nd", "ef", "\nx", "y\n", "pq", - "\nu", "vw", "x"] + def f(): + blocks = [] + while 1: + block = file.read(2) + if not block: + break + blocks.append(block) + if not file.read(0) == "": + return False + return blocks == ["ab", "\nd", "ef", "\nx", "y\n", "pq", + "\nu", "vw", "x"] + res = self.interpret(f, []) + assert res def test_read_4(self): file = self.makeStream() - blocks = [] - while 1: - block = file.read(4) - if not block: - break - blocks.append(block) - assert file.read(0) == "" - assert blocks == ["ab\nd", "ef\nx", "y\npq", "\nuvw", "x"] + def f(): + blocks = [] + while 1: + block = file.read(4) + if not block: + break + blocks.append(block) + if not file.read(0) == "": + return True + return blocks == ["ab\nd", "ef\nx", "y\npq", "\nuvw", "x"] + res = self.interpret(f, []) + assert res - def test_read_4_after_readline(self): + def Xtest_read_4_after_readline(self): file = self.makeStream() - assert file.readline() == "ab\n" - assert file.readline() == "def\n" - blocks = [file.read(4)] - while 1: - block = file.read(4) - if not block: - break - blocks.append(block) - assert file.read(0) == "" - assert blocks == ["xy\np", "q\nuv", "wx"] + def f(): + os.write(1, "1\n") + res = file.readline() + if not res == "ab\n": + os.write(1, "1f\nxxx" + res + "yyy\n" + str(len(res)) + "\n") + return False + os.write(1, "2\n") + if not file.readline() == "def\n": + os.write(1, "2f\n") + return False + os.write(1, "3\n") + blocks = [file.read(4)] + while 1: + block = file.read(4) + if not block: + break + blocks.append(block) + os.write(1, "4\n") + if not file.read(0) == "": + os.write(1, "4f\n") + return False + os.write(1, "5\n") + for element in blocks: + os.write(1, element + "XXX\n") + return blocks == ["xy\np", "q\nuv", "wx"] + res = self.interpret(f, []) + assert res def test_read_4_small_bufsize(self): file = self.makeStream(bufsize=1) - blocks = [] - while 1: - block = file.read(4) - if not block: - break - blocks.append(block) - assert blocks == ["ab\nd", "ef\nx", "y\npq", "\nuvw", "x"] + def f(): + blocks = [] + while 1: + block = file.read(4) + if not block: + break + blocks.append(block) + return blocks == ["ab\nd", "ef\nx", "y\npq", "\nuvw", "x"] + res = self.interpret(f, []) + assert res def test_tell_1(self): file = self.makeStream(tell=True) - pos = 0 - while 1: - assert file.tell() == pos - n = len(file.read(1)) - if not n: - break - pos += n + def f(): + pos = 0 + while 1: + if not file.tell() == pos: + return False + n = len(file.read(1)) + if not n: + break + pos += n + return True + res = self.interpret(f, []) + assert res - def test_tell_1_after_readline(self): + def Xtest_tell_1_after_readline(self): file = self.makeStream(tell=True) - pos = 0 - pos += len(file.readline()) - assert file.tell() == pos - pos += len(file.readline()) - assert file.tell() == pos - while 1: - assert file.tell() == pos - n = len(file.read(1)) - if not n: - break - pos += n + def f(): + pos = 0 + pos += len(file.readline()) + if not file.tell() == pos: + return False + pos += len(file.readline()) + if not file.tell() == pos: + return False + while 1: + if not file.tell() == pos: + return False + n = len(file.read(1)) + if not n: + break + pos += n + return True + res = self.interpret(f, []) + assert res def test_tell_2(self): file = self.makeStream(tell=True) - pos = 0 - while 1: - assert file.tell() == pos - n = len(file.read(2)) - if not n: - break - pos += n + def f(): + pos = 0 + while 1: + if not file.tell() == pos: + return False + n = len(file.read(2)) + if not n: + break + pos += n + return True + res = self.interpret(f, []) + assert res def test_tell_4(self): file = self.makeStream(tell=True) - pos = 0 - while 1: - assert file.tell() == pos - n = len(file.read(4)) - if not n: - break - pos += n + def f(): + pos = 0 + while 1: + if not file.tell() == pos: + return False + n = len(file.read(4)) + if not n: + break + pos += n + return True + res = self.interpret(f, []) + assert res def test_tell_readline(self): file = self.makeStream(tell=True) - pos = 0 - while 1: - assert file.tell() == pos - n = len(file.readline()) - if not n: - break - pos += n + def f(): + pos = 0 + while 1: + if not file.tell() == pos: + return False + n = len(file.readline()) + if not n: + break + pos += n + return True + res = self.interpret(f, []) + assert res - def test_seek(self): + def Xtest_seek(self): file = self.makeStream(tell=True, seek=True) - all = file.readall() - end = len(all) - for readto in range(0, end+1): - for seekto in range(0, end+1): - for whence in 0, 1, 2: - file.seek(0) - assert file.tell() == 0 - head = file.read(readto) - assert head == all[:readto] - if whence == 1: - offset = seekto - readto - elif whence == 2: - offset = seekto - end - else: - offset = seekto - file.seek(offset, whence) - here = file.tell() - assert here == seekto - rest = file.readall() - assert rest == all[seekto:] + def f(): + all = file.readall() + end = len(all) + for readto in range(0, end+1): + for seekto in range(0, end+1): + for whence in [0, 1, 2]: + file.seek(0) + if not file.tell() == 0: + return False + head = file.read(readto) + if not head == all[:readto]: + return False + if whence == 1: + offset = seekto - readto + elif whence == 2: + offset = seekto - end + else: + offset = seekto + file.seek(offset, whence) + here = file.tell() + if not here == seekto: + return False + rest = file.readall() + if not rest == all[seekto:]: + return False + return True + res = self.interpret(f, []) + assert res def test_seek_noseek(self): file = self.makeStream() all = file.readall() end = len(all) - for readto in range(0, end+1): - for seekto in range(readto, end+1): - for whence in 1, 2: - file = self.makeStream() - head = file.read(readto) - assert head == all[:readto] - if whence == 1: - offset = seekto - readto - elif whence == 2: - offset = seekto - end - file.seek(offset, whence) - rest = file.readall() - assert rest == all[seekto:] + def f(): + for readto in range(0, end+1): + for seekto in range(readto, end+1): + for whence in [1, 2]: + base = TSource(self.packets) + file = streamio.BufferingInputStream(base) + head = file.read(readto) + if not head == all[:readto]: + return False + offset = 42 # for the flow space + if whence == 1: + offset = seekto - readto + elif whence == 2: + offset = seekto - end + file.seek(offset, whence) + rest = file.readall() + assert rest == all[seekto:] + return True + res = self.interpret(f, []) + assert res + +class TestBufferingInputStreamTests(BaseTestBufferingInputStreamTests): + def interpret(self, func, args, **kwds): + return func(*args) + +class TestBufferingInputStreamTestsLLinterp(BaseTestBufferingInputStreamTests, + LLRtypeMixin): + pass + +class TestBufferedRead: + packets = ["a", "b", "\n", "def", "\nxy\npq\nuv", "wx"] + lines = ["ab\n", "def\n", "xy\n", "pq\n", "uvwx"] + + def makeStream(self, tell=False, seek=False, bufsize=-1): + base = TSource(self.packets) + self.source = base + def f(*args): + raise NotImplementedError + if not tell: + base.tell = f + if not seek: + base.seek = f + return streamio.BufferingInputStream(base, bufsize) -class TestBufferedRead(TestBufferingInputStreamTests): def test_dont_read_small(self): import sys file = self.makeStream(bufsize=4) @@ -327,7 +456,7 @@ for want, got, pos in self.source.chunks: assert want >= 4 -class TestBufferingOutputStream: +class TestBufferingOutputStream: def test_write(self): base = TWriter() @@ -382,7 +511,7 @@ filter.close() assert base.buf == '1234' + '\0' * 4 + 'y' -class TestLineBufferingOutputStreamTests: +class TestLineBufferingOutputStreamTests: def test_write(self): base = TWriter() @@ -410,7 +539,7 @@ filter.close() assert base.buf == "x"*3 + "y"*2 + "x"*1 -class TestCRLFFilter: +class TestCRLFFilter: def test_filter(self): packets = ["abc\ndef\rghi\r\nxyz\r", "123\r", "\n456"] @@ -424,11 +553,14 @@ blocks.append(block) assert blocks == expected -class TestMMapFile(TestBufferingInputStreamTests): +class TestMMapFile(BaseTestBufferingInputStreamTests): tfn = None fd = None Counter = 0 + def interpret(self, func, args, **kwargs): + return func(*args) + def teardown_method(self, method): tfn = self.tfn if tfn: From xoraxax at codespeak.net Fri Nov 3 16:09:03 2006 From: xoraxax at codespeak.net (xoraxax at codespeak.net) Date: Fri, 3 Nov 2006 16:09:03 +0100 (CET) Subject: [pypy-svn] r34114 - pypy/dist/pypy/translator/jvm Message-ID: <20061103150903.E3BFA1007A@code0.codespeak.net> Author: xoraxax Date: Fri Nov 3 16:09:00 2006 New Revision: 34114 Modified: pypy/dist/pypy/translator/jvm/database.py Log: Fixed assert in jvm/database Modified: pypy/dist/pypy/translator/jvm/database.py ============================================================================== --- pypy/dist/pypy/translator/jvm/database.py (original) +++ pypy/dist/pypy/translator/jvm/database.py Fri Nov 3 16:09:00 2006 @@ -288,7 +288,7 @@ if OOTYPE in self._type_printing_methods: return self._type_printing_methods[OOTYPE] pclass = self.pending_class(OOTYPE) - assert hasattr(pclass, 'dump_method'), "No dump_method for "+OOTYPE + assert hasattr(pclass, 'dump_method'), "No dump_method for %r" % (OOTYPE, ) return pclass.dump_method.method() # Type translation functions From fijal at codespeak.net Fri Nov 3 16:13:19 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 16:13:19 +0100 (CET) Subject: [pypy-svn] r34115 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061103151319.8C7D01007A@code0.codespeak.net> Author: fijal Date: Fri Nov 3 16:13:15 2006 New Revision: 34115 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (samuele, fijal) - __dict__ writing/reading. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py Fri Nov 3 16:13:15 2006 @@ -57,6 +57,21 @@ obj = proxy(self.A, c.perform) del obj.f raises(AttributeError, "obj.f") + + def test__dict__(self): + a = self.A() + a.x = 3 + c = self.Controller(a) + obj = proxy(self.A, c.perform) + assert 'x' in obj.__dict__ + + def test_set__dict__(self): + a = self.A() + c = self.Controller(a) + obj = proxy(self.A, c.perform) + obj.__dict__ = {'x':3} + assert obj.x == 3 + assert obj.__dict__.keys() == ['x'] class AppTestProxyObjectList(AppTestProxyObj): def setup_method(self, meth): Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Fri Nov 3 16:13:15 2006 @@ -11,9 +11,10 @@ # self.controller = w_controller class W_Transparent(W_Object): - def __init__(self, w_type, w_controller): + def __init__(self, space, w_type, w_controller): self.w_type = w_type self.w_controller = w_controller + self.space = space def getclass(self, space): return self.w_type @@ -51,6 +52,13 @@ raise return False + def getdict(self): + return self.getdictvalue(self.space, self.space.wrap('__dict__')) + + def setdict(self, space, w_dict): + if not self.setdictvalue(space, space.wrap('__dict__'), w_dict): + W_Root.setdict(self, space, w_dict) + from pypy.objspace.std.objecttype import object_typedef as typedef class W_TransparentList(W_Transparent): Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Fri Nov 3 16:13:15 2006 @@ -13,11 +13,11 @@ raise OperationError(space.w_TypeError, space.wrap("controller should be function")) if space.is_true(space.issubtype(w_type, space.w_list)): - return W_TransparentList(w_type, w_controller) + return W_TransparentList(space, w_type, w_controller) if space.is_true(space.issubtype(w_type, space.w_dict)): - return W_TransparentDict(w_type, w_controller) + return W_TransparentDict(space, w_type, w_controller) if w_type.instancetypedef is space.w_object.instancetypedef: - return W_Transparent(w_type, w_controller) + return W_Transparent(space, w_type, w_controller) #return type_cache[w_type or w_type.w_bestbase] raise OperationError(space.w_TypeError, space.wrap("Object type %s could not"\ "be wrapped (YET)" % w_type.getname(space, "?"))) From santagada at codespeak.net Fri Nov 3 16:19:02 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Fri, 3 Nov 2006 16:19:02 +0100 (CET) Subject: [pypy-svn] r34116 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061103151902.A767A1007A@code0.codespeak.net> Author: santagada Date: Fri Nov 3 16:19:00 2006 New Revision: 34116 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) Implemented Blocks Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Fri Nov 3 16:19:00 2006 @@ -18,6 +18,11 @@ self.identifier = identifier self.expr = expr +class Block(Node): + def __init__(self, nodes): + self.nodes = nodes + + class Call(Node): def __init__(self, identifier, arglist): self.identifier = identifier @@ -42,7 +47,6 @@ #self.scope = Scope(copy(scope.dict)) class Group(Node): - """The Group class.""" def __init__(self, expr): self.expr = expr @@ -166,5 +170,7 @@ return Comma(from_dict(d['0']),from_dict(d['1'])) elif tp == 'VAR': return Vars(getlist(d)) + elif tp == 'BLOCK': + return Block(getlist(d)) else: raise NotImplementedError("Dont know how to handler %s" % tp) Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Fri Nov 3 16:19:00 2006 @@ -27,6 +27,16 @@ scope_manager.set_variable(self.identifier.name, val) return val +class __extend__(Block): + def call(self, context=None): + try: + last = w_Undefined + for node in self.nodes: + last = node.call(context) + return last + except ExecutionReturned, e: + return e.value + class __extend__(Call): def call(self, context=None): name = self.identifier.get_literal() @@ -146,15 +156,16 @@ ncontext.assign('arguments', w_Arguments) try: + last = w_Undefined for node in self.nodes: - node.call(ncontext) + last = node.call(ncontext) + return last except ExecutionReturned, e: return e.value - return w_Undefined class __extend__(Semicolon): def call(self, context=None): - self.expr.call(context) + return self.expr.call(context) class __extend__(String): def call(self, context=None): Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Fri Nov 3 16:19:00 2006 @@ -3,6 +3,7 @@ from pypy.lang.js import interpreter from pypy.lang.js.parser import parse from pypy.lang.js.interpreter import ThrowException +from pypy.lang.js.jsobj import W_Number import py.test import sys @@ -18,7 +19,8 @@ # s.call() l = [] interpreter.writer = l.append - Script([Semicolon(Call(Identifier('print', None), List([Number(1), Number(2)])))],[],[]).call() + Script([Semicolon(Call(Identifier('print', None), + List([Number(1), Number(2)])))],[],[]).call() assert l == ['1,2'] def assert_prints(self, code, assval): @@ -30,6 +32,10 @@ l.append("uncaught exception: "+str(excpt.exception)) assert l == assval + def assert_result(self, code, result): + r = code.call() + assert r.ToString() == result.ToString() + def test_interp_parse(self): self.assert_prints(parse_d("print(1+1)"), ["2"]) self.assert_prints(parse_d("print(1+2+3); print(1)"), ["6", "1"]) @@ -40,7 +46,7 @@ self.assert_prints(parse_d("x=3;y=4;print(x+y);"), ["7"]) def test_string_var(self): - self.assert_prints(parse_d("print(\"sss\");"), ["sss"]) + self.assert_prints(parse_d('print(\"sss\");'), ["sss"]) def test_string_concat(self): self.assert_prints(parse_d('x="xxx"; y="yyy"; print(x+y);'), ["xxxyyy"]) @@ -149,7 +155,7 @@ self.assert_prints(parse_d("print((500,3))"), ["3"]) def test_try_catch(self): - py.test.skip('Under Construction') + py.test.skip("not ready yet") self.assert_prints(parse_d(""" try { throw(3); @@ -158,4 +164,8 @@ print(x); } """), ["3"]) + + def test_block(self): + self.assert_result(parse_d("{ 5}"), W_Number(5)) + self.assert_result(parse_d("{3; 5}"), W_Number(5)) \ No newline at end of file From niko at codespeak.net Fri Nov 3 16:26:51 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 3 Nov 2006 16:26:51 +0100 (CET) Subject: [pypy-svn] r34117 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061103152651.1AD801007C@code0.codespeak.net> Author: niko Date: Fri Nov 3 16:26:51 2006 New Revision: 34117 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: (mwh, niko) add a preliminary version of a greedy register allocator Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Fri Nov 3 16:26:51 2006 @@ -44,25 +44,71 @@ class RegisterAllocation: def __init__(self, initial_mapping): self.insns = [] + self.freeregs = gprs[3:] self.reg2var = {} self.var2reg = {} + self.var2spill = {} for var, reg in initial_mapping.iteritems(): self.reg2var[reg] = var self.var2reg[var] = reg self.crfinfo = [(0, 0)] * 8 + self._spill_index = 0 + + def _spill(self): + self._spill_index += 4 + return self._spill_index + + def _allocate_reg(self, newarg, lru): + + # check if there is a register available + if self.freeregs: + reg = self.freeregs.pop() + self.reg2var[reg] = newarg + self.var2reg[newarg] = reg + return reg + + # if not, find something to spill + argtospill = lru.pop(0) + assert argtospill in self.var2reg + spill = self._spill() + reg = self.var2reg[argtospill] # move argtospill to spill slot + self.var2spill[argtospill] = spill + del self.var2reg[argtospill] + self.reg2var[reg] = newarg # assign reg to newarg + self.var2reg[newarg] = reg + self.insns.append(Spill(argtospill, reg, spill)) + return reg + def allocate_for_insns(self, insns): + # Walk through instructions in forward order + lru = [] for insn in insns: + + # put things into the lru + for arg in insn.reg_args: + if arg in lru: + del lru[lru.index(arg)] + lru.append(arg) + + # We need to allocate a register for each used + # argument that is not already in one for i in range(len(insn.reg_args)): arg = insn.reg_args[i] argcls = insn.reg_arg_regclasses[i] - assert arg in self.var2reg + + if arg not in self.var2reg: + # It has no register now because it has been spilled + assert argcls is GP_REGISTER, "uh-oh" + reg = self._allocate_reg(arg, lru) + self.insns.append( + Unspill(arg, reg, self.var2spill[arg])) + del self.var2spill[arg] + + # Need to allocate a register for the destination + assert not insn.result or insn.result not in self.var2reg cand = None if insn.result_regclass is GP_REGISTER: - for cand in gprs[3:]: - if cand not in self.reg2var: - break - if not cand: - assert 0 + cand = self._allocate_reg(insn.result, lru) elif insn.result_regclass is CR_FIELD: assert crfs[0] not in self.reg2var cand = crfs[0] @@ -238,6 +284,38 @@ BO = 4 # jump if relavent bit is NOT set in the CR asm.bcctr(BO, self.bit) +class Unspill(Insn): + """ A special instruction inserted by our register "allocator." It + indicates that we need to load a value from the stack into a register + because we spilled a particular value. """ + def __init__(self, var, reg, offset): + """ + var --- the var we spilled (a Var) + reg --- the reg we spilled it from (an integer) + offset --- the offset on the stack we spilled it to (an integer) + """ + self.var = var + self.reg = reg + self.offset = offset + def emit(self, asm): + asm.lwz(self.reg.number, rSP, self.offset) + +class Spill(Insn): + """ A special instruction inserted by our register "allocator." + It indicates that we need to store a value from the register into + the stack because we spilled a particular value.""" + def __init__(self, var, reg, offset): + """ + var --- the var we are spilling (a Var) + reg --- the reg we are spilling it from (an integer) + offset --- the offset on the stack we are spilling it to (an integer) + """ + self.var = var + self.reg = reg + self.offset = offset + def emit(self, asm): + asm.stw(self.reg.number, rSP, self.offset) + from pypy.jit.codegen.ppc import codebuf_posix as memhandler from ctypes import POINTER, cast, c_char, c_void_p, CFUNCTYPE, c_int @@ -455,7 +533,7 @@ return (gv_result, gv_x.load(self)) def op_int_add(self, gv_x, gv_y): - if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2*16: + if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2**16: gv_result = self.newvar() self.insns.append( Insn_GPR__GPR_IMM(RPPCAssembler.addi, From arigo at codespeak.net Fri Nov 3 16:27:22 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 3 Nov 2006 16:27:22 +0100 (CET) Subject: [pypy-svn] r34118 - in pypy/dist/pypy/rpython: . lltypesystem Message-ID: <20061103152722.487471007F@code0.codespeak.net> Author: arigo Date: Fri Nov 3 16:27:21 2006 New Revision: 34118 Modified: pypy/dist/pypy/rpython/lltypesystem/opimpl.py pypy/dist/pypy/rpython/rlist.py Log: (Re-)introduce asserts in rlist.py. Modified: pypy/dist/pypy/rpython/lltypesystem/opimpl.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/opimpl.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/opimpl.py Fri Nov 3 16:27:21 2006 @@ -362,7 +362,12 @@ def op_debug_assert(expr, *ll_args): if not isinstance(expr, str): - expr = ''.join(expr.chars) + if hasattr(expr, 'chars'): # for lltypesystem + expr = ''.join(expr.chars) + elif hasattr(expr, '_str'): # for ootypesystem + expr = expr._str + else: + raise TypeError("what is %r??" % (expr,)) names = ['v%d' % i for i in range(len(ll_args))] d = dict(zip(names, ll_args)) names = tuple(names) Modified: pypy/dist/pypy/rpython/rlist.py ============================================================================== --- pypy/dist/pypy/rpython/rlist.py (original) +++ pypy/dist/pypy/rpython/rlist.py Fri Nov 3 16:27:21 2006 @@ -6,6 +6,7 @@ from pypy.rpython.rslice import AbstractSliceRepr from pypy.rpython.lltypesystem.lltype import typeOf, Ptr, Void, Signed, Bool from pypy.rpython.lltypesystem.lltype import nullptr, Char, UniChar +from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython import robject from pypy.rlib.objectmodel import malloc_zero_filled from pypy.rpython.annlowlevel import ADTInterface @@ -639,7 +640,8 @@ def ll_listslice_minusone(RESLIST, l1): newlength = l1.ll_length() - 1 - #assert newlength >= 0 # XXX assert doesn't work in ootypesystem + llop.debug_assert(Void, "%s >= 0 # empty list is sliced with [:-1]", + newlength) l = RESLIST.ll_newlist(newlength) j = 0 while j < newlength: @@ -680,8 +682,9 @@ def ll_listsetslice(l1, slice, l2): count = l2.ll_length() - # XXX: assert doesn't work in ootypesystem - #assert count == slice.stop - slice.start, "setslice cannot resize lists in RPython") + llop.debug_assert(Void, + "%s == %s - %s # setslice cannot resize lists in RPython", + count, slice.stop, slice.start) # XXX but it should be easy enough to support, soon start = slice.start j = start From fijal at codespeak.net Fri Nov 3 16:32:30 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 16:32:30 +0100 (CET) Subject: [pypy-svn] r34119 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061103153230.9E35D1007E@code0.codespeak.net> Author: fijal Date: Fri Nov 3 16:32:27 2006 New Revision: 34119 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Log: Fixed a bug and added a test. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py Fri Nov 3 16:32:27 2006 @@ -4,6 +4,20 @@ from pypy.objspace.std.test.test_proxy import AppProxyBasic +class AppTestProxyNoDict(AppProxyBasic): + def setup_method(self, meth): + super(AppTestProxyNoDict, self).setup_method(meth) + self.w_A = self.space.appexec([], """(): + class A(object): + __slots__ = [] + return A + """) + + def test_write_dict(self): + c = self.Controller(self.A()) + obj = proxy(self.A, c.perform) + raises(AttributeError, "obj.__dict__ = {}") + class AppTestProxyObj(AppProxyBasic): def setup_method(self, meth): super(AppTestProxyObj, self).setup_method(meth) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Fri Nov 3 16:32:27 2006 @@ -5,6 +5,7 @@ from pypy.objspace.std.objspace import * from pypy.objspace.std.proxy_helpers import register_type from pypy.interpreter.error import OperationError +from pypy.interpreter import baseobjspace #class W_Transparent(W_Object): # def __init__(self, w_controller): @@ -57,7 +58,7 @@ def setdict(self, space, w_dict): if not self.setdictvalue(space, space.wrap('__dict__'), w_dict): - W_Root.setdict(self, space, w_dict) + baseobjspace.W_Root.setdict(self, space, w_dict) from pypy.objspace.std.objecttype import object_typedef as typedef From arigo at codespeak.net Fri Nov 3 16:33:00 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 3 Nov 2006 16:33:00 +0100 (CET) Subject: [pypy-svn] r34120 - in pypy/dist/pypy/rlib: . test Message-ID: <20061103153300.A72E110080@code0.codespeak.net> Author: arigo Date: Fri Nov 3 16:32:54 2006 New Revision: 34120 Modified: pypy/dist/pypy/rlib/streamio.py pypy/dist/pypy/rlib/test/test_streamio.py Log: (cfbolz, anto, arigo) Fix a non-RPython construct. Modified: pypy/dist/pypy/rlib/streamio.py ============================================================================== --- pypy/dist/pypy/rlib/streamio.py (original) +++ pypy/dist/pypy/rlib/streamio.py Fri Nov 3 16:32:54 2006 @@ -404,7 +404,8 @@ cutoff = len(data) - (k-n) assert cutoff >= 0 lines.append(data[:cutoff]) - self.lines[:i+1] = [data[cutoff:]] + del self.lines[:i] + self.lines[0] = data[cutoff:] return "\n".join(lines) k += 1 i += 1 Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 16:32:54 2006 @@ -138,7 +138,7 @@ base.seek = f return streamio.BufferingInputStream(base, bufsize) - def Xtest_readline(self): + def test_readline(self): for file in [self.makeStream(), self.makeStream(bufsize=1)]: def f(): i = 0 @@ -176,7 +176,7 @@ res = self.interpret(f, []) assert res - def Xtest_read_1_after_readline(self): + def test_read_1_after_readline(self): file = self.makeStream() def f(): if not file.readline() == "ab\n": @@ -246,7 +246,7 @@ res = self.interpret(f, []) assert res - def Xtest_read_4_after_readline(self): + def test_read_4_after_readline(self): file = self.makeStream() def f(): os.write(1, "1\n") @@ -304,7 +304,7 @@ res = self.interpret(f, []) assert res - def Xtest_tell_1_after_readline(self): + def test_tell_1_after_readline(self): file = self.makeStream(tell=True) def f(): pos = 0 @@ -370,7 +370,7 @@ res = self.interpret(f, []) assert res - def Xtest_seek(self): + def test_seek(self): file = self.makeStream(tell=True, seek=True) def f(): all = file.readall() From fijal at codespeak.net Fri Nov 3 16:41:08 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 16:41:08 +0100 (CET) Subject: [pypy-svn] r34121 - pypy/branch/transparent-proxy/pypy/objspace/std Message-ID: <20061103154108.4A96E10076@code0.codespeak.net> Author: fijal Date: Fri Nov 3 16:41:06 2006 New Revision: 34121 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: simple solution. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Fri Nov 3 16:41:06 2006 @@ -7,6 +7,7 @@ from pypy.interpreter.error import OperationError from pypy.objspace.std.tlistobject import W_TransparentList, W_TransparentDict,\ W_Transparent +from pypy.objspace.std.typeobject import W_TypeObject def proxy(space, w_type, w_controller): if not space.is_true(space.callable(w_controller)): @@ -16,8 +17,9 @@ return W_TransparentList(space, w_type, w_controller) if space.is_true(space.issubtype(w_type, space.w_dict)): return W_TransparentDict(space, w_type, w_controller) - if w_type.instancetypedef is space.w_object.instancetypedef: - return W_Transparent(space, w_type, w_controller) + if isinstance(w_type, W_TypeObject): + if w_type.instancetypedef is space.w_object.instancetypedef: + return W_Transparent(space, w_type, w_controller) #return type_cache[w_type or w_type.w_bestbase] raise OperationError(space.w_TypeError, space.wrap("Object type %s could not"\ "be wrapped (YET)" % w_type.getname(space, "?"))) From antocuni at codespeak.net Fri Nov 3 16:45:13 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 3 Nov 2006 16:45:13 +0100 (CET) Subject: [pypy-svn] r34122 - pypy/dist/pypy/rlib/test Message-ID: <20061103154513.31D331007B@code0.codespeak.net> Author: antocuni Date: Fri Nov 3 16:45:12 2006 New Revision: 34122 Modified: pypy/dist/pypy/rlib/test/test_streamio.py Log: More tests using the llinterpreter. Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 16:45:12 2006 @@ -456,60 +456,79 @@ for want, got, pos in self.source.chunks: assert want >= 4 -class TestBufferingOutputStream: +class BaseTestBufferingOutputStream(BaseRtypingTest): def test_write(self): - base = TWriter() - filter = streamio.BufferingOutputStream(base, 4) - filter.write("123") - assert not base.chunks - assert filter.tell() == 3 - filter.write("456") - filter.write("789ABCDEF") - filter.write("0123") - assert filter.tell() == 19 - filter.close() - assert base.buf == "123456789ABCDEF0123" - for chunk in base.chunks[:-1]: - assert len(chunk[1]) >= 4 + def f(): + base = TWriter() + filter = streamio.BufferingOutputStream(base, 4) + filter.write("123") + assert not base.chunks + assert filter.tell() == 3 + filter.write("456") + filter.write("789ABCDEF") + filter.write("0123") + assert filter.tell() == 19 + filter.close() + assert base.buf == "123456789ABCDEF0123" + for chunk in base.chunks[:-1]: + assert len(chunk[1]) >= 4 + self.interpret(f, []) def test_write_seek(self): - base = TWriter() - filter = streamio.BufferingOutputStream(base, 4) - filter.write("x"*6) - filter.seek(3) - filter.write("y"*2) - filter.close() - assert base.buf == "x"*3 + "y"*2 + "x"*1 + def f(): + base = TWriter() + filter = streamio.BufferingOutputStream(base, 4) + filter.write("x"*6) + filter.seek(3) + filter.write("y"*2) + filter.close() + assert base.buf == "x"*3 + "y"*2 + "x"*1 + self.interpret(f, []) def test_write_seek_beyond_end(self): "Linux behaviour. May be different on other platforms." - base = TWriter() - filter = streamio.BufferingOutputStream(base, 4) - filter.seek(3) - filter.write("y"*2) - filter.close() - assert base.buf == "\0"*3 + "y"*2 + def f(): + base = TWriter() + filter = streamio.BufferingOutputStream(base, 4) + filter.seek(3) + filter.write("y"*2) + filter.close() + assert base.buf == "\0"*3 + "y"*2 + self.interpret(f, []) def test_truncate(self): "Linux behaviour. May be different on other platforms." - base = TWriter() - filter = streamio.BufferingOutputStream(base, 4) - filter.write('x') - filter.truncate(4) - filter.write('y') - filter.close() - assert base.buf == 'xy' + '\0' * 2 + def f(): + base = TWriter() + filter = streamio.BufferingOutputStream(base, 4) + filter.write('x') + filter.truncate(4) + filter.write('y') + filter.close() + assert base.buf == 'xy' + '\0' * 2 + self.interpret(f, []) def test_truncate2(self): "Linux behaviour. May be different on other platforms." - base = TWriter() - filter = streamio.BufferingOutputStream(base, 4) - filter.write('12345678') - filter.truncate(4) - filter.write('y') - filter.close() - assert base.buf == '1234' + '\0' * 4 + 'y' + def f(): + base = TWriter() + filter = streamio.BufferingOutputStream(base, 4) + filter.write('12345678') + filter.truncate(4) + filter.write('y') + filter.close() + assert base.buf == '1234' + '\0' * 4 + 'y' + self.interpret(f, []) + +class TestBufferingOutputStream(BaseTestBufferingOutputStream): + def interpret(self, func, args, **kwds): + return func(*args) + +class TestBufferingOutputStreamLLinterp(BaseTestBufferingOutputStream, + LLRtypeMixin): + pass + class TestLineBufferingOutputStreamTests: From fijal at codespeak.net Fri Nov 3 16:55:40 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 16:55:40 +0100 (CET) Subject: [pypy-svn] r34123 - in pypy/dist/pypy: annotation annotation/test tool Message-ID: <20061103155540.2D00E10034@code0.codespeak.net> Author: fijal Date: Fri Nov 3 16:55:38 2006 New Revision: 34123 Modified: pypy/dist/pypy/annotation/annrpython.py pypy/dist/pypy/annotation/specialize.py pypy/dist/pypy/annotation/test/test_annrpython.py pypy/dist/pypy/tool/error.py Log: Fixed a bit displaying of annotation errors. Added more specialisation possibilities. Modified: pypy/dist/pypy/annotation/annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/annrpython.py (original) +++ pypy/dist/pypy/annotation/annrpython.py Fri Nov 3 16:55:38 2006 @@ -312,7 +312,7 @@ graph = position_key[0] msgstr = format_someobject_error(self, position_key, what, s_value, - called_from_graph) + called_from_graph, self.bindings[what]) raise AnnotatorError(msgstr) Modified: pypy/dist/pypy/annotation/specialize.py ============================================================================== --- pypy/dist/pypy/annotation/specialize.py (original) +++ pypy/dist/pypy/annotation/specialize.py Fri Nov 3 16:55:38 2006 @@ -377,9 +377,9 @@ key = tuple([args_s[i].const for i in argindices]) return funcdesc.cachedgraph(key) -def specialize_argtype(funcdesc, args_s, i): - key = args_s[i].knowntype - return funcdesc.cachedgraph(key) +def specialize_argtype(funcdesc, args_s, *argindices): + key = tuple([args_s[i].knowntype for i in argindices]) + return funcdesc.cachedgraph(key) def specialize_arglistitemtype(funcdesc, args_s, i): s = args_s[i] Modified: pypy/dist/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_annrpython.py (original) +++ pypy/dist/pypy/annotation/test/test_annrpython.py Fri Nov 3 16:55:38 2006 @@ -1006,6 +1006,42 @@ assert a.binding(graph2.getreturnvar()).classdef == C2df assert graph1 in a.translator.graphs assert graph2 in a.translator.graphs + + def test_specialcase_args(self): + class C1(object): + pass + + class C2(object): + pass + + def alloc(cls, cls2): + i = cls() + assert isinstance(i, cls) + j = cls2() + assert isinstance(j, cls2) + return i + + def f(): + alloc(C1, C1) + alloc(C1, C2) + alloc(C2, C1) + alloc(C2, C2) + + alloc._annspecialcase_ = "specialize:arg(0,1)" + + a = self.RPythonAnnotator() + C1df = a.bookkeeper.getuniqueclassdef(C1) + C2df = a.bookkeeper.getuniqueclassdef(C2) + s = a.build_types(f, []) + allocdesc = a.bookkeeper.getdesc(alloc) + s_C1 = a.bookkeeper.immutablevalue(C1) + s_C2 = a.bookkeeper.immutablevalue(C2) + graph1 = allocdesc.specialize([s_C1, s_C2]) + graph2 = allocdesc.specialize([s_C2, s_C2]) + assert a.binding(graph1.getreturnvar()).classdef == C1df + assert a.binding(graph2.getreturnvar()).classdef == C2df + assert graph1 in a.translator.graphs + assert graph2 in a.translator.graphs def test_assert_list_doesnt_lose_info(self): class T(object): Modified: pypy/dist/pypy/tool/error.py ============================================================================== --- pypy/dist/pypy/tool/error.py (original) +++ pypy/dist/pypy/tool/error.py Fri Nov 3 16:55:38 2006 @@ -99,7 +99,7 @@ text.append(gather_error(annotator, block, graph)) return '\n'.join(text) -def format_someobject_error(annotator, position_key, what, s_value, called_from_graph): +def format_someobject_error(annotator, position_key, what, s_value, called_from_graph, binding=""): #block = getattr(annotator, 'flowin_block', None) or block msg = ["annotation of %r degenerated to SomeObject()" % (what,)] if position_key is not None: @@ -111,6 +111,8 @@ if s_value.origin is not None: msg.append(".. SomeObject() origin: %s" % ( annotator.whereami(s_value.origin),)) + msg.append("Previous annotation:") + msg.append(" " + str(binding)) return "\n".join(msg) def format_global_error(graph, offset, message): From rxe at codespeak.net Fri Nov 3 16:56:33 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 16:56:33 +0100 (CET) Subject: [pypy-svn] r34124 - in pypy/dist/pypy/jit/hintannotator: . test Message-ID: <20061103155633.12C281006E@code0.codespeak.net> Author: rxe Date: Fri Nov 3 16:56:27 2006 New Revision: 34124 Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py pypy/dist/pypy/jit/hintannotator/model.py pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Log: specialize calls with deepfrozen arguments. add deepfrozen to constructor on SomeLLAbstractConstant. Propgate some more deepfrozen in some places. (arre, rxe) Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/bookkeeper.py (original) +++ pypy/dist/pypy/jit/hintannotator/bookkeeper.py Fri Nov 3 16:56:27 2006 @@ -175,6 +175,14 @@ specialize = True else: key.append('x') + + if (isinstance(arg_hs, hintmodel.SomeLLAbstractConstant) + and arg_hs.deepfrozen): + key.append('D') + specialize = True + else: + key.append('x') + if specialize: return ''.join(key) else: Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Fri Nov 3 16:56:27 2006 @@ -134,13 +134,14 @@ class SomeLLAbstractConstant(SomeLLAbstractValue): " color: dont know yet.. " - deepfrozen = False - - def __init__(self, T, origins, eager_concrete=False, myorigin=None): + + def __init__(self, T, origins, eager_concrete=False, myorigin=None, + deepfrozen=False): SomeLLAbstractValue.__init__(self, T) self.origins = origins self.eager_concrete = eager_concrete self.myorigin = myorigin + self.deepfrozen = deepfrozen assert myorigin is None or myorigin.spaceop is not None def fmt_origins(self, origins): @@ -235,7 +236,9 @@ if isinstance(hs_dep, SomeLLAbstractConstant)] d = newset({getbookkeeper().myorigin(): True}, *deps_origins) - return SomeLLAbstractConstant(hs_v1.concretetype, d, eager_concrete=hs_v1.eager_concrete) + return SomeLLAbstractConstant(hs_v1.concretetype, d, + eager_concrete=hs_v1.eager_concrete, + deepfrozen=hs_v1.deepfrozen) else: return hs_v1 @@ -256,8 +259,6 @@ def hint(hs_v1, hs_flags): if hs_flags.const.get('variable', False): # only for testing purposes!!! return SomeLLAbstractVariable(hs_v1.concretetype) - if hs_flags.const.get('concrete', False): - raise HintError("cannot make a concrete from %r" % (hs_v1,)) if hs_flags.const.get('forget', False): # turn a variable to a constant origin = getbookkeeper().myorigin() @@ -266,7 +267,9 @@ hs_concrete = SomeLLAbstractConstant(hs_v1.concretetype, {}) hs_concrete.eager_concrete = True return hs_concrete - + raise HintError("hint %s makes no sense on %r" % (hs_flags.const, + hs_v1)) + def getfield(hs_v1, hs_fieldname): S = hs_v1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) @@ -329,10 +332,9 @@ assert isinstance(hs_c1, SomeLLAbstractConstant) return reorigin(hs_c1) if hs_flags.const.get('deepfreeze', False): - hs_concrete = SomeLLAbstractConstant(hs_c1.concretetype, - hs_c1.origins) - hs_concrete.deepfrozen = True - return hs_concrete + return SomeLLAbstractConstant(hs_c1.concretetype, + hs_c1.origins, + deepfrozen = True) return SomeLLAbstractValue.hint(hs_c1, hs_flags) def direct_call(hs_f1, *args_hs): @@ -349,6 +351,7 @@ # don't try to annotate suggested_primitive graphs if getattr(getattr(fnobj, '_callable', None), 'suggested_primitive', False): return SomeLLAbstractVariable(lltype.typeOf(fnobj).RESULT) + # normal call if not hasattr(fnobj, 'graph'): raise NotImplementedError("XXX call to externals or primitives") @@ -359,7 +362,7 @@ if isinstance(hs_res, SomeLLAbstractConstant): hs_res.myorigin = bookkeeper.myorigin() hs_res.myorigin.is_call_result = True - + # we need to make sure that hs_res does not become temporarily less # general as a result of calling another specialized version of the # function @@ -371,11 +374,10 @@ if S._hints.get('immutable', False) or hs_c1.deepfrozen: origin = getbookkeeper().myorigin() d = setadd(hs_c1.origins, origin) - res = SomeLLAbstractConstant(FIELD_TYPE, d, - eager_concrete=hs_c1.eager_concrete, - myorigin=origin) - res.deepfrozen = hs_c1.deepfrozen - return res + return SomeLLAbstractConstant(FIELD_TYPE, d, + eager_concrete=hs_c1.eager_concrete, + myorigin=origin, + deepfrozen=hs_c1.deepfrozen) else: return SomeLLAbstractVariable(FIELD_TYPE) @@ -384,10 +386,9 @@ SUB_TYPE = getattr(S, hs_fieldname.const) origin = getbookkeeper().myorigin() d = setadd(hs_c1.origins, origin) - res = SomeLLAbstractConstant(lltype.Ptr(SUB_TYPE), d, myorigin=origin) - res.deepfrozen = hs_c1.deepfrozen - return res - + return SomeLLAbstractConstant(lltype.Ptr(SUB_TYPE), d, + myorigin=origin, + deepfrozen=hs_c1.deepfrozen) class __extend__(SomeLLAbstractContainer): @@ -455,7 +456,8 @@ return SomeLLAbstractConstant(hs_c1.concretetype, d, eager_concrete = hs_c1.eager_concrete and hs_c2.eager_concrete, - myorigin = myorigin) + myorigin = myorigin, + deepfrozen = hs_c1.deepfrozen and hs_c2.deepfrozen) def getarrayitem((hs_c1, hs_index)): @@ -464,11 +466,10 @@ if A._hints.get('immutable', False) or hs_c1.deepfrozen: origin = getbookkeeper().myorigin() d = newset(hs_c1.origins, hs_index.origins, {origin: True}) - res = SomeLLAbstractConstant(READ_TYPE, d, - eager_concrete=hs_c1.eager_concrete, - myorigin=origin) - res.deepfrozen = hs_c1.deepfrozen - return res + return SomeLLAbstractConstant(READ_TYPE, d, + eager_concrete=hs_c1.eager_concrete, + myorigin=origin, + deepfrozen=hs_c1.deepfrozen) else: return SomeLLAbstractVariable(READ_TYPE) @@ -573,6 +574,7 @@ return SomeLLAbstractVariable(RESTYPE) def const_unary(hs_c1): + #XXX unsure hacks bk = getbookkeeper() origin = bk.myorigin() d = setadd(hs_c1.origins, origin) @@ -580,8 +582,10 @@ return SomeLLAbstractConstant(RESTYPE, d, eager_concrete = hs_c1.eager_concrete, myorigin = origin) + #deepfrozen = hs_c1.deepfrozen) def const_binary((hs_c1, hs_c2)): + #XXX unsure hacks bk = getbookkeeper() origin = bk.myorigin() d = newset(hs_c1.origins, hs_c2.origins, {origin: True}) @@ -590,6 +594,7 @@ eager_concrete = hs_c1.eager_concrete or hs_c2.eager_concrete, myorigin = origin) + #deepfrozen = hs_c1.deepfrozen and hs_c2.deepfrozen) def setup(oplist, ValueCls, var_fn, ConstantCls, const_fn): for name in oplist: Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Fri Nov 3 16:56:27 2006 @@ -18,6 +18,9 @@ P_OOPSPEC_NOVIRTUAL.oopspec = True P_OOPSPEC_NOVIRTUAL.novirtualcontainer = True +P_NOVIRTUAL = AnnotatorPolicy() +P_NOVIRTUAL.novirtualcontainer = True + def hannotate(func, argtypes, policy=None, annotator=False, inline=None, backendoptimize=False): # build the normal ll graphs for ll_function @@ -96,7 +99,31 @@ hs = hannotate(ll_function, [annmodel.SomePtr(lltype.Ptr(A)), int]) assert type(hs) is SomeLLAbstractVariable assert hs.concretetype == lltype.Signed - + +def test_lists_deepfreeze(): + + l1 = [1,2,3,4,5] + l2 = [6,7,8,9,10] + + def getlist(n): + if n: + return l1 + else: + return l2 + + def ll_function(n, i): + l = getlist(n) + l = hint(l, deepfreeze=True) + + res = l[i] + res = hint(res, concrete=True) + + res = hint(res, variable=True) + return res + + hs = hannotate(ll_function, [int, int], policy=P_NOVIRTUAL) + assert hs.concretetype == lltype.Signed + def test_simple_hint_origins(): def ll_function(cond, x,y): if cond: @@ -429,8 +456,9 @@ ll_add_graph = graphof(ha.base_translator, ll_add) gdesc = ha.bookkeeper.getdesc(ll_add_graph) assert len(gdesc._cache) == 2 - assert 'Ex' in gdesc._cache - v1, v2 = gdesc._cache['Ex'].getargs() + assert 'Exxx' in gdesc._cache + v1, v2 = gdesc._cache['Exxx'].getargs() + assert isinstance(ha.binding(v1), SomeLLAbstractConstant) assert isinstance(ha.binding(v2), SomeLLAbstractConstant) assert ha.binding(v1).eager_concrete From fijal at codespeak.net Fri Nov 3 17:05:07 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 17:05:07 +0100 (CET) Subject: [pypy-svn] r34125 - pypy/branch/transparent-proxy/pypy/interpreter Message-ID: <20061103160507.0289410070@code0.codespeak.net> Author: fijal Date: Fri Nov 3 17:05:06 2006 New Revision: 34125 Modified: pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py Log: (arigo, fijal) - small fix for translation. Modified: pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py Fri Nov 3 17:05:06 2006 @@ -27,6 +27,24 @@ return space.finditem(w_dict, w_attr) return None + def setdictvalue(self, space, w_attr, w_value): + w_dict = self.getdict() + if w_dict is not None: + space.set_str_keyed_item(w_dict, w_attr, w_value) + return True + return False + + def deldictvalue(self, space, w_name): + w_dict = self.getdict() + if w_dict is not None: + try: + space.delitem(w_dict, w_name) + return True + except OperationError, ex: + if not ex.match(space, space.w_KeyError): + raise + return False + def setdict(self, space, w_dict): typename = space.type(self).getname(space, '?') raise OperationError(space.w_TypeError, From santagada at codespeak.net Fri Nov 3 17:06:35 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Fri, 3 Nov 2006 17:06:35 +0100 (CET) Subject: [pypy-svn] r34126 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061103160635.39AEE10070@code0.codespeak.net> Author: santagada Date: Fri Nov 3 17:06:34 2006 New Revision: 34126 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) Trying to make try work... broken Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Fri Nov 3 17:06:34 2006 @@ -105,6 +105,14 @@ def __init__(self, exception): self.exception = exception +class Try(Node): + """The Try class.""" + def __init__(self, tryblock, catchblock, finallyblock, catchparam): + self.tryblock = tryblock + self.catchblock = catchblock + self.finallyblock = finallyblock + self.catchparam = catchparam + class Vars(Node): def __init__(self, nodes): @@ -172,5 +180,16 @@ return Vars(getlist(d)) elif tp == 'BLOCK': return Block(getlist(d)) + elif tp == 'TRY': + finallyblock = None + catchblock = None + catchparam = '' + if 'finallyBlock' in d: + finallyblock = from_dict(d['finallyBlock']) + if 'catchClauses' in d: + #multiple catch clauses is a spidermonkey extension + catchblock = from_dict(d['catchClauses']['block']) + catchparam = d['catchClauses']['varName'] + return Try(from_dict(d['tryBlock']), catchblock, finallyblock, catchparam) else: raise NotImplementedError("Dont know how to handler %s" % tp) Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Fri Nov 3 17:06:34 2006 @@ -43,12 +43,6 @@ if name == 'print': writer(",".join([i.ToString() for i in self.arglist.call(context)])) else: - # #import pdb;pdb.set_trace() - -# # -# retval = self.body.call() -# #scope_manager.current_scope = backup_scope -# return retval backup_scope = scope_manager.current_scope w_obj = scope_manager.get_variable(name) scope_manager.current_scope = w_obj.function.scope @@ -138,7 +132,6 @@ num_right = prim_right.ToNumber() # XXX: obey all the rules return W_Number(num_left + num_right) - #return self.left.call(context).add(self.right.call(context)) class __extend__(Script): def call(self, context=None, args=(), this=None, params=None): @@ -181,7 +174,32 @@ class __extend__(Throw): def call(self, context=None): raise ThrowException(self.exception.call(context)) - + +class __extend__(Try): + def call(self, context=None): + e = None + try: + tryresult = self.tryblock.call(context) + except ThrowException, e: + e = e + ncontext = ExecutionContext(context) + print "tried to catch it :)" + ncontext.assign(self.catchparam, e.exception) + if self.catchblock is not None: + tryresult = self.catchblock.call(ncontext) + + print self.finallyblock + if self.finallyblock is not None: + print "asdasd" + tryresult = self.finallyblock.call(context) + print "saddsa" + print a + #if there is no catchblock reraise the exception + if (e is not None) and (self.catchblock is not None): + raise e + + return tryresult + class __extend__(Vars): def call(self, context=None): for var in self.nodes: Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Fri Nov 3 17:06:34 2006 @@ -155,7 +155,6 @@ self.assert_prints(parse_d("print((500,3))"), ["3"]) def test_try_catch(self): - py.test.skip("not ready yet") self.assert_prints(parse_d(""" try { throw(3); From santagada at codespeak.net Fri Nov 3 17:15:00 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Fri, 3 Nov 2006 17:15:00 +0100 (CET) Subject: [pypy-svn] r34127 - pypy/dist/pypy/lang/js Message-ID: <20061103161500.47E0110070@code0.codespeak.net> Author: santagada Date: Fri Nov 3 17:14:57 2006 New Revision: 34127 Modified: pypy/dist/pypy/lang/js/interpreter.py Log: (stephan, santagada, richard) Try block working Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Fri Nov 3 17:14:57 2006 @@ -14,6 +14,7 @@ class ThrowException(Exception): def __init__(self, exception): self.exception = exception + self.args = self.exception class __extend__(Array): @@ -180,22 +181,18 @@ e = None try: tryresult = self.tryblock.call(context) - except ThrowException, e: - e = e + except ThrowException, excpt: + e = excpt ncontext = ExecutionContext(context) - print "tried to catch it :)" ncontext.assign(self.catchparam, e.exception) if self.catchblock is not None: tryresult = self.catchblock.call(ncontext) - print self.finallyblock if self.finallyblock is not None: - print "asdasd" tryresult = self.finallyblock.call(context) - print "saddsa" - print a + #if there is no catchblock reraise the exception - if (e is not None) and (self.catchblock is not None): + if (e is not None) and (self.catchblock is None): raise e return tryresult From santagada at codespeak.net Fri Nov 3 17:17:49 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Fri, 3 Nov 2006 17:17:49 +0100 (CET) Subject: [pypy-svn] r34128 - pypy/dist/pypy/lang/js/test Message-ID: <20061103161749.266B610070@code0.codespeak.net> Author: santagada Date: Fri Nov 3 17:17:48 2006 New Revision: 34128 Modified: pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) One more test for the try block Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Fri Nov 3 17:17:48 2006 @@ -167,4 +167,17 @@ def test_block(self): self.assert_result(parse_d("{ 5}"), W_Number(5)) self.assert_result(parse_d("{3; 5}"), W_Number(5)) + + def test_try_catch_finally(self): + self.assert_prints(parse_d(""" + try { + throw(3); + } + catch (x) { + print(x); + } + finally { + print(5) + } + """), ["3", "5"]) \ No newline at end of file From rxe at codespeak.net Fri Nov 3 17:18:33 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 17:18:33 +0100 (CET) Subject: [pypy-svn] r34129 - pypy/dist/pypy/jit/hintannotator/test Message-ID: <20061103161833.11B8610076@code0.codespeak.net> Author: rxe Date: Fri Nov 3 17:18:31 2006 New Revision: 34129 Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Log: add a test to specialize deepfreezing call - pls review\! Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Fri Nov 3 17:18:31 2006 @@ -464,6 +464,41 @@ assert ha.binding(v1).eager_concrete assert not ha.binding(v2).is_fixed() +def test_specialize_deepfreeze_calls(): + + l1 = [1,2,3,4,5] + l2 = [6,7,8,9,10] + + def getlist(n): + if n: + return l1 + else: + return l2 + + def ll_get(l, i): + return l[i] + + def ll_function(n, i): + l = getlist(n) + l = hint(l, deepfreeze=True) + + res = ll_get(l, i) + return res + + hs, ha = hannotate(ll_function, [int, int], annotator=True, policy=P_NOVIRTUAL) + assert hs.deepfrozen + assert hs.concretetype == lltype.Signed + ll_get_graph = graphof(ha.base_translator, ll_get) + gdesc = ha.bookkeeper.getdesc(ll_get_graph) + assert len(gdesc._cache) == 1 + assert 'xDxx' in gdesc._cache + v1, v2 = gdesc._cache['xDxx'].getargs() + + assert isinstance(ha.binding(v1), SomeLLAbstractConstant) + assert isinstance(ha.binding(v2), SomeLLAbstractConstant) + assert ha.binding(v1).deepfrozen + assert not ha.binding(v2).is_fixed() + def test_propagate_fixing_across_func_arguments(): def ll_func2(z): z = hint(z, concrete=True) From rxe at codespeak.net Fri Nov 3 17:22:40 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 17:22:40 +0100 (CET) Subject: [pypy-svn] r34130 - pypy/dist/pypy/jit/hintannotator/test Message-ID: <20061103162240.C410210070@code0.codespeak.net> Author: rxe Date: Fri Nov 3 17:22:37 2006 New Revision: 34130 Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Log: ensure we specialize by adding another call case. - (arre, rxe) Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Fri Nov 3 17:22:37 2006 @@ -480,8 +480,10 @@ def ll_function(n, i): l = getlist(n) - l = hint(l, deepfreeze=True) + l2 = ll_get(l, 0) + + l = hint(l, deepfreeze=True) res = ll_get(l, i) return res @@ -490,14 +492,13 @@ assert hs.concretetype == lltype.Signed ll_get_graph = graphof(ha.base_translator, ll_get) gdesc = ha.bookkeeper.getdesc(ll_get_graph) - assert len(gdesc._cache) == 1 + assert len(gdesc._cache) == 2 assert 'xDxx' in gdesc._cache v1, v2 = gdesc._cache['xDxx'].getargs() assert isinstance(ha.binding(v1), SomeLLAbstractConstant) assert isinstance(ha.binding(v2), SomeLLAbstractConstant) assert ha.binding(v1).deepfrozen - assert not ha.binding(v2).is_fixed() def test_propagate_fixing_across_func_arguments(): def ll_func2(z): From cfbolz at codespeak.net Fri Nov 3 17:27:40 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 17:27:40 +0100 (CET) Subject: [pypy-svn] r34131 - pypy/dist/pypy/rlib Message-ID: <20061103162740.C393910070@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 17:27:38 2006 New Revision: 34131 Modified: pypy/dist/pypy/rlib/streamio.py Log: fix rtyping Modified: pypy/dist/pypy/rlib/streamio.py ============================================================================== --- pypy/dist/pypy/rlib/streamio.py (original) +++ pypy/dist/pypy/rlib/streamio.py Fri Nov 3 17:27:38 2006 @@ -528,10 +528,12 @@ if datalen + buflen < self.bufsize: self.buf += data elif buflen: - self.buf += data[:self.bufsize-buflen] + slice = self.bufsize - buflen + assert slice >= 0 + self.buf += data[:slice] self.do_write(self.buf) self.buf = "" - self.write(data[self.bufsize-buflen:]) + self.write(data[slice:]) else: self.do_write(data) From cfbolz at codespeak.net Fri Nov 3 17:53:03 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 17:53:03 +0100 (CET) Subject: [pypy-svn] r34132 - pypy/dist/pypy/rlib/test Message-ID: <20061103165303.7DBFA1006F@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 17:52:59 2006 New Revision: 34132 Modified: pypy/dist/pypy/rlib/test/test_streamio.py Log: (cfbolz, arigo around) convert more tests, that pass immediately Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 17:52:59 2006 @@ -34,8 +34,7 @@ self.pos = 0 while self.pos < offset: data = self.read(offset - self.pos) - if not data: - break + assert data assert self.pos == offset def read(self, n): @@ -72,8 +71,10 @@ self.buf += "\0" * (self.pos - len(self.buf)) + data self.pos = len(self.buf) else: - self.buf = (self.buf[:self.pos] + data + - self.buf[self.pos + len(data):]) + start = self.pos + assert start >= 0 + self.buf = (self.buf[:start] + data + + self.buf[start + len(data):]) self.pos += len(data) def tell(self): @@ -109,13 +110,17 @@ class TReaderWriter(TWriter): def read(self, n=-1): + start = self.pos + assert start >= 0 if n < 1: - result = self.buf[self.pos: ] + result = self.buf[start: ] self.pos = len(self.buf) else: - if self.pos + n > len(self.buf): - n = len(self.buf) - self.pos - result = self.buf[self.pos: self.pos+n] + if n > len(self.buf) - start: + n = len(self.buf) - start + stop = start + n + assert stop >= 0 + result = self.buf[start: stop] self.pos += n return result @@ -136,6 +141,7 @@ base.tell = f if not seek: base.seek = f + return streamio.BufferingInputStream(base, bufsize) def test_readline(self): @@ -179,10 +185,8 @@ def test_read_1_after_readline(self): file = self.makeStream() def f(): - if not file.readline() == "ab\n": - return False - if not file.readline() == "def\n": - return False + assert file.readline() == "ab\n" + assert file.readline() == "def\n" os.write(1, "3\n") blocks = [] while 1: @@ -193,8 +197,7 @@ break os.write(1, "5\n") blocks.append(block) - if not file.read(0) == "": - return False + assert file.read(0) == "" os.write(1, "6\n") return "".join(blocks) == "".join(self.lines)[7:] res = self.interpret(f, []) @@ -209,8 +212,7 @@ if not block: break blocks.append(block) - if not file.read(0) == "": - return False + assert file.read(0) == "" return "".join(blocks) == "".join(self.lines) res = self.interpret(f, []) assert res @@ -224,8 +226,7 @@ if not block: break blocks.append(block) - if not file.read(0) == "": - return False + assert file.read(0) == "" return blocks == ["ab", "\nd", "ef", "\nx", "y\n", "pq", "\nu", "vw", "x"] res = self.interpret(f, []) @@ -240,8 +241,7 @@ if not block: break blocks.append(block) - if not file.read(0) == "": - return True + assert file.read(0) == "" return blocks == ["ab\nd", "ef\nx", "y\npq", "\nuvw", "x"] res = self.interpret(f, []) assert res @@ -251,13 +251,9 @@ def f(): os.write(1, "1\n") res = file.readline() - if not res == "ab\n": - os.write(1, "1f\nxxx" + res + "yyy\n" + str(len(res)) + "\n") - return False + assert res == "ab\n" os.write(1, "2\n") - if not file.readline() == "def\n": - os.write(1, "2f\n") - return False + assert file.readline() == "def\n" os.write(1, "3\n") blocks = [file.read(4)] while 1: @@ -266,9 +262,7 @@ break blocks.append(block) os.write(1, "4\n") - if not file.read(0) == "": - os.write(1, "4f\n") - return False + assert file.read(0) == "" os.write(1, "5\n") for element in blocks: os.write(1, element + "XXX\n") @@ -294,8 +288,7 @@ def f(): pos = 0 while 1: - if not file.tell() == pos: - return False + assert file.tell() == pos n = len(file.read(1)) if not n: break @@ -309,14 +302,11 @@ def f(): pos = 0 pos += len(file.readline()) - if not file.tell() == pos: - return False + assert file.tell() == pos pos += len(file.readline()) - if not file.tell() == pos: - return False + assert file.tell() == pos while 1: - if not file.tell() == pos: - return False + assert file.tell() == pos n = len(file.read(1)) if not n: break @@ -330,8 +320,7 @@ def f(): pos = 0 while 1: - if not file.tell() == pos: - return False + assert file.tell() == pos n = len(file.read(2)) if not n: break @@ -345,8 +334,7 @@ def f(): pos = 0 while 1: - if not file.tell() == pos: - return False + assert file.tell() == pos n = len(file.read(4)) if not n: break @@ -360,8 +348,7 @@ def f(): pos = 0 while 1: - if not file.tell() == pos: - return False + assert file.tell() == pos n = len(file.readline()) if not n: break @@ -379,11 +366,9 @@ for seekto in range(0, end+1): for whence in [0, 1, 2]: file.seek(0) - if not file.tell() == 0: - return False + assert file.tell() == 0 head = file.read(readto) - if not head == all[:readto]: - return False + assert head == all[:readto] if whence == 1: offset = seekto - readto elif whence == 2: @@ -392,11 +377,9 @@ offset = seekto file.seek(offset, whence) here = file.tell() - if not here == seekto: - return False + assert here == seekto rest = file.readall() - if not rest == all[seekto:]: - return False + assert rest == all[seekto:] return True res = self.interpret(f, []) assert res @@ -412,8 +395,7 @@ base = TSource(self.packets) file = streamio.BufferingInputStream(base) head = file.read(readto) - if not head == all[:readto]: - return False + assert head == all[:readto] offset = 42 # for the flow space if whence == 1: offset = seekto - readto @@ -624,51 +606,55 @@ assert file.tell() == len("BooHoo\nBarf\na\nb\nc\n") - - - -class TestBufferingInputOutputStreamTests: +class BaseTestBufferingInputOutputStreamTests(BaseRtypingTest): def test_write(self): import sys base = TReaderWriter() filter = streamio.BufferingInputStream( streamio.BufferingOutputStream(base, 4), 4) - filter.write("123456789") - for chunk in base.chunks: - assert len(chunk[1]) >= 4 - s = filter.read(sys.maxint) - assert base.buf == "123456789" - base.chunks = [] - filter.write("abc") - assert not base.chunks - s = filter.read(sys.maxint) - assert base.buf == "123456789abc" - base.chunks = [] - filter.write("012") - assert not base.chunks - filter.seek(4, 0) - assert base.buf == "123456789abc012" - assert filter.read(3) == "567" - filter.write('x') - filter.flush() - assert base.buf == "1234567x9abc012" + def f(): + filter.write("123456789") + for chunk in base.chunks: + assert len(chunk[1]) >= 4 + s = filter.read(sys.maxint) + assert base.buf == "123456789" + base.chunks = [] + filter.write("abc") + assert not base.chunks + s = filter.read(sys.maxint) + assert base.buf == "123456789abc" + base.chunks = [] + filter.write("012") + assert not base.chunks + filter.seek(4, 0) + assert base.buf == "123456789abc012" + assert filter.read(3) == "567" + filter.write('x') + filter.flush() + assert base.buf == "1234567x9abc012" + self.interpret(f, []) def test_write_seek_beyond_end(self): "Linux behaviour. May be different on other platforms." base = TReaderWriter() filter = streamio.BufferingInputStream( streamio.BufferingOutputStream(base, 4), 4) - filter.seek(3) - filter.write("y"*2) - filter.close() - assert base.buf == "\0"*3 + "y"*2 - - - - + def f(): + filter.seek(3) + filter.write("y"*2) + filter.close() + assert base.buf == "\0"*3 + "y"*2 + self.interpret(f, []) +class TestBufferingInputOutputStreamTests( + BaseTestBufferingInputOutputStreamTests): + def interpret(self, func, args): + return func(*args) +class TestBufferingInputOutputStreamTestsLLinterp( + BaseTestBufferingInputOutputStreamTests, LLRtypeMixin): + pass class TestTextInputFilter: From cfbolz at codespeak.net Fri Nov 3 18:02:48 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 18:02:48 +0100 (CET) Subject: [pypy-svn] r34133 - in pypy/dist/pypy/rlib: . test Message-ID: <20061103170248.5E9BF1006F@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 18:02:47 2006 New Revision: 34133 Modified: pypy/dist/pypy/rlib/streamio.py pypy/dist/pypy/rlib/test/test_streamio.py Log: fix a small rtyping bug, more tests Modified: pypy/dist/pypy/rlib/streamio.py ============================================================================== --- pypy/dist/pypy/rlib/streamio.py (original) +++ pypy/dist/pypy/rlib/streamio.py Fri Nov 3 18:02:47 2006 @@ -556,7 +556,7 @@ def write(self, data): BufferingOutputStream.write(self, data) p = self.buf.rfind('\n') + 1 - if p: + if p >= 0: self.do_write(self.buf[:p]) self.buf = self.buf[p:] Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 18:02:47 2006 @@ -512,24 +512,26 @@ pass -class TestLineBufferingOutputStreamTests: +class BaseTestLineBufferingOutputStream(BaseRtypingTest): def test_write(self): base = TWriter() filter = streamio.LineBufferingOutputStream(base) - filter.bufsize = 4 # More handy for testing than the default - filter.write("123") - assert base.buf == "" - assert filter.tell() == 3 - filter.write("456") - assert base.buf == "1234" - filter.write("789ABCDEF\n") - assert base.buf == "123456789ABCDEF\n" - filter.write("0123") - assert base.buf == "123456789ABCDEF\n0123" - assert filter.tell() == 20 - filter.close() - assert base.buf == "123456789ABCDEF\n0123" + def f(): + filter.bufsize = 4 # More handy for testing than the default + filter.write("123") + assert base.buf == "" + assert filter.tell() == 3 + filter.write("456") + assert base.buf == "1234" + filter.write("789ABCDEF\n") + assert base.buf == "123456789ABCDEF\n" + filter.write("0123") + assert base.buf == "123456789ABCDEF\n0123" + assert filter.tell() == 20 + filter.close() + assert base.buf == "123456789ABCDEF\n0123" + self.interpret(f, []) def xtest_write_seek(self): base = TWriter() @@ -540,6 +542,15 @@ filter.close() assert base.buf == "x"*3 + "y"*2 + "x"*1 +class TestLineBufferingOutputStream(BaseTestLineBufferingOutputStream): + def interpret(self, func, args, **kwds): + return func(*args) + +class TestLineBufferingOutputStreamLLinterp(BaseTestLineBufferingOutputStream, + LLRtypeMixin): + pass + + class TestCRLFFilter: def test_filter(self): From cfbolz at codespeak.net Fri Nov 3 18:04:23 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 18:04:23 +0100 (CET) Subject: [pypy-svn] r34134 - pypy/dist/pypy/rlib/test Message-ID: <20061103170423.75EFD10076@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 18:04:22 2006 New Revision: 34134 Modified: pypy/dist/pypy/rlib/test/test_streamio.py Log: another test Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 18:04:22 2006 @@ -533,14 +533,16 @@ assert base.buf == "123456789ABCDEF\n0123" self.interpret(f, []) - def xtest_write_seek(self): + def test_write_seek(self): base = TWriter() filter = streamio.BufferingOutputStream(base, 4) - filter.write("x"*6) - filter.seek(3) - filter.write("y"*2) - filter.close() - assert base.buf == "x"*3 + "y"*2 + "x"*1 + def f(): + filter.write("x"*6) + filter.seek(3) + filter.write("y"*2) + filter.close() + assert base.buf == "x"*3 + "y"*2 + "x"*1 + self.interpret(f, []) class TestLineBufferingOutputStream(BaseTestLineBufferingOutputStream): def interpret(self, func, args, **kwds): From cfbolz at codespeak.net Fri Nov 3 18:08:52 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 18:08:52 +0100 (CET) Subject: [pypy-svn] r34135 - pypy/dist/pypy/rlib/test Message-ID: <20061103170852.1649110076@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 18:08:51 2006 New Revision: 34135 Modified: pypy/dist/pypy/rlib/test/test_streamio.py Log: crlf filter works out of the box Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 18:08:51 2006 @@ -549,23 +549,33 @@ return func(*args) class TestLineBufferingOutputStreamLLinterp(BaseTestLineBufferingOutputStream, - LLRtypeMixin): + LLRtypeMixin): pass -class TestCRLFFilter: +class BaseTestCRLFFilter(BaseRtypingTest): def test_filter(self): packets = ["abc\ndef\rghi\r\nxyz\r", "123\r", "\n456"] expected = ["abc\ndef\nghi\nxyz\n", "123\n", "456"] crlf = streamio.CRLFFilter(TSource(packets)) - blocks = [] - while 1: - block = crlf.read(100) - if not block: - break - blocks.append(block) - assert blocks == expected + def f(): + blocks = [] + while 1: + block = crlf.read(100) + if not block: + break + blocks.append(block) + assert blocks == expected + self.interpret(f, []) + +class TestCRLFFilter(BaseTestCRLFFilter): + def interpret(self, func, args, **kwds): + return func(*args) + +class TestCRLFFilterLLinterp(BaseTestCRLFFilter, LLRtypeMixin): + pass + class TestMMapFile(BaseTestBufferingInputStreamTests): tfn = None From cfbolz at codespeak.net Fri Nov 3 18:21:48 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 3 Nov 2006 18:21:48 +0100 (CET) Subject: [pypy-svn] r34136 - pypy/dist/pypy/rlib/test Message-ID: <20061103172148.CAF9A10070@code0.codespeak.net> Author: cfbolz Date: Fri Nov 3 18:21:47 2006 New Revision: 34136 Modified: pypy/dist/pypy/rlib/test/test_streamio.py Log: converted the rest of the test. all pass. puh Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 18:21:47 2006 @@ -680,7 +680,10 @@ pass -class TestTextInputFilter: +class BaseTestTextInputFilter(BaseRtypingTest): + + def _freeze_(self): + return True packets = [ "foo\r", @@ -729,101 +732,137 @@ def test_read(self): base = TReader(self.packets) filter = streamio.TextInputFilter(base) - for data, pos in self.expected: - assert filter.read(100) == data + def f(): + for data, pos in self.expected: + assert filter.read(100) == data + self.interpret(f, []) def test_read_tell(self): base = TReader(self.packets) filter = streamio.TextInputFilter(base) - for data, pos in self.expected_with_tell: - assert filter.read(100) == data - assert filter.tell() == pos - assert filter.tell() == pos # Repeat the tell() ! + def f(): + for data, pos in self.expected_with_tell: + assert filter.read(100) == data + assert filter.tell() == pos + assert filter.tell() == pos # Repeat the tell() ! + self.interpret(f, []) def test_seek(self): base = TReader(self.packets) filter = streamio.TextInputFilter(base) - sofar = "" - pairs = [] - while True: - pairs.append((sofar, filter.tell())) - c = filter.read(1) - if not c: - break - assert len(c) == 1 - sofar += c - all = sofar - for i in range(len(pairs)): - sofar, pos = pairs[i] - filter.seek(pos) - assert filter.tell() == pos - assert filter.tell() == pos - bufs = [sofar] + def f(): + sofar = "" + pairs = [] while True: - data = filter.read(100) - if not data: - assert filter.read(100) == "" + pairs.append((sofar, filter.tell())) + c = filter.read(1) + if not c: break - bufs.append(data) - assert "".join(bufs) == all + assert len(c) == 1 + sofar += c + all = sofar + for i in range(len(pairs)): + sofar, pos = pairs[i] + filter.seek(pos) + assert filter.tell() == pos + assert filter.tell() == pos + bufs = [sofar] + while True: + data = filter.read(100) + if not data: + assert filter.read(100) == "" + break + bufs.append(data) + assert "".join(bufs) == all + self.interpret(f, []) -class TestTextOutputFilter: +class TestTextInputFilter(BaseTestTextInputFilter): + def interpret(self, func, args): + return func(*args) + +class TestTextInputFilterLLinterp(BaseTestTextInputFilter, LLRtypeMixin): + pass + + +class BaseTestTextOutputFilter(BaseRtypingTest): def test_write_nl(self): - base = TWriter() - filter = streamio.TextOutputFilter(base, linesep="\n") - filter.write("abc") - filter.write("def\npqr\nuvw") - filter.write("\n123\n") - assert base.buf == "abcdef\npqr\nuvw\n123\n" + def f(): + base = TWriter() + filter = streamio.TextOutputFilter(base, linesep="\n") + filter.write("abc") + filter.write("def\npqr\nuvw") + filter.write("\n123\n") + assert base.buf == "abcdef\npqr\nuvw\n123\n" + self.interpret(f, []) def test_write_cr(self): - base = TWriter() - filter = streamio.TextOutputFilter(base, linesep="\r") - filter.write("abc") - filter.write("def\npqr\nuvw") - filter.write("\n123\n") - assert base.buf == "abcdef\rpqr\ruvw\r123\r" + def f(): + base = TWriter() + filter = streamio.TextOutputFilter(base, linesep="\r") + filter.write("abc") + filter.write("def\npqr\nuvw") + filter.write("\n123\n") + assert base.buf == "abcdef\rpqr\ruvw\r123\r" + self.interpret(f, []) def test_write_crnl(self): - base = TWriter() - filter = streamio.TextOutputFilter(base, linesep="\r\n") - filter.write("abc") - filter.write("def\npqr\nuvw") - filter.write("\n123\n") - assert base.buf == "abcdef\r\npqr\r\nuvw\r\n123\r\n" + def f(): + base = TWriter() + filter = streamio.TextOutputFilter(base, linesep="\r\n") + filter.write("abc") + filter.write("def\npqr\nuvw") + filter.write("\n123\n") + assert base.buf == "abcdef\r\npqr\r\nuvw\r\n123\r\n" + self.interpret(f, []) def test_write_tell_nl(self): - base = TWriter() - filter = streamio.TextOutputFilter(base, linesep="\n") - filter.write("xxx") - assert filter.tell() == 3 - filter.write("\nabc\n") - assert filter.tell() == 8 + def f(): + base = TWriter() + filter = streamio.TextOutputFilter(base, linesep="\n") + filter.write("xxx") + assert filter.tell() == 3 + filter.write("\nabc\n") + assert filter.tell() == 8 + self.interpret(f, []) def test_write_tell_cr(self): - base = TWriter() - filter = streamio.TextOutputFilter(base, linesep="\r") - filter.write("xxx") - assert filter.tell() == 3 - filter.write("\nabc\n") - assert filter.tell() == 8 + def f(): + base = TWriter() + filter = streamio.TextOutputFilter(base, linesep="\r") + filter.write("xxx") + assert filter.tell() == 3 + filter.write("\nabc\n") + assert filter.tell() == 8 + self.interpret(f, []) def test_write_tell_crnl(self): - base = TWriter() - filter = streamio.TextOutputFilter(base, linesep="\r\n") - filter.write("xxx") - assert filter.tell() == 3 - filter.write("\nabc\n") - assert filter.tell() == 10 + def f(): + base = TWriter() + filter = streamio.TextOutputFilter(base, linesep="\r\n") + filter.write("xxx") + assert filter.tell() == 3 + filter.write("\nabc\n") + assert filter.tell() == 10 + self.interpret(f, []) def test_write_seek(self): - base = TWriter() - filter = streamio.TextOutputFilter(base, linesep="\n") - filter.write("x"*100) - filter.seek(50) - filter.write("y"*10) - assert base.buf == "x"*50 + "y"*10 + "x"*40 + def f(): + base = TWriter() + filter = streamio.TextOutputFilter(base, linesep="\n") + filter.write("x"*100) + filter.seek(50) + filter.write("y"*10) + assert base.buf == "x"*50 + "y"*10 + "x"*40 + self.interpret(f, []) + +class TestTextOutputFilter(BaseTestTextOutputFilter): + def interpret(self, func, args): + return func(*args) + +class TestTextOutputFilterLLinterp(BaseTestTextOutputFilter, LLRtypeMixin): + pass + class TestDecodingInputFilter: From rxe at codespeak.net Fri Nov 3 18:49:07 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 18:49:07 +0100 (CET) Subject: [pypy-svn] r34137 - in pypy/dist/pypy/jit: hintannotator timeshifter/test Message-ID: <20061103174907.7F2391006F@code0.codespeak.net> Author: rxe Date: Fri Nov 3 18:48:56 2006 New Revision: 34137 Modified: pypy/dist/pypy/jit/hintannotator/model.py pypy/dist/pypy/jit/timeshifter/test/test_portal.py Log: fix broken tests with over eager HintError. add some more binary ops. add test for dfa recognizeparts() - (arre, rxe) Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Fri Nov 3 18:48:56 2006 @@ -17,7 +17,7 @@ ptr_nonzero ptr_iszero""".split() -BINARY_OPERATIONS = """int_add int_sub int_mul int_mod int_and int_rshift int_floordiv +BINARY_OPERATIONS = """int_add int_sub int_mul int_mod int_and int_rshift int_floordiv int_xor int_or uint_add uint_sub uint_mul uint_mod uint_and uint_lshift uint_rshift uint_floordiv char_gt char_lt char_le char_ge char_eq char_ne int_gt int_lt int_le int_ge int_eq int_ne @@ -267,6 +267,10 @@ hs_concrete = SomeLLAbstractConstant(hs_v1.concretetype, {}) hs_concrete.eager_concrete = True return hs_concrete + for name in ["reverse_split_queue", "global_merge_point"]: + if hs_flags.const.get(name, False): + return + raise HintError("hint %s makes no sense on %r" % (hs_flags.const, hs_v1)) Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Fri Nov 3 18:48:56 2006 @@ -153,6 +153,19 @@ res = self.timeshift_from_portal(main, recognizetable, [1], policy=P_NOVIRTUAL) assert not res + def test_dfa_compile2(self): + from pypy.lang.automata.dfa import getautomaton, recognizeparts + a = getautomaton() + def main(gets): + s = ["aaaaaaaaaab", "aaaa"][gets] + return recognizeparts(a.transitions, a.final_states, s) + + res = self.timeshift_from_portal(main, recognizeparts, [0], policy=P_NOVIRTUAL) + assert res + + res = self.timeshift_from_portal(main, recognizeparts, [1], policy=P_NOVIRTUAL) + assert not res + def test_method_call_promote(self): class Base(object): pass From rxe at codespeak.net Fri Nov 3 18:49:46 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 18:49:46 +0100 (CET) Subject: [pypy-svn] r34138 - pypy/dist/pypy/lang/automata Message-ID: <20061103174946.969AE1006F@code0.codespeak.net> Author: rxe Date: Fri Nov 3 18:49:45 2006 New Revision: 34138 Modified: pypy/dist/pypy/lang/automata/dfa.py Log: some updates for recognizer - arre, rxe Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Fri Nov 3 18:49:45 2006 @@ -103,18 +103,23 @@ " a less simple recognizer " trans = hint(trans, deepfreeze=True) finals = hint(finals, deepfreeze=True) - - state = 0 - try: - hint(None, global_mp_to_follow=True) - for char in s: - char = hint(char, promote=True) - state = trans[state, char] - hint(state, concrete=True) - except KeyError: - return False + indx = 0 + state = 0 + while True: + hint(None, global_merge_point=True) + if indx >= len(s): + break + + char = s[indx] + char = hint(char, promote=True) + state = trans.get((state, char), -1) + if state == -1: + return False + hint(state, concrete=True) + indx += 1 + res = state in finals res = hint(res, variable=True) return res From rxe at codespeak.net Fri Nov 3 18:51:30 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 18:51:30 +0100 (CET) Subject: [pypy-svn] r34139 - pypy/dist/pypy/jit/timeshifter/test Message-ID: <20061103175130.7762F10070@code0.codespeak.net> Author: rxe Date: Fri Nov 3 18:51:29 2006 New Revision: 34139 Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py Log: skip failing test for tonight Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Fri Nov 3 18:51:29 2006 @@ -154,6 +154,7 @@ assert not res def test_dfa_compile2(self): + py.test.skip('wip') from pypy.lang.automata.dfa import getautomaton, recognizeparts a = getautomaton() def main(gets): From arigo at codespeak.net Fri Nov 3 18:53:35 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 3 Nov 2006 18:53:35 +0100 (CET) Subject: [pypy-svn] r34140 - pypy/dist/pypy/rlib/test Message-ID: <20061103175335.030AB10070@code0.codespeak.net> Author: arigo Date: Fri Nov 3 18:53:35 2006 New Revision: 34140 Modified: pypy/dist/pypy/rlib/test/test_streamio.py Log: Only run some cases in the test_seek*() on top of the llinterp, otherwise it takes ages. Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Fri Nov 3 18:53:35 2006 @@ -2,6 +2,7 @@ import os import time +import random from pypy.tool.udir import udir from pypy.rlib import streamio @@ -359,27 +360,33 @@ def test_seek(self): file = self.makeStream(tell=True, seek=True) + end = len(file.readall()) + file.seek(0) + cases = [(readto, seekto, whence) for readto in range(0, end+1) + for seekto in range(0, end+1) + for whence in [0, 1, 2]] + random.shuffle(cases) + if isinstance(self, LLRtypeMixin): + cases = cases[:7] # pick some cases at random - too slow! def f(): all = file.readall() - end = len(all) - for readto in range(0, end+1): - for seekto in range(0, end+1): - for whence in [0, 1, 2]: - file.seek(0) - assert file.tell() == 0 - head = file.read(readto) - assert head == all[:readto] - if whence == 1: - offset = seekto - readto - elif whence == 2: - offset = seekto - end - else: - offset = seekto - file.seek(offset, whence) - here = file.tell() - assert here == seekto - rest = file.readall() - assert rest == all[seekto:] + assert end == len(all) + for readto, seekto, whence in cases: + file.seek(0) + assert file.tell() == 0 + head = file.read(readto) + assert head == all[:readto] + if whence == 1: + offset = seekto - readto + elif whence == 2: + offset = seekto - end + else: + offset = seekto + file.seek(offset, whence) + here = file.tell() + assert here == seekto + rest = file.readall() + assert rest == all[seekto:] return True res = self.interpret(f, []) assert res @@ -388,22 +395,26 @@ file = self.makeStream() all = file.readall() end = len(all) - def f(): - for readto in range(0, end+1): - for seekto in range(readto, end+1): - for whence in [1, 2]: - base = TSource(self.packets) - file = streamio.BufferingInputStream(base) - head = file.read(readto) - assert head == all[:readto] - offset = 42 # for the flow space - if whence == 1: - offset = seekto - readto - elif whence == 2: - offset = seekto - end - file.seek(offset, whence) - rest = file.readall() - assert rest == all[seekto:] + cases = [(readto, seekto, whence) for readto in range(0, end+1) + for seekto in range(readto, end+1) + for whence in [1, 2]] + random.shuffle(cases) + if isinstance(self, LLRtypeMixin): + cases = cases[:7] # pick some cases at random - too slow! + def f(): + for readto, seekto, whence in cases: + base = TSource(self.packets) + file = streamio.BufferingInputStream(base) + head = file.read(readto) + assert head == all[:readto] + offset = 42 # for the flow space + if whence == 1: + offset = seekto - readto + elif whence == 2: + offset = seekto - end + file.seek(offset, whence) + rest = file.readall() + assert rest == all[seekto:] return True res = self.interpret(f, []) assert res From fijal at codespeak.net Fri Nov 3 19:12:09 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 19:12:09 +0100 (CET) Subject: [pypy-svn] r34142 - in pypy/branch/transparent-proxy/pypy: interpreter objspace objspace/std objspace/std/test Message-ID: <20061103181209.18C021006E@code0.codespeak.net> Author: fijal Date: Fri Nov 3 19:12:06 2006 New Revision: 34142 Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py (contents, props changed) Modified: pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py pypy/branch/transparent-proxy/pypy/interpreter/gateway.py pypy/branch/transparent-proxy/pypy/interpreter/typedef.py pypy/branch/transparent-proxy/pypy/objspace/descroperation.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (pedronis, fijal) - Added immature function call support. It's a bit a mess. Modified: pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py Fri Nov 3 19:12:06 2006 @@ -101,6 +101,12 @@ typename = space.type(self).getname(space, '?') raise OperationError(space.w_TypeError, space.wrap( "cannot create weak reference to '%s' object" % typename)) + + def descr_call_not_understood(self, space, reqcls, name, args): + msg = "'%s' object expected, got '%s' instead" % ( + reqcls.typedef.name, + self.getclass(space).getname(space, '?')) + raise OperationError(space.w_TypeError, space.wrap(msg)) class Wrappable(W_Root): """A subclass of Wrappable is an internal, interpreter-level class @@ -480,6 +486,7 @@ return None obj = self.interpclass_w(w_obj) if not isinstance(obj, RequiredClass): # or obj is None + import pdb;pdb.set_trace() msg = "'%s' object expected, got '%s' instead" % ( RequiredClass.typedef.name, w_obj.getclass(self).getname(self, '?')) Modified: pypy/branch/transparent-proxy/pypy/interpreter/gateway.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/gateway.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/gateway.py Fri Nov 3 19:12:06 2006 @@ -197,9 +197,9 @@ self.run_args.append("space.%s_w(%s)" % (typ.__name__, self.scopenext())) - def _make_unwrap_activation_class(self, unwrap_spec, cache={}): + def _make_unwrap_activation_class(self, unwrap_spec, not_understood, cache={}): try: - key = tuple(unwrap_spec) + key = (tuple(unwrap_spec), not_understood) activation_factory_cls, run_args = cache[key] assert run_args == self.run_args, ( "unexpected: same spec, different run_args") @@ -216,10 +216,23 @@ #print label d = {} - source = """if 1: - def _run_UWS_%s(self, space, scope_w): - return self.behavior(%s) - \n""" % (label, ', '.join(self.run_args)) + if not_understood is None: + source = """if 1: + def _run_UWS_%s(self, space, scope_w): + return self.behavior(%s) + \n""" % (label, ', '.join(self.run_args)) + else: + assert issubclass(unwrap_spec[0], Wrappable) + args = ', '.join(self.run_args[1:]) + reqcls = self.use(unwrap_spec[0]) + source = """if 1: + def _run_UWS_%s(self, space, scope_w): + w_self = scope_w[0] + if not isinstance(w_self, %s): + return w_self.descr_call_not_understood(space, %s, %r, %s) + return self.behavior(w_self, %s) + \n""" % (label, reqcls, reqcls, not_understood, args, args) + exec compile2(source) in self.miniglobals, d d['_run'] = d['_run_UWS_%s' % label] del d['_run_UWS_%s' % label] @@ -230,10 +243,11 @@ cache[key] = activation_cls, self.run_args return activation_cls - def make_activation(unwrap_spec, func): + def make_activation(unwrap_spec, func, not_understood): emit = UnwrapSpec_EmitRun() emit.apply_over(unwrap_spec) - activation_uw_cls = emit._make_unwrap_activation_class(unwrap_spec) + activation_uw_cls = emit._make_unwrap_activation_class(unwrap_spec, + not_understood) return activation_uw_cls(func) make_activation = staticmethod(make_activation) @@ -302,12 +316,12 @@ self.unwrap.append("space.%s_w(%s)" % (typ.__name__, self.nextarg())) - def make_fastfunc(unwrap_spec, func): + def make_fastfunc(unwrap_spec, func, not_understood): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) narg = unwrap_info.n args = ['space'] + unwrap_info.args - if args == unwrap_info.unwrap: + if args == unwrap_info.unwrap and not_understood is None: fastfunc = func else: # try to avoid excessive bloat @@ -320,12 +334,28 @@ raise FastFuncNotSupported d = {} unwrap_info.miniglobals['func'] = func - source = """if 1: - def fastfunc_%s_%d(%s): - return func(%s) - \n""" % (func.__name__, narg, - ', '.join(args), - ', '.join(unwrap_info.unwrap)) + if not_understood is None: + source = """if 1: + def fastfunc_%s_%d(%s): + return func(%s) + \n""" % (func.__name__, narg, + ', '.join(args), + ', '.join(unwrap_info.unwrap)) + else: + #def _run_UWS_%s(self, space, scope_w): + # w_self = scope_w[0] + # if not isinstance(w_self, %s): + # return w_self.descr_call_not_understood(space, %r, %s) + # return self.behavior(w_self, %s) + assert issubclass(unwrap_spec[0], Wrappable) + reqcls = self.use(unwrap_spec[0]) + source = """if 1: + def fastfunc_%s_%d(%s): + if not isinstance(w0, %s): + return w0.descr_call_not_understood(space, %s, %r, %s) + return func(%s) + \n""" % (func.__name__, narg, ",".join(args), reqcls, reqcls, + not_understood, ",".join(args[2:]), ",".join(unwrap_info.unwrap)) exec compile2(source) in unwrap_info.miniglobals, d fastfunc = d['fastfunc_%s_%d' % (func.__name__, narg)] return narg, fastfunc @@ -340,7 +370,7 @@ NOT_RPYTHON_ATTRIBUTES = ['_bltin', '_unwrap_spec'] - def __init__(self, func, unwrap_spec = None, self_type = None): + def __init__(self, func, unwrap_spec = None, self_type = None, not_understood=None): "NOT_RPYTHON" # 'implfunc' is the interpreter-level function. # Note that this uses a lot of (construction-time) introspection. @@ -376,6 +406,8 @@ assert unwrap_spec[0] == 'self',"self_type without 'self' spec element" unwrap_spec = list(unwrap_spec) unwrap_spec[0] = self_type + else: + assert not_understood is None, "not_understood without a self-type specified" orig_sig = Signature(func, argnames, varargname, kwargname) app_sig = Signature(func) @@ -391,7 +423,8 @@ else: self.maxargs = self.minargs - self.activation = UnwrapSpec_EmitRun.make_activation(unwrap_spec, func) + self.activation = UnwrapSpec_EmitRun.make_activation(unwrap_spec, func, + not_understood=not_understood) self._bltin = func self._unwrap_spec = unwrap_spec @@ -399,12 +432,15 @@ if 0 <= len(unwrap_spec) <= 5: try: arity, fastfunc = UnwrapSpec_FastFunc_Unwrap.make_fastfunc( - unwrap_spec, func) + unwrap_spec, func, + not_understood=not_understood) except FastFuncNotSupported: if unwrap_spec == [ObjSpace, Arguments]: + assert not_understood is None self.__class__ = BuiltinCodePassThroughArguments0 self.func__args__ = func elif unwrap_spec == [ObjSpace, W_Root, Arguments]: + assert not_understood is None self.__class__ = BuiltinCodePassThroughArguments1 self.func__args__ = func else: @@ -569,7 +605,7 @@ NOT_RPYTHON_ATTRIBUTES = ['_staticdefs'] - def __init__(self, f, app_name=None, unwrap_spec = None): + def __init__(self, f, app_name=None, unwrap_spec = None, not_understood=None): "NOT_RPYTHON" Wrappable.__init__(self) # f must be a function whose name does NOT start with 'app_' @@ -584,7 +620,8 @@ raise ValueError, ("function name %r suspiciously starts " "with 'app_'" % f.func_name) app_name = f.func_name - self._code = BuiltinCode(f, unwrap_spec=unwrap_spec, self_type = self_type) + self._code = BuiltinCode(f, unwrap_spec=unwrap_spec, self_type = self_type, + not_understood=not_understood) self.__name__ = f.func_name self.name = app_name self._staticdefs = list(f.func_defaults or ()) Modified: pypy/branch/transparent-proxy/pypy/interpreter/typedef.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/typedef.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/typedef.py Fri Nov 3 19:12:06 2006 @@ -583,7 +583,7 @@ Function.typedef = TypeDef("function", __new__ = interp2app(Function.descr_method__new__.im_func), __call__ = interp2app(Function.descr_function_call, - unwrap_spec=['self', Arguments]), + unwrap_spec=['self', Arguments], not_understood="__call__"), __get__ = interp2app(descr_function_get), __repr__ = interp2app(Function.descr_function_repr), __reduce__ = interp2app(Function.descr_function__reduce__, Modified: pypy/branch/transparent-proxy/pypy/objspace/descroperation.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/descroperation.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/descroperation.py Fri Nov 3 19:12:06 2006 @@ -35,9 +35,7 @@ if space.is_data_descr(w_descr): space.set(w_descr, w_obj, w_value) return - w_dict = w_obj.getdict() - if w_dict is not None: - space.set_str_keyed_item(w_dict, w_name, w_value) + if w_obj.setdictvalue(space, w_name, w_value): return raiseattrerror(space, w_obj, name, w_descr) @@ -48,14 +46,8 @@ if space.is_data_descr(w_descr): space.delete(w_descr, w_obj) return - w_dict = w_obj.getdict() - if w_dict is not None: - try: - space.delitem(w_dict, w_name) - return - except OperationError, ex: - if not ex.match(space, space.w_KeyError): - raise + if w_obj.deldictvalue(space, w_name): + return raiseattrerror(space, w_obj, name, w_descr) def descr__init__(space, w_obj, __args__): @@ -404,9 +396,11 @@ if space.is_w(w_obj2, space.w_None): return space.wrap(1) if space.is_w(w_typ1, w_typ2): + #print "WARNING, comparison by address!" w_id1 = space.id(w_obj1) w_id2 = space.id(w_obj2) else: + #print "WARNING, comparison by address!" w_id1 = space.id(w_typ1) w_id2 = space.id(w_typ2) if space.is_true(space.lt(w_id1, w_id2)): @@ -451,6 +445,9 @@ left, right = specialnames op = getattr(operator, left) def comparison_impl(space, w_obj1, w_obj2): + #from pypy.objspace.std.tlistobject import W_TransparentList + #if isinstance(w_obj1, W_TransparentList): + # import pdb;pdb.set_trace() w_typ1 = space.type(w_obj1) w_typ2 = space.type(w_obj2) w_left_src, w_left_impl = space.lookup_in_type_where(w_typ1, left) @@ -523,9 +520,9 @@ l = ["space.is_true(space.isinstance(w_result, %s))" % x for x in checkerspec] checker = " or ".join(l) - source = """if 1: + source = """if 1: def %(targetname)s(space, w_obj): - w_impl = space.lookup(w_obj, %(specialname)r) + w_impl = space.lookup(w_obj, %(specialname)r) if w_impl is None: raise OperationError(space.w_TypeError, space.wrap("operand does not support unary %(targetname)s")) Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py Fri Nov 3 19:12:06 2006 @@ -0,0 +1,24 @@ + +""" test proxy on functions and other crazy goodies +""" + +from pypy.objspace.std.test.test_proxy import AppProxyBasic + +class AppTestProxyFunction(AppProxyBasic): + def test_function_noargs(self): + def f(): + return 3 + + import types + c = self.Controller(f) + fun = proxy(types.FunctionType, c.perform) + assert fun() == f() + + def test_simple_function(self): + def f(x): + return x + + import types + c = self.Controller(f) + fun = proxy(types.FunctionType, c.perform) + assert fun(3) == f(3) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py Fri Nov 3 19:12:06 2006 @@ -86,6 +86,12 @@ obj.__dict__ = {'x':3} assert obj.x == 3 assert obj.__dict__.keys() == ['x'] + + def test_repr(self): + a = self.A() + c = self.Controller(a) + obj = proxy(self.A, c.perform) + assert repr(obj)[:6] == repr(a)[:6] class AppTestProxyObjectList(AppTestProxyObj): def setup_method(self, meth): Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Fri Nov 3 19:12:06 2006 @@ -62,6 +62,14 @@ from pypy.objspace.std.objecttype import object_typedef as typedef +class W_TransparentFunction(W_Transparent): + from pypy.interpreter.function import Function + typedef = Function.typedef + + def descr_call_not_understood(self, space, reqcls, name, args): + args = args.prepend(space.wrap(name)) + return space.call_args(self.w_controller, args) + class W_TransparentList(W_Transparent): from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Fri Nov 3 19:12:06 2006 @@ -6,22 +6,28 @@ from pypy.interpreter.function import Function from pypy.interpreter.error import OperationError from pypy.objspace.std.tlistobject import W_TransparentList, W_TransparentDict,\ - W_Transparent + W_Transparent, W_TransparentFunction from pypy.objspace.std.typeobject import W_TypeObject def proxy(space, w_type, w_controller): + from pypy.interpreter.typedef import Function + if not space.is_true(space.callable(w_controller)): raise OperationError(space.w_TypeError, space.wrap("controller should be function")) - if space.is_true(space.issubtype(w_type, space.w_list)): - return W_TransparentList(space, w_type, w_controller) - if space.is_true(space.issubtype(w_type, space.w_dict)): - return W_TransparentDict(space, w_type, w_controller) if isinstance(w_type, W_TypeObject): + if space.is_true(space.issubtype(w_type, space.w_list)): + return W_TransparentList(space, w_type, w_controller) + if space.is_true(space.issubtype(w_type, space.w_dict)): + return W_TransparentDict(space, w_type, w_controller) + if space.is_true(space.issubtype(w_type, space.gettypeobject(Function.typedef))): + return W_TransparentFunction(space, w_type, w_controller) if w_type.instancetypedef is space.w_object.instancetypedef: return W_Transparent(space, w_type, w_controller) + else: + raise OperationError(space.w_TypeError, space.wrap("type expected as first argument")) #return type_cache[w_type or w_type.w_bestbase] - raise OperationError(space.w_TypeError, space.wrap("Object type %s could not"\ + raise OperationError(space.w_TypeError, space.wrap("Object type %s could not "\ "be wrapped (YET)" % w_type.getname(space, "?"))) app_proxy = gateway.interp2app(proxy, unwrap_spec=[gateway.ObjSpace, gateway.W_Root, \ From niko at codespeak.net Fri Nov 3 19:16:21 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 3 Nov 2006 19:16:21 +0100 (CET) Subject: [pypy-svn] r34143 - in pypy/dist/pypy/jit/codegen: ppc ppc/test test Message-ID: <20061103181621.6979F1006E@code0.codespeak.net> Author: niko Date: Fri Nov 3 19:16:19 2006 New Revision: 34143 Added: pypy/dist/pypy/jit/codegen/ppc/test/test_emit_moves.py Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Log: (mwh, niko) Wrote test sub class that ensures register allocation actually spills *something* by artifically restricting number of regs it uses Fixed many bugs Wrote general code to reshuffle data on basic block edges, added unit tests for the algorithm Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Fri Nov 3 19:16:19 2006 @@ -4,9 +4,23 @@ from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.codegen.ppc.conftest import option -class Register(object): - def __init__(self): - pass +class AllocationSlot(object): + pass + +class _StackSlot(AllocationSlot): + is_register = False + def __init__(self, offset): + self.offset = offset + +_stack_slot_cache = {} +def stack_slot(offset): + if offset in _stack_slot_cache: + return _stack_slot_cache[offset] + _stack_slot_cache[offset] = res = _StackSlot(offset) + return res + +class Register(AllocationSlot): + is_register = True class GPR(Register): def __init__(self, number): @@ -42,92 +56,142 @@ CT_REGISTER = 3 class RegisterAllocation: - def __init__(self, initial_mapping): - self.insns = [] - self.freeregs = gprs[3:] - self.reg2var = {} - self.var2reg = {} - self.var2spill = {} - for var, reg in initial_mapping.iteritems(): - self.reg2var[reg] = var - self.var2reg[var] = reg + def __init__(self, minreg, initial_mapping): + #print + #print "RegisterAllocation __init__" + + self.insns = [] # Output list of instructions + self.freeregs = gprs[minreg:] # Registers with dead values + self.var2loc = {} # Maps a Var to an AllocationSlot + self.loc2var = {} # Maps an AllocationSlot to a Var + self.lru = [] # Least-recently-used list of vars; first is oldest. + # Contains all vars in registers, and no vars on stack + self._spill_index = 0 # Where to put next spilled value + + # Go through the initial mapping and initialize the data structures + for var, loc in initial_mapping.iteritems(): + self.loc2var[loc] = var + self.var2loc[var] = loc + if loc in self.freeregs: + del self.freeregs[self.freeregs.index(loc)] + self.lru.append(var) self.crfinfo = [(0, 0)] * 8 - self._spill_index = 0 - def _spill(self): + def spill(self): + """ Returns an offset onto the stack for an unused spill location """ + # TODO --- reuse spill slots when contained values go dead? self._spill_index += 4 return self._spill_index - def _allocate_reg(self, newarg, lru): + def _allocate_reg(self, newarg): # check if there is a register available if self.freeregs: reg = self.freeregs.pop() - self.reg2var[reg] = newarg - self.var2reg[newarg] = reg + self.loc2var[reg] = newarg + self.var2loc[newarg] = reg + #print "allocate_reg: Putting %r into fresh register %r" % ( + # newarg, reg) return reg # if not, find something to spill - argtospill = lru.pop(0) - assert argtospill in self.var2reg - spill = self._spill() - reg = self.var2reg[argtospill] # move argtospill to spill slot - self.var2spill[argtospill] = spill - del self.var2reg[argtospill] - self.reg2var[reg] = newarg # assign reg to newarg - self.var2reg[newarg] = reg + argtospill = self.lru.pop(0) + reg = self.var2loc[argtospill] + assert reg.is_register + + # Move the value we are spilling onto the stack, both in the + # data structures and in the instructions: + spill = stack_slot(self.spill()) + self.var2loc[argtospill] = spill + self.loc2var[spill] = argtospill self.insns.append(Spill(argtospill, reg, spill)) + #print "allocate_reg: Spilled %r to %r." % (argtospill, spill) + + # If the value is currently on the stack, load it up into the + # register we are putting it into + if newarg in self.var2loc: + spill = self.var2loc[newarg] + assert not spill.is_register + self.insns.append(Unspill(newarg, reg, spill)) + del self.loc2var[spill] # not stored there anymore, reuse?? + #print "allocate_reg: Unspilled %r from %r." % (newarg, spill) + + # Update data structures to put newarg into the register + self.var2loc[newarg] = reg + self.loc2var[reg] = newarg + #print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) return reg + + def _promote(self, arg): + if arg in self.lru: + del self.lru[self.lru.index(arg)] + self.lru.append(arg) def allocate_for_insns(self, insns): # Walk through instructions in forward order - lru = [] for insn in insns: + #print "Processing instruction %r with args %r and result %r:" % ( + # insn, insn.reg_args, insn.result) + # + #print "LRU list was: %r" % (self.lru,) + # put things into the lru - for arg in insn.reg_args: - if arg in lru: - del lru[lru.index(arg)] - lru.append(arg) + for i in range(len(insn.reg_args)): + arg = insn.reg_args[i] + argcls = insn.reg_arg_regclasses[i] + if argcls == GP_REGISTER: + self._promote(arg) + if insn.result and insn.result_regclass == GP_REGISTER: + self._promote(insn.result) + #print "LRU list is now: %r" % (self.lru,) # We need to allocate a register for each used # argument that is not already in one for i in range(len(insn.reg_args)): arg = insn.reg_args[i] argcls = insn.reg_arg_regclasses[i] + #print "Allocating register for %r..." % (arg,) - if arg not in self.var2reg: + if not self.var2loc[arg].is_register: # It has no register now because it has been spilled assert argcls is GP_REGISTER, "uh-oh" - reg = self._allocate_reg(arg, lru) - self.insns.append( - Unspill(arg, reg, self.var2spill[arg])) - del self.var2spill[arg] + self._allocate_reg(arg) # Need to allocate a register for the destination - assert not insn.result or insn.result not in self.var2reg + assert not insn.result or insn.result not in self.var2loc cand = None if insn.result_regclass is GP_REGISTER: - cand = self._allocate_reg(insn.result, lru) + #print "Allocating register for result %r..." % (cand,) + cand = self._allocate_reg(insn.result) elif insn.result_regclass is CR_FIELD: - assert crfs[0] not in self.reg2var + assert crfs[0] not in self.loc2var + assert isinstance(insn, CMPInsn) cand = crfs[0] self.crfinfo[0] = insn.info elif insn.result_regclass is CT_REGISTER: - assert ctr not in self.reg2var + assert ctr not in self.loc2var cand = ctr elif insn.result_regclass is not NO_REGISTER: assert 0 - if cand is not None: - self.var2reg[insn.result] = cand - self.reg2var[cand] = insn.result + if cand is not None and cand not in self.loc2var: + self.var2loc[insn.result] = cand + self.loc2var[cand] = insn.result + else: + assert cand is None or self.loc2var[cand] is insn.result insn.allocate(self) self.insns.append(insn) return self.insns +_var_index = [0] class Var(GenVar): + def __init__(self): + self.__magic_index = _var_index[0] + _var_index[0] += 1 def load(self, builder): return self + def __repr__(self): + return "" % self.__magic_index class IntConst(GenConst): @@ -158,9 +222,16 @@ reg_args is the vars that need to have registers allocated for them reg_arg_regclasses is the type of register that needs to be allocated ''' + info = (0,0) + def __init__(self): + self.__magic_index = _var_index[0] + _var_index[0] += 1 + def __repr__(self): + return "<%s %d>" % (self.__class__.__name__, self.__magic_index) class Insn_GPR__GPR_GPR(Insn): def __init__(self, methptr, result, args): + Insn.__init__(self) self.methptr = methptr self.result = result @@ -169,9 +240,9 @@ self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] def allocate(self, allocator): - self.result_reg = allocator.var2reg[self.result] - self.arg_reg1 = allocator.var2reg[self.reg_args[0]] - self.arg_reg2 = allocator.var2reg[self.reg_args[1]] + self.result_reg = allocator.var2loc[self.result] + self.arg_reg1 = allocator.var2loc[self.reg_args[0]] + self.arg_reg2 = allocator.var2loc[self.reg_args[1]] def emit(self, asm): self.methptr(asm, @@ -181,6 +252,7 @@ class Insn_GPR__GPR_IMM(Insn): def __init__(self, methptr, result, args): + Insn.__init__(self) self.methptr = methptr self.imm = args[1] @@ -189,8 +261,8 @@ self.reg_args = [args[0]] self.reg_arg_regclasses = [GP_REGISTER] def allocate(self, allocator): - self.result_reg = allocator.var2reg[self.result] - self.arg_reg = allocator.var2reg[self.reg_args[0]] + self.result_reg = allocator.var2loc[self.result] + self.arg_reg = allocator.var2loc[self.reg_args[0]] def emit(self, asm): self.methptr(asm, self.result_reg.number, @@ -199,6 +271,7 @@ class Insn_GPR__IMM(Insn): def __init__(self, methptr, result, args): + Insn.__init__(self) self.methptr = methptr self.imm = args[0] @@ -207,14 +280,18 @@ self.reg_args = [] self.reg_arg_regclasses = [] def allocate(self, allocator): - self.result_reg = allocator.var2reg[self.result] + self.result_reg = allocator.var2loc[self.result] def emit(self, asm): self.methptr(asm, self.result_reg.number, self.imm.value) -class CMPW(Insn): +class CMPInsn(Insn): + pass + +class CMPW(CMPInsn): def __init__(self, info, result, args): + Insn.__init__(self) self.info = info self.result = result @@ -224,15 +301,16 @@ self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] def allocate(self, allocator): - self.result_reg = allocator.var2reg[self.result] - self.arg_reg1 = allocator.var2reg[self.reg_args[0]] - self.arg_reg2 = allocator.var2reg[self.reg_args[1]] + self.result_reg = allocator.var2loc[self.result] + self.arg_reg1 = allocator.var2loc[self.reg_args[0]] + self.arg_reg2 = allocator.var2loc[self.reg_args[1]] def emit(self, asm): asm.cmpw(self.result_reg.number, self.arg_reg1.number, self.arg_reg2.number) -class CMPWI(Insn): +class CMPWI(CMPInsn): def __init__(self, info, result, args): + Insn.__init__(self) self.info = info self.imm = args[1] @@ -243,14 +321,15 @@ self.reg_arg_regclasses = [GP_REGISTER] def allocate(self, allocator): - self.result_reg = allocator.var2reg[self.result] - self.arg_reg = allocator.var2reg[self.reg_args[0]] + self.result_reg = allocator.var2loc[self.result] + self.arg_reg = allocator.var2loc[self.reg_args[0]] def emit(self, asm): asm.cmpwi(self.result_reg.number, self.arg_reg.number, self.imm.value) class MTCTR(Insn): def __init__(self, result, args): + Insn.__init__(self) self.result = result self.result_regclass = CT_REGISTER @@ -258,13 +337,14 @@ self.reg_arg_regclasses = [GP_REGISTER] def allocate(self, allocator): - self.arg_reg = allocator.var2reg[self.reg_args[0]] + self.arg_reg = allocator.var2loc[self.reg_args[0]] def emit(self, asm): asm.mtctr(self.arg_reg.number) class Jump(Insn): def __init__(self, gv_cond, gv_target, jump_if_true): + Insn.__init__(self) self.gv_cond = gv_cond self.gv_target = gv_target self.jump_if_true = jump_if_true @@ -274,8 +354,8 @@ self.reg_args = [gv_cond, gv_target] self.reg_arg_regclasses = [CR_FIELD, CT_REGISTER] def allocate(self, allocator): - assert allocator.var2reg[self.reg_args[1]] is ctr - self.crf = allocator.var2reg[self.reg_args[0]] + assert allocator.var2loc[self.reg_args[1]] is ctr + self.crf = allocator.var2loc[self.reg_args[0]] self.bit, self.negated = allocator.crfinfo[self.crf.number] def emit(self, asm): if self.negated ^ self.jump_if_true: @@ -288,33 +368,51 @@ """ A special instruction inserted by our register "allocator." It indicates that we need to load a value from the stack into a register because we spilled a particular value. """ - def __init__(self, var, reg, offset): + def __init__(self, var, reg, stack): """ var --- the var we spilled (a Var) reg --- the reg we spilled it from (an integer) offset --- the offset on the stack we spilled it to (an integer) """ + Insn.__init__(self) self.var = var self.reg = reg - self.offset = offset + self.stack = stack def emit(self, asm): - asm.lwz(self.reg.number, rSP, self.offset) + asm.lwz(self.reg.number, rSP, self.stack.offset) class Spill(Insn): """ A special instruction inserted by our register "allocator." It indicates that we need to store a value from the register into the stack because we spilled a particular value.""" - def __init__(self, var, reg, offset): + def __init__(self, var, reg, stack): """ var --- the var we are spilling (a Var) reg --- the reg we are spilling it from (an integer) offset --- the offset on the stack we are spilling it to (an integer) """ + Insn.__init__(self) self.var = var self.reg = reg - self.offset = offset + self.stack = stack def emit(self, asm): - asm.stw(self.reg.number, rSP, self.offset) + asm.stw(self.reg.number, rSP, self.stack.offset) + +class Return(Insn): + """ Ensures the return value is in r3 """ + def __init__(self, var): + Insn.__init__(self) + self.var = var + self.reg_args = [self.var] + self.reg_arg_regclasses = [GP_REGISTER] + self.result = None + self.result_regclass = NO_REGISTER + self.reg = None + def allocate(self, allocator): + self.reg = allocator.var2loc[self.var] + def emit(self, asm): + if self.reg.number != 3: + asm.mr(r3, self.reg.number) from pypy.jit.codegen.ppc import codebuf_posix as memhandler from ctypes import POINTER, cast, c_char, c_void_p, CFUNCTYPE, c_int @@ -336,25 +434,129 @@ self.mc.write(value) RPPCAssembler.emit = emit -def prepare_for_jump(builder, cur_locations, target): - assert len(target.arg_locations) == len(cur_locations) - targetregs = target.arg_locations - outregs = cur_locations - for i in range(len(cur_locations)): - treg = targetregs[i] - oreg = outregs[i] - if oreg == treg: - continue - if treg in outregs: - outi = outregs.index(treg) - assert outi > i - builder.asm.xor(treg.number, treg.number, oreg.number) - builder.asm.xor(oreg.number, treg.number, oreg.number) - builder.asm.xor(treg.number, treg.number, oreg.number) - outregs[outi] = oreg - outregs[i] == treg - else: - builder.asm.mr(treg.number, oreg.number) +class CycleData: + # tar2src -> map target var to source var + # src2tar -> map source var to target var (!) + # tar2loc -> map target var to location + # src2loc -> map source var to location + # loc2src -> map location to source var + # srcstack -> list of source vars + # freshctr -> how many fresh locations have we made so far + # emitted -> list of emitted targets + pass + +def emit_moves(gen, tar2src, tar2loc, src2loc): + + # Basic idea: + # + # Construct a graph for each move (Ti <- Si) + # There is an edge between two nodes i and j if loc[Ti] == loc[Sj] + # If there are no cycles, then a simple tree walk will suffice + # Algorithm is: avoid cycles by creating temps when needed + # + # Do tree walk, if backedge is detected to node j, then move Sj to + # a fresh slot Sn, and change Sj from Ti <- Sj to Ti <- Sn. Now + # there is no need for the backedge, so don't add it and continue. + # When finishing a leaf node, emit the move. + + tarvars = tar2src.keys() + + data = CycleData() + data.tar2src = tar2src + data.src2tar = {} + data.tar2loc = tar2loc + data.src2loc = src2loc + data.loc2src = {} + data.srcstack = [] + data.freshctr = 0 + data.emitted = [] + + for tar, src in tar2src.items(): + data.src2tar[src] = tar + + for src, loc in src2loc.items(): + if src in data.src2tar: + data.loc2src[loc] = src + + for tarvar in tarvars: + _cycle_walk(gen, tarvar, data) + + return data + +def _cycle_walk(gen, tarvar, data): + + if tarvar in data.emitted: return + + tarloc = data.tar2loc[tarvar] + srcvar = data.tar2src[tarvar] + srcloc = data.src2loc[srcvar] + + # if location we are about to write to is not going to be read + # by anyone, we are safe + if tarloc not in data.loc2src: + gen.emit_move(tarloc, srcloc) + data.emitted.append(tarvar) + return + + # Find source node that conflicts with us + conflictsrcvar = data.loc2src[tarloc] + + if conflictsrcvar not in data.srcstack: + # No cycle on our stack yet + data.srcstack.append(srcvar) + _cycle_walk(gen, data.src2tar[conflictsrcvar], data) + srcloc = data.src2loc[srcvar] # warning: may have changed, so reload + gen.emit_move(tarloc, srcloc) + data.emitted.append(tarvar) + return + + # Cycle detected, break it by moving the other node's source data + # somewhere else so we can overwrite it + freshloc = gen.create_fresh_location() + conflictsrcloc = data.src2loc[conflictsrcvar] + gen.emit_move(freshloc, conflictsrcloc) + data.src2loc[conflictsrcvar] = freshloc + gen.emit_move(tarloc, srcloc) # now safe to do our move + data.emitted.append(tarvar) + return + +class JumpPatchupGenerator(object): + + def __init__(self, asm, regalloc): + self.asm = asm + self.regalloc = regalloc + + def emit_move(self, tarloc, srcloc): + if tarloc == srcloc: return + if tarloc.is_register and srcloc.is_register: + self.asm.mr(tarloc.number, srcloc.number) + elif tarloc.is_register and not srcloc.is_register: + self.asm.lwz(tarloc.number, rSP, srcloc.offset) + elif not tarloc.is_register and srcloc.is_register: + self.asm.stw(srcloc.number, rSP, tarloc.offset) + elif not tarloc.is_register and not srcloc.is_register: + self.asm.lwz(r0, rSP, srcloc.offset) + self.asm.stw(r0, rSP, tarloc.offset) + + def create_fresh_location(self): + offset = self.regalloc.spill() + return stack_slot(offset) + +def prepare_for_jump(asm, allocator, sourcevars, src2loc, target): + + tar2src = {} # tar var -> src var + tar2loc = {} + + # construct mapping of targets to sources; note that "target vars" + # and "target locs" are the same thing right now + targetlocs = target.arg_locations + for i in range(len(targetlocs)): + tloc = targetlocs[i] + tar2loc[tloc] = tloc + tar2src[tloc] = sourcevars[i] + + gen = JumpPatchupGenerator(asm, allocator) + emit_moves(gen, tar2src, tar2loc, src2loc) class MachineCodeBlock: @@ -475,21 +677,21 @@ def emit(self): if self.parent is not None: - allocator = RegisterAllocation(self.parent.var2reg) + allocator = RegisterAllocation( + self.rgenop.MINUSERREG, self.parent.var2loc) else: - allocator = RegisterAllocation(self.initial_varmapping) + allocator = RegisterAllocation( + self.rgenop.MINUSERREG, self.initial_varmapping) self.insns = allocator.allocate_for_insns(self.insns) for insn in self.insns: insn.emit(self.asm) - self.var2reg = allocator.var2reg + self.var2loc = allocator.var2loc return allocator def finish_and_return(self, sigtoken, gv_returnvar): gv_returnvar = gv_returnvar.load(self) + self.insns.append(Return(gv_returnvar)) allocator = self.emit() - reg = allocator.var2reg[gv_returnvar] - if reg.number != 3: - self.asm.mr(r3, reg.number) # Emit standard epilogue: self.asm.lwz(rSP,rSP,0) # restore old SP @@ -501,8 +703,8 @@ def finish_and_goto(self, outputargs_gv, target): allocator = self.emit() - cur_locations = [allocator.var2reg[v] for v in outputargs_gv] - prepare_for_jump(self, cur_locations, target) + prepare_for_jump( + self.asm, allocator, outputargs_gv, allocator.var2loc, target) self.asm.load_word(0, target.startaddr) self.asm.mtctr(0) self.asm.bctr() @@ -515,9 +717,9 @@ gv = args_gv[i] = gv.load(self) allocator = self.emit() for gv in args_gv: - arg_locations.append(allocator.var2reg[gv]) + arg_locations.append(allocator.var2loc[gv]) self.insns = [] - self.initial_varmapping = allocator.var2reg + self.initial_varmapping = allocator.var2loc return Label(self.asm.mc.tell(), arg_locations) def newvar(self): @@ -532,6 +734,13 @@ gv_result = self.newvar() return (gv_result, gv_x.load(self)) + def op_int_mul(self, gv_x, gv_y): + gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y) + self.insns.append( + Insn_GPR__GPR_GPR(RPPCAssembler.mullw, + gv_result, [gv_x, gv_y])) + return gv_result + def op_int_add(self, gv_x, gv_y): if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2**16: gv_result = self.newvar() @@ -604,6 +813,10 @@ class RPPCGenOp(AbstractRGenOp): from pypy.jit.codegen.i386.codebuf import MachineCodeBlock + # minimum register we will use for register allocation + # we can artifically restrict it for testing purposes + MINUSERREG = 3 + def __init__(self): self.mcs = [] # machine code blocks where no-one is currently writing Added: pypy/dist/pypy/jit/codegen/ppc/test/test_emit_moves.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_emit_moves.py Fri Nov 3 19:16:19 2006 @@ -0,0 +1,54 @@ +import py +from pypy.jit.codegen.ppc.rgenop import emit_moves + +class TheHeap(object): + def __init__(self, locs): + self.data = {} + for i in range(locs): + self.data[i] = i + self.numlocs = locs + def emit_move(self, tar, src): + self.data[tar] = self.data[src] + def create_fresh_location(self): + self.numlocs += 1 + return self.numlocs-1 + +def test_simple_cycle(): + heap = TheHeap(2) + tar2src = {'A':'b', 'B':'a'} + tar2loc = {'A':0, 'B':1} + src2loc = {'a':0, 'b':1} + assert heap.data[0] == 0 + assert heap.data[1] == 1 + emit_moves(heap, tar2src, tar2loc, src2loc) + assert heap.data[0] == 1 + assert heap.data[1] == 0 + assert heap.numlocs == 3 # only creates 1 extra loc + +def test_cycle_3(): + heap = TheHeap(3) + tar2src = {'A':'b', 'B':'c', 'C':'a'} + tar2loc = {'A':0, 'B':1, 'C':2} + src2loc = {'a':0, 'b':1, 'c':2} + assert heap.data[0] == 0 + assert heap.data[1] == 1 + assert heap.data[2] == 2 + emit_moves(heap, tar2src, tar2loc, src2loc) + assert heap.data[0] == 1 + assert heap.data[1] == 2 + assert heap.data[2] == 0 + assert heap.numlocs == 4 # only creates 1 extra loc + +def test_dag(): + heap = TheHeap(3) + tar2src = {'A':'a', 'B':'b'} + tar2loc = {'A':0, 'B':1} + src2loc = {'a':1, 'b':2} + assert heap.data[0] == 0 + assert heap.data[1] == 1 + assert heap.data[2] == 2 + emit_moves(heap, tar2src, tar2loc, src2loc) + assert heap.data[0] == 1 + assert heap.data[1] == 2 + assert heap.data[2] == 2 + assert heap.numlocs == 3 # only creates 1 extra loc Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Fri Nov 3 19:16:19 2006 @@ -1,5 +1,15 @@ +import py from pypy.jit.codegen.ppc.rgenop import RPPCGenOp from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTests +class FewRegisters(RPPCGenOp): + MINUSERREG = 29 + class TestRPPCGenop(AbstractRGenOpTests): RGenOp = RPPCGenOp + +class TestRPPCGenopNoRegs(AbstractRGenOpTests): + RGenOp = FewRegisters + + def compile(self, runner, argtypes): + py.test.skip("Skip compiled tests w/ restricted register allocator") Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py ============================================================================== --- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py (original) +++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Fri Nov 3 19:16:19 2006 @@ -96,31 +96,42 @@ def make_goto(rgenop): + # z = 1 # while x > 0: # y += x + # z *= x # x -= 1 + # y += z # return y signed_kind = rgenop.kindToken(lltype.Signed) sigtoken = rgenop.sigToken(FUNC2) builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) # loop start block - args_gv = [gv_x, gv_y] - loopblock = builder.enter_next_block([signed_kind, signed_kind], args_gv) - [gv_x, gv_y] = args_gv + args_gv = [gv_x, gv_y, rgenop.genconst(1)] + loopblock = builder.enter_next_block( + [signed_kind, signed_kind, signed_kind], args_gv) + [gv_x, gv_y, gv_z] = args_gv gv_cond = builder.genop2("int_gt", gv_x, rgenop.genconst(0)) bodybuilder = builder.jump_if_true(gv_cond) - builder.finish_and_return(sigtoken, gv_y) + args_gv = [gv_y, gv_z] + builder.enter_next_block( + [signed_kind, signed_kind], args_gv) + [gv_y, gv_z] = args_gv + gv_y3 = builder.genop2("int_add", gv_y, gv_z) + builder.finish_and_return(sigtoken, gv_y3) # loop body - args_gv = [gv_y, gv_x] - bodybuilder.enter_next_block([signed_kind, signed_kind], args_gv) - [gv_y, gv_x] = args_gv + args_gv = [gv_z, gv_y, gv_x] + bodybuilder.enter_next_block( + [signed_kind, signed_kind, signed_kind], args_gv) + [gv_z, gv_y, gv_x] = args_gv + gv_z2 = bodybuilder.genop2("int_mul", gv_x, gv_z) gv_y2 = bodybuilder.genop2("int_add", gv_x, gv_y) gv_x2 = bodybuilder.genop2("int_sub", gv_x, rgenop.genconst(1)) - bodybuilder.finish_and_goto([gv_x2, gv_y2], loopblock) + bodybuilder.finish_and_goto([gv_x2, gv_y2, gv_z2], loopblock) # done gv_gotofn = rgenop.gencallableconst(sigtoken, "goto", entrypoint) @@ -293,17 +304,17 @@ gv_gotofn = make_goto(rgenop) print gv_gotofn.value fnptr = cast(c_void_p(gv_gotofn.value), CFUNCTYPE(c_int, c_int, c_int)) - res = fnptr(30, 17) # <== the segfault is here - assert res == 31 * 15 + 17 + res = fnptr(10, 17) # <== the segfault is here + assert res == 3628872 res = fnptr(3, 17) # <== or here - assert res == 23 + assert res == 29 def test_goto_compile(self): fn = self.compile(get_goto_runner(self.RGenOp), [int, int]) - res = fn(30, 17) - assert res == 31 * 15 + 17 + res = fn(10, 17) + assert res == 3628872 res = fn(3, 17) - assert res == 23 + assert res == 29 def test_if_direct(self): rgenop = self.RGenOp() From fijal at codespeak.net Fri Nov 3 19:18:12 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 3 Nov 2006 19:18:12 +0100 (CET) Subject: [pypy-svn] r34144 - pypy/branch/transparent-proxy/pypy/interpreter Message-ID: <20061103181812.CE3361006E@code0.codespeak.net> Author: fijal Date: Fri Nov 3 19:18:11 2006 New Revision: 34144 Modified: pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py Log: oops. Modified: pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py Fri Nov 3 19:18:11 2006 @@ -486,7 +486,6 @@ return None obj = self.interpclass_w(w_obj) if not isinstance(obj, RequiredClass): # or obj is None - import pdb;pdb.set_trace() msg = "'%s' object expected, got '%s' instead" % ( RequiredClass.typedef.name, w_obj.getclass(self).getname(self, '?')) From rxe at codespeak.net Fri Nov 3 19:29:31 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 3 Nov 2006 19:29:31 +0100 (CET) Subject: [pypy-svn] r34145 - in pypy/dist/pypy/lang/automata: . test Message-ID: <20061103182931.1F5BE10075@code0.codespeak.net> Author: rxe Date: Fri Nov 3 19:29:26 2006 New Revision: 34145 Modified: pypy/dist/pypy/lang/automata/dfa.py pypy/dist/pypy/lang/automata/test/test_dfa.py Log: two steps back, one step forward Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Fri Nov 3 19:29:26 2006 @@ -99,10 +99,17 @@ res = hint(res, variable=True) return res -def recognizeparts(trans, finals, s): +def convertagain(automaton): + alltrans = {} + for (s, c), r in automaton.transitions.items(): + statetrans = alltrans.setdefault(s, {}) + statetrans[c] = r + return alltrans, automaton.final_states + +def recognizeparts(alltrans, finals, s): " a less simple recognizer " - trans = hint(trans, deepfreeze=True) finals = hint(finals, deepfreeze=True) + alltrans = hint(alltrans, deepfreeze=True) indx = 0 state = 0 @@ -114,10 +121,12 @@ char = s[indx] char = hint(char, promote=True) - state = trans.get((state, char), -1) + statetrans = alltrans[state] + state = statetrans.get(char, -1) + + hint(state, concrete=True) if state == -1: return False - hint(state, concrete=True) indx += 1 res = state in finals Modified: pypy/dist/pypy/lang/automata/test/test_dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/test/test_dfa.py (original) +++ pypy/dist/pypy/lang/automata/test/test_dfa.py Fri Nov 3 19:29:26 2006 @@ -40,4 +40,13 @@ return recognizetable(dfatable, s, final_states) assert interpret(main, [0]) assert not interpret(main, [1]) + +def test_dfa_compiledummy2(): + def main(gets): + a = getautomaton() + alltrans, final_states = convertagain(a) + s = ["aaaaaaaaaab", "aaaa"][gets] + return recognizeparts(alltrans, final_states, s) + assert interpret(main, [0]) + assert not interpret(main, [1]) From niko at codespeak.net Fri Nov 3 19:35:04 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 3 Nov 2006 19:35:04 +0100 (CET) Subject: [pypy-svn] r34146 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061103183504.A3F7B10075@code0.codespeak.net> Author: niko Date: Fri Nov 3 19:35:02 2006 New Revision: 34146 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: (mwh, niko) minor tweak of no import to please annotator Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Fri Nov 3 19:35:02 2006 @@ -222,7 +222,6 @@ reg_args is the vars that need to have registers allocated for them reg_arg_regclasses is the type of register that needs to be allocated ''' - info = (0,0) def __init__(self): self.__magic_index = _var_index[0] _var_index[0] += 1 @@ -287,6 +286,7 @@ self.imm.value) class CMPInsn(Insn): + info = (0,0) # please the annotator for tests that don't use CMPW/CMPWI pass class CMPW(CMPInsn): From niko at codespeak.net Fri Nov 3 19:39:55 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Fri, 3 Nov 2006 19:39:55 +0100 (CET) Subject: [pypy-svn] r34147 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061103183955.CC04C10077@code0.codespeak.net> Author: niko Date: Fri Nov 3 19:39:54 2006 New Revision: 34147 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: expand on description of emit_moves() algorithm Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Fri Nov 3 19:39:54 2006 @@ -449,15 +449,24 @@ # Basic idea: # - # Construct a graph for each move (Ti <- Si) - # There is an edge between two nodes i and j if loc[Ti] == loc[Sj] - # If there are no cycles, then a simple tree walk will suffice - # Algorithm is: avoid cycles by creating temps when needed + # Construct a dependency graph, with a node for each move (Ti <- + # Si). Add an edge between two nodes i and j if loc[Ti] == + # loc[Sj]. (If executing the node's move would overwrite the + # source for another move). If there are no cycles, then a + # simple tree walk will suffice. If there *ARE* cycles, however, + # something more is needed. # - # Do tree walk, if backedge is detected to node j, then move Sj to - # a fresh slot Sn, and change Sj from Ti <- Sj to Ti <- Sn. Now - # there is no need for the backedge, so don't add it and continue. - # When finishing a leaf node, emit the move. + # In a nutshell, the algorithm is to walk the tree, and whenever + # a backedge is detected break the cycle by creating a fresh + # location and remapping the source of the node so that it no + # longer conflicts. So, if you are in node i, and you detect a + # cycle involving node j (so, Ti and Sj are the same location), + # then you create a fresh location Sn. You move Sj to Sn, and + # remap node j so that instead of being Tj <- Sj it is Tj <- Sn. + # Now there is no need for the backedge, so you can continue. + # Whenever you have visited every edge going out from a node, all of + # its dependent moves have been performed, so you can emit the + # node's move and return. tarvars = tar2src.keys() From mwh at codespeak.net Sat Nov 4 11:36:05 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sat, 4 Nov 2006 11:36:05 +0100 (CET) Subject: [pypy-svn] r34157 - in pypy/dist/pypy: annotation rpython rpython/test Message-ID: <20061104103605.098E410070@code0.codespeak.net> Author: mwh Date: Sat Nov 4 11:36:03 2006 New Revision: 34157 Modified: pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/rpython/rlist.py pypy/dist/pypy/rpython/test/test_rlist.py Log: (niko,mwh) implement list.remove for RPython Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Sat Nov 4 11:36:03 2006 @@ -290,6 +290,10 @@ def method_insert(lst, s_index, s_value): lst.method_append(s_value) + def method_remove(lst, s_value): + lst.listdef.resize() + lst.listdef.generalize(s_value) + def method_pop(lst, s_index=None): lst.listdef.resize() return lst.listdef.read_item() Modified: pypy/dist/pypy/rpython/rlist.py ============================================================================== --- pypy/dist/pypy/rpython/rlist.py (original) +++ pypy/dist/pypy/rpython/rlist.py Sat Nov 4 11:36:03 2006 @@ -103,6 +103,13 @@ hop.exception_cannot_occur() hop.gendirectcall(ll_reverse,v_lst) + def rtype_method_remove(self, hop): + v_lst, v_value = hop.inputargs(self, self.item_repr) + hop.has_implicit_exception(ValueError) # record that we know about it + hop.exception_is_here() + return hop.gendirectcall(ll_listremove, v_lst, v_value, + self.get_eqfunc()) + def rtype_method_index(self, hop): v_lst, v_value = hop.inputargs(self, self.item_repr) hop.has_implicit_exception(ValueError) # record that we know about it @@ -744,6 +751,11 @@ j += 1 raise ValueError # can't say 'list.index(x): x not in list' +def ll_listremove(lst, obj, eqfn): + index = ll_listindex(lst, obj, eqfn) # raises ValueError if obj not in lst + ll_delitem_nonneg(dum_nocheck, lst, index) +ll_listremove.oopspec = 'list.remove(obj)' + def ll_inplace_mul(l, factor): length = l.ll_length() if factor < 0: Modified: pypy/dist/pypy/rpython/test/test_rlist.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rlist.py (original) +++ pypy/dist/pypy/rpython/test/test_rlist.py Sat Nov 4 11:36:03 2006 @@ -1023,6 +1023,13 @@ assert lst in lst2 self.interpret(dummyfn, [3]) + def test_list_remove(self): + def dummyfn(n, p): + l = range(n) + l.remove(p) + return len(l) + res = self.interpret(dummyfn, [1, 0]) + assert res == 0 class TestLLtype(BaseTestRlist, LLRtypeMixin): rlist = ll_rlist From cfbolz at codespeak.net Sat Nov 4 11:46:10 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 11:46:10 +0100 (CET) Subject: [pypy-svn] r34158 - pypy/extradoc/sprintinfo/ddorf2006b Message-ID: <20061104104610.B079910077@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 11:46:09 2006 New Revision: 34158 Modified: pypy/extradoc/sprintinfo/ddorf2006b/planning.txt Log: planning for today Modified: pypy/extradoc/sprintinfo/ddorf2006b/planning.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2006b/planning.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2006b/planning.txt Sat Nov 4 11:46:09 2006 @@ -4,6 +4,7 @@ times: 10am - ... Wednesday morning: various presentations Thursday breakday + Saturday: py-lib release thinking Attendees: Carl Friedrich, Armin, Michael, Antonio, Samuele, Anders, Maciej, Stephan, @@ -13,11 +14,12 @@ Tasks ===== - - javascript interpreter (leonardo, stephan, maciek around) + - javascript interpreter (leonardo, stephan, guido around) addition of numbers, strings (with proper, twisted semantics) works integration of the narcissus parser nested scopes, variable declarations, functions without parameters - function arguments working, windows support, in-progress: argument attribute + function arguments working, windows support, argument attribute + implemented grouping, the comma-operator, mac-os support, exceptions - jvm backend sharing code between gencli and genjvm @@ -25,23 +27,27 @@ number manipulations, field access more tests running! added support for classes, in-progress: constants - - transparent proxies (maciek, guido, samuele around) + - transparent proxies (maciek, samuele, antonio around) lists are working somehow, refactoring in progress dictionaries seem to work somewhat provide a way to implement an object that is of type list, but the behaviour is defined at app-level + implemented objects, lists and dictionaries, function calls in an sucky way - apigen tool changes to instance variables after calls to functions - - build tool + - build tool + discussions (carl friedrich, guido) it's now actually building pypy, sending the usession directory back - .net integration, fixing pypy.net quick hack, but pypy.net is no longer broken + planning session has happened! experiments to come - - making streams RPython (anto, carl friedrich) - in progress + - making streams RPython + done + +- using the RPython streams for pypy files (guido, carl friedrich) - jit code generation lots of documentation about the jit-backend interface, fighting with @@ -51,11 +57,15 @@ hackish way: produce strings in memory and have llvm parse them - jit ppc code generation (mwh, niko) + wrote a simple greedy register allocator, spills work + implement links between basic blocks, placing the arguments in the right way + - jit front end (armin, arre, richard) IN-PROGRESS fixed the last known bug, experimentation needed porting portal tests to run with the backends + deepfreezing implemented! hint that a structure is not going to change - running tests on the translated pypy-cs (related to py.test refactoring?) @@ -70,5 +80,6 @@ kind of worked, some progress - fixing pypy on windows, adding some more os functions (christian) + unknown amount of progress - general wizardry (samuele) From niko at codespeak.net Sat Nov 4 12:27:04 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Sat, 4 Nov 2006 12:27:04 +0100 (CET) Subject: [pypy-svn] r34159 - pypy/dist/pypy/jit/codegen/test Message-ID: <20061104112704.4BA7E1006E@code0.codespeak.net> Author: niko Date: Sat Nov 4 12:27:03 2006 New Revision: 34159 Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Log: refactor the test_goto so that the flow of variables is clearer (and correct an accidental reuse of vars that we found) Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py ============================================================================== --- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py (original) +++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Sat Nov 4 12:27:03 2006 @@ -94,20 +94,8 @@ return res return branching_runner - -def make_goto(rgenop): - # z = 1 - # while x > 0: - # y += x - # z *= x - # x -= 1 - # y += z - # return y - signed_kind = rgenop.kindToken(lltype.Signed) - sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) - - # loop start block +# loop start block +def loop_start(rgenop, builder, signed_kind, gv_x, gv_y): args_gv = [gv_x, gv_y, rgenop.genconst(1)] loopblock = builder.enter_next_block( [signed_kind, signed_kind, signed_kind], args_gv) @@ -115,6 +103,10 @@ gv_cond = builder.genop2("int_gt", gv_x, rgenop.genconst(0)) bodybuilder = builder.jump_if_true(gv_cond) + return args_gv, loopblock, bodybuilder + +# loop exit +def loop_exit(builder, sigtoken, signed_kind, gv_y, gv_z): args_gv = [gv_y, gv_z] builder.enter_next_block( [signed_kind, signed_kind], args_gv) @@ -122,7 +114,8 @@ gv_y3 = builder.genop2("int_add", gv_y, gv_z) builder.finish_and_return(sigtoken, gv_y3) - # loop body +# loop body +def loop_body(rgenop, loopblock, bodybuilder, signed_kind, gv_x, gv_y, gv_z): args_gv = [gv_z, gv_y, gv_x] bodybuilder.enter_next_block( [signed_kind, signed_kind, signed_kind], args_gv) @@ -133,6 +126,25 @@ gv_x2 = bodybuilder.genop2("int_sub", gv_x, rgenop.genconst(1)) bodybuilder.finish_and_goto([gv_x2, gv_y2, gv_z2], loopblock) +def make_goto(rgenop): + # z = 1 + # while x > 0: + # y += x + # z *= x + # x -= 1 + # y += z + # return y + signed_kind = rgenop.kindToken(lltype.Signed) + sigtoken = rgenop.sigToken(FUNC2) + builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) + + [gv_x, gv_y, gv_z],loopblock,bodybuilder = loop_start( + rgenop, builder, signed_kind, gv_x, gv_y) + loop_exit( + builder, sigtoken, signed_kind, gv_y, gv_z) + loop_body( + rgenop, loopblock, bodybuilder, signed_kind, gv_x, gv_y, gv_z) + # done gv_gotofn = rgenop.gencallableconst(sigtoken, "goto", entrypoint) return gv_gotofn From stephan at codespeak.net Sat Nov 4 12:32:31 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Sat, 4 Nov 2006 12:32:31 +0100 (CET) Subject: [pypy-svn] r34160 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061104113231.18B2C10079@code0.codespeak.net> Author: stephan Date: Sat Nov 4 12:32:29 2006 New Revision: 34160 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/jsobj.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) implemented booleans, if-then-else and gt operator Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Sat Nov 4 12:32:29 2006 @@ -9,6 +9,13 @@ # def __init__(self, lineno = 1): # self.lineno = lineno +class BinaryOperator(Node): + """super class for binary operators""" + def __init__(self, left, right): + self.left = left + self.right = right + + class Array(Node): def __init__(self, items=()): self.items = items @@ -50,11 +57,19 @@ def __init__(self, expr): self.expr = expr +class Gt(BinaryOperator): pass + class Identifier(Node): def __init__(self, name, initialiser): self.name = name self.initialiser = initialiser +class If(Node): + def __init__(self, condition, thenPart=None, elsePart=None): + self.condition = condition + self.thenPart = thenPart + self.elsePart = elsePart + class Index(Node): def __init__(self, left, expr): self.left = left @@ -72,10 +87,7 @@ def __init__(self, properties): self.properties = properties -class Plus(Node): - def __init__(self, left, right): - self.left = left - self.right = right +class Plus(BinaryOperator):pass class PropertyInit(Node): def __init__(self, name, value): @@ -106,7 +118,7 @@ self.exception = exception class Try(Node): - """The Try class.""" + # TODO: rewrite to use 'Undefined' def __init__(self, tryblock, catchblock, finallyblock, catchparam): self.tryblock = tryblock self.catchblock = catchblock @@ -114,6 +126,10 @@ self.catchparam = catchparam +class Undefined(Node): + def __init__(self): + pass + class Vars(Node): def __init__(self, nodes): self.nodes = nodes @@ -133,53 +149,64 @@ if d is None: return d tp = d['type'] - if tp == 'SCRIPT': - # XXX: Cannot parse it right now - return Script(getlist(d), [], []) - elif tp == 'ARRAY_INIT': + if tp == 'ARRAY_INIT': return Array(getlist(d)) - elif tp == 'SEMICOLON': - return Semicolon(from_dict(d['expression'])) - elif tp == 'NUMBER': - return Number(float(d['value'])) - elif tp == 'IDENTIFIER': - return Identifier(d['value'], from_dict(d.get('initializer', None))) - elif tp == 'LIST': - return List(getlist(d)) - elif tp == 'CALL': - return Call(from_dict(d['0']), from_dict(d['1'])) - elif tp == 'PLUS': - return Plus(from_dict(d['0']), from_dict(d['1'])) elif tp == 'ASSIGN': return Assign(from_dict(d['0']), from_dict(d['1'])) - elif tp == 'STRING': - return String(d['value']) - elif tp == 'PROPERTY_INIT': - return PropertyInit(from_dict(d['0']), from_dict(d['1'])) - elif tp == 'OBJECT_INIT': - return ObjectInit(getlist(d)) + elif tp == 'BLOCK': + return Block(getlist(d)) + elif tp == 'CALL': + return Call(from_dict(d['0']), from_dict(d['1'])) + elif tp == 'COMMA': + return Comma(from_dict(d['0']),from_dict(d['1'])) elif tp == 'DOT': return Dot(from_dict(d['0']), from_dict(d['1'])) - elif tp == 'INDEX': - return Index(from_dict(d['0']), from_dict(d['1'])) elif tp == 'FUNCTION': scope = scope_manager.enter_scope() body = from_dict(d['body']) f = Function(d['params'].split(','), body, scope) scope_manager.leave_scope() return f + elif tp == 'GROUP': + return Group(from_dict(d['0'])) + elif tp == 'GT': + return Gt(from_dict(d['0']), from_dict(d['1'])) + elif tp == 'IDENTIFIER': + return Identifier(d['value'], from_dict(d.get('initializer', None))) + elif tp == 'IF': + condition = from_dict(d['condition']) + if d['thenPart'] == 'null': + thenPart = Undefined() + else: + thenPart = from_dict(d['thenPart']) + if d['elsePart'] == 'null': + elsePart = Undefined() + else: + elsePart = from_dict(d['elsePart']) + return If(condition,thenPart,elsePart) + elif tp == 'INDEX': + return Index(from_dict(d['0']), from_dict(d['1'])) + elif tp == 'LIST': + return List(getlist(d)) + elif tp == 'NUMBER': + return Number(float(d['value'])) + elif tp == 'OBJECT_INIT': + return ObjectInit(getlist(d)) + elif tp == 'PLUS': + return Plus(from_dict(d['0']), from_dict(d['1'])) + elif tp == 'PROPERTY_INIT': + return PropertyInit(from_dict(d['0']), from_dict(d['1'])) elif tp == 'RETURN': return Return(from_dict(d['value'])) + elif tp == 'SCRIPT': + # XXX: Cannot parse it right now + return Script(getlist(d), [], []) + elif tp == 'SEMICOLON': + return Semicolon(from_dict(d['expression'])) + elif tp == 'STRING': + return String(d['value']) elif tp == 'THROW': return Throw(from_dict(d['exception'])) - elif tp == 'GROUP': - return Group(from_dict(d['0'])) - elif tp == 'COMMA': - return Comma(from_dict(d['0']),from_dict(d['1'])) - elif tp == 'VAR': - return Vars(getlist(d)) - elif tp == 'BLOCK': - return Block(getlist(d)) elif tp == 'TRY': finallyblock = None catchblock = None @@ -191,5 +218,7 @@ catchblock = from_dict(d['catchClauses']['block']) catchparam = d['catchClauses']['varName'] return Try(from_dict(d['tryBlock']), catchblock, finallyblock, catchparam) + elif tp == 'VAR': + return Vars(getlist(d)) else: raise NotImplementedError("Dont know how to handler %s" % tp) Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sat Nov 4 12:32:29 2006 @@ -1,7 +1,8 @@ from pypy.lang.js.astgen import * from pypy.lang.js.context import ExecutionContext -from pypy.lang.js.jsobj import W_Number, W_String, W_Object, w_Undefined, W_Arguments +from pypy.lang.js.jsobj import W_Number, W_String, W_Object +from pypy.lang.js.jsobj import w_Undefined, W_Arguments, W_Boolean from pypy.lang.js.scope import scope_manager def writer(x): @@ -80,11 +81,31 @@ def get_literal(self): return self.name +class __extend__(If): + def call(self, context=None): + if self.condition.call(context).ToBoolean(): + return self.thenPart.call(context) + else: + return self.elsePart.call(context) + class __extend__(Group): """The __extend__ class.""" def call(self, context = None): return self.expr.call(context) +def AbstractRelationalLt(value1, value2): + # TODO: really implement the algorithm + return value10)"),["true"]) + self.assert_prints(parse_d("print(0>1)"),["false"]) From antocuni at codespeak.net Sat Nov 4 12:55:27 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 4 Nov 2006 12:55:27 +0100 (CET) Subject: [pypy-svn] r34161 - pypy/dist/pypy/translator/cli/src Message-ID: <20061104115527.883ED1006E@code0.codespeak.net> Author: antocuni Date: Sat Nov 4 12:55:25 2006 New Revision: 34161 Modified: pypy/dist/pypy/translator/cli/src/ll_os.cs Log: More .NET-to-rpython exception conversion Modified: pypy/dist/pypy/translator/cli/src/ll_os.cs ============================================================================== --- pypy/dist/pypy/translator/cli/src/ll_os.cs (original) +++ pypy/dist/pypy/translator/cli/src/ll_os.cs Sat Nov 4 12:55:25 2006 @@ -235,6 +235,10 @@ try { stream = new FileStream(name, f_mode, f_access, FileShare.ReadWrite); } + catch(UnauthorizedAccessException e) { + raise_OSError(Errno.EACCES, e.Message); + return -1; + } catch(FileNotFoundException e) { raise_OSError(Errno.ENOENT, e.Message); return -1; From antocuni at codespeak.net Sat Nov 4 12:57:30 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sat, 4 Nov 2006 12:57:30 +0100 (CET) Subject: [pypy-svn] r34162 - in pypy/dist/pypy/translator/cli: . src Message-ID: <20061104115730.BE20E10080@code0.codespeak.net> Author: antocuni Date: Sat Nov 4 12:57:29 2006 New Revision: 34162 Modified: pypy/dist/pypy/translator/cli/query.py pypy/dist/pypy/translator/cli/src/query.cs Log: It seems that mono on snake uses a slighly different string representation for array types than the one on my box (notice that the two version are exactly the same!!). Modified: pypy/dist/pypy/translator/cli/query.py ============================================================================== --- pypy/dist/pypy/translator/cli/query.py (original) +++ pypy/dist/pypy/translator/cli/query.py Sat Nov 4 12:57:29 2006 @@ -83,7 +83,9 @@ return NamespaceDesc(name) def load_class_maybe(name): - if name not in ClassCache: + if name.startswith('System.Array+InternalArray'): + ClassCache[name] = ClassCache['System.Array'] + elif name not in ClassCache: load_class_or_namespace(name) Modified: pypy/dist/pypy/translator/cli/src/query.cs ============================================================================== --- pypy/dist/pypy/translator/cli/src/query.cs (original) +++ pypy/dist/pypy/translator/cli/src/query.cs Sat Nov 4 12:57:29 2006 @@ -126,6 +126,7 @@ && t != typeof(void) &&(t == typeof(System.ValueType) || t == typeof(System.Array) || + t.FullName.StartsWith("System.Array+InternalArray") || t.IsValueType || t.IsByRef || t.IsPointer || From stephan at codespeak.net Sat Nov 4 13:19:28 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Sat, 4 Nov 2006 13:19:28 +0100 (CET) Subject: [pypy-svn] r34163 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061104121928.F24B810082@code0.codespeak.net> Author: stephan Date: Sat Nov 4 13:19:25 2006 New Revision: 34163 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) while, less than and errorfix in abstract ls operator Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Sat Nov 4 13:19:25 2006 @@ -79,6 +79,8 @@ def __init__(self, nodes): self.nodes = nodes +class Lt(BinaryOperator): pass + class Number(Node): def __init__(self, num): self.num = num @@ -135,6 +137,11 @@ self.nodes = nodes [scope_manager.add_variable(id.name, w_Undefined) for id in nodes] +class While(Node): + def __init__(self, condition, body): + self.condition = condition + self.body = body + def getlist(d): if 'length' not in d: return [] @@ -188,6 +195,8 @@ return Index(from_dict(d['0']), from_dict(d['1'])) elif tp == 'LIST': return List(getlist(d)) + elif tp == 'LT': + return Lt(from_dict(d['0']), from_dict(d['1'])) elif tp == 'NUMBER': return Number(float(d['value'])) elif tp == 'OBJECT_INIT': @@ -220,5 +229,9 @@ return Try(from_dict(d['tryBlock']), catchblock, finallyblock, catchparam) elif tp == 'VAR': return Vars(getlist(d)) + elif tp == 'WHILE': + body = from_dict(d['body']) + condition = from_dict(d['condition']) + return While(condition, body) else: raise NotImplementedError("Dont know how to handler %s" % tp) Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sat Nov 4 13:19:25 2006 @@ -95,7 +95,9 @@ def AbstractRelationalLt(value1, value2): # TODO: really implement the algorithm - return value10)"),["true"]) self.assert_prints(parse_d("print(0>1)"),["false"]) + + def test_while(self): + self.assert_prints(parse_d(""" + i = 0; + while (i<3) { + print(i); + i = i+1; + } + print(i); + """), ["0","1","2","3"]) From arigo at codespeak.net Sat Nov 4 13:26:06 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 4 Nov 2006 13:26:06 +0100 (CET) Subject: [pypy-svn] r34164 - pypy/dist/pypy/jit/hintannotator Message-ID: <20061104122606.C8AD21008E@code0.codespeak.net> Author: arigo Date: Sat Nov 4 13:26:04 2006 New Revision: 34164 Modified: pypy/dist/pypy/jit/hintannotator/model.py Log: Avoid crashing on the debug_assert operation. Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Sat Nov 4 13:26:04 2006 @@ -15,7 +15,8 @@ cast_char_to_int cast_bool_to_int ptr_nonzero - ptr_iszero""".split() + ptr_iszero + debug_assert""".split() BINARY_OPERATIONS = """int_add int_sub int_mul int_mod int_and int_rshift int_floordiv int_xor int_or uint_add uint_sub uint_mul uint_mod uint_and uint_lshift uint_rshift uint_floordiv @@ -273,7 +274,10 @@ raise HintError("hint %s makes no sense on %r" % (hs_flags.const, hs_v1)) - + + def debug_assert(hs_v1, *args_hs): + pass + def getfield(hs_v1, hs_fieldname): S = hs_v1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) @@ -341,6 +345,9 @@ deepfrozen = True) return SomeLLAbstractValue.hint(hs_c1, hs_flags) + def debug_assert(hs_c1, *args_hs): + pass + def direct_call(hs_f1, *args_hs): bookkeeper = getbookkeeper() fnobj = hs_f1.const._obj From pedronis at codespeak.net Sat Nov 4 14:25:41 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 4 Nov 2006 14:25:41 +0100 (CET) Subject: [pypy-svn] r34165 - in pypy/branch/transparent-proxy/pypy: interpreter objspace/std Message-ID: <20061104132541.B4E6E10092@code0.codespeak.net> Author: pedronis Date: Sat Nov 4 14:25:39 2006 New Revision: 34165 Modified: pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py pypy/branch/transparent-proxy/pypy/interpreter/gateway.py pypy/branch/transparent-proxy/pypy/interpreter/typedef.py pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Log: (pedronis, fijal) saner support for transparent proxy function calls. Modified: pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/baseobjspace.py Sat Nov 4 14:25:39 2006 @@ -92,6 +92,12 @@ def setslotvalue(self, index, w_val): raise NotImplementedError + def descr_call_mismatch(self, space, opname, RequiredClass, args): + msg = "'%s' object expected, got '%s' instead" % ( + RequiredClass.typedef.name, + self.getclass(space).getname(space, '?')) + raise OperationError(space.w_TypeError, space.wrap(msg)) + # used by _weakref implemenation def getweakref(self): @@ -101,12 +107,6 @@ typename = space.type(self).getname(space, '?') raise OperationError(space.w_TypeError, space.wrap( "cannot create weak reference to '%s' object" % typename)) - - def descr_call_not_understood(self, space, reqcls, name, args): - msg = "'%s' object expected, got '%s' instead" % ( - reqcls.typedef.name, - self.getclass(space).getname(space, '?')) - raise OperationError(space.w_TypeError, space.wrap(msg)) class Wrappable(W_Root): """A subclass of Wrappable is an internal, interpreter-level class @@ -154,6 +154,9 @@ def __str__(self): return self.msg +class DescrMismatch(Exception): + pass + class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" @@ -477,6 +480,13 @@ return w_obj return None + def descr_self_interp_w(self, RequiredClass, w_obj): + obj = self.interpclass_w(w_obj) + if not isinstance(obj, RequiredClass): + raise DescrMismatch() + return obj + descr_self_interp_w._annspecialcase_ = 'specialize:arg(1)' + def interp_w(self, RequiredClass, w_obj, can_be_None=False): """ Unwrap w_obj, checking that it is an instance of the required internal Modified: pypy/branch/transparent-proxy/pypy/interpreter/gateway.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/gateway.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/gateway.py Sat Nov 4 14:25:39 2006 @@ -16,7 +16,7 @@ from pypy.interpreter import eval from pypy.interpreter.function import Function, Method from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable -from pypy.interpreter.baseobjspace import Wrappable, SpaceCache +from pypy.interpreter.baseobjspace import Wrappable, SpaceCache, DescrMismatch from pypy.interpreter.argument import Arguments, AbstractArguments from pypy.tool.sourcetools import NiceCompile, compile2 @@ -55,7 +55,10 @@ if isinstance(el, str): getattr(self, "visit_%s" % (el,))(el, *args) elif isinstance(el, tuple): - self.visit_function(el, *args) + if el[0] == 'self': + self.visit_self(el[1], *args) + else: + self.visit_function(el, *args) else: for typ in self.bases_order: if issubclass(el, typ): @@ -100,6 +103,9 @@ def visit_function(self, (func, cls), app_sig): self.dispatch(cls, app_sig) + + def visit_self(self, cls, app_sig): + self.visit__Wrappable(cls, app_sig) def visit__Wrappable(self, el, app_sig): name = el.__name__ @@ -170,6 +176,10 @@ self.run_args.append("%s(%s)" % (self.use(func), self.scopenext())) + def visit_self(self, typ): + self.run_args.append("space.descr_self_interp_w(%s, %s)" % + (self.use(typ), self.scopenext())) + def visit__Wrappable(self, typ): self.run_args.append("space.interp_w(%s, %s)" % (self.use(typ), self.scopenext())) @@ -197,9 +207,9 @@ self.run_args.append("space.%s_w(%s)" % (typ.__name__, self.scopenext())) - def _make_unwrap_activation_class(self, unwrap_spec, not_understood, cache={}): + def _make_unwrap_activation_class(self, unwrap_spec, cache={}): try: - key = (tuple(unwrap_spec), not_understood) + key = tuple(unwrap_spec) activation_factory_cls, run_args = cache[key] assert run_args == self.run_args, ( "unexpected: same spec, different run_args") @@ -216,23 +226,10 @@ #print label d = {} - if not_understood is None: - source = """if 1: - def _run_UWS_%s(self, space, scope_w): - return self.behavior(%s) - \n""" % (label, ', '.join(self.run_args)) - else: - assert issubclass(unwrap_spec[0], Wrappable) - args = ', '.join(self.run_args[1:]) - reqcls = self.use(unwrap_spec[0]) - source = """if 1: - def _run_UWS_%s(self, space, scope_w): - w_self = scope_w[0] - if not isinstance(w_self, %s): - return w_self.descr_call_not_understood(space, %s, %r, %s) - return self.behavior(w_self, %s) - \n""" % (label, reqcls, reqcls, not_understood, args, args) - + source = """if 1: + def _run_UWS_%s(self, space, scope_w): + return self.behavior(%s) + \n""" % (label, ', '.join(self.run_args)) exec compile2(source) in self.miniglobals, d d['_run'] = d['_run_UWS_%s' % label] del d['_run_UWS_%s' % label] @@ -243,11 +240,10 @@ cache[key] = activation_cls, self.run_args return activation_cls - def make_activation(unwrap_spec, func, not_understood): + def make_activation(unwrap_spec, func): emit = UnwrapSpec_EmitRun() emit.apply_over(unwrap_spec) - activation_uw_cls = emit._make_unwrap_activation_class(unwrap_spec, - not_understood) + activation_uw_cls = emit._make_unwrap_activation_class(unwrap_spec) return activation_uw_cls(func) make_activation = staticmethod(make_activation) @@ -289,6 +285,10 @@ def visit_function(self, (func, cls)): raise FastFuncNotSupported + def visit_self(self, typ): + self.unwrap.append("space.descr_self_interp_w(%s, %s)" % + (self.use(typ), self.nextarg())) + def visit__Wrappable(self, typ): self.unwrap.append("space.interp_w(%s, %s)" % (self.use(typ), self.nextarg())) @@ -316,12 +316,12 @@ self.unwrap.append("space.%s_w(%s)" % (typ.__name__, self.nextarg())) - def make_fastfunc(unwrap_spec, func, not_understood): + def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) narg = unwrap_info.n args = ['space'] + unwrap_info.args - if args == unwrap_info.unwrap and not_understood is None: + if args == unwrap_info.unwrap: fastfunc = func else: # try to avoid excessive bloat @@ -334,28 +334,12 @@ raise FastFuncNotSupported d = {} unwrap_info.miniglobals['func'] = func - if not_understood is None: - source = """if 1: - def fastfunc_%s_%d(%s): - return func(%s) - \n""" % (func.__name__, narg, - ', '.join(args), - ', '.join(unwrap_info.unwrap)) - else: - #def _run_UWS_%s(self, space, scope_w): - # w_self = scope_w[0] - # if not isinstance(w_self, %s): - # return w_self.descr_call_not_understood(space, %r, %s) - # return self.behavior(w_self, %s) - assert issubclass(unwrap_spec[0], Wrappable) - reqcls = self.use(unwrap_spec[0]) - source = """if 1: - def fastfunc_%s_%d(%s): - if not isinstance(w0, %s): - return w0.descr_call_not_understood(space, %s, %r, %s) - return func(%s) - \n""" % (func.__name__, narg, ",".join(args), reqcls, reqcls, - not_understood, ",".join(args[2:]), ",".join(unwrap_info.unwrap)) + source = """if 1: + def fastfunc_%s_%d(%s): + return func(%s) + \n""" % (func.__name__, narg, + ', '.join(args), + ', '.join(unwrap_info.unwrap)) exec compile2(source) in unwrap_info.miniglobals, d fastfunc = d['fastfunc_%s_%d' % (func.__name__, narg)] return narg, fastfunc @@ -364,13 +348,16 @@ class BuiltinCode(eval.Code): "The code object implementing a built-in (interpreter-level) hook." hidden_applevel = True + descrmismatch_op = None + descr_reqcls = None # When a BuiltinCode is stored in a Function object, # you get the functionality of CPython's built-in function type. NOT_RPYTHON_ATTRIBUTES = ['_bltin', '_unwrap_spec'] - def __init__(self, func, unwrap_spec = None, self_type = None, not_understood=None): + def __init__(self, func, unwrap_spec = None, self_type = None, + descrmismatch=None): "NOT_RPYTHON" # 'implfunc' is the interpreter-level function. # Note that this uses a lot of (construction-time) introspection. @@ -405,9 +392,17 @@ if self_type: assert unwrap_spec[0] == 'self',"self_type without 'self' spec element" unwrap_spec = list(unwrap_spec) - unwrap_spec[0] = self_type + if descrmismatch is not None: + assert issubclass(self_type, Wrappable) + unwrap_spec[0] = ('self', self_type) + self.descrmismatch_op = descrmismatch + self.descr_reqcls = self_type + else: + unwrap_spec[0] = self_type else: - assert not_understood is None, "not_understood without a self-type specified" + assert descrmismatch is None, ( + "descrmismatch without a self-type specified") + orig_sig = Signature(func, argnames, varargname, kwargname) app_sig = Signature(func) @@ -423,8 +418,7 @@ else: self.maxargs = self.minargs - self.activation = UnwrapSpec_EmitRun.make_activation(unwrap_spec, func, - not_understood=not_understood) + self.activation = UnwrapSpec_EmitRun.make_activation(unwrap_spec, func) self._bltin = func self._unwrap_spec = unwrap_spec @@ -432,15 +426,12 @@ if 0 <= len(unwrap_spec) <= 5: try: arity, fastfunc = UnwrapSpec_FastFunc_Unwrap.make_fastfunc( - unwrap_spec, func, - not_understood=not_understood) + unwrap_spec, func) except FastFuncNotSupported: if unwrap_spec == [ObjSpace, Arguments]: - assert not_understood is None self.__class__ = BuiltinCodePassThroughArguments0 self.func__args__ = func elif unwrap_spec == [ObjSpace, W_Root, Arguments]: - assert not_understood is None self.__class__ = BuiltinCodePassThroughArguments1 self.func__args__ = func else: @@ -469,7 +460,12 @@ raise OperationError(space.w_MemoryError, space.w_None) except RuntimeError, e: raise OperationError(space.w_RuntimeError, - space.wrap("internal error: " + str(e))) + space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return scope_w[0].descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + args) if w_result is None: w_result = space.w_None return w_result @@ -489,6 +485,11 @@ except RuntimeError, e: raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return scope_w[0].descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + args) if w_result is None: w_result = space.w_None return w_result @@ -511,6 +512,11 @@ except RuntimeError, e: raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return scope_w[0].descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + args) if w_result is None: w_result = space.w_None return w_result @@ -522,8 +528,8 @@ except KeyboardInterrupt: raise OperationError(space.w_KeyboardInterrupt, space.w_None) except MemoryError: - raise OperationError(space.w_MemoryError, space.w_None) - except RuntimeError, e: + raise OperationError(space.w_MemoryError, space.w_None) + except (RuntimeError, DescrMismatch), e: raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) if w_result is None: @@ -540,7 +546,12 @@ raise OperationError(space.w_MemoryError, space.w_None) except RuntimeError, e: raise OperationError(space.w_RuntimeError, - space.wrap("internal error: " + str(e))) + space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return w1.descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + Arguments(space, [w1])) if w_result is None: w_result = space.w_None return w_result @@ -556,6 +567,11 @@ except RuntimeError, e: raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return w1.descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + Arguments(space, [w1, w2])) if w_result is None: w_result = space.w_None return w_result @@ -570,7 +586,12 @@ raise OperationError(space.w_MemoryError, space.w_None) except RuntimeError, e: raise OperationError(space.w_RuntimeError, - space.wrap("internal error: " + str(e))) + space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return w1.descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + Arguments(space, [w1, w2, w3])) if w_result is None: w_result = space.w_None return w_result @@ -585,7 +606,13 @@ raise OperationError(space.w_MemoryError, space.w_None) except RuntimeError, e: raise OperationError(space.w_RuntimeError, - space.wrap("internal error: " + str(e))) + space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return w1.descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + Arguments(space, + [w1, w2, w3, w4])) if w_result is None: w_result = space.w_None return w_result @@ -605,7 +632,8 @@ NOT_RPYTHON_ATTRIBUTES = ['_staticdefs'] - def __init__(self, f, app_name=None, unwrap_spec = None, not_understood=None): + def __init__(self, f, app_name=None, unwrap_spec = None, + descrmismatch=None): "NOT_RPYTHON" Wrappable.__init__(self) # f must be a function whose name does NOT start with 'app_' @@ -620,8 +648,9 @@ raise ValueError, ("function name %r suspiciously starts " "with 'app_'" % f.func_name) app_name = f.func_name - self._code = BuiltinCode(f, unwrap_spec=unwrap_spec, self_type = self_type, - not_understood=not_understood) + self._code = BuiltinCode(f, unwrap_spec=unwrap_spec, + self_type = self_type, + descrmismatch=descrmismatch) self.__name__ = f.func_name self.name = app_name self._staticdefs = list(f.func_defaults or ()) Modified: pypy/branch/transparent-proxy/pypy/interpreter/typedef.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/typedef.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/typedef.py Sat Nov 4 14:25:39 2006 @@ -583,7 +583,8 @@ Function.typedef = TypeDef("function", __new__ = interp2app(Function.descr_method__new__.im_func), __call__ = interp2app(Function.descr_function_call, - unwrap_spec=['self', Arguments], not_understood="__call__"), + unwrap_spec=['self', Arguments], + descrmismatch='__call__'), __get__ = interp2app(descr_function_get), __repr__ = interp2app(Function.descr_function_repr), __reduce__ = interp2app(Function.descr_function__reduce__, Modified: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Sat Nov 4 14:25:39 2006 @@ -66,7 +66,8 @@ from pypy.interpreter.function import Function typedef = Function.typedef - def descr_call_not_understood(self, space, reqcls, name, args): + def descr_call_mismatch(self, space, name, reqcls, args): + _, args = args.popfirst() args = args.prepend(space.wrap(name)) return space.call_args(self.w_controller, args) From fijal at codespeak.net Sat Nov 4 14:33:05 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 14:33:05 +0100 (CET) Subject: [pypy-svn] r34166 - pypy/branch/transparent-proxy/pypy/objspace/std Message-ID: <20061104133305.3B7D710095@code0.codespeak.net> Author: fijal Date: Sat Nov 4 14:33:03 2006 New Revision: 34166 Added: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py (contents, props changed) Removed: pypy/branch/transparent-proxy/pypy/objspace/std/tlistobject.py Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (pedronis, fijal) - Refactoring of names. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/model.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/model.py Sat Nov 4 14:33:03 2006 @@ -66,7 +66,7 @@ from pypy.objspace.std import stringobject from pypy.objspace.std import strsliceobject from pypy.objspace.std import strjoinobject - from pypy.objspace.std import tlistobject + from pypy.objspace.std import proxyobject from pypy.objspace.std import typeobject from pypy.objspace.std import sliceobject from pypy.objspace.std import longobject @@ -121,8 +121,8 @@ imported_but_not_registered[implcls] = True # xxx config - self.typeorder[tlistobject.W_TransparentList] = [] - self.typeorder[tlistobject.W_TransparentDict] = [] + self.typeorder[proxyobject.W_TransparentList] = [] + self.typeorder[proxyobject.W_TransparentDict] = [] if config.objspace.std.withstrdict: del self.typeorder[dictobject.W_DictObject] Added: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py Sat Nov 4 14:33:03 2006 @@ -0,0 +1,87 @@ + +""" transparent list implementation +""" + +from pypy.objspace.std.objspace import * +from pypy.objspace.std.proxy_helpers import register_type +from pypy.interpreter.error import OperationError +from pypy.interpreter import baseobjspace + +#class W_Transparent(W_Object): +# def __init__(self, w_controller): +# self.controller = w_controller + +class W_Transparent(W_Object): + def __init__(self, space, w_type, w_controller): + self.w_type = w_type + self.w_controller = w_controller + self.space = space + + def getclass(self, space): + return self.w_type + + def setclass(self, space, w_subtype): + raise OperationError(space.w_TypeError, + space.wrap("You cannot override __class__ for transparent proxies")) + + def getdictvalue(self, space, w_attr): + try: + return space.call_function(self.w_controller, space.wrap('__getattribute__'), + w_attr) + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return None + + def setdictvalue(self, space, w_attr, w_value): + try: + space.call_function(self.w_controller, space.wrap('__setattr__'), + w_attr, w_value) + return True + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return False + + def deldictvalue(self, space, w_attr): + try: + space.call_function(self.w_controller, space.wrap('__delattr__'), + w_attr) + return True + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return False + + def getdict(self): + return self.getdictvalue(self.space, self.space.wrap('__dict__')) + + def setdict(self, space, w_dict): + if not self.setdictvalue(space, space.wrap('__dict__'), w_dict): + baseobjspace.W_Root.setdict(self, space, w_dict) + + from pypy.objspace.std.objecttype import object_typedef as typedef + +class W_TransparentFunction(W_Transparent): + from pypy.interpreter.function import Function + typedef = Function.typedef + + def descr_call_mismatch(self, space, name, reqcls, args): + _, args = args.popfirst() + args = args.prepend(space.wrap(name)) + return space.call_args(self.w_controller, args) + +class W_TransparentList(W_Transparent): + from pypy.objspace.std.listobject import W_ListObject as original + from pypy.objspace.std.listtype import list_typedef as typedef + +class W_TransparentDict(W_Transparent): + from pypy.objspace.std.dictobject import W_DictObject as original + from pypy.objspace.std.dicttype import dict_typedef as typedef + +registerimplementation(W_TransparentList) +registerimplementation(W_TransparentDict) + + +register_type(W_TransparentList) +register_type(W_TransparentDict) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Sat Nov 4 14:33:03 2006 @@ -5,7 +5,7 @@ from pypy.interpreter import gateway from pypy.interpreter.function import Function from pypy.interpreter.error import OperationError -from pypy.objspace.std.tlistobject import W_TransparentList, W_TransparentDict,\ +from pypy.objspace.std.proxyobject import W_TransparentList, W_TransparentDict,\ W_Transparent, W_TransparentFunction from pypy.objspace.std.typeobject import W_TypeObject From fijal at codespeak.net Sat Nov 4 15:23:36 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 15:23:36 +0100 (CET) Subject: [pypy-svn] r34169 - in pypy/branch/transparent-proxy/pypy: interpreter objspace/std/test Message-ID: <20061104142336.4CFE7100A2@code0.codespeak.net> Author: fijal Date: Sat Nov 4 15:23:33 2006 New Revision: 34169 Modified: pypy/branch/transparent-proxy/pypy/interpreter/argument.py pypy/branch/transparent-proxy/pypy/interpreter/typedef.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py Log: (samuele, fijal) - Implementation of function. Modified: pypy/branch/transparent-proxy/pypy/interpreter/argument.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/argument.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/argument.py Sat Nov 4 15:23:33 2006 @@ -350,6 +350,11 @@ "Return a ([w1,w2...], {'kw':w3...}) pair." self._unpack() return self.arguments_w, self.kwds_w + + def popfirst(self): + self._unpack() + return self.arguments_w[0], Arguments(self.space, self.arguments_w[1:], + kwds_w = self.kwds_w) def _unpack(self): "unpack the *arg and **kwd into w_arguments and kwds_w" @@ -418,7 +423,7 @@ if not e.match(self.space, self.space.w_StopIteration): raise return None - + ### Parsing for function calls ### def _match_signature(self, scope_w, argnames, has_vararg=False, Modified: pypy/branch/transparent-proxy/pypy/interpreter/typedef.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/typedef.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/typedef.py Sat Nov 4 15:23:33 2006 @@ -5,7 +5,8 @@ import py from pypy.interpreter.gateway import interp2app from pypy.interpreter.argument import Arguments -from pypy.interpreter.baseobjspace import Wrappable, W_Root, ObjSpace +from pypy.interpreter.baseobjspace import Wrappable, W_Root, ObjSpace, \ + DescrMismatch from pypy.interpreter.error import OperationError from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate @@ -242,7 +243,7 @@ assert issubclass(cls, Wrappable) source = """ def descr_typecheck_%(name)s(space, w_obj, %(extra)s): - obj = space.interp_w(%(cls_name)s, w_obj) + obj = space.descr_self_interp_w(%(cls_name)s, w_obj) return %(name)s(space, obj, %(extra)s) """ miniglobals[cls_name] = cls @@ -295,6 +296,7 @@ self.fset = fset self.fdel = fdel self.doc = doc + self.reqcls = cls self.name = '' self.objclass_getter = objclass_getter @@ -307,7 +309,12 @@ #print property, w_obj, w_cls return space.wrap(property) else: - return property.fget(space, w_obj) + try: + return property.fget(space, w_obj) + except DescrMismatch, e: + return w_obj.descr_call_mismatch(space, '__getattribute__',\ + property.reqcls, Arguments(space, [w_obj, + space.wrap(property.name)])) def descr_property_set(space, property, w_obj, w_value): """property.__set__(obj, value) @@ -316,7 +323,12 @@ if fset is None: raise OperationError(space.w_TypeError, space.wrap("readonly attribute")) - fset(space, w_obj, w_value) + try: + fset(space, w_obj, w_value) + except DescrMismatch, e: + w_obj.descr_call_mismatch(space, '__setattr__',\ + property.reqcls, Arguments(space, [w_obj, + space.wrap(property.name), w_value])) def descr_property_del(space, property, w_obj): """property.__delete__(obj) @@ -325,7 +337,12 @@ if fdel is None: raise OperationError(space.w_AttributeError, space.wrap("cannot delete attribute")) - fdel(space, w_obj) + try: + fdel(space, w_obj) + except DescrMismatch, e: + w_obj.descr_call_mismatch(space, '__delattr__',\ + property.reqcls, Arguments(space, [w_obj, + space.wrap(property.name)])) def descr_get_objclass(space, property): return property.objclass_getter(space) @@ -586,7 +603,7 @@ unwrap_spec=['self', Arguments], descrmismatch='__call__'), __get__ = interp2app(descr_function_get), - __repr__ = interp2app(Function.descr_function_repr), + __repr__ = interp2app(Function.descr_function_repr, descrmismatch='__repr__'), __reduce__ = interp2app(Function.descr_function__reduce__, unwrap_spec=['self', ObjSpace]), __setstate__ = interp2app(Function.descr_function__setstate__, Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py Sat Nov 4 15:23:33 2006 @@ -4,21 +4,74 @@ from pypy.objspace.std.test.test_proxy import AppProxyBasic -class AppTestProxyFunction(AppProxyBasic): +class AppTestProxyFunction(object): + def setup_method(self, meth): + self.w_get_proxy = self.space.appexec([], """(): + class Controller(object): + def __init__(self, obj): + self.obj = obj + + def perform(self, name, *args, **kwargs): + return getattr(self.obj, name)(*args, **kwargs) + def get_proxy(f): + import types + return proxy(types.FunctionType, Controller(f).perform) + return get_proxy + """) + def test_function_noargs(self): def f(): return 3 - import types - c = self.Controller(f) - fun = proxy(types.FunctionType, c.perform) + fun = self.get_proxy(f) assert fun() == f() def test_simple_function(self): def f(x): return x - - import types - c = self.Controller(f) - fun = proxy(types.FunctionType, c.perform) + + fun = self.get_proxy(f) assert fun(3) == f(3) + + def test_function_args(self): + def f(x, y): + return x + + fun = self.get_proxy(f) + raises(TypeError, "fun(3)") + assert fun(1,2) == 1 + + def test_method_bind(self): + def f(self): + return 3 + + class A: + pass + + fun = self.get_proxy(f) + assert fun.__get__(A())() == 3 + + def test_function_repr(self): + def f(): + pass + + fun = self.get_proxy(f) + assert repr(fun).startswith(" Author: stephan Date: Sat Nov 4 15:29:25 2006 New Revision: 34170 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/jsobj.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (stephan, santagada) somewhat working object creation Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Sat Nov 4 15:29:25 2006 @@ -60,7 +60,7 @@ class Gt(BinaryOperator): pass class Identifier(Node): - def __init__(self, name, initialiser): + def __init__(self, name, initialiser=None): self.name = name self.initialiser = initialiser @@ -81,6 +81,10 @@ class Lt(BinaryOperator): pass +class New(Node): + def __init__(self, identifier): + self.identifier = identifier + class Number(Node): def __init__(self, num): self.num = num @@ -197,6 +201,8 @@ return List(getlist(d)) elif tp == 'LT': return Lt(from_dict(d['0']), from_dict(d['1'])) + elif tp == 'NEW': + return New(d['0']['value']) elif tp == 'NUMBER': return Number(float(d['value'])) elif tp == 'OBJECT_INIT': @@ -214,6 +220,8 @@ return Semicolon(from_dict(d['expression'])) elif tp == 'STRING': return String(d['value']) + elif tp == 'THIS': + return Identifier(d['value']) elif tp == 'THROW': return Throw(from_dict(d['exception'])) elif tp == 'TRY': Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sat Nov 4 15:29:25 2006 @@ -126,6 +126,23 @@ def call(self, context=None): return [node.call(context) for node in self.nodes] +class __extend__(New): + def call(self, context=None): + print context.__dict__ + obj = W_Object({}) + obj.Class = 'Object' + try: + constructor = context.access(self.identifier) + except NameError: + constructor = scope_manager.get_variable(self.identifier) + obj.dict_w['prototype'] = constructor.dict_w['prototype'] + nctx = ExecutionContext(context) + nctx.assign('this',obj) + constructor.Call(nctx) + + return obj + + class __extend__(Number): def call(self, context): return W_Number(self.num) @@ -165,6 +182,7 @@ class __extend__(Script): def call(self, context=None, args=(), this=None, params=None): + print 'params',params if params == None: params = [] ncontext = ExecutionContext(context) Modified: pypy/dist/pypy/lang/js/jsobj.py ============================================================================== --- pypy/dist/pypy/lang/js/jsobj.py (original) +++ pypy/dist/pypy/lang/js/jsobj.py Sat Nov 4 15:29:25 2006 @@ -35,6 +35,7 @@ self.dict_w['toString'] = W_Builtin({}, self.w_string) # XXX A bit hairy here, we store here a Function, and Script # is a self.function.body + self.dict_w['prototype'] = self self.function = function #self.class_ = None @@ -44,7 +45,7 @@ args=args, this=this, params= self.function.params) else: - raise SeePage(33) + return W_Object({}) def w_string(self): return W_String(str(self)) Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Sat Nov 4 15:29:25 2006 @@ -3,7 +3,8 @@ from pypy.lang.js import interpreter from pypy.lang.js.parser import parse from pypy.lang.js.interpreter import ThrowException -from pypy.lang.js.jsobj import W_Number +from pypy.lang.js.jsobj import W_Number, W_Object +from pypy.lang.js.context import ExecutionContext import py.test import sys @@ -26,8 +27,10 @@ def assert_prints(self, code, assval): l = [] interpreter.writer = l.append + ctx = ExecutionContext() + ctx.globals['Object'] = W_Object({}) try: - code.call() + code.call(ctx) except ThrowException, excpt: l.append("uncaught exception: "+str(excpt.exception)) assert l == assval @@ -210,3 +213,18 @@ } print(i); """), ["0","1","2","3"]) + + def test_object_creation(self): + self.assert_prints(parse_d(""" + o = new Object(); + print(o); + """), ["[object Object]"]) + + def test_new_with_function(self): + self.assert_prints(parse_d(""" + x = function() {this.info = 'hello';}; + o = new x(); + print(o.info); + """), ["hello"]) + + From cfbolz at codespeak.net Sat Nov 4 15:34:51 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 15:34:51 +0100 (CET) Subject: [pypy-svn] r34171 - pypy/branch/refactor-file Message-ID: <20061104143451.622BD100AA@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 15:34:50 2006 New Revision: 34171 Added: pypy/branch/refactor-file/ - copied from r34170, pypy/dist/ Log: (guido, cfbolz) hopefully short-lived branch for refactoring of files From rxe at codespeak.net Sat Nov 4 15:35:33 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Sat, 4 Nov 2006 15:35:33 +0100 (CET) Subject: [pypy-svn] r34172 - in pypy/dist/pypy/jit/hintannotator: . test Message-ID: <20061104143533.D4B3C100AF@code0.codespeak.net> Author: rxe Date: Sat Nov 4 15:35:31 2006 New Revision: 34172 Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py pypy/dist/pypy/jit/hintannotator/model.py pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Log: implement deepfrozen for dicts - arre,fijal,arigo,rxe Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/bookkeeper.py (original) +++ pypy/dist/pypy/jit/hintannotator/bookkeeper.py Sat Nov 4 15:35:31 2006 @@ -1,5 +1,5 @@ from pypy.tool.tls import tlsobject -from pypy.objspace.flow.model import copygraph, SpaceOperation +from pypy.objspace.flow.model import copygraph, SpaceOperation, Constant from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem import lltype from pypy.tool.algo.unionfind import UnionFind @@ -129,12 +129,14 @@ def immutableconstant(self, const): res = hintmodel.SomeLLAbstractConstant(const.concretetype, {}) res.const = const.value + # we want null pointers to be deepfrozen! + if isinstance(const.concretetype, lltype.Ptr): + if not const.value: + res.deepfrozen = True return res - def immutablevalue(self, value): - res = hintmodel.SomeLLAbstractConstant(lltype.typeOf(value), {}) - res.const = value - return res + def immutablevalue(self, value): + return self.immutableconstant(Constant(value, lltype.typeOf(value))) def current_op_concretetype(self): _, block, i = self.position_key Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Sat Nov 4 15:35:31 2006 @@ -401,6 +401,7 @@ myorigin=origin, deepfrozen=hs_c1.deepfrozen) + class __extend__(SomeLLAbstractContainer): def setfield(hs_s1, hs_fieldname, hs_value): @@ -484,7 +485,15 @@ else: return SomeLLAbstractVariable(READ_TYPE) - + def getarraysubstruct((hs_c1, hs_index)): + A = hs_c1.concretetype.TO + SUB_TYPE = A.OF + origin = getbookkeeper().myorigin() + d = newset(hs_c1.origins, hs_index.origins, {origin: True}) + return SomeLLAbstractConstant(lltype.Ptr(SUB_TYPE), d, + myorigin=origin, + deepfrozen=hs_c1.deepfrozen) + class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractContainer)): def union((hs_cont1, hs_cont2)): Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Sat Nov 4 15:35:31 2006 @@ -124,6 +124,31 @@ hs = hannotate(ll_function, [int, int], policy=P_NOVIRTUAL) assert hs.concretetype == lltype.Signed +def test_dicts_deepfreeze(): + + d1 = {1:2, 2:3} + d2 = {2:3, 3:4} + + def getdict(n): + if n: + return d1 + else: + return d2 + + def ll_function(n, i): + d = getdict(n) + d = hint(d, deepfreeze=True) + + res = d[i] + res = hint(res, concrete=True) + + res = hint(res, variable=True) + return res + + hs = hannotate(ll_function, [int, int], policy=P_NOVIRTUAL) + assert hs.concretetype == lltype.Signed + + def test_simple_hint_origins(): def ll_function(cond, x,y): if cond: From rxe at codespeak.net Sat Nov 4 15:36:37 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Sat, 4 Nov 2006 15:36:37 +0100 (CET) Subject: [pypy-svn] r34173 - pypy/dist/pypy/jit/timeshifter Message-ID: <20061104143637.4C32A100B4@code0.codespeak.net> Author: rxe Date: Sat Nov 4 15:36:35 2006 New Revision: 34173 Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py Log: hack for when have fieldtype of void - arre,arigo,rxe Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/dist/pypy/jit/timeshifter/rcontainer.py Sat Nov 4 15:36:35 2006 @@ -48,7 +48,10 @@ innermostdesc = substructdesc.innermostdesc else: index = len(fielddescs) - desc = StructFieldDesc(RGenOp, self.PTRTYPE, name, index) + if FIELDTYPE is lltype.Void: + desc = None + else: + desc = StructFieldDesc(RGenOp, self.PTRTYPE, name, index) fielddescs.append(desc) fielddesc_by_name[name] = desc self.fielddescs = fielddescs From rxe at codespeak.net Sat Nov 4 15:37:40 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Sat, 4 Nov 2006 15:37:40 +0100 (CET) Subject: [pypy-svn] r34174 - in pypy/dist/pypy: jit/timeshifter/test lang/automata Message-ID: <20061104143740.4E570100B8@code0.codespeak.net> Author: rxe Date: Sat Nov 4 15:37:39 2006 New Revision: 34174 Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/lang/automata/dfa.py Log: current state of dfa test Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Sat Nov 4 15:37:39 2006 @@ -155,11 +155,12 @@ def test_dfa_compile2(self): py.test.skip('wip') - from pypy.lang.automata.dfa import getautomaton, recognizeparts + from pypy.lang.automata.dfa import getautomaton, convertagain, recognizeparts a = getautomaton() def main(gets): + alltrans, final_states = convertagain(a) s = ["aaaaaaaaaab", "aaaa"][gets] - return recognizeparts(a.transitions, a.final_states, s) + return recognizeparts(alltrans, final_states, s) res = self.timeshift_from_portal(main, recognizeparts, [0], policy=P_NOVIRTUAL) assert res Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Sat Nov 4 15:37:39 2006 @@ -121,7 +121,7 @@ char = s[indx] char = hint(char, promote=True) - statetrans = alltrans[state] + statetrans = alltrans.get(state, None) state = statetrans.get(char, -1) hint(state, concrete=True) From fijal at codespeak.net Sat Nov 4 15:51:37 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 15:51:37 +0100 (CET) Subject: [pypy-svn] r34175 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061104145137.E7524100BC@code0.codespeak.net> Author: fijal Date: Sat Nov 4 15:51:35 2006 New Revision: 34175 Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (contents, props changed) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: First example of traceback accidentally just works. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py Sat Nov 4 15:51:35 2006 @@ -59,18 +59,22 @@ def setdict(self, space, w_dict): if not self.setdictvalue(space, space.wrap('__dict__'), w_dict): baseobjspace.W_Root.setdict(self, space, w_dict) + + def descr_call_mismatch(self, space, name, reqcls, args): + _, args = args.popfirst() + args = args.prepend(space.wrap(name)) + return space.call_args(self.w_controller, args) from pypy.objspace.std.objecttype import object_typedef as typedef class W_TransparentFunction(W_Transparent): from pypy.interpreter.function import Function typedef = Function.typedef - - def descr_call_mismatch(self, space, name, reqcls, args): - _, args = args.popfirst() - args = args.prepend(space.wrap(name)) - return space.call_args(self.w_controller, args) +class W_TransparentTraceback(W_Transparent): + from pypy.interpreter.pytraceback import PyTraceback + typedef = PyTraceback.typedef + class W_TransparentList(W_Transparent): from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sat Nov 4 15:51:35 2006 @@ -0,0 +1,38 @@ + +""" test proxy internals like code, traceback, frame +""" + +class AppTestProxyInternals(object): + def setup_method(self, meth): + self.w_get_proxy = self.space.appexec([], """(): + class Controller(object): + def __init__(self, obj): + self.obj = obj + + def perform(self, name, *args, **kwargs): + return getattr(self.obj, name)(*args, **kwargs) + def get_proxy(f): + return proxy(type(f), Controller(f).perform) + return get_proxy + """) + + def test_traceback_basic(self): + try: + 1/0 + except: + import sys + e = sys.exc_info() + + tb = self.get_proxy(e[2]) + assert tb.tb_frame is e[2].tb_frame + + def test_traceback_reraise(self): + try: + 1/0 + except: + import sys + e = sys.exc_info() + + tb = self.get_proxy(e[2]) + raises(ZeroDivisionError, "raise (e[0], e[1], tb)") + raises(ZeroDivisionError, "raise (e[0], self.get_proxy(e[1]), tb)") Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Sat Nov 4 15:51:35 2006 @@ -5,12 +5,11 @@ from pypy.interpreter import gateway from pypy.interpreter.function import Function from pypy.interpreter.error import OperationError -from pypy.objspace.std.proxyobject import W_TransparentList, W_TransparentDict,\ - W_Transparent, W_TransparentFunction +from pypy.objspace.std.proxyobject import * from pypy.objspace.std.typeobject import W_TypeObject def proxy(space, w_type, w_controller): - from pypy.interpreter.typedef import Function + from pypy.interpreter.typedef import Function, PyTraceback if not space.is_true(space.callable(w_controller)): raise OperationError(space.w_TypeError, space.wrap("controller should be function")) @@ -22,6 +21,8 @@ return W_TransparentDict(space, w_type, w_controller) if space.is_true(space.issubtype(w_type, space.gettypeobject(Function.typedef))): return W_TransparentFunction(space, w_type, w_controller) + if space.is_true(space.issubtype(w_type, space.gettypeobject(PyTraceback.typedef))): + return W_TransparentTraceback(space, w_type, w_controller) if w_type.instancetypedef is space.w_object.instancetypedef: return W_Transparent(space, w_type, w_controller) else: From fijal at codespeak.net Sat Nov 4 15:56:55 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 15:56:55 +0100 (CET) Subject: [pypy-svn] r34176 - pypy/branch/transparent-proxy/pypy/interpreter Message-ID: <20061104145655.2D97B100BD@code0.codespeak.net> Author: fijal Date: Sat Nov 4 15:56:53 2006 New Revision: 34176 Modified: pypy/branch/transparent-proxy/pypy/interpreter/gateway.py Log: Small fix. Modified: pypy/branch/transparent-proxy/pypy/interpreter/gateway.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/gateway.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/gateway.py Sat Nov 4 15:56:53 2006 @@ -486,7 +486,7 @@ raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) except DescrMismatch, e: - return scope_w[0].descr_call_mismatch(space, + return args.firstarg().descr_call_mismatch(space, self.descrmismatch_op, self.descr_reqcls, args) From cfbolz at codespeak.net Sat Nov 4 16:00:11 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 16:00:11 +0100 (CET) Subject: [pypy-svn] r34177 - pypy/branch/refactor-file/pypy/rlib/test Message-ID: <20061104150011.00EBB100AD@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 16:00:10 2006 New Revision: 34177 Modified: pypy/branch/refactor-file/pypy/rlib/test/test_streamio.py Log: remove debug prints Modified: pypy/branch/refactor-file/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/branch/refactor-file/pypy/rlib/test/test_streamio.py (original) +++ pypy/branch/refactor-file/pypy/rlib/test/test_streamio.py Sat Nov 4 16:00:10 2006 @@ -188,18 +188,13 @@ def f(): assert file.readline() == "ab\n" assert file.readline() == "def\n" - os.write(1, "3\n") blocks = [] while 1: block = file.read(1) - os.write(1, "XXXX" + block + "YYYY") - os.write(1, "4\n") if not block: break - os.write(1, "5\n") blocks.append(block) assert file.read(0) == "" - os.write(1, "6\n") return "".join(blocks) == "".join(self.lines)[7:] res = self.interpret(f, []) assert res @@ -250,23 +245,16 @@ def test_read_4_after_readline(self): file = self.makeStream() def f(): - os.write(1, "1\n") res = file.readline() assert res == "ab\n" - os.write(1, "2\n") assert file.readline() == "def\n" - os.write(1, "3\n") blocks = [file.read(4)] while 1: block = file.read(4) if not block: break blocks.append(block) - os.write(1, "4\n") assert file.read(0) == "" - os.write(1, "5\n") - for element in blocks: - os.write(1, element + "XXX\n") return blocks == ["xy\np", "q\nuv", "wx"] res = self.interpret(f, []) assert res From cfbolz at codespeak.net Sat Nov 4 16:00:43 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 16:00:43 +0100 (CET) Subject: [pypy-svn] r34178 - pypy/branch/refactor-file/pypy/rlib Message-ID: <20061104150043.6ED04100B6@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 16:00:42 2006 New Revision: 34178 Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py Log: (guido, cfbolz, anto, arigo): moving the helpers from lib/_file.py to here. Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py ============================================================================== --- pypy/branch/refactor-file/pypy/rlib/streamio.py (original) +++ pypy/branch/refactor-file/pypy/rlib/streamio.py Sat Nov 4 16:00:42 2006 @@ -29,8 +29,19 @@ import os, sys -# ____________________________________________________________ +from os import O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC +O_BINARY = getattr(os, "O_BINARY", 0) + +# (basemode, plus) +OS_MODE = {('r', False): O_RDONLY, + ('r', True): O_RDWR, + ('w', False): O_WRONLY | O_CREAT | O_TRUNC, + ('w', True): O_RDWR | O_CREAT | O_TRUNC, + ('a', False): O_WRONLY | O_CREAT, + ('a', True): O_RDWR | O_CREAT, + } +# ____________________________________________________________ def replace_crlf_with_lf(s): @@ -49,6 +60,85 @@ return s.join(string.split(c)) +def open_file_as_stream(path, mode="r", buffering=-1): + os_flags, universal, reading, writing, basemode = decode_mode(mode) + stream = open_path_helper(path, os_flags, basemode == "a") + return construct_stream_tower(stream, buffering, universal, reading, + writing) + +def fdopen_as_stream(fd, mode, buffering): + # XXX XXX XXX you want do check whether the modes are compatible + # otherwise you get funny results + os_flags, universal, reading, writing, basemode = decode_mode(mode) + stream = DiskFile(fd) + return construct_stream_tower(stream, buffering, universal, reading, + writing) + +def open_path_helper(path, os_flags, append): + # XXX for now always return DiskFile + fd = os.open(path, os_flags) + if append: + try: + os.lseek(fd, 0, 2) + except OSError: + # XXX does this pass make sense? + pass + return DiskFile(fd) + +def decode_mode(mode): + if mode[0] == 'U': + mode = 'r' + mode + + basemode = mode[0] # 'r', 'w' or 'a' + plus = False + universal = False + binary = False + + for c in mode[1:]: + if c == '+': + plus = True + elif c == 'U': + universal = True + elif c == 'b': + binary = True + else: + break + + flag = OS_MODE[basemode, plus] + if binary or universal: + flag |= O_BINARY + + reading = basemode == 'r' or plus + writing = basemode != 'r' or plus + + return flag, universal, reading, writing, basemode + + +def construct_stream_tower(stream, buffering, universal, reading, writing): + if buffering == 0: # no buffering + pass + elif buffering == 1: # line-buffering + if writing: + stream = LineBufferingOutputStream(stream) + if reading: + stream = BufferingInputStream(stream) + + else: # default or explicit buffer sizes + if buffering is not None and buffering < 0: + buffering = -1 + if writing: + stream = BufferingOutputStream(stream, buffering) + if reading: + stream = BufferingInputStream(stream, buffering) + + if universal: # Wants universal newlines + if writing and os.linesep != '\n': + stream = TextOutputFilter(stream) + if reading: + stream = TextInputFilter(stream) + return stream + + class StreamError(Exception): def __init__(self, message): self.message = message From fijal at codespeak.net Sat Nov 4 16:14:11 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 16:14:11 +0100 (CET) Subject: [pypy-svn] r34179 - pypy/branch/transparent-proxy/pypy/interpreter Message-ID: <20061104151411.4EC96100BA@code0.codespeak.net> Author: fijal Date: Sat Nov 4 16:14:10 2006 New Revision: 34179 Modified: pypy/branch/transparent-proxy/pypy/interpreter/gateway.py Log: translation Modified: pypy/branch/transparent-proxy/pypy/interpreter/gateway.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/gateway.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/gateway.py Sat Nov 4 16:14:10 2006 @@ -513,7 +513,7 @@ raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) except DescrMismatch, e: - return scope_w[0].descr_call_mismatch(space, + return args.firstarg().descr_call_mismatch(space, self.descrmismatch_op, self.descr_reqcls, args) From mwh at codespeak.net Sat Nov 4 16:15:55 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sat, 4 Nov 2006 16:15:55 +0100 (CET) Subject: [pypy-svn] r34180 - in pypy/dist/pypy/jit/codegen: ppc test Message-ID: <20061104151555.DC18C100C0@code0.codespeak.net> Author: mwh Date: Sat Nov 4 16:15:54 2006 New Revision: 34180 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Log: (niko, mwh) develop and implement an almost sane model for managing the stack. Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Sat Nov 4 16:15:54 2006 @@ -56,9 +56,9 @@ CT_REGISTER = 3 class RegisterAllocation: - def __init__(self, minreg, initial_mapping): + def __init__(self, minreg, initial_mapping, initial_spill_offset): #print - #print "RegisterAllocation __init__" + #print "RegisterAllocation __init__", initial_mapping self.insns = [] # Output list of instructions self.freeregs = gprs[minreg:] # Registers with dead values @@ -66,22 +66,24 @@ self.loc2var = {} # Maps an AllocationSlot to a Var self.lru = [] # Least-recently-used list of vars; first is oldest. # Contains all vars in registers, and no vars on stack - self._spill_index = 0 # Where to put next spilled value + self.spill_offset = initial_spill_offset # Where to put next spilled + # value, relative to rFP, + # measured in bytes # Go through the initial mapping and initialize the data structures for var, loc in initial_mapping.iteritems(): self.loc2var[loc] = var self.var2loc[var] = loc if loc in self.freeregs: - del self.freeregs[self.freeregs.index(loc)] + self.freeregs.remove(loc) self.lru.append(var) self.crfinfo = [(0, 0)] * 8 def spill(self): """ Returns an offset onto the stack for an unused spill location """ # TODO --- reuse spill slots when contained values go dead? - self._spill_index += 4 - return self._spill_index + self.spill_offset -= 4 + return self.spill_offset def _allocate_reg(self, newarg): @@ -90,8 +92,7 @@ reg = self.freeregs.pop() self.loc2var[reg] = newarg self.var2loc[newarg] = reg - #print "allocate_reg: Putting %r into fresh register %r" % ( - # newarg, reg) + #print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) return reg # if not, find something to spill @@ -124,16 +125,15 @@ def _promote(self, arg): if arg in self.lru: - del self.lru[self.lru.index(arg)] + self.lru.remove(arg) self.lru.append(arg) - + def allocate_for_insns(self, insns): # Walk through instructions in forward order for insn in insns: - #print "Processing instruction %r with args %r and result %r:" % ( - # insn, insn.reg_args, insn.result) - # + #print "Processing instruction %r with args %r and result %r:" % (insn, insn.reg_args, insn.result) + #print "LRU list was: %r" % (self.lru,) # put things into the lru @@ -157,12 +157,15 @@ # It has no register now because it has been spilled assert argcls is GP_REGISTER, "uh-oh" self._allocate_reg(arg) + else: + #print "it was in ", self.var2loc[arg] + pass # Need to allocate a register for the destination assert not insn.result or insn.result not in self.var2loc cand = None if insn.result_regclass is GP_REGISTER: - #print "Allocating register for result %r..." % (cand,) + #print "Allocating register for result %r..." % (insn.result,) cand = self._allocate_reg(insn.result) elif insn.result_regclass is CR_FIELD: assert crfs[0] not in self.loc2var @@ -214,6 +217,13 @@ var, [self])) return var + def load_now(self, asm, loc): + if loc.is_register: + asm.load_word(loc.number, self.value) + else: + asm.load_word(rSCRATCH, self.value) + asm.stw(rSCRATCH, rFP, loc.offset) + class Insn(object): ''' result is the Var instance that holds the result, or None @@ -379,7 +389,7 @@ self.reg = reg self.stack = stack def emit(self, asm): - asm.lwz(self.reg.number, rSP, self.stack.offset) + asm.lwz(self.reg.number, rFP, self.stack.offset) class Spill(Insn): """ A special instruction inserted by our register "allocator." @@ -396,7 +406,7 @@ self.reg = reg self.stack = stack def emit(self, asm): - asm.stw(self.reg.number, rSP, self.stack.offset) + asm.stw(self.reg.number, rFP, self.stack.offset) class Return(Insn): """ Ensures the return value is in r3 """ @@ -428,7 +438,9 @@ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, \ r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, \ r23, r24, r25, r26, r27, r28, r29, r30, r31 = range(32) +rSCRATCH = r0 rSP = r1 +rFP = r2 # the ABI doesn't specify a frame pointer. however, we want one def emit(self, value): self.mc.write(value) @@ -531,27 +543,28 @@ class JumpPatchupGenerator(object): - def __init__(self, asm, regalloc): + def __init__(self, asm, min_offset): self.asm = asm - self.regalloc = regalloc + self.min_offset = min_offset def emit_move(self, tarloc, srcloc): if tarloc == srcloc: return if tarloc.is_register and srcloc.is_register: self.asm.mr(tarloc.number, srcloc.number) elif tarloc.is_register and not srcloc.is_register: - self.asm.lwz(tarloc.number, rSP, srcloc.offset) + self.asm.lwz(tarloc.number, rFP, srcloc.offset) elif not tarloc.is_register and srcloc.is_register: - self.asm.stw(srcloc.number, rSP, tarloc.offset) + self.asm.stw(srcloc.number, rFP, tarloc.offset) elif not tarloc.is_register and not srcloc.is_register: - self.asm.lwz(r0, rSP, srcloc.offset) - self.asm.stw(r0, rSP, tarloc.offset) + self.asm.lwz(rSCRATCH, rFP, srcloc.offset) + self.asm.stw(rSCRATCH, rFP, tarloc.offset) def create_fresh_location(self): - offset = self.regalloc.spill() - return stack_slot(offset) + r = self.min_offset + self.min_offset -= 4 + return stack_slot(r) -def prepare_for_jump(asm, allocator, sourcevars, src2loc, target): +def prepare_for_jump(asm, min_offset, sourcevars, src2loc, target): tar2src = {} # tar var -> src var tar2loc = {} @@ -564,8 +577,9 @@ tar2loc[tloc] = tloc tar2src[tloc] = sourcevars[i] - gen = JumpPatchupGenerator(asm, allocator) + gen = JumpPatchupGenerator(asm, min_offset) emit_moves(gen, tar2src, tar2loc, src2loc) + return gen.min_offset class MachineCodeBlock: @@ -598,9 +612,10 @@ class Label(GenLabel): - def __init__(self, startaddr, arg_locations): + def __init__(self, startaddr, arg_locations, min_stack_offset): self.startaddr = startaddr self.arg_locations = arg_locations + self.min_stack_offset = min_stack_offset ## class FlexSwitch(CodeGenSwitch): @@ -639,41 +654,56 @@ class Builder(GenBuilder): - def __init__(self, rgenop, mc, parent): + def __init__(self, rgenop, mc): self.rgenop = rgenop self.asm = RPPCAssembler() self.asm.mc = mc self.insns = [] - self.parent = parent + self.stack_adj_addr = 0 + self.initial_spill_offset = 0 + self.initial_var2loc = None + self.fresh_from_jump = False + + def make_fresh_from_jump(self, initial_var2loc): + self.fresh_from_jump = True + self.initial_var2loc = initial_var2loc def _write_prologue(self, sigtoken): - assert self.parent is None numargs = sigtoken # for now if not we_are_translated() and option.trap: self.asm.trap() - self.inputargs = [self.newvar() for i in range(numargs)] - self.initial_varmapping = {} - for arg in self.inputargs: - self.initial_varmapping[arg] = gprs[3+len(self.initial_varmapping)] + inputargs = [self.newvar() for i in range(numargs)] + assert self.initial_var2loc is None + self.initial_var2loc = {} + for arg in inputargs: + self.initial_var2loc[arg] = gprs[3+len(self.initial_var2loc)] + self.initial_spill_offset = self._var_offset(0) # Emit standard prologue # Minimum space = 24+params+lv+4*GPR+8*FPR # GPR=19 # Initially, we allocate only enough space for GPRs, and allow # each basic block to ensure it has enough space to continue. - minspace = self._stack_offset(0,0) - self.asm.mflr(r0) - self.asm.stw(r0,rSP,8) + minspace = self._stack_size(0,self._var_offset(0)) + self.asm.mflr(rSCRATCH) + self.asm.stw(rSCRATCH,rSP,8) self.asm.stmw(r13,rSP,-(4*20)) # save all regs from 13-31 to stack + self.asm.mr(rFP, rSP) # set up our frame pointer self.asm.stwu(rSP,rSP,-minspace) - - return self.inputargs - def _stack_offset(self, param, lv): - """ Returns the required stack offset to store all data, assuming - that there are 'param' words of parameters for callee functions and - 'lv' words of local variable information. """ - return ((24 + param*4 + lv*4 + 4*19) & ~15)+16 + return inputargs + + def _var_offset(self, v): + """v represents an offset into the local variable area in bytes; + this returns the offset relative to rFP""" + return -(4*19+4+v) + + def _stack_size(self, param, lv): + """ Returns the required stack size to store all data, assuming + that there are 'param' bytes of parameters for callee functions and + 'lv' is the largest (wrt to abs() :) rFP-relative byte offset of + any variable on the stack.""" + return ((24 + param - lv) & ~15)+16 def _close(self): self.rgenop.close_mc(self.asm.mc) @@ -684,52 +714,121 @@ genmethod = getattr(self, 'op_' + opname) return genmethod(gv_arg1, gv_arg2) - def emit(self): - if self.parent is not None: - allocator = RegisterAllocation( - self.rgenop.MINUSERREG, self.parent.var2loc) - else: - allocator = RegisterAllocation( - self.rgenop.MINUSERREG, self.initial_varmapping) + def allocate_and_emit(self): + assert self.initial_var2loc is not None + allocator = RegisterAllocation( + self.rgenop.MINUSERREG, self.initial_var2loc, self.initial_spill_offset) self.insns = allocator.allocate_for_insns(self.insns) + if self.insns: + self.patch_stack_adjustment(self._stack_size(0, allocator.spill_offset)) for insn in self.insns: insn.emit(self.asm) - self.var2loc = allocator.var2loc return allocator def finish_and_return(self, sigtoken, gv_returnvar): gv_returnvar = gv_returnvar.load(self) self.insns.append(Return(gv_returnvar)) - allocator = self.emit() + allocator = self.allocate_and_emit() # Emit standard epilogue: - self.asm.lwz(rSP,rSP,0) # restore old SP - self.asm.lmw(r13,rSP,-4*20) # restore all GPRs - self.asm.lwz(r0,rSP,8) # load old Link Register and jump to it - self.asm.mtlr(r0) # - self.asm.blr() # + self.asm.lwz(rSP,rSP,0) # restore old SP + self.asm.lmw(r13,rSP,-4*20) # restore all GPRs + self.asm.lwz(rSCRATCH,rSP,8) # load old Link Register and jump to it + self.asm.mtlr(rSCRATCH) # + self.asm.blr() # self._close() def finish_and_goto(self, outputargs_gv, target): - allocator = self.emit() - prepare_for_jump( - self.asm, allocator, outputargs_gv, allocator.var2loc, target) - self.asm.load_word(0, target.startaddr) - self.asm.mtctr(0) + allocator = self.allocate_and_emit() + min_offset = min(allocator.spill_offset, target.min_stack_offset) + min_offset = prepare_for_jump( + self.asm, min_offset, outputargs_gv, allocator.var2loc, target) + self.patch_stack_adjustment(self._stack_size(0, min_offset)) + self.asm.load_word(rSCRATCH, target.startaddr) + self.asm.mtctr(rSCRATCH) self.asm.bctr() self._close() + def emit_stack_adjustment(self): + # the ABI requires that at all times that r1 is valid, in the + # sense that it must point to the bottom of the stack and that + # executing SP <- *(SP) repeatedly walks the stack. + # this code satisfies this, although there is a 1-instruction + # window where such walking would find a strange intermediate + # "frame" (apart from when the delta is 0... XXX) + # as we emit these instructions waaay before doing the + # register allocation for this block we don't know how much + # stack will be required, so we patch it later (see + # patch_stack_adjustment below). + self.stack_adj_addr = self.asm.mc.tell() + self.asm.addi(rSCRATCH, rFP, 0) # this is the immediate that later gets patched + self.asm.sub(rSCRATCH, rSCRATCH, rSP) # rSCRATCH should now be <= 0 + self.asm.stwux(rSP, rSP, rSCRATCH) + self.asm.stw(rFP, rSP, 0) + + def patch_stack_adjustment(self, newsize): + if self.stack_adj_addr == 0: + return + # we build an addi instruction by hand here + opcode = 14 << 26 + rD = rSCRATCH << 21 + rA = rFP << 16 + # if we decided to use r0 as the frame pointer, this would + # emit addi rFOO, r0, SIMM which would just load SIMM into + # rFOO and be "unlikely" to work + assert rA != 0 + SIMM = (-newsize) & 0xFFFF + p_instruction = cast(c_void_p(self.stack_adj_addr), POINTER(c_int*1)) + p_instruction.contents[0] = opcode | rD | rA | SIMM + def enter_next_block(self, kinds, args_gv): + if self.fresh_from_jump: + var2loc = self.initial_var2loc + self.fresh_from_jump = False + else: + var2loc = self.allocate_and_emit().var2loc + + #print "enter_next_block:", args_gv, var2loc + + min_stack_offset = self._var_offset(0) + usedregs = {} + livevar2loc = {} + for gv in args_gv: + if isinstance(gv, Var): + assert gv in var2loc + loc = var2loc[gv] + livevar2loc[gv] = loc + if not loc.is_register: + min_stack_offset = min(min_stack_offset, loc.offset) + else: + usedregs[loc] = None # XXX use this + + unusedregs = [loc for loc in gprs[self.rgenop.MINUSERREG:] if loc not in usedregs] arg_locations = [] + for i in range(len(args_gv)): gv = args_gv[i] - gv = args_gv[i] = gv.load(self) - allocator = self.emit() - for gv in args_gv: - arg_locations.append(allocator.var2loc[gv]) + if isinstance(gv, Var): + arg_locations.append(livevar2loc[gv]) + else: + if unusedregs: + loc = unusedregs.pop() + else: + loc = stack_slot(min_stack_offset) + min_stack_offset -= 4 + gv.load_now(self.asm, loc) + args_gv[i] = gv = Var() + livevar2loc[gv] = loc + arg_locations.append(loc) + + #print livevar2loc + self.insns = [] - self.initial_varmapping = allocator.var2loc - return Label(self.asm.mc.tell(), arg_locations) + self.initial_var2loc = livevar2loc + self.initial_spill_offset = min_stack_offset + target_addr = self.asm.mc.tell() + self.emit_stack_adjustment() + return Label(target_addr, arg_locations, min_stack_offset) def newvar(self): gv = Var() @@ -798,6 +897,7 @@ def _jump(self, gv_condition, if_true): targetbuilder = self._fork() + gv = self.newvar() self.insns.append( Insn_GPR__IMM(RPPCAssembler.load_word, @@ -807,6 +907,11 @@ MTCTR(gv2, [gv])) self.insns.append( Jump(gv_condition, gv2, if_true)) + + allocator = self.allocate_and_emit() + self.make_fresh_from_jump(allocator.var2loc) + targetbuilder.make_fresh_from_jump(allocator.var2loc) + return targetbuilder def jump_if_false(self, gv_condition): @@ -816,7 +921,7 @@ return self._jump(gv_condition, True) def _fork(self): - return self.rgenop.openbuilder(self) + return self.rgenop.openbuilder() class RPPCGenOp(AbstractRGenOp): @@ -848,12 +953,12 @@ def kindToken(T): return None # for now - def openbuilder(self, parent): - return Builder(self, self.open_mc(), parent) + def openbuilder(self): + return Builder(self, self.open_mc()) def newgraph(self, sigtoken): numargs = sigtoken # for now - builder = self.openbuilder(None) + builder = self.openbuilder() entrypoint = builder.asm.mc.tell() inputargs_gv = builder._write_prologue(sigtoken) return builder, entrypoint, inputargs_gv Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py ============================================================================== --- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py (original) +++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Sat Nov 4 16:15:54 2006 @@ -77,6 +77,9 @@ builder.finish_and_return(sigtoken, gv_s2) # false path + args_gv = [gv_y] + false_builder.enter_next_block([signed_kind], args_gv) + [gv_y] = args_gv false_builder.finish_and_return(sigtoken, gv_y) # done From pedronis at codespeak.net Sat Nov 4 16:17:52 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 4 Nov 2006 16:17:52 +0100 (CET) Subject: [pypy-svn] r34181 - pypy/dist/pypy/jit/codegen/llgraph Message-ID: <20061104151752.A8BD6100C1@code0.codespeak.net> Author: pedronis Date: Sat Nov 4 16:17:51 2006 New Revision: 34181 Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py Log: add sanity check Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llgraph/llimpl.py (original) +++ pypy/dist/pypy/jit/codegen/llgraph/llimpl.py Sat Nov 4 16:17:51 2006 @@ -153,7 +153,12 @@ if example == 0: example = type(example)(1) # to avoid ZeroDivisionError examples.append(example) - result = op.fold(*examples) + try: + result = op.fold(*examples) + except (KeyboardInterrupt, SystemExit): + raise + except Exception, e: + assert 0, "failed to guess the type of %s: %s" % (opname, e) return lltype.typeOf(result) def gencallableconst(name, graph, gv_FUNCTYPE): From mwh at codespeak.net Sat Nov 4 16:28:56 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sat, 4 Nov 2006 16:28:56 +0100 (CET) Subject: [pypy-svn] r34182 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061104152856.6D661100C9@code0.codespeak.net> Author: mwh Date: Sat Nov 4 16:28:55 2006 New Revision: 34182 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: (mwh, niko) avoid a one instruction window where the stack layout would be invalid. Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Sat Nov 4 16:28:55 2006 @@ -755,16 +755,19 @@ # executing SP <- *(SP) repeatedly walks the stack. # this code satisfies this, although there is a 1-instruction # window where such walking would find a strange intermediate - # "frame" (apart from when the delta is 0... XXX) + # "frame" # as we emit these instructions waaay before doing the # register allocation for this block we don't know how much # stack will be required, so we patch it later (see # patch_stack_adjustment below). self.stack_adj_addr = self.asm.mc.tell() self.asm.addi(rSCRATCH, rFP, 0) # this is the immediate that later gets patched - self.asm.sub(rSCRATCH, rSCRATCH, rSP) # rSCRATCH should now be <= 0 + self.asm.subx(rSCRATCH, rSCRATCH, rSP) # rSCRATCH should now be <= 0 + self.asm.beq(3) # if rSCRATCH == 0, there is no actual adjustment, so + # don't end up with the situation where *(rSP) == rSP self.asm.stwux(rSP, rSP, rSCRATCH) self.asm.stw(rFP, rSP, 0) + # branch to "here" def patch_stack_adjustment(self, newsize): if self.stack_adj_addr == 0: From santagada at codespeak.net Sat Nov 4 16:30:22 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Sat, 4 Nov 2006 16:30:22 +0100 (CET) Subject: [pypy-svn] r34183 - pypy/dist/pypy/lang/js Message-ID: <20061104153022.74BE7100CD@code0.codespeak.net> Author: santagada Date: Sat Nov 4 16:30:21 2006 New Revision: 34183 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/jsobj.py Log: (stephan, santagada) trying to make this work Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Sat Nov 4 16:30:21 2006 @@ -175,7 +175,11 @@ elif tp == 'FUNCTION': scope = scope_manager.enter_scope() body = from_dict(d['body']) - f = Function(d['params'].split(','), body, scope) + if d['params'] == '': + params = [] + else: + params = d['params'].split(',') + f = Function(params, body, scope) scope_manager.leave_scope() return f elif tp == 'GROUP': Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sat Nov 4 16:30:21 2006 @@ -26,11 +26,10 @@ class __extend__(Assign): def call(self, context): val = self.expr.call(context) - scope_manager.set_variable(self.identifier.name, val) - return val + self.identifier.put(context,val) class __extend__(Block): - def call(self, context=None): + def call(self, context): try: last = w_Undefined for node in self.nodes: @@ -40,7 +39,7 @@ return e.value class __extend__(Call): - def call(self, context=None): + def call(self, context): name = self.identifier.get_literal() if name == 'print': writer(",".join([i.ToString() for i in self.arglist.call(context)])) @@ -54,7 +53,7 @@ return retval class __extend__(Comma): - def call(self, context=None): + def call(self, context): self.left.call(context) return self.right.call(context) @@ -63,6 +62,12 @@ w_obj = self.left.call(context).GetValue().ToObject() name = self.right.get_literal() return w_obj.Get(name) + + def put(self, context, val): + w_obj = self.left.call(context).GetValue().ToObject() + name = self.right.get_literal() + w_obj.dict_w[self.name] = val + class __extend__(Function): def call(self, context=None): @@ -76,7 +81,11 @@ try: return context.access(self.name) except NameError: - return scope_manager.get_variable(self.name) + try: + return scope_manager.get_variable(self.name) + except NameError: + return self.name + def get_literal(self): return self.name @@ -128,7 +137,6 @@ class __extend__(New): def call(self, context=None): - print context.__dict__ obj = W_Object({}) obj.Class = 'Object' try: @@ -181,10 +189,7 @@ return W_Number(num_left + num_right) class __extend__(Script): - def call(self, context=None, args=(), this=None, params=None): - print 'params',params - if params == None: - params = [] + def call(self, context=None, args=(), params=[]): ncontext = ExecutionContext(context) for i, item in enumerate(params): try: Modified: pypy/dist/pypy/lang/js/jsobj.py ============================================================================== --- pypy/dist/pypy/lang/js/jsobj.py (original) +++ pypy/dist/pypy/lang/js/jsobj.py Sat Nov 4 16:30:21 2006 @@ -39,10 +39,10 @@ self.function = function #self.class_ = None - def Call(self, context=None, args=None, this=None): + def Call(self, context=None, args=[]): if self.function: return self.function.body.call(context=context, - args=args, this=this, + args=args, params= self.function.params) else: return W_Object({}) From ac at codespeak.net Sat Nov 4 16:34:43 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Sat, 4 Nov 2006 16:34:43 +0100 (CET) Subject: [pypy-svn] r34184 - in pypy/dist/pypy/rpython/rctypes: . test Message-ID: <20061104153443.53BAC10091@code0.codespeak.net> Author: ac Date: Sat Nov 4 16:34:42 2006 New Revision: 34184 Modified: pypy/dist/pypy/rpython/rctypes/astringbuf.py pypy/dist/pypy/rpython/rctypes/test/test_rstringbuf.py Log: Support r_uint arguments to create_string_buffer. Modified: pypy/dist/pypy/rpython/rctypes/astringbuf.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/astringbuf.py (original) +++ pypy/dist/pypy/rpython/rctypes/astringbuf.py Sat Nov 4 16:34:42 2006 @@ -1,7 +1,7 @@ from pypy.rpython.extregistry import ExtRegistryEntry from pypy.rpython.rctypes.implementation import CTypesObjEntry from pypy.annotation.model import SomeCTypesObject, SomeString, SomeInteger - +from pypy.rlib.rarithmetic import r_uint from ctypes import create_string_buffer, c_char, sizeof ###################################################################### @@ -25,7 +25,7 @@ _about_ = create_string_buffer def compute_result_annotation(self, s_length): - if s_length.knowntype != int: + if s_length.knowntype not in (int, r_uint): raise Exception("only supports create_string_buffer(length)") return SomeCTypesObject(StringBufferType, ownsmemory=True) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rstringbuf.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rstringbuf.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rstringbuf.py Sat Nov 4 16:34:42 2006 @@ -15,6 +15,7 @@ from ctypes import create_string_buffer, cast, POINTER, c_void_p, c_char from ctypes import c_char_p, c_long, pointer, sizeof, c_int from pypy.rpython.rctypes.astringbuf import StringBufferType +from pypy.rlib.rarithmetic import r_uint class Test_annotation: @@ -29,6 +30,14 @@ if conftest.option.view: a.translator.view() + a = RPythonAnnotator() + s = a.build_types(func, [r_uint]) + assert s.knowntype == StringBufferType + + if conftest.option.view: + a.translator.view() + + def test_annotate_access(self): def func(n): buf = create_string_buffer(n) @@ -94,6 +103,13 @@ assert len(c_data) == 17 py.test.raises(IndexError, "c_data[17]") + res = interpret(func, [r_uint(17)]) + c_data = res.c_data + assert c_data[0] == '\x00' + assert c_data[16] == '\x00' + assert len(c_data) == 17 + py.test.raises(IndexError, "c_data[17]") + def test_specialize_access(self): def func(n): buf = create_string_buffer(n) From cfbolz at codespeak.net Sat Nov 4 16:35:44 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 16:35:44 +0100 (CET) Subject: [pypy-svn] r34185 - in pypy/branch/refactor-file/pypy: lib lib/test2 module/_file module/_file/test rlib Message-ID: <20061104153544.6274D10098@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 16:35:43 2006 New Revision: 34185 Added: pypy/branch/refactor-file/pypy/module/_file/ (props changed) pypy/branch/refactor-file/pypy/module/_file/__init__.py (contents, props changed) pypy/branch/refactor-file/pypy/module/_file/app_file.py (contents, props changed) pypy/branch/refactor-file/pypy/module/_file/interp_file.py (contents, props changed) pypy/branch/refactor-file/pypy/module/_file/test/ (props changed) pypy/branch/refactor-file/pypy/module/_file/test/__init__.py (contents, props changed) pypy/branch/refactor-file/pypy/module/_file/test/test_file.py (contents, props changed) pypy/branch/refactor-file/pypy/module/_file/test/test_file_extra.py - copied, changed from r34171, pypy/branch/refactor-file/pypy/lib/test2/test_file_extra.py Removed: pypy/branch/refactor-file/pypy/lib/_file.py pypy/branch/refactor-file/pypy/lib/test2/test_file_extra.py Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py Log: make _file a mixed module. seems to work even! Added: pypy/branch/refactor-file/pypy/module/_file/__init__.py ============================================================================== --- (empty file) +++ pypy/branch/refactor-file/pypy/module/_file/__init__.py Sat Nov 4 16:35:43 2006 @@ -0,0 +1,14 @@ + +# Package initialisation +from pypy.interpreter.mixedmodule import MixedModule + +class Module(MixedModule): + appleveldefs = { + "file": "app_file.file", + } + + interpleveldefs = { + "open_file_as_stream": "interp_file.open_file_as_stream", + "fdopen_as_stream": "interp_file.fdopen_as_stream", + } + Added: pypy/branch/refactor-file/pypy/module/_file/app_file.py ============================================================================== --- (empty file) +++ pypy/branch/refactor-file/pypy/module/_file/app_file.py Sat Nov 4 16:35:43 2006 @@ -0,0 +1,252 @@ +"""NOT_RPYTHON""" + +import os + +class file(object): + """file(name[, mode[, buffering]]) -> file object + +Open a file. The mode can be 'r', 'w' or 'a' for reading (default), +writing or appending. The file will be created if it doesn't exist +when opened for writing or appending; it will be truncated when +opened for writing. Add a 'b' to the mode for binary files. +Add a '+' to the mode to allow simultaneous reading and writing. +If the buffering argument is given, 0 means unbuffered, 1 means line +buffered, and larger numbers specify the buffer size. +Add a 'U' to mode to open the file for input with universal newline +support. Any line ending in the input file will be seen as a '\n' +in Python. Also, a file so opened gains the attribute 'newlines'; +the value for this attribute is one of None (no newline read yet), +'\r', '\n', '\r\n' or a tuple containing all the newline types seen. + +Note: open() is an alias for file(). + """ + + _closed = True # Until the file is successfully opened + + def __init__(self, name, mode='r', buffering=-1): + import _file + self._name = name + self.softspace = 0 # Required according to file object docs + self.encoding = None # This is not used internally by file objects + self._closed = False + self.stream = _file.open_file_as_stream(self._name, mode, buffering) + self._mode = mode + self.fd = self.stream.try_to_find_file_descriptor() + assert self.fd != -1 + + def fdopen(cls, fd, mode='r', buffering=-1): + f = cls.__new__(cls) + f._fdopen(fd, mode, buffering, '') + return f + fdopen = classmethod(fdopen) + + def _fdopen(self, fd, mode, buffering, name): + import _file + self.fd = fd + self._name = name + self.softspace = 0 # Required according to file object docs + self.encoding = None # This is not used internally by file objects + self._closed = False + self.stream = _file.fdopen_as_stream(fd, mode, buffering) + self._mode = mode + + def getnewlines(self): + "end-of-line convention used in this file" + if isinstance(self.stream, _sio.TextInputFilter): + return self.stream.getnewlines() + else: + return None + + mode = property(lambda self: self._mode, + doc = "file mode ('r', 'U', 'w', 'a', " + "possibly with 'b' or '+' added)") + name = property(lambda self: self._name, doc = "file name") + closed = property(lambda self: self._closed, + doc = "True if the file is closed") + newlines = property(lambda self: self.getnewlines(), + doc = "end-of-line convention used in this file") + + def read(self, n=-1): + """read([size]) -> read at most size bytes, returned as a string. + +If the size argument is negative or omitted, read until EOF is reached. +Notice that when in non-blocking mode, less data than what was requested +may be returned, even if no size parameter was given.""" + if self._closed: + raise ValueError('I/O operation on closed file') + if n < 0: + return self.stream.readall() + else: + result = [] + while n > 0: + data = self.stream.read(n) + if not data: + break + n -= len(data) + result.append(data) + return ''.join(result) + + def readline(self, size=-1): + """readline([size]) -> next line from the file, as a string. + +Retain newline. A non-negative size argument limits the maximum +number of bytes to return (an incomplete line may be returned then). +Return an empty string at EOF.""" + if self._closed: + raise ValueError('I/O operation on closed file') + if size < 0: + return self.stream.readline() + else: + # XXX slow + chars = [] + for i in xrange(size): + char = self.stream.read(1) + chars.append(char) + if char == '' or char == '\n': + break + return ''.join(chars) + + def readlines(self, size=-1): + """readlines([size]) -> list of strings, each a line from the file. + +Call readline() repeatedly and return a list of the lines so read. +The optional size argument, if given, is an approximate bound on the +total number of bytes in the lines returned.""" + if self._closed: + raise ValueError('I/O operation on closed file') + if size < 0: + return list(iter(self.stream.readline, "")) + else: + result = [] + while size > 0: + line = self.stream.readline() + if not line: + break + result.append(line) + size -= len(line) + return result + + def write(self, data): + """write(str) -> None. Write string str to file. + +Note that due to buffering, flush() or close() may be needed before +the file on disk reflects the data written.""" + if self._closed: + raise ValueError('I/O operation on closed file') + if not isinstance(data, str): + raise TypeError('write() argument must be a string (for now)') + return self.stream.write(data) + + def writelines(self, sequence_of_strings): + """writelines(sequence_of_strings) -> None. Write the strings to the file. + +Note that newlines are not added. The sequence can be any iterable object +producing strings. This is equivalent to calling write() for each string.""" + if self._closed: + raise ValueError('I/O operation on closed file') + for line in sequence_of_strings: + if not isinstance(line, str): + raise TypeError('writelines() argument must be a list ' + 'of strings') + self.stream.write(line) + + def tell(self): + """tell() -> current file position, an integer (may be a long integer).""" + if self._closed: + raise ValueError('I/O operation on closed file') + return self.stream.tell() + + def seek(self, offset, whence=0): + """seek(offset[, whence]) -> None. Move to new file position. + +Argument offset is a byte count. Optional argument whence defaults to +0 (offset from start of file, offset should be >= 0); other values are 1 +(move relative to current position, positive or negative), and 2 (move +relative to end of file, usually negative, although many platforms allow +seeking beyond the end of a file). If the file is opened in text mode, +only offsets returned by tell() are legal. Use of other offsets causes +undefined behavior. +Note that not all file objects are seekable.""" + if self._closed: + raise ValueError('I/O operation on closed file') + self.stream.seek(offset, whence) + + def __iter__(self): + """Iterating over files, as in 'for line in f:', returns each line of +the file one by one.""" + if self._closed: + raise ValueError('I/O operation on closed file') + return self + xreadlines = __iter__ + + def next(self): + """next() -> the next line in the file, or raise StopIteration""" + if self._closed: + raise ValueError('I/O operation on closed file') + line = self.stream.readline() + if line == '': + raise StopIteration + return line + + def truncate(self, size=None): + """truncate([size]) -> None. Truncate the file to at most size bytes. + +Size defaults to the current file position, as returned by tell().""" + if self._closed: + raise ValueError('I/O operation on closed file') + if size is None: + size = self.stream.tell() + self.stream.truncate(size) + + def flush(self): + """flush() -> None. Flush the internal I/O buffer.""" + if self._closed: + raise ValueError('I/O operation on closed file') + self.stream.flush() + + def close(self): + """close() -> None or (perhaps) an integer. Close the file. + +Sets data attribute .closed to True. A closed file cannot be used for +further I/O operations. close() may be called more than once without +error. Some kinds of file objects (for example, opened by popen()) +may return an exit status upon closing.""" + if not self._closed: + self._closed = True + self.stream.close() + + __del__ = close + + def readinto(self, a): + """readinto() -> Undocumented. Don't use this; it may go away.""" + if self._closed: + raise ValueError('I/O operation on closed file') + from array import array + if not isinstance(a, array): + raise TypeError('Can only read into array objects') + length = len(a) + data = self.read(length) + del a[:] + a.fromstring(data + '\x00' * (length-len(data))) + return len(data) + + def fileno(self): + '''fileno() -> integer "file descriptor". + +This is needed for lower-level file interfaces, such os.read().''' + if self._closed: + raise ValueError('I/O operation on closed file') + return self.fd + + def isatty(self): + """isatty() -> true or false. True if the file is connected to a tty device.""" + if self._closed: + raise ValueError('I/O operation on closed file') + return os.isatty(self.fd) + + def __repr__(self): + return '<%s file %r, mode %r at 0x%x>' % ( + self._closed and 'closed' or 'open', + self._name, + self._mode, + id(self)) Added: pypy/branch/refactor-file/pypy/module/_file/interp_file.py ============================================================================== --- (empty file) +++ pypy/branch/refactor-file/pypy/module/_file/interp_file.py Sat Nov 4 16:35:43 2006 @@ -0,0 +1,83 @@ +import py +from pypy.rlib import streamio + +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped, applevel +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import interp2app + +import os + + +def wrap_oserror_as_ioerror(space, e): + assert isinstance(e, OSError) + errno = e.errno + try: + msg = os.strerror(errno) + except ValueError: + msg = 'error %d' % errno + w_error = space.call_function(space.w_IOError, + space.wrap(errno), + space.wrap(msg)) + return OperationError(space.w_IOError, w_error) + + +EXPOSED_STREAM_METHODS = [ + ("read", [int]), + ("write", [str]), + ("tell", []), + ("seek", [int, int]), + ("readall", []), + ("readline", []), + ("truncate", [int]), + ("flush", []), + ("close", []), + ("peek", []), + ("try_to_find_file_descriptor", []), + ] + +class W_Stream(Wrappable): + def __init__(self, space, stream): + self.stream = stream + +for name, argtypes in EXPOSED_STREAM_METHODS: + numargs = len(argtypes) + args = ", ".join(["v%s" % i for i in range(numargs)]) + exec py.code.Source(""" + def %(name)s(self, space, %(args)s): + try: + return space.wrap(self.stream.%(name)s(%(args)s)) + except streamio.StreamError, e: + raise OperationError(space.w_ValueError, + space.wrap(e.message)) + except OSError, e: + raise wrap_oserror_as_ioerror(space, e) + %(name)s.unwrap_spec = [W_Stream, ObjSpace] + argtypes + """ % locals()).compile() in globals() + +W_Stream.typedef = TypeDef("Stream", + **dict([(name, interp2app(globals()[name])) + for name, _ in EXPOSED_STREAM_METHODS])) + + +def is_mode_ok(space, mode): + if not mode or mode[0] not in ['r', 'w', 'a', 'U']: + raise OperationError( + IOError, + space.wrap('invalid mode : %s' % mode)) + +def open_file_as_stream(space, path, mode="r", buffering=-1): + is_mode_ok(space, mode) + try: + return space.wrap(W_Stream( + space, streamio.open_file_as_stream(path, mode, buffering))) + except OSError, e: + raise wrap_oserror_as_ioerror(e) +open_file_as_stream.unwrap_spec = [ObjSpace, str, str, int] + +def fdopen_as_stream(space, fd, mode="r", buffering=-1): + is_mode_ok(space, mode) + return space.wrap(W_Stream( + space, streamio.fdopen_as_stream(fd, mode, buffering))) +fdopen_as_stream.unwrap_spec = [ObjSpace, int, str, int] Added: pypy/branch/refactor-file/pypy/module/_file/test/__init__.py ============================================================================== Added: pypy/branch/refactor-file/pypy/module/_file/test/test_file.py ============================================================================== --- (empty file) +++ pypy/branch/refactor-file/pypy/module/_file/test/test_file.py Sat Nov 4 16:35:43 2006 @@ -0,0 +1,43 @@ +import py + +from pypy.conftest import gettestobjspace + +class AppTestFile(object): + def setup_class(cls): + cls.space = gettestobjspace(usemodules=("_file", )) + cls.w_temppath = cls.space.wrap( + str(py.test.ensuretemp("fileimpl").join("foo.txt"))) + + def test_simple(self): + import _file + f = _file.file(self.temppath, "w") + try: + f.write("foo") + finally: + f.close() + f = _file.file(self.temppath, "r") + try: + s = f.read() + assert s == "foo" + finally: + f.close() + + def test_fdopen(self): + import _file, os + f = _file.file(self.temppath, "w") + try: + f.write("foo") + finally: + f.close() + fd = os.open(self.temppath, os.O_WRONLY | os.O_CREAT) + f2 = _file.file.fdopen(fd, "a") + f2.seek(0, 2) + f2.write("bar") + f2.close() + # don't close fd, will get a whining __del__ + f = _file.file(self.temppath, "r") + try: + s = f.read() + assert s == "foobar" + finally: + f.close() Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py ============================================================================== --- pypy/branch/refactor-file/pypy/rlib/streamio.py (original) +++ pypy/branch/refactor-file/pypy/rlib/streamio.py Sat Nov 4 16:35:43 2006 @@ -203,6 +203,9 @@ def peek(self): return '' + def try_to_find_file_descriptor(self): + return -1 + class DiskFile(Stream): @@ -215,7 +218,8 @@ os.lseek(self.fd, offset, whence) def tell(self): - return os.lseek(self.fd, 0, 1) + #XXX for running on top of the cpy objspace. later we want r_longlong + return int(os.lseek(self.fd, 0, 1)) def read(self, n): return os.read(self.fd, n) @@ -235,6 +239,8 @@ def truncate(self, size): os.ftruncate(self.fd, size) + def try_to_find_file_descriptor(self): + return self.fd # next class is not RPython @@ -329,6 +335,9 @@ def flush(self): self.mm.flush() + def try_to_find_file_descriptor(self): + return self.fd + # ____________________________________________________________ @@ -583,6 +592,9 @@ flush = PassThrough("flush", flush_buffers=True) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + class BufferingOutputStream(Stream): @@ -635,6 +647,9 @@ flush = PassThrough("flush", flush_buffers=True) close = PassThrough("close", flush_buffers=True) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + class LineBufferingOutputStream(BufferingOutputStream): @@ -650,6 +665,10 @@ self.do_write(self.buf[:p]) self.buf = self.buf[p:] + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + + # ____________________________________________________________ @@ -680,6 +699,8 @@ flush = PassThrough("flush", flush_buffers=False) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() class TextInputFilter(Stream): @@ -829,6 +850,9 @@ flush = PassThrough("flush", flush_buffers=True) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + class TextOutputFilter(Stream): @@ -852,6 +876,8 @@ flush = PassThrough("flush", flush_buffers=False) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() # _________________________________________________ @@ -901,6 +927,8 @@ flush = PassThrough("flush", flush_buffers=False) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() class EncodingOutputFilter(Stream): @@ -926,3 +954,7 @@ truncate = PassThrough("truncate", flush_buffers=False) flush = PassThrough("flush", flush_buffers=False) close = PassThrough("close", flush_buffers=False) + + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + From cfbolz at codespeak.net Sat Nov 4 16:36:59 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 16:36:59 +0100 (CET) Subject: [pypy-svn] r34186 - pypy/branch/refactor-file/pypy/module/_file Message-ID: <20061104153659.910D210097@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 16:36:56 2006 New Revision: 34186 Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py Log: (guido, cfbolz): trivial checkin to mention that guido was working on the last checkin too! Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/interp_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/interp_file.py Sat Nov 4 16:36:56 2006 @@ -81,3 +81,4 @@ return space.wrap(W_Stream( space, streamio.fdopen_as_stream(fd, mode, buffering))) fdopen_as_stream.unwrap_spec = [ObjSpace, int, str, int] + From mwh at codespeak.net Sat Nov 4 16:58:25 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sat, 4 Nov 2006 16:58:25 +0100 (CET) Subject: [pypy-svn] r34187 - in pypy/dist/pypy/jit/codegen/ppc: . test Message-ID: <20061104155825.152EC1007B@code0.codespeak.net> Author: mwh Date: Sat Nov 4 16:58:23 2006 New Revision: 34187 Added: pypy/dist/pypy/jit/codegen/ppc/codebuf.py (contents, props changed) pypy/dist/pypy/jit/codegen/ppc/emit_moves.py (contents, props changed) pypy/dist/pypy/jit/codegen/ppc/instruction.py (contents, props changed) pypy/dist/pypy/jit/codegen/ppc/regalloc.py (contents, props changed) Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/ppc/test/test_emit_moves.py Log: (mwh,niko) split ppc/rgenop.py into multiple files. Added: pypy/dist/pypy/jit/codegen/ppc/codebuf.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/ppc/codebuf.py Sat Nov 4 16:58:23 2006 @@ -0,0 +1,28 @@ +from pypy.jit.codegen.ppc import codebuf_posix as memhandler +from ctypes import POINTER, cast, c_void_p, c_int + +class CodeBlockOverflow(Exception): + pass + +class MachineCodeBlock: + + def __init__(self, map_size): + assert map_size % 4 == 0 + res = memhandler.alloc(map_size) + self._data = cast(res, POINTER(c_int * (map_size / 4))) + self._size = map_size/4 + self._pos = 0 + + def write(self, data): + p = self._pos + if p >= self._size: + raise CodeBlockOverflow + self._data.contents[p] = data + self._pos = p + 1 + + def tell(self): + baseaddr = cast(self._data, c_void_p).value + return baseaddr + self._pos * 4 + + def __del__(self): + memhandler.free(cast(self._data, memhandler.PTR), self._size * 4) Added: pypy/dist/pypy/jit/codegen/ppc/emit_moves.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/ppc/emit_moves.py Sat Nov 4 16:58:23 2006 @@ -0,0 +1,95 @@ + +class CycleData: + # tar2src -> map target var to source var + # src2tar -> map source var to target var (!) + # tar2loc -> map target var to location + # src2loc -> map source var to location + # loc2src -> map location to source var + # srcstack -> list of source vars + # freshctr -> how many fresh locations have we made so far + # emitted -> list of emitted targets + pass + +def emit_moves(gen, tar2src, tar2loc, src2loc): + + # Basic idea: + # + # Construct a dependency graph, with a node for each move (Ti <- + # Si). Add an edge between two nodes i and j if loc[Ti] == + # loc[Sj]. (If executing the node's move would overwrite the + # source for another move). If there are no cycles, then a + # simple tree walk will suffice. If there *ARE* cycles, however, + # something more is needed. + # + # In a nutshell, the algorithm is to walk the tree, and whenever + # a backedge is detected break the cycle by creating a fresh + # location and remapping the source of the node so that it no + # longer conflicts. So, if you are in node i, and you detect a + # cycle involving node j (so, Ti and Sj are the same location), + # then you create a fresh location Sn. You move Sj to Sn, and + # remap node j so that instead of being Tj <- Sj it is Tj <- Sn. + # Now there is no need for the backedge, so you can continue. + # Whenever you have visited every edge going out from a node, all of + # its dependent moves have been performed, so you can emit the + # node's move and return. + + tarvars = tar2src.keys() + + data = CycleData() + data.tar2src = tar2src + data.src2tar = {} + data.tar2loc = tar2loc + data.src2loc = src2loc + data.loc2src = {} + data.srcstack = [] + data.freshctr = 0 + data.emitted = [] + + for tar, src in tar2src.items(): + data.src2tar[src] = tar + + for src, loc in src2loc.items(): + if src in data.src2tar: + data.loc2src[loc] = src + + for tarvar in tarvars: + _cycle_walk(gen, tarvar, data) + + return data + +def _cycle_walk(gen, tarvar, data): + + if tarvar in data.emitted: return + + tarloc = data.tar2loc[tarvar] + srcvar = data.tar2src[tarvar] + srcloc = data.src2loc[srcvar] + + # if location we are about to write to is not going to be read + # by anyone, we are safe + if tarloc not in data.loc2src: + gen.emit_move(tarloc, srcloc) + data.emitted.append(tarvar) + return + + # Find source node that conflicts with us + conflictsrcvar = data.loc2src[tarloc] + + if conflictsrcvar not in data.srcstack: + # No cycle on our stack yet + data.srcstack.append(srcvar) + _cycle_walk(gen, data.src2tar[conflictsrcvar], data) + srcloc = data.src2loc[srcvar] # warning: may have changed, so reload + gen.emit_move(tarloc, srcloc) + data.emitted.append(tarvar) + return + + # Cycle detected, break it by moving the other node's source data + # somewhere else so we can overwrite it + freshloc = gen.create_fresh_location() + conflictsrcloc = data.src2loc[conflictsrcvar] + gen.emit_move(freshloc, conflictsrcloc) + data.src2loc[conflictsrcvar] = freshloc + gen.emit_move(tarloc, srcloc) # now safe to do our move + data.emitted.append(tarvar) + return Added: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Sat Nov 4 16:58:23 2006 @@ -0,0 +1,256 @@ +r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, \ + r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, \ + r23, r24, r25, r26, r27, r28, r29, r30, r31 = range(32) +rSCRATCH = r0 +rSP = r1 +rFP = r2 # the ABI doesn't specify a frame pointer. however, we want one + +class AllocationSlot(object): + pass + +class _StackSlot(AllocationSlot): + is_register = False + def __init__(self, offset): + self.offset = offset + +_stack_slot_cache = {} +def stack_slot(offset): + if offset in _stack_slot_cache: + return _stack_slot_cache[offset] + _stack_slot_cache[offset] = res = _StackSlot(offset) + return res + +class Register(AllocationSlot): + is_register = True + +class GPR(Register): + def __init__(self, number): + self.number = number + def __repr__(self): + return 'r' + str(self.number) +gprs = map(GPR, range(32)) + +class FPR(Register): + def __init__(self, number): + self.number = number + +fprs = map(GPR, range(32)) + +class CRF(Register): + def __init__(self, number): + self.number = number + +crfs = map(CRF, range(8)) + +class CTR(Register): + pass + +ctr = CTR() + +NO_REGISTER = -1 +GP_REGISTER = 0 +FP_REGISTER = 1 +CR_FIELD = 2 +CT_REGISTER = 3 + +_insn_index = [0] + +class Insn(object): + ''' + result is the Var instance that holds the result, or None + result_regclass is the class of the register the result goes into + + reg_args is the vars that need to have registers allocated for them + reg_arg_regclasses is the type of register that needs to be allocated + ''' + def __init__(self): + self.__magic_index = _insn_index[0] + _insn_index[0] += 1 + def __repr__(self): + return "<%s %d>" % (self.__class__.__name__, self.__magic_index) + +class Insn_GPR__GPR_GPR(Insn): + def __init__(self, methptr, result, args): + Insn.__init__(self) + self.methptr = methptr + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = args + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] + + def allocate(self, allocator): + self.result_reg = allocator.var2loc[self.result] + self.arg_reg1 = allocator.var2loc[self.reg_args[0]] + self.arg_reg2 = allocator.var2loc[self.reg_args[1]] + + def emit(self, asm): + self.methptr(asm, + self.result_reg.number, + self.arg_reg1.number, + self.arg_reg2.number) + +class Insn_GPR__GPR_IMM(Insn): + def __init__(self, methptr, result, args): + Insn.__init__(self) + self.methptr = methptr + self.imm = args[1] + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [args[0]] + self.reg_arg_regclasses = [GP_REGISTER] + def allocate(self, allocator): + self.result_reg = allocator.var2loc[self.result] + self.arg_reg = allocator.var2loc[self.reg_args[0]] + def emit(self, asm): + self.methptr(asm, + self.result_reg.number, + self.arg_reg.number, + self.imm.value) + +class Insn_GPR__IMM(Insn): + def __init__(self, methptr, result, args): + Insn.__init__(self) + self.methptr = methptr + self.imm = args[0] + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [] + self.reg_arg_regclasses = [] + def allocate(self, allocator): + self.result_reg = allocator.var2loc[self.result] + def emit(self, asm): + self.methptr(asm, + self.result_reg.number, + self.imm.value) + +class CMPInsn(Insn): + info = (0,0) # please the annotator for tests that don't use CMPW/CMPWI + pass + +class CMPW(CMPInsn): + def __init__(self, info, result, args): + Insn.__init__(self) + self.info = info + + self.result = result + self.result_regclass = CR_FIELD + + self.reg_args = args + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] + + def allocate(self, allocator): + self.result_reg = allocator.var2loc[self.result] + self.arg_reg1 = allocator.var2loc[self.reg_args[0]] + self.arg_reg2 = allocator.var2loc[self.reg_args[1]] + + def emit(self, asm): + asm.cmpw(self.result_reg.number, self.arg_reg1.number, self.arg_reg2.number) + +class CMPWI(CMPInsn): + def __init__(self, info, result, args): + Insn.__init__(self) + self.info = info + self.imm = args[1] + + self.result = result + self.result_regclass = CR_FIELD + + self.reg_args = [args[0]] + self.reg_arg_regclasses = [GP_REGISTER] + + def allocate(self, allocator): + self.result_reg = allocator.var2loc[self.result] + self.arg_reg = allocator.var2loc[self.reg_args[0]] + + def emit(self, asm): + asm.cmpwi(self.result_reg.number, self.arg_reg.number, self.imm.value) + +class MTCTR(Insn): + def __init__(self, result, args): + Insn.__init__(self) + self.result = result + self.result_regclass = CT_REGISTER + + self.reg_args = args + self.reg_arg_regclasses = [GP_REGISTER] + + def allocate(self, allocator): + self.arg_reg = allocator.var2loc[self.reg_args[0]] + + def emit(self, asm): + asm.mtctr(self.arg_reg.number) + +class Jump(Insn): + def __init__(self, gv_cond, gv_target, jump_if_true): + Insn.__init__(self) + self.gv_cond = gv_cond + self.gv_target = gv_target + self.jump_if_true = jump_if_true + + self.result = None + self.result_regclass = NO_REGISTER + self.reg_args = [gv_cond, gv_target] + self.reg_arg_regclasses = [CR_FIELD, CT_REGISTER] + def allocate(self, allocator): + assert allocator.var2loc[self.reg_args[1]] is ctr + self.crf = allocator.var2loc[self.reg_args[0]] + self.bit, self.negated = allocator.crfinfo[self.crf.number] + def emit(self, asm): + if self.negated ^ self.jump_if_true: + BO = 12 # jump if relavent bit is set in the CR + else: + BO = 4 # jump if relavent bit is NOT set in the CR + asm.bcctr(BO, self.bit) + +class Unspill(Insn): + """ A special instruction inserted by our register "allocator." It + indicates that we need to load a value from the stack into a register + because we spilled a particular value. """ + def __init__(self, var, reg, stack): + """ + var --- the var we spilled (a Var) + reg --- the reg we spilled it from (an integer) + offset --- the offset on the stack we spilled it to (an integer) + """ + Insn.__init__(self) + self.var = var + self.reg = reg + self.stack = stack + def emit(self, asm): + asm.lwz(self.reg.number, rFP, self.stack.offset) + +class Spill(Insn): + """ A special instruction inserted by our register "allocator." + It indicates that we need to store a value from the register into + the stack because we spilled a particular value.""" + def __init__(self, var, reg, stack): + """ + var --- the var we are spilling (a Var) + reg --- the reg we are spilling it from (an integer) + offset --- the offset on the stack we are spilling it to (an integer) + """ + Insn.__init__(self) + self.var = var + self.reg = reg + self.stack = stack + def emit(self, asm): + asm.stw(self.reg.number, rFP, self.stack.offset) + +class Return(Insn): + """ Ensures the return value is in r3 """ + def __init__(self, var): + Insn.__init__(self) + self.var = var + self.reg_args = [self.var] + self.reg_arg_regclasses = [GP_REGISTER] + self.result = None + self.result_regclass = NO_REGISTER + self.reg = None + def allocate(self, allocator): + self.reg = allocator.var2loc[self.var] + def emit(self, asm): + if self.reg.number != 3: + asm.mr(r3, self.reg.number) Added: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Sat Nov 4 16:58:23 2006 @@ -0,0 +1,133 @@ +from pypy.jit.codegen.ppc.instruction import gprs, NO_REGISTER, GP_REGISTER, \ + FP_REGISTER, CR_FIELD, CT_REGISTER, CMPInsn, Spill, Unspill, crfs, ctr, stack_slot + +class RegisterAllocation: + def __init__(self, minreg, initial_mapping, initial_spill_offset): + #print + #print "RegisterAllocation __init__", initial_mapping + + self.insns = [] # Output list of instructions + self.freeregs = gprs[minreg:] # Registers with dead values + self.var2loc = {} # Maps a Var to an AllocationSlot + self.loc2var = {} # Maps an AllocationSlot to a Var + self.lru = [] # Least-recently-used list of vars; first is oldest. + # Contains all vars in registers, and no vars on stack + self.spill_offset = initial_spill_offset # Where to put next spilled + # value, relative to rFP, + # measured in bytes + + # Go through the initial mapping and initialize the data structures + for var, loc in initial_mapping.iteritems(): + self.loc2var[loc] = var + self.var2loc[var] = loc + if loc in self.freeregs: + self.freeregs.remove(loc) + self.lru.append(var) + self.crfinfo = [(0, 0)] * 8 + + def spill(self): + """ Returns an offset onto the stack for an unused spill location """ + # TODO --- reuse spill slots when contained values go dead? + self.spill_offset -= 4 + return self.spill_offset + + def _allocate_reg(self, newarg): + + # check if there is a register available + if self.freeregs: + reg = self.freeregs.pop() + self.loc2var[reg] = newarg + self.var2loc[newarg] = reg + #print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) + return reg + + # if not, find something to spill + argtospill = self.lru.pop(0) + reg = self.var2loc[argtospill] + assert reg.is_register + + # Move the value we are spilling onto the stack, both in the + # data structures and in the instructions: + spill = stack_slot(self.spill()) + self.var2loc[argtospill] = spill + self.loc2var[spill] = argtospill + self.insns.append(Spill(argtospill, reg, spill)) + #print "allocate_reg: Spilled %r to %r." % (argtospill, spill) + + # If the value is currently on the stack, load it up into the + # register we are putting it into + if newarg in self.var2loc: + spill = self.var2loc[newarg] + assert not spill.is_register + self.insns.append(Unspill(newarg, reg, spill)) + del self.loc2var[spill] # not stored there anymore, reuse?? + #print "allocate_reg: Unspilled %r from %r." % (newarg, spill) + + # Update data structures to put newarg into the register + self.var2loc[newarg] = reg + self.loc2var[reg] = newarg + #print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) + return reg + + def _promote(self, arg): + if arg in self.lru: + self.lru.remove(arg) + self.lru.append(arg) + + def allocate_for_insns(self, insns): + # Walk through instructions in forward order + for insn in insns: + + #print "Processing instruction %r with args %r and result %r:" % (insn, insn.reg_args, insn.result) + + #print "LRU list was: %r" % (self.lru,) + + # put things into the lru + for i in range(len(insn.reg_args)): + arg = insn.reg_args[i] + argcls = insn.reg_arg_regclasses[i] + if argcls == GP_REGISTER: + self._promote(arg) + if insn.result and insn.result_regclass == GP_REGISTER: + self._promote(insn.result) + #print "LRU list is now: %r" % (self.lru,) + + # We need to allocate a register for each used + # argument that is not already in one + for i in range(len(insn.reg_args)): + arg = insn.reg_args[i] + argcls = insn.reg_arg_regclasses[i] + #print "Allocating register for %r..." % (arg,) + + if not self.var2loc[arg].is_register: + # It has no register now because it has been spilled + assert argcls is GP_REGISTER, "uh-oh" + self._allocate_reg(arg) + else: + #print "it was in ", self.var2loc[arg] + pass + + # Need to allocate a register for the destination + assert not insn.result or insn.result not in self.var2loc + cand = None + if insn.result_regclass is GP_REGISTER: + #print "Allocating register for result %r..." % (insn.result,) + cand = self._allocate_reg(insn.result) + elif insn.result_regclass is CR_FIELD: + assert crfs[0] not in self.loc2var + assert isinstance(insn, CMPInsn) + cand = crfs[0] + self.crfinfo[0] = insn.info + elif insn.result_regclass is CT_REGISTER: + assert ctr not in self.loc2var + cand = ctr + elif insn.result_regclass is not NO_REGISTER: + assert 0 + if cand is not None and cand not in self.loc2var: + self.var2loc[insn.result] = cand + self.loc2var[cand] = insn.result + else: + assert cand is None or self.loc2var[cand] is insn.result + insn.allocate(self) + self.insns.append(insn) + return self.insns Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Sat Nov 4 16:58:23 2006 @@ -3,188 +3,22 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rlib.objectmodel import specialize, we_are_translated from pypy.jit.codegen.ppc.conftest import option +from ctypes import POINTER, cast, c_void_p, c_int -class AllocationSlot(object): - pass +from pypy.jit.codegen.ppc import codebuf +from pypy.jit.codegen.ppc.instruction import rSP, rFP, rSCRATCH, gprs +from pypy.jit.codegen.ppc import instruction as insn +from pypy.jit.codegen.ppc.regalloc import RegisterAllocation +from pypy.jit.codegen.ppc.emit_moves import emit_moves -class _StackSlot(AllocationSlot): - is_register = False - def __init__(self, offset): - self.offset = offset - -_stack_slot_cache = {} -def stack_slot(offset): - if offset in _stack_slot_cache: - return _stack_slot_cache[offset] - _stack_slot_cache[offset] = res = _StackSlot(offset) - return res - -class Register(AllocationSlot): - is_register = True - -class GPR(Register): - def __init__(self, number): - self.number = number - def __repr__(self): - return 'r' + str(self.number) -gprs = map(GPR, range(32)) +from pypy.translator.asm.ppcgen.rassemblermaker import make_rassembler +from pypy.translator.asm.ppcgen.ppc_assembler import MyPPCAssembler -class FPR(Register): - def __init__(self, number): - self.number = number - -fprs = map(GPR, range(32)) - -class CRF(Register): - def __init__(self, number): - self.number = number - -crfs = map(CRF, range(8)) - -class CTR(Register): - pass - -ctr = CTR() - -class NullRegister(Register): - pass - -NO_REGISTER = -1 -GP_REGISTER = 0 -FP_REGISTER = 1 -CR_FIELD = 2 -CT_REGISTER = 3 - -class RegisterAllocation: - def __init__(self, minreg, initial_mapping, initial_spill_offset): - #print - #print "RegisterAllocation __init__", initial_mapping - - self.insns = [] # Output list of instructions - self.freeregs = gprs[minreg:] # Registers with dead values - self.var2loc = {} # Maps a Var to an AllocationSlot - self.loc2var = {} # Maps an AllocationSlot to a Var - self.lru = [] # Least-recently-used list of vars; first is oldest. - # Contains all vars in registers, and no vars on stack - self.spill_offset = initial_spill_offset # Where to put next spilled - # value, relative to rFP, - # measured in bytes - - # Go through the initial mapping and initialize the data structures - for var, loc in initial_mapping.iteritems(): - self.loc2var[loc] = var - self.var2loc[var] = loc - if loc in self.freeregs: - self.freeregs.remove(loc) - self.lru.append(var) - self.crfinfo = [(0, 0)] * 8 - - def spill(self): - """ Returns an offset onto the stack for an unused spill location """ - # TODO --- reuse spill slots when contained values go dead? - self.spill_offset -= 4 - return self.spill_offset - - def _allocate_reg(self, newarg): - - # check if there is a register available - if self.freeregs: - reg = self.freeregs.pop() - self.loc2var[reg] = newarg - self.var2loc[newarg] = reg - #print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) - return reg - - # if not, find something to spill - argtospill = self.lru.pop(0) - reg = self.var2loc[argtospill] - assert reg.is_register - - # Move the value we are spilling onto the stack, both in the - # data structures and in the instructions: - spill = stack_slot(self.spill()) - self.var2loc[argtospill] = spill - self.loc2var[spill] = argtospill - self.insns.append(Spill(argtospill, reg, spill)) - #print "allocate_reg: Spilled %r to %r." % (argtospill, spill) - - # If the value is currently on the stack, load it up into the - # register we are putting it into - if newarg in self.var2loc: - spill = self.var2loc[newarg] - assert not spill.is_register - self.insns.append(Unspill(newarg, reg, spill)) - del self.loc2var[spill] # not stored there anymore, reuse?? - #print "allocate_reg: Unspilled %r from %r." % (newarg, spill) - - # Update data structures to put newarg into the register - self.var2loc[newarg] = reg - self.loc2var[reg] = newarg - #print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) - return reg - - def _promote(self, arg): - if arg in self.lru: - self.lru.remove(arg) - self.lru.append(arg) - - def allocate_for_insns(self, insns): - # Walk through instructions in forward order - for insn in insns: - - #print "Processing instruction %r with args %r and result %r:" % (insn, insn.reg_args, insn.result) - - #print "LRU list was: %r" % (self.lru,) - - # put things into the lru - for i in range(len(insn.reg_args)): - arg = insn.reg_args[i] - argcls = insn.reg_arg_regclasses[i] - if argcls == GP_REGISTER: - self._promote(arg) - if insn.result and insn.result_regclass == GP_REGISTER: - self._promote(insn.result) - #print "LRU list is now: %r" % (self.lru,) - - # We need to allocate a register for each used - # argument that is not already in one - for i in range(len(insn.reg_args)): - arg = insn.reg_args[i] - argcls = insn.reg_arg_regclasses[i] - #print "Allocating register for %r..." % (arg,) - - if not self.var2loc[arg].is_register: - # It has no register now because it has been spilled - assert argcls is GP_REGISTER, "uh-oh" - self._allocate_reg(arg) - else: - #print "it was in ", self.var2loc[arg] - pass +RPPCAssembler = make_rassembler(MyPPCAssembler) - # Need to allocate a register for the destination - assert not insn.result or insn.result not in self.var2loc - cand = None - if insn.result_regclass is GP_REGISTER: - #print "Allocating register for result %r..." % (insn.result,) - cand = self._allocate_reg(insn.result) - elif insn.result_regclass is CR_FIELD: - assert crfs[0] not in self.loc2var - assert isinstance(insn, CMPInsn) - cand = crfs[0] - self.crfinfo[0] = insn.info - elif insn.result_regclass is CT_REGISTER: - assert ctr not in self.loc2var - cand = ctr - elif insn.result_regclass is not NO_REGISTER: - assert 0 - if cand is not None and cand not in self.loc2var: - self.var2loc[insn.result] = cand - self.loc2var[cand] = insn.result - else: - assert cand is None or self.loc2var[cand] is insn.result - insn.allocate(self) - self.insns.append(insn) - return self.insns +def emit(self, value): + self.mc.write(value) +RPPCAssembler.emit = emit _var_index = [0] class Var(GenVar): @@ -213,7 +47,7 @@ def load(self, builder): var = builder.newvar() builder.insns.append( - Insn_GPR__IMM(RPPCAssembler.load_word, + insn.Insn_GPR__IMM(RPPCAssembler.load_word, var, [self])) return var @@ -224,323 +58,6 @@ asm.load_word(rSCRATCH, self.value) asm.stw(rSCRATCH, rFP, loc.offset) -class Insn(object): - ''' - result is the Var instance that holds the result, or None - result_regclass is the class of the register the result goes into - - reg_args is the vars that need to have registers allocated for them - reg_arg_regclasses is the type of register that needs to be allocated - ''' - def __init__(self): - self.__magic_index = _var_index[0] - _var_index[0] += 1 - def __repr__(self): - return "<%s %d>" % (self.__class__.__name__, self.__magic_index) - -class Insn_GPR__GPR_GPR(Insn): - def __init__(self, methptr, result, args): - Insn.__init__(self) - self.methptr = methptr - - self.result = result - self.result_regclass = GP_REGISTER - self.reg_args = args - self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] - - def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - self.arg_reg1 = allocator.var2loc[self.reg_args[0]] - self.arg_reg2 = allocator.var2loc[self.reg_args[1]] - - def emit(self, asm): - self.methptr(asm, - self.result_reg.number, - self.arg_reg1.number, - self.arg_reg2.number) - -class Insn_GPR__GPR_IMM(Insn): - def __init__(self, methptr, result, args): - Insn.__init__(self) - self.methptr = methptr - self.imm = args[1] - - self.result = result - self.result_regclass = GP_REGISTER - self.reg_args = [args[0]] - self.reg_arg_regclasses = [GP_REGISTER] - def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - self.arg_reg = allocator.var2loc[self.reg_args[0]] - def emit(self, asm): - self.methptr(asm, - self.result_reg.number, - self.arg_reg.number, - self.imm.value) - -class Insn_GPR__IMM(Insn): - def __init__(self, methptr, result, args): - Insn.__init__(self) - self.methptr = methptr - self.imm = args[0] - - self.result = result - self.result_regclass = GP_REGISTER - self.reg_args = [] - self.reg_arg_regclasses = [] - def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - def emit(self, asm): - self.methptr(asm, - self.result_reg.number, - self.imm.value) - -class CMPInsn(Insn): - info = (0,0) # please the annotator for tests that don't use CMPW/CMPWI - pass - -class CMPW(CMPInsn): - def __init__(self, info, result, args): - Insn.__init__(self) - self.info = info - - self.result = result - self.result_regclass = CR_FIELD - - self.reg_args = args - self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] - - def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - self.arg_reg1 = allocator.var2loc[self.reg_args[0]] - self.arg_reg2 = allocator.var2loc[self.reg_args[1]] - - def emit(self, asm): - asm.cmpw(self.result_reg.number, self.arg_reg1.number, self.arg_reg2.number) - -class CMPWI(CMPInsn): - def __init__(self, info, result, args): - Insn.__init__(self) - self.info = info - self.imm = args[1] - - self.result = result - self.result_regclass = CR_FIELD - - self.reg_args = [args[0]] - self.reg_arg_regclasses = [GP_REGISTER] - - def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - self.arg_reg = allocator.var2loc[self.reg_args[0]] - - def emit(self, asm): - asm.cmpwi(self.result_reg.number, self.arg_reg.number, self.imm.value) - -class MTCTR(Insn): - def __init__(self, result, args): - Insn.__init__(self) - self.result = result - self.result_regclass = CT_REGISTER - - self.reg_args = args - self.reg_arg_regclasses = [GP_REGISTER] - - def allocate(self, allocator): - self.arg_reg = allocator.var2loc[self.reg_args[0]] - - def emit(self, asm): - asm.mtctr(self.arg_reg.number) - -class Jump(Insn): - def __init__(self, gv_cond, gv_target, jump_if_true): - Insn.__init__(self) - self.gv_cond = gv_cond - self.gv_target = gv_target - self.jump_if_true = jump_if_true - - self.result = None - self.result_regclass = NO_REGISTER - self.reg_args = [gv_cond, gv_target] - self.reg_arg_regclasses = [CR_FIELD, CT_REGISTER] - def allocate(self, allocator): - assert allocator.var2loc[self.reg_args[1]] is ctr - self.crf = allocator.var2loc[self.reg_args[0]] - self.bit, self.negated = allocator.crfinfo[self.crf.number] - def emit(self, asm): - if self.negated ^ self.jump_if_true: - BO = 12 # jump if relavent bit is set in the CR - else: - BO = 4 # jump if relavent bit is NOT set in the CR - asm.bcctr(BO, self.bit) - -class Unspill(Insn): - """ A special instruction inserted by our register "allocator." It - indicates that we need to load a value from the stack into a register - because we spilled a particular value. """ - def __init__(self, var, reg, stack): - """ - var --- the var we spilled (a Var) - reg --- the reg we spilled it from (an integer) - offset --- the offset on the stack we spilled it to (an integer) - """ - Insn.__init__(self) - self.var = var - self.reg = reg - self.stack = stack - def emit(self, asm): - asm.lwz(self.reg.number, rFP, self.stack.offset) - -class Spill(Insn): - """ A special instruction inserted by our register "allocator." - It indicates that we need to store a value from the register into - the stack because we spilled a particular value.""" - def __init__(self, var, reg, stack): - """ - var --- the var we are spilling (a Var) - reg --- the reg we are spilling it from (an integer) - offset --- the offset on the stack we are spilling it to (an integer) - """ - Insn.__init__(self) - self.var = var - self.reg = reg - self.stack = stack - def emit(self, asm): - asm.stw(self.reg.number, rFP, self.stack.offset) - -class Return(Insn): - """ Ensures the return value is in r3 """ - def __init__(self, var): - Insn.__init__(self) - self.var = var - self.reg_args = [self.var] - self.reg_arg_regclasses = [GP_REGISTER] - self.result = None - self.result_regclass = NO_REGISTER - self.reg = None - def allocate(self, allocator): - self.reg = allocator.var2loc[self.var] - def emit(self, asm): - if self.reg.number != 3: - asm.mr(r3, self.reg.number) - -from pypy.jit.codegen.ppc import codebuf_posix as memhandler -from ctypes import POINTER, cast, c_char, c_void_p, CFUNCTYPE, c_int - -class CodeBlockOverflow(Exception): - pass - -from pypy.translator.asm.ppcgen.rassemblermaker import make_rassembler -from pypy.translator.asm.ppcgen.ppc_assembler import MyPPCAssembler - -RPPCAssembler = make_rassembler(MyPPCAssembler) - -r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, \ - r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, \ - r23, r24, r25, r26, r27, r28, r29, r30, r31 = range(32) -rSCRATCH = r0 -rSP = r1 -rFP = r2 # the ABI doesn't specify a frame pointer. however, we want one - -def emit(self, value): - self.mc.write(value) -RPPCAssembler.emit = emit - -class CycleData: - # tar2src -> map target var to source var - # src2tar -> map source var to target var (!) - # tar2loc -> map target var to location - # src2loc -> map source var to location - # loc2src -> map location to source var - # srcstack -> list of source vars - # freshctr -> how many fresh locations have we made so far - # emitted -> list of emitted targets - pass - -def emit_moves(gen, tar2src, tar2loc, src2loc): - - # Basic idea: - # - # Construct a dependency graph, with a node for each move (Ti <- - # Si). Add an edge between two nodes i and j if loc[Ti] == - # loc[Sj]. (If executing the node's move would overwrite the - # source for another move). If there are no cycles, then a - # simple tree walk will suffice. If there *ARE* cycles, however, - # something more is needed. - # - # In a nutshell, the algorithm is to walk the tree, and whenever - # a backedge is detected break the cycle by creating a fresh - # location and remapping the source of the node so that it no - # longer conflicts. So, if you are in node i, and you detect a - # cycle involving node j (so, Ti and Sj are the same location), - # then you create a fresh location Sn. You move Sj to Sn, and - # remap node j so that instead of being Tj <- Sj it is Tj <- Sn. - # Now there is no need for the backedge, so you can continue. - # Whenever you have visited every edge going out from a node, all of - # its dependent moves have been performed, so you can emit the - # node's move and return. - - tarvars = tar2src.keys() - - data = CycleData() - data.tar2src = tar2src - data.src2tar = {} - data.tar2loc = tar2loc - data.src2loc = src2loc - data.loc2src = {} - data.srcstack = [] - data.freshctr = 0 - data.emitted = [] - - for tar, src in tar2src.items(): - data.src2tar[src] = tar - - for src, loc in src2loc.items(): - if src in data.src2tar: - data.loc2src[loc] = src - - for tarvar in tarvars: - _cycle_walk(gen, tarvar, data) - - return data - -def _cycle_walk(gen, tarvar, data): - - if tarvar in data.emitted: return - - tarloc = data.tar2loc[tarvar] - srcvar = data.tar2src[tarvar] - srcloc = data.src2loc[srcvar] - - # if location we are about to write to is not going to be read - # by anyone, we are safe - if tarloc not in data.loc2src: - gen.emit_move(tarloc, srcloc) - data.emitted.append(tarvar) - return - - # Find source node that conflicts with us - conflictsrcvar = data.loc2src[tarloc] - - if conflictsrcvar not in data.srcstack: - # No cycle on our stack yet - data.srcstack.append(srcvar) - _cycle_walk(gen, data.src2tar[conflictsrcvar], data) - srcloc = data.src2loc[srcvar] # warning: may have changed, so reload - gen.emit_move(tarloc, srcloc) - data.emitted.append(tarvar) - return - - # Cycle detected, break it by moving the other node's source data - # somewhere else so we can overwrite it - freshloc = gen.create_fresh_location() - conflictsrcloc = data.src2loc[conflictsrcvar] - gen.emit_move(freshloc, conflictsrcloc) - data.src2loc[conflictsrcvar] = freshloc - gen.emit_move(tarloc, srcloc) # now safe to do our move - data.emitted.append(tarvar) - return - class JumpPatchupGenerator(object): def __init__(self, asm, min_offset): @@ -562,7 +79,7 @@ def create_fresh_location(self): r = self.min_offset self.min_offset -= 4 - return stack_slot(r) + return insn.stack_slot(r) def prepare_for_jump(asm, min_offset, sourcevars, src2loc, target): @@ -581,34 +98,6 @@ emit_moves(gen, tar2src, tar2loc, src2loc) return gen.min_offset -class MachineCodeBlock: - - def __init__(self, map_size): - assert map_size % 4 == 0 - res = memhandler.alloc(map_size) - self._data = cast(res, POINTER(c_int * (map_size / 4))) - self._size = map_size/4 - self._pos = 0 - - def write(self, data): - p = self._pos - if p >= self._size: - raise CodeBlockOverflow - self._data.contents[p] = data - self._pos = p + 1 - - def tell(self): - baseaddr = cast(self._data, c_void_p).value - return baseaddr + self._pos * 4 - - def __del__(self): - memhandler.free(cast(self._data, memhandler.PTR), self._size * 4) - -## def execute(self, arg1, arg2): -## fnptr = cast(self._data, binaryfn) -## return fnptr(arg1, arg2) - -## binaryfn = CFUNCTYPE(c_int, c_int, c_int) # for testing class Label(GenLabel): @@ -687,7 +176,7 @@ minspace = self._stack_size(0,self._var_offset(0)) self.asm.mflr(rSCRATCH) self.asm.stw(rSCRATCH,rSP,8) - self.asm.stmw(r13,rSP,-(4*20)) # save all regs from 13-31 to stack + self.asm.stmw(gprs[13].number,rSP,-(4*20)) # save all regs from 13-31 to stack self.asm.mr(rFP, rSP) # set up our frame pointer self.asm.stwu(rSP,rSP,-minspace) @@ -727,12 +216,12 @@ def finish_and_return(self, sigtoken, gv_returnvar): gv_returnvar = gv_returnvar.load(self) - self.insns.append(Return(gv_returnvar)) + self.insns.append(insn.Return(gv_returnvar)) allocator = self.allocate_and_emit() # Emit standard epilogue: self.asm.lwz(rSP,rSP,0) # restore old SP - self.asm.lmw(r13,rSP,-4*20) # restore all GPRs + self.asm.lmw(gprs[13].number,rSP,-4*20) # restore all GPRs self.asm.lwz(rSCRATCH,rSP,8) # load old Link Register and jump to it self.asm.mtlr(rSCRATCH) # self.asm.blr() # @@ -817,7 +306,7 @@ if unusedregs: loc = unusedregs.pop() else: - loc = stack_slot(min_stack_offset) + loc = insn.stack_slot(min_stack_offset) min_stack_offset -= 4 gv.load_now(self.asm, loc) args_gv[i] = gv = Var() @@ -848,38 +337,38 @@ def op_int_mul(self, gv_x, gv_y): gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y) self.insns.append( - Insn_GPR__GPR_GPR(RPPCAssembler.mullw, - gv_result, [gv_x, gv_y])) - return gv_result + insn.Insn_GPR__GPR_GPR(RPPCAssembler.mullw, + gv_result, [gv_x, gv_y])) + return gv_result def op_int_add(self, gv_x, gv_y): if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2**16: gv_result = self.newvar() self.insns.append( - Insn_GPR__GPR_IMM(RPPCAssembler.addi, - gv_result, [gv_x.load(self), gv_y])) + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_result, [gv_x.load(self), gv_y])) return gv_result elif isinstance(gv_x, IntConst): return self.op_int_add(gv_y, gv_x) else: gv_result = self.newvar() self.insns.append( - Insn_GPR__GPR_GPR(RPPCAssembler.add, - gv_result, [gv_x.load(self), gv_y.load(self)])) + insn.Insn_GPR__GPR_GPR(RPPCAssembler.add, + gv_result, [gv_x.load(self), gv_y.load(self)])) return gv_result def op_int_sub(self, gv_x, gv_y): gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y) self.insns.append( - Insn_GPR__GPR_GPR(RPPCAssembler.sub, - gv_result, [gv_x, gv_y])) + insn.Insn_GPR__GPR_GPR(RPPCAssembler.sub, + gv_result, [gv_x, gv_y])) return gv_result def op_int_floordiv(self, gv_x, gv_y): gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y) self.insns.append( - Insn_GPR__GPR_GPR(RPPCAssembler.divw, - gv_result, [gv_x.load(self), gv_y.load(self)])) + insn.Insn_GPR__GPR_GPR(RPPCAssembler.divw, + gv_result, [gv_x.load(self), gv_y.load(self)])) return gv_result def _compare(self, op, gv_x, gv_y): @@ -887,12 +376,12 @@ result = self.newvar() if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2*16: gv_x = gv_x.load(self) - self.insns.append(CMPWI((1, 0), result, [gv_x, gv_y])) + self.insns.append(insn.CMPWI((1, 0), result, [gv_x, gv_y])) elif isinstance(gv_x, IntConst) and abs(gv_x.value) < 2*16: gv_y = gv_y.load(self) - self.insns.append(CMPWI((1, 1), result, [gv_y, gv_x])) + self.insns.append(insn.CMPWI((1, 1), result, [gv_y, gv_x])) else: - self.insns.append(CMPW((1, 0), result, [gv_x.load(self), gv_y.load(self)])) + self.insns.append(insn.CMPW((1, 0), result, [gv_x.load(self), gv_y.load(self)])) return result def op_int_gt(self, gv_x, gv_y): @@ -903,13 +392,13 @@ gv = self.newvar() self.insns.append( - Insn_GPR__IMM(RPPCAssembler.load_word, - gv, [IntConst(targetbuilder.asm.mc.tell())])) + insn.Insn_GPR__IMM(RPPCAssembler.load_word, + gv, [IntConst(targetbuilder.asm.mc.tell())])) gv2 = self.newvar() self.insns.append( - MTCTR(gv2, [gv])) + insn.MTCTR(gv2, [gv])) self.insns.append( - Jump(gv_condition, gv2, if_true)) + insn.Jump(gv_condition, gv2, if_true)) allocator = self.allocate_and_emit() self.make_fresh_from_jump(allocator.var2loc) @@ -928,7 +417,6 @@ class RPPCGenOp(AbstractRGenOp): - from pypy.jit.codegen.i386.codebuf import MachineCodeBlock # minimum register we will use for register allocation # we can artifically restrict it for testing purposes @@ -941,7 +429,7 @@ if self.mcs: return self.mcs.pop() else: - return MachineCodeBlock(65536) # XXX supposed infinite for now + return codebuf.MachineCodeBlock(65536) # XXX supposed infinite for now def close_mc(self, mc): self.mcs.append(mc) Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_emit_moves.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_emit_moves.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_emit_moves.py Sat Nov 4 16:58:23 2006 @@ -1,5 +1,5 @@ import py -from pypy.jit.codegen.ppc.rgenop import emit_moves +from pypy.jit.codegen.ppc.emit_moves import emit_moves class TheHeap(object): def __init__(self, locs): From stephan at codespeak.net Sat Nov 4 16:59:25 2006 From: stephan at codespeak.net (stephan at codespeak.net) Date: Sat, 4 Nov 2006 16:59:25 +0100 (CET) Subject: [pypy-svn] r34188 - pypy/dist/pypy/lang/js Message-ID: <20061104155925.5119910081@code0.codespeak.net> Author: stephan Date: Sat Nov 4 16:59:24 2006 New Revision: 34188 Modified: pypy/dist/pypy/lang/js/interpreter.py Log: (stephan, santagada) assignment is still somewhat broken... Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sat Nov 4 16:59:24 2006 @@ -63,10 +63,18 @@ name = self.right.get_literal() return w_obj.Get(name) - def put(self, context, val): - w_obj = self.left.call(context).GetValue().ToObject() - name = self.right.get_literal() - w_obj.dict_w[self.name] = val + def put(self, context, val, obj=None): + if isinstance(self.left,Identifier): + assobj = obj or context + assobj.assign(self.left.name,val) + elif isinstance(self.left,Dot): + assobj = self.left.put(context, val, obj) + + return assobj + + #w_obj = self.left.put(context).GetValue().ToObject() + #name = self.right.get_literal() + #w_obj.dict_w[self.name] = val class __extend__(Function): @@ -85,7 +93,19 @@ return scope_manager.get_variable(self.name) except NameError: return self.name - + + def put(self, context, val, obj=None): + if self.initialiser is not None: + scope_manager.set_variable(self.name, self.initialiser.call(context)) + try: + nobj = context.access(self.name) + except NameError: + try: + nobj = scope_manager.get_variable(self.name) + except NameError: + return self.name + nobj.assign(self.name, val) + return nobj def get_literal(self): return self.name From rxe at codespeak.net Sat Nov 4 17:02:01 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Sat, 4 Nov 2006 17:02:01 +0100 (CET) Subject: [pypy-svn] r34189 - in pypy/dist/pypy: jit/timeshifter/test lang/automata Message-ID: <20061104160201.839BD100A8@code0.codespeak.net> Author: rxe Date: Sat Nov 4 17:01:59 2006 New Revision: 34189 Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/lang/automata/dfa.py Log: fix the tests - yay it works! - arigo,rxe Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Sat Nov 4 17:01:59 2006 @@ -154,18 +154,18 @@ assert not res def test_dfa_compile2(self): - py.test.skip('wip') from pypy.lang.automata.dfa import getautomaton, convertagain, recognizeparts - a = getautomaton() - def main(gets): - alltrans, final_states = convertagain(a) + more = [convertagain(getautomaton()), convertagain(getautomaton())] + def main(gets, gets2): + alltrans, final_states = more[gets2] s = ["aaaaaaaaaab", "aaaa"][gets] return recognizeparts(alltrans, final_states, s) - res = self.timeshift_from_portal(main, recognizeparts, [0], policy=P_NOVIRTUAL) + res = self.timeshift_from_portal(main, recognizeparts, [0, 0], policy=P_NOVIRTUAL) assert res - res = self.timeshift_from_portal(main, recognizeparts, [1], policy=P_NOVIRTUAL) + # XXX unfortunately we have to create a new version each time - because of pbc + res = self.timeshift_from_portal(main, recognizeparts, [1, 0], policy=P_NOVIRTUAL) assert not res def test_method_call_promote(self): Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Sat Nov 4 17:01:59 2006 @@ -130,5 +130,6 @@ indx += 1 res = state in finals + res = hint(res, concrete=True) res = hint(res, variable=True) return res From santagada at codespeak.net Sat Nov 4 17:12:02 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Sat, 4 Nov 2006 17:12:02 +0100 (CET) Subject: [pypy-svn] r34190 - pypy/dist/pypy/lang/js Message-ID: <20061104161202.94571100A0@code0.codespeak.net> Author: santagada Date: Sat Nov 4 17:12:01 2006 New Revision: 34190 Modified: pypy/dist/pypy/lang/js/interpreter.py Log: (stephan, santagada) scoping is still broken... the rest of the test pass Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sat Nov 4 17:12:01 2006 @@ -45,7 +45,8 @@ writer(",".join([i.ToString() for i in self.arglist.call(context)])) else: backup_scope = scope_manager.current_scope - w_obj = scope_manager.get_variable(name) + + w_obj = context.access(name) scope_manager.current_scope = w_obj.function.scope retval = w_obj.Call(context=context, args=[i for i in self.arglist.call(context)]) @@ -89,23 +90,10 @@ try: return context.access(self.name) except NameError: - try: - return scope_manager.get_variable(self.name) - except NameError: - return self.name + return scope_manager.get_variable(self.name) def put(self, context, val, obj=None): - if self.initialiser is not None: - scope_manager.set_variable(self.name, self.initialiser.call(context)) - try: - nobj = context.access(self.name) - except NameError: - try: - nobj = scope_manager.get_variable(self.name) - except NameError: - return self.name - nobj.assign(self.name, val) - return nobj + context.assign(self.name, val) def get_literal(self): return self.name From arigo at codespeak.net Sat Nov 4 17:17:20 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 4 Nov 2006 17:17:20 +0100 (CET) Subject: [pypy-svn] r34191 - in pypy/dist/pypy/jit/codegen/i386: . test Message-ID: <20061104161720.880F2100AA@code0.codespeak.net> Author: arigo Date: Sat Nov 4 17:17:19 2006 New Revision: 34191 Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_portal.py pypy/dist/pypy/jit/codegen/i386/viewcode.py Log: - missing renames in test_genc_portal - fix the viewer, which now works on larger examples too Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_portal.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/test/test_genc_portal.py (original) +++ pypy/dist/pypy/jit/codegen/i386/test/test_genc_portal.py Sat Nov 4 17:17:19 2006 @@ -68,9 +68,9 @@ def check_insns(self, expected=None, **counts): "Cannot check instructions in the generated assembler." -class TestPromotion(I386PortalTestMixin, - test_portal.TestPortal): +class TestPortal(I386PortalTestMixin, + test_portal.TestPortal): # for the individual tests see - # ====> ../../../timeshifter/test/test_promotion.py + # ====> ../../../timeshifter/test/test_portal.py pass Modified: pypy/dist/pypy/jit/codegen/i386/viewcode.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/viewcode.py (original) +++ pypy/dist/pypy/jit/codegen/i386/viewcode.py Sat Nov 4 17:17:19 2006 @@ -53,6 +53,7 @@ # ____________________________________________________________ class CodeRange(object): + fallthrough = False def __init__(self, addr, data): self.addr = addr @@ -90,7 +91,8 @@ def findjumps(self): text = self.disassemble() - for i, line in enumerate(text.splitlines()): + lines = text.splitlines() + for i, line in enumerate(lines): if '\tj' not in line: # poor heuristic to recognize lines that continue # could be jump instructions addrs = list(lineaddresses(line)) @@ -98,6 +100,8 @@ continue addr = addrs[-1] yield i, addr + if self.fallthrough: + yield len(lines), self.addr + len(self.data) class World(object): @@ -125,30 +129,31 @@ break else: self.ranges.append(coderange) -## # find cross-references between blocks -## for r in self.ranges: -## for lineno, targetaddr in r.findjumps(): -## self.labeltargets[targetaddr] = True -## # split blocks at labeltargets -## # XXX slooooow! -## t = self.labeltargets -## print t -## for r in self.ranges: -## print r.addr, r.addr + len(r.data) -## for i in range(r.addr + 1, r.addr + len(r.data)): -## if i in t: -## print i -## ofs = i - r.addr -## self.ranges.append(CodeRange(i, r.data[ofs:])) -## r.data = r.data[:ofs] -## del r.text -## break -## # hack hack hacked + # find cross-references between blocks + for r in self.ranges: + for lineno, targetaddr in r.findjumps(): + self.labeltargets[targetaddr] = True + # split blocks at labeltargets + # XXX slooooow! + t = self.labeltargets + print t + for r in self.ranges: + print r.addr, r.addr + len(r.data) + for i in range(r.addr + 1, r.addr + len(r.data)): + if i in t: + print i + ofs = i - r.addr + self.ranges.append(CodeRange(i, r.data[ofs:])) + r.data = r.data[:ofs] + r.fallthrough = True + del r.text + break + # hack hack hacked def show(self): g1 = Graph('codedump') for r in self.ranges: - text = r.disassemble() + text = r.disassemble().replace('\t', ' ') text = '0x%x\n\n%s' % (r.addr, text) g1.emit_node('N_%x' % r.addr, shape="box", label=text) for lineno, targetaddr in r.findjumps(): From cfbolz at codespeak.net Sat Nov 4 17:18:18 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 17:18:18 +0100 (CET) Subject: [pypy-svn] r34192 - in pypy/branch/refactor-file/pypy: . config config/test module/__builtin__ module/posix module/posix/test module/sys objspace/std tool Message-ID: <20061104161818.AE534100B0@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 17:18:17 2006 New Revision: 34192 Modified: pypy/branch/refactor-file/pypy/config/pypyoption.py pypy/branch/refactor-file/pypy/config/test/test_pypyoption.py pypy/branch/refactor-file/pypy/conftest.py pypy/branch/refactor-file/pypy/module/__builtin__/__init__.py pypy/branch/refactor-file/pypy/module/__builtin__/state.py pypy/branch/refactor-file/pypy/module/posix/app_posix.py pypy/branch/refactor-file/pypy/module/posix/test/test_posix_libfile.py pypy/branch/refactor-file/pypy/module/sys/__init__.py pypy/branch/refactor-file/pypy/module/sys/state.py pypy/branch/refactor-file/pypy/objspace/std/objspace.py pypy/branch/refactor-file/pypy/tool/option.py Log: (guido, cfbolz): remove config.objspace.uselibfile options because we can now always use our own file implementation! good!! progress! less code, less faking, happyness. Modified: pypy/branch/refactor-file/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/refactor-file/pypy/config/pypyoption.py (original) +++ pypy/branch/refactor-file/pypy/config/pypyoption.py Sat Nov 4 17:18:17 2006 @@ -11,7 +11,7 @@ [#"unicodedata", "_codecs", "gc", "_weakref", "array", "marshal", "errno", "math", "_sre", "_pickle_support", "sys", "exceptions", "__builtins__", - "recparser", "symbol", "_random"]) + "recparser", "symbol", "_random", "_file"]) pypy_optiondescription = OptionDescription("pypy", "All PyPy Options", [ OptionDescription("objspace", "Object Space Option", [ @@ -34,16 +34,11 @@ BoolOption("nofaking", "disallow faking in the object space", default=False, requires=[ - ("objspace.uselibfile", True), ("objspace.usemodules.posix", True), ("objspace.usemodules.time", True), ("objspace.usemodules.errno", True)], cmdline='--nofaking'), - BoolOption("uselibfile", "use the applevel file implementation", - default=False, - cmdline='--uselibfile'), - OptionDescription("usemodules", "Which Modules should be used", [ BoolOption(modname, "use module %s" % (modname, ), default=modname in default_modules, Modified: pypy/branch/refactor-file/pypy/config/test/test_pypyoption.py ============================================================================== --- pypy/branch/refactor-file/pypy/config/test/test_pypyoption.py (original) +++ pypy/branch/refactor-file/pypy/config/test/test_pypyoption.py Sat Nov 4 17:18:17 2006 @@ -6,10 +6,6 @@ conf = Config(pypy_optiondescription) assert not conf.translating - conf.objspace.nofaking = True - assert conf.objspace.uselibfile - py.test.raises(ValueError, "conf.objspace.uselibfile = False") - assert conf.objspace.usemodules.gc conf.objspace.std.withsmallint = True Modified: pypy/branch/refactor-file/pypy/conftest.py ============================================================================== --- pypy/branch/refactor-file/pypy/conftest.py (original) +++ pypy/branch/refactor-file/pypy/conftest.py Sat Nov 4 17:18:17 2006 @@ -28,9 +28,6 @@ help="object space to run tests on."), Option('--oldstyle', action="store_true",dest="oldstyle", default=False, help="enable oldstyle classes as default metaclass"), - Option('--uselibfile', action="store_true", - dest="uselibfile", default=False, - help="enable our applevel file implementation"), Option('--nofaking', action="store_true", dest="nofaking", default=False, help="avoid faking of modules and objects completely."), Modified: pypy/branch/refactor-file/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/__builtin__/__init__.py (original) +++ pypy/branch/refactor-file/pypy/module/__builtin__/__init__.py Sat Nov 4 17:18:17 2006 @@ -72,8 +72,8 @@ 'object' : '(space.w_object)', 'unicode' : '(space.w_unicode)', - 'file' : 'state.get(space).w_file', - 'open' : 'state.get(space).w_file', + 'file' : 'state.get(space).w_file', + 'open' : 'state.get(space).w_file', # old-style classes dummy support '_classobj' : 'space.w_classobj', Modified: pypy/branch/refactor-file/pypy/module/__builtin__/state.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/__builtin__/state.py (original) +++ pypy/branch/refactor-file/pypy/module/__builtin__/state.py Sat Nov 4 17:18:17 2006 @@ -1,10 +1,9 @@ -class State: - def __init__(self, space): - if space.config.objspace.uselibfile: - self.w_file = space.builtin.get('__filestub') - else: - self.w_file = space.wrap(file) +class State: + def __init__(self, space): + self.w_file = space.appexec([], """(): + import _file; + return _file.file""") -def get(space): +def get(space): return space.fromcache(State) Modified: pypy/branch/refactor-file/pypy/module/posix/app_posix.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/posix/app_posix.py (original) +++ pypy/branch/refactor-file/pypy/module/posix/app_posix.py Sat Nov 4 17:18:17 2006 @@ -28,8 +28,5 @@ Return an open file object connected to a file descriptor.""" - try: - return file.fdopen(fd, mode, buffering) - except AttributeError: - raise NotImplementedError, "fdopen only works if you use PyPy's file implementation." + return file.fdopen(fd, mode, buffering) Modified: pypy/branch/refactor-file/pypy/module/posix/test/test_posix_libfile.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/posix/test/test_posix_libfile.py (original) +++ pypy/branch/refactor-file/pypy/module/posix/test/test_posix_libfile.py Sat Nov 4 17:18:17 2006 @@ -2,9 +2,9 @@ from pypy.tool.udir import udir import os -def setup_module(mod): - mod.space = gettestobjspace(usemodules=['posix'], uselibfile=True) - mod.path = udir.join('posixtestfile.txt') +def setup_module(mod): + mod.space = gettestobjspace(usemodules=['posix']) + mod.path = udir.join('posixtestfile.txt') mod.path.write("this is a test") class AppTestPosix: Modified: pypy/branch/refactor-file/pypy/module/sys/__init__.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/sys/__init__.py (original) +++ pypy/branch/refactor-file/pypy/module/sys/__init__.py Sat Nov 4 17:18:17 2006 @@ -20,12 +20,12 @@ 'prefix' : 'space.wrap(sys.prefix)', 'maxunicode' : 'space.wrap(sys.maxunicode)', 'maxint' : 'space.wrap(sys.maxint)', - 'stdin' : 'state.getio(space).w_stdin', - '__stdin__' : 'state.getio(space).w_stdin', - 'stdout' : 'state.getio(space).w_stdout', - '__stdout__' : 'state.getio(space).w_stdout', - 'stderr' : 'state.getio(space).w_stderr', - '__stderr__' : 'state.getio(space).w_stderr', + 'stdin' : 'state.getio(space).w_stdin', + '__stdin__' : 'state.getio(space).w_stdin', + 'stdout' : 'state.getio(space).w_stdout', + '__stdout__' : 'state.getio(space).w_stdout', + 'stderr' : 'state.getio(space).w_stderr', + '__stderr__' : 'state.getio(space).w_stderr', 'pypy_objspaceclass' : 'space.wrap(repr(space))', 'path' : 'state.get(space).w_path', Modified: pypy/branch/refactor-file/pypy/module/sys/state.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/sys/state.py (original) +++ pypy/branch/refactor-file/pypy/module/sys/state.py Sat Nov 4 17:18:17 2006 @@ -72,23 +72,33 @@ pypy_initial_path.unwrap_spec = [ObjSpace, str] -def get(space): +def get(space): return space.fromcache(State) -class IOState: - def __init__(self, space): +class IOState: + def __init__(self, space): self.space = space - if space.config.objspace.uselibfile: - self.w_stdout = space.call_function(space.builtin.get('file')) - self.w_stderr = space.call_function(space.builtin.get('file')) - self.w_stdin = space.call_function(space.builtin.get('file')) - else: - self.w_stdout = space.wrap(sys.__stdout__) - self.w_stderr = space.wrap(sys.__stderr__) - self.w_stdin = space.wrap(sys.__stdin__) -def getio(space): - return space.fromcache(IOState) + w_fdopen = space.getattr(space.builtin.get('file'), + space.wrap("fdopen")) + self.w_stdin = space.call_function( + w_fdopen, space.wrap(0), space.wrap("r"), + space.wrap(1)) + space.setattr(self.w_stdin, space.wrap("_name"), + space.wrap("")) + self.w_stdout = space.call_function( + w_fdopen, space.wrap(1), space.wrap("w"), + space.wrap(1)) + space.setattr(self.w_stdout, space.wrap("_name"), + space.wrap("")) + self.w_stderr = space.call_function( + w_fdopen, space.wrap(2), space.wrap("w"), + space.wrap(0)) + space.setattr(self.w_stderr, space.wrap("_name"), + space.wrap("")) + +def getio(space): + return space.fromcache(IOState) def _pypy_getudir(space): """NOT_RPYTHON""" Modified: pypy/branch/refactor-file/pypy/objspace/std/objspace.py ============================================================================== --- pypy/branch/refactor-file/pypy/objspace/std/objspace.py (original) +++ pypy/branch/refactor-file/pypy/objspace/std/objspace.py Sat Nov 4 17:18:17 2006 @@ -125,12 +125,9 @@ r[s] = value return r dict.fromkeys = classmethod(fromkeys) - """) + """) - if self.config.objspace.uselibfile: - self.inituselibfile() - - if self.config.objspace.std.oldstyle: + if self.config.objspace.std.oldstyle: self.enable_old_style_classes_as_default_metaclass() # final setup @@ -178,36 +175,6 @@ w_mod = self.wrap(mod) return w_mod, w_dic - def inituselibfile(self): - """ NOT_RPYTHON use our application level file implementation - including re-wrapping sys.stdout/err/in - """ - assert self.config.objspace.uselibfile - space = self - # nice print helper if the below does not work - # (we dont have prints working at applevel before - # inituselibfile is complete) - #from pypy.interpreter import gateway - #def printit(space, w_msg): - # s = space.str_w(w_msg) - # print "$", s, - #w_p = space.wrap(gateway.interp2app(printit)) - #self.appexec([w_p], '''(p): - self.appexec([], '''(): - import sys - sys.stdin - sys.stdout - sys.stderr # force unlazifying from mixedmodule - from _file import file as libfile - for name, value in libfile.__dict__.items(): - if (name != '__dict__' and name != '__doc__' - and name != '__module__' and name != '__weakref__'): - setattr(file, name, value) - sys.stdin._fdopen(0, "r", 1, '') - sys.stdout._fdopen(1, "w", 1, '') - sys.stderr._fdopen(2, "w", 0, '') - ''') - def setup_exceptions(self): """NOT_RPYTHON""" ## hacking things in Modified: pypy/branch/refactor-file/pypy/tool/option.py ============================================================================== --- pypy/branch/refactor-file/pypy/tool/option.py (original) +++ pypy/branch/refactor-file/pypy/tool/option.py Sat Nov 4 17:18:17 2006 @@ -10,7 +10,6 @@ class Options: objspace = "std" oldstyle = 0 - uselibfile = 0 nofaking = 0 parser = "pypy" # "cpython" / "pypy" compiler = "ast" @@ -71,9 +70,6 @@ setattr(conf.objspace.usemodules, modname, True) if getattr(cmdlineopt, "nofaking", False) or kwds.get("nofaking", False): conf.objspace.nofaking = True - if (getattr(cmdlineopt, "uselibfile", False) or - kwds.get("uselibfile", False)): - conf.objspace.uselibfile = True if getattr(cmdlineopt, "oldstyle", False) or kwds.get("oldstyle", False): conf.objspace.std.oldstyle = True if hasattr(cmdlineopt, "parser") and cmdlineopt.parser is not None: From pedronis at codespeak.net Sat Nov 4 17:21:10 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 4 Nov 2006 17:21:10 +0100 (CET) Subject: [pypy-svn] r34193 - in pypy/dist/pypy/rpython: . test Message-ID: <20061104162110.CEC90100B8@code0.codespeak.net> Author: pedronis Date: Sat Nov 4 17:21:08 2006 New Revision: 34193 Modified: pypy/dist/pypy/rpython/rpbc.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: some support for class or None in the rtyper. With a simple instantation test. Modified: pypy/dist/pypy/rpython/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/rpbc.py (original) +++ pypy/dist/pypy/rpython/rpbc.py Sat Nov 4 17:21:08 2006 @@ -595,9 +595,9 @@ def __init__(self, rtyper, s_pbc): self.rtyper = rtyper self.s_pbc = s_pbc - if s_pbc.can_be_None: - raise TyperError("unsupported: variable of type " - "class-pointer or None") + #if s_pbc.can_be_None: + # raise TyperError("unsupported: variable of type " + # "class-pointer or None") if s_pbc.is_constant(): self.lowleveltype = Void else: @@ -627,6 +627,12 @@ return rclass.get_type_repr(self.rtyper).convert_desc(desc) def convert_const(self, cls): + if cls is None: + if self.lowleveltype is Void: + return None + else: + T = self.lowleveltype + return self.rtyper.type_system.null_callable(T) bk = self.rtyper.annotator.bookkeeper classdesc = bk.getdesc(cls) return self.convert_desc(classdesc) @@ -664,8 +670,10 @@ s_instance = hop.s_result r_instance = hop.r_result - if self.lowleveltype is Void: + if len(self.s_pbc.descriptions) == 1: # instantiating a single class + if self.lowleveltype is not Void: + assert 0, "XXX None-or-1-class instantation not implemented" assert isinstance(s_instance, annmodel.SomeInstance) classdef = hop.s_result.classdef s_init = classdef.classdesc.s_read_attribute('__init__') @@ -693,13 +701,13 @@ vtypeptr = hop.inputarg(self, arg=0) try: access_set, r_class = self.get_access_set('__init__') - except MissingRTypeAttribute: + except rclass.MissingRTypeAttribute: s_init = annmodel.s_ImpossibleValue else: s_init = access_set.s_value v_init = r_class.getpbcfield(vtypeptr, access_set, '__init__', hop.llops) - v_instance = self._instantiate_runtime_class(hop, vtypeptr, r_instance) + v_instance = self._instantiate_runtime_class(hop, vtypeptr, r_instance) if isinstance(s_init, annmodel.SomeImpossibleValue): assert hop.nb_args == 1, ("arguments passed to __init__, " 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 Sat Nov 4 17:21:08 2006 @@ -568,6 +568,31 @@ res = self.interpret(f, [1]) assert self.class_name(res) == 'B' + def test_call_classes_or_None(self): + class A: pass + class B(A): pass + def f(i): + if i == -1: + cls = None + elif i == 1: + cls = B + else: + cls = A + return cls() + res = self.interpret(f, [0]) + assert self.class_name(res) == 'A' + res = self.interpret(f, [1]) + assert self.class_name(res) == 'B' + + #def f(i): + # if i == -1: + # cls = None + # else: + # cls = A + # return cls() + #res = self.interpret(f, [0]) + #assert self.class_name(res) == 'A' + def test_call_classes_with_init2(self): class A: def __init__(self, z): From fijal at codespeak.net Sat Nov 4 17:23:52 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 17:23:52 +0100 (CET) Subject: [pypy-svn] r34194 - pypy/branch/transparent-proxy/pypy/objspace/std/test Message-ID: <20061104162352.1C6CF100BE@code0.codespeak.net> Author: fijal Date: Sat Nov 4 17:23:52 2006 New Revision: 34194 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Log: (pedronis, fijal) - Fix test Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sat Nov 4 17:23:52 2006 @@ -27,6 +27,7 @@ assert tb.tb_frame is e[2].tb_frame def test_traceback_reraise(self): + py.test.skip("Not implemented yet") try: 1/0 except: @@ -34,5 +35,5 @@ e = sys.exc_info() tb = self.get_proxy(e[2]) - raises(ZeroDivisionError, "raise (e[0], e[1], tb)") - raises(ZeroDivisionError, "raise (e[0], self.get_proxy(e[1]), tb)") + raises(ZeroDivisionError, "raise e[0], e[1], tb") + raises(ZeroDivisionError, "raise e[0], self.get_proxy(e[1]), tb") From fijal at codespeak.net Sat Nov 4 17:24:02 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 17:24:02 +0100 (CET) Subject: [pypy-svn] r34195 - in pypy/branch/transparent-proxy/pypy/rpython: . test Message-ID: <20061104162402.97344100C4@code0.codespeak.net> Author: fijal Date: Sat Nov 4 17:24:01 2006 New Revision: 34195 Modified: pypy/branch/transparent-proxy/pypy/rpython/rpbc.py pypy/branch/transparent-proxy/pypy/rpython/test/test_rpbc.py Log: Merge back from dist. Modified: pypy/branch/transparent-proxy/pypy/rpython/rpbc.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/rpython/rpbc.py (original) +++ pypy/branch/transparent-proxy/pypy/rpython/rpbc.py Sat Nov 4 17:24:01 2006 @@ -595,9 +595,9 @@ def __init__(self, rtyper, s_pbc): self.rtyper = rtyper self.s_pbc = s_pbc - if s_pbc.can_be_None: - raise TyperError("unsupported: variable of type " - "class-pointer or None") + #if s_pbc.can_be_None: + # raise TyperError("unsupported: variable of type " + # "class-pointer or None") if s_pbc.is_constant(): self.lowleveltype = Void else: @@ -627,6 +627,12 @@ return rclass.get_type_repr(self.rtyper).convert_desc(desc) def convert_const(self, cls): + if cls is None: + if self.lowleveltype is Void: + return None + else: + T = self.lowleveltype + return self.rtyper.type_system.null_callable(T) bk = self.rtyper.annotator.bookkeeper classdesc = bk.getdesc(cls) return self.convert_desc(classdesc) @@ -664,8 +670,10 @@ s_instance = hop.s_result r_instance = hop.r_result - if self.lowleveltype is Void: + if len(self.s_pbc.descriptions) == 1: # instantiating a single class + if self.lowleveltype is not Void: + assert 0, "XXX None-or-1-class instantation not implemented" assert isinstance(s_instance, annmodel.SomeInstance) classdef = hop.s_result.classdef s_init = classdef.classdesc.s_read_attribute('__init__') @@ -693,13 +701,13 @@ vtypeptr = hop.inputarg(self, arg=0) try: access_set, r_class = self.get_access_set('__init__') - except MissingRTypeAttribute: + except rclass.MissingRTypeAttribute: s_init = annmodel.s_ImpossibleValue else: s_init = access_set.s_value v_init = r_class.getpbcfield(vtypeptr, access_set, '__init__', hop.llops) - v_instance = self._instantiate_runtime_class(hop, vtypeptr, r_instance) + v_instance = self._instantiate_runtime_class(hop, vtypeptr, r_instance) if isinstance(s_init, annmodel.SomeImpossibleValue): assert hop.nb_args == 1, ("arguments passed to __init__, " Modified: pypy/branch/transparent-proxy/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/rpython/test/test_rpbc.py (original) +++ pypy/branch/transparent-proxy/pypy/rpython/test/test_rpbc.py Sat Nov 4 17:24:01 2006 @@ -568,6 +568,31 @@ res = self.interpret(f, [1]) assert self.class_name(res) == 'B' + def test_call_classes_or_None(self): + class A: pass + class B(A): pass + def f(i): + if i == -1: + cls = None + elif i == 1: + cls = B + else: + cls = A + return cls() + res = self.interpret(f, [0]) + assert self.class_name(res) == 'A' + res = self.interpret(f, [1]) + assert self.class_name(res) == 'B' + + #def f(i): + # if i == -1: + # cls = None + # else: + # cls = A + # return cls() + #res = self.interpret(f, [0]) + #assert self.class_name(res) == 'A' + def test_call_classes_with_init2(self): class A: def __init__(self, z): From cfbolz at codespeak.net Sat Nov 4 17:27:06 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 17:27:06 +0100 (CET) Subject: [pypy-svn] r34196 - in pypy/branch/refactor-file/pypy/module/posix: . test Message-ID: <20061104162706.116F7100BF@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 17:27:05 2006 New Revision: 34196 Modified: pypy/branch/refactor-file/pypy/module/posix/app_posix.py pypy/branch/refactor-file/pypy/module/posix/test/test_posix2.py Log: (guido, cfbolz): fix the default for buffering. fix test that checked that fdopen does not work (!). Modified: pypy/branch/refactor-file/pypy/module/posix/app_posix.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/posix/app_posix.py (original) +++ pypy/branch/refactor-file/pypy/module/posix/app_posix.py Sat Nov 4 17:27:05 2006 @@ -23,7 +23,7 @@ st_mtime = tuple_item_getter(8) st_ctime = tuple_item_getter(9) -def fdopen(fd, mode='r', buffering=None): +def fdopen(fd, mode='r', buffering=-1): """fdopen(fd [, mode='r' [, buffering]]) -> file_object Return an open file object connected to a file descriptor.""" Modified: pypy/branch/refactor-file/pypy/module/posix/test/test_posix2.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/posix/test/test_posix2.py (original) +++ pypy/branch/refactor-file/pypy/module/posix/test/test_posix2.py Sat Nov 4 17:27:05 2006 @@ -72,15 +72,11 @@ ex(self.posix.dup, UNUSEDFD) def test_fdopen(self): - path = self.path - posix = self.posix + path = self.path + posix = self.posix fd = posix.open(path, posix.O_RDONLY, 0777) - try: - f = posix.fdopen(fd, "r") - except NotImplementedError: - pass - else: - raise "did not raise" + f = posix.fdopen(fd, "r") + f.close() def test_listdir(self): pdir = self.pdir From cfbolz at codespeak.net Sat Nov 4 17:39:05 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 17:39:05 +0100 (CET) Subject: [pypy-svn] r34197 - in pypy/branch/refactor-file/pypy/module/_file: . test Message-ID: <20061104163905.7C671100A9@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 17:39:04 2006 New Revision: 34197 Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py pypy/branch/refactor-file/pypy/module/_file/test/test_file.py Log: (guido, cfbolz): use wrapped IOError Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/interp_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/interp_file.py Sat Nov 4 17:39:04 2006 @@ -64,7 +64,7 @@ def is_mode_ok(space, mode): if not mode or mode[0] not in ['r', 'w', 'a', 'U']: raise OperationError( - IOError, + space.w_IOError, space.wrap('invalid mode : %s' % mode)) def open_file_as_stream(space, path, mode="r", buffering=-1): Modified: pypy/branch/refactor-file/pypy/module/_file/test/test_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/test/test_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/test/test_file.py Sat Nov 4 17:39:04 2006 @@ -41,3 +41,7 @@ assert s == "foobar" finally: f.close() + + def test_badmode(self): + import _file + raises(IOError, _file.file, "foo", "bar") From mwh at codespeak.net Sat Nov 4 17:43:38 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sat, 4 Nov 2006 17:43:38 +0100 (CET) Subject: [pypy-svn] r34198 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061104164338.02EEC100CC@code0.codespeak.net> Author: mwh Date: Sat Nov 4 17:43:36 2006 New Revision: 34198 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: (niko, mwh) reduce the magic number density. the amount of mistakes i made doing this suggests that it must nearly be time for dinner. Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Sat Nov 4 17:43:36 2006 @@ -20,6 +20,8 @@ self.mc.write(value) RPPCAssembler.emit = emit +NSAVEDREGISTERS = 19 + _var_index = [0] class Var(GenVar): def __init__(self): @@ -170,13 +172,14 @@ # Emit standard prologue # Minimum space = 24+params+lv+4*GPR+8*FPR - # GPR=19 + # GPR=NSAVEDREGISTERS # Initially, we allocate only enough space for GPRs, and allow # each basic block to ensure it has enough space to continue. - minspace = self._stack_size(0,self._var_offset(0)) + minspace = self._stack_size(0, self._var_offset(0)) self.asm.mflr(rSCRATCH) self.asm.stw(rSCRATCH,rSP,8) - self.asm.stmw(gprs[13].number,rSP,-(4*20)) # save all regs from 13-31 to stack + # save all regs from -31 to stack + self.asm.stmw(gprs[32-NSAVEDREGISTERS].number,rSP,-4*(NSAVEDREGISTERS + 1)) self.asm.mr(rFP, rSP) # set up our frame pointer self.asm.stwu(rSP,rSP,-minspace) @@ -185,7 +188,7 @@ def _var_offset(self, v): """v represents an offset into the local variable area in bytes; this returns the offset relative to rFP""" - return -(4*19+4+v) + return -(4*NSAVEDREGISTERS+4+v) def _stack_size(self, param, lv): """ Returns the required stack size to store all data, assuming @@ -221,7 +224,7 @@ # Emit standard epilogue: self.asm.lwz(rSP,rSP,0) # restore old SP - self.asm.lmw(gprs[13].number,rSP,-4*20) # restore all GPRs + self.asm.lmw(gprs[32-NSAVEDREGISTERS].number,rSP,-4*(NSAVEDREGISTERS+1)) # restore all GPRs self.asm.lwz(rSCRATCH,rSP,8) # load old Link Register and jump to it self.asm.mtlr(rSCRATCH) # self.asm.blr() # From cfbolz at codespeak.net Sat Nov 4 17:47:12 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 17:47:12 +0100 (CET) Subject: [pypy-svn] r34199 - in pypy/branch/refactor-file/pypy/module/_file: . test Message-ID: <20061104164712.261A1100D1@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 17:47:10 2006 New Revision: 34199 Modified: pypy/branch/refactor-file/pypy/module/_file/app_file.py pypy/branch/refactor-file/pypy/module/_file/interp_file.py pypy/branch/refactor-file/pypy/module/_file/test/test_file.py Log: (guido, cfbolz): fix another error path, and make __del__ not fail if the object was constructed with __new__ but not __init__ialized. Modified: pypy/branch/refactor-file/pypy/module/_file/app_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/app_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/app_file.py Sat Nov 4 17:47:10 2006 @@ -211,7 +211,7 @@ further I/O operations. close() may be called more than once without error. Some kinds of file objects (for example, opened by popen()) may return an exit status upon closing.""" - if not self._closed: + if not self._closed and hasattr(self, 'stream'): self._closed = True self.stream.close() Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/interp_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/interp_file.py Sat Nov 4 17:47:10 2006 @@ -73,7 +73,7 @@ return space.wrap(W_Stream( space, streamio.open_file_as_stream(path, mode, buffering))) except OSError, e: - raise wrap_oserror_as_ioerror(e) + raise wrap_oserror_as_ioerror(space, e) open_file_as_stream.unwrap_spec = [ObjSpace, str, str, int] def fdopen_as_stream(space, fd, mode="r", buffering=-1): Modified: pypy/branch/refactor-file/pypy/module/_file/test/test_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/test/test_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/test/test_file.py Sat Nov 4 17:47:10 2006 @@ -45,3 +45,7 @@ def test_badmode(self): import _file raises(IOError, _file.file, "foo", "bar") + + def test_wraposerror(self): + import _file + raises(IOError, _file.file, "hopefully/not/existant.bar") From fijal at codespeak.net Sat Nov 4 17:58:11 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 17:58:11 +0100 (CET) Subject: [pypy-svn] r34200 - in pypy/branch/transparent-proxy/pypy: interpreter objspace/std objspace/std/test Message-ID: <20061104165811.70DA9100C2@code0.codespeak.net> Author: fijal Date: Sat Nov 4 17:58:08 2006 New Revision: 34200 Modified: pypy/branch/transparent-proxy/pypy/interpreter/pyopcode.py pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Log: (pedronis, fijal) - Basics of traceback now works. Modified: pypy/branch/transparent-proxy/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/pyopcode.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/pyopcode.py Sat Nov 4 17:58:08 2006 @@ -351,7 +351,8 @@ raise operror else: tb = space.interpclass_w(w_traceback) - if not isinstance(tb, pytraceback.PyTraceback): + if tb is None or not space.is_true(space.isinstance(tb, + space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("raise: arg 3 must be a traceback or None")) operror.application_traceback = tb Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py Sat Nov 4 17:58:08 2006 @@ -11,61 +11,72 @@ # def __init__(self, w_controller): # self.controller = w_controller -class W_Transparent(W_Object): - def __init__(self, space, w_type, w_controller): - self.w_type = w_type - self.w_controller = w_controller - self.space = space - - def getclass(self, space): - return self.w_type - - def setclass(self, space, w_subtype): - raise OperationError(space.w_TypeError, - space.wrap("You cannot override __class__ for transparent proxies")) - - def getdictvalue(self, space, w_attr): - try: - return space.call_function(self.w_controller, space.wrap('__getattribute__'), - w_attr) - except OperationError, e: - if not e.match(space, space.w_AttributeError): - raise - return None - - def setdictvalue(self, space, w_attr, w_value): - try: - space.call_function(self.w_controller, space.wrap('__setattr__'), - w_attr, w_value) - return True - except OperationError, e: - if not e.match(space, space.w_AttributeError): - raise - return False - - def deldictvalue(self, space, w_attr): - try: - space.call_function(self.w_controller, space.wrap('__delattr__'), - w_attr) - return True - except OperationError, e: - if not e.match(space, space.w_AttributeError): - raise - return False - - def getdict(self): - return self.getdictvalue(self.space, self.space.wrap('__dict__')) - - def setdict(self, space, w_dict): - if not self.setdictvalue(space, space.wrap('__dict__'), w_dict): - baseobjspace.W_Root.setdict(self, space, w_dict) - - def descr_call_mismatch(self, space, name, reqcls, args): - _, args = args.popfirst() - args = args.prepend(space.wrap(name)) - return space.call_args(self.w_controller, args) +#class W_TransparentWrappable(Wrappable): - from pypy.objspace.std.objecttype import object_typedef as typedef +def transparent_class(name, BaseCls): + + class W_Transparent(BaseCls): + def __init__(self, space, w_type, w_controller): + self.w_type = w_type + self.w_controller = w_controller + self.space = space + + def descr_call_mismatch(self, space, name, reqcls, args): + _, args = args.popfirst() + args = args.prepend(space.wrap(name)) + return space.call_args(self.w_controller, args) + + def getclass(self, space): + return self.w_type + + def setclass(self, space, w_subtype): + raise OperationError(space.w_TypeError, + space.wrap("You cannot override __class__ for transparent proxies")) + + def getdictvalue(self, space, w_attr): + try: + return space.call_function(self.w_controller, space.wrap('__getattribute__'), + w_attr) + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return None + + def setdictvalue(self, space, w_attr, w_value): + try: + space.call_function(self.w_controller, space.wrap('__setattr__'), + w_attr, w_value) + return True + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return False + + def deldictvalue(self, space, w_attr): + try: + space.call_function(self.w_controller, space.wrap('__delattr__'), + w_attr) + return True + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return False + + def getdict(self): + return self.getdictvalue(self.space, self.space.wrap('__dict__')) + + def setdict(self, space, w_dict): + if not self.setdictvalue(space, space.wrap('__dict__'), w_dict): + baseobjspace.W_Root.setdict(self, space, w_dict) + + W_Transparent.__name__ = name + return W_Transparent + +W_Transparent = transparent_class('W_Transparent', Wrappable) +W_TransparentObject = transparent_class('W_TransparentObject', W_Object) + +from pypy.objspace.std.objecttype import object_typedef +W_TransparentObject.typedef = object_typedef class W_TransparentFunction(W_Transparent): from pypy.interpreter.function import Function @@ -74,12 +85,12 @@ class W_TransparentTraceback(W_Transparent): from pypy.interpreter.pytraceback import PyTraceback typedef = PyTraceback.typedef - -class W_TransparentList(W_Transparent): + +class W_TransparentList(W_TransparentObject): from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef - -class W_TransparentDict(W_Transparent): + +class W_TransparentDict(W_TransparentObject): from pypy.objspace.std.dictobject import W_DictObject as original from pypy.objspace.std.dicttype import dict_typedef as typedef Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sat Nov 4 17:58:08 2006 @@ -27,7 +27,7 @@ assert tb.tb_frame is e[2].tb_frame def test_traceback_reraise(self): - py.test.skip("Not implemented yet") + #skip("Not implemented yet") try: 1/0 except: @@ -37,3 +37,5 @@ tb = self.get_proxy(e[2]) raises(ZeroDivisionError, "raise e[0], e[1], tb") raises(ZeroDivisionError, "raise e[0], self.get_proxy(e[1]), tb") + import traceback + assert len(traceback.format_tb(tb)) == 1 From cfbolz at codespeak.net Sat Nov 4 18:12:58 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 18:12:58 +0100 (CET) Subject: [pypy-svn] r34201 - in pypy/branch/refactor-file/pypy: module/_file rlib Message-ID: <20061104171258.ABBF310034@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 18:12:56 2006 New Revision: 34201 Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py pypy/branch/refactor-file/pypy/rlib/streamio.py Log: (guido, cfbolz): don't use *args to try to not confuse the rtyper (more specifically the call normalization). thanks samuele. Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/interp_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/interp_file.py Sat Nov 4 18:12:56 2006 @@ -23,25 +23,11 @@ return OperationError(space.w_IOError, w_error) -EXPOSED_STREAM_METHODS = [ - ("read", [int]), - ("write", [str]), - ("tell", []), - ("seek", [int, int]), - ("readall", []), - ("readline", []), - ("truncate", [int]), - ("flush", []), - ("close", []), - ("peek", []), - ("try_to_find_file_descriptor", []), - ] - class W_Stream(Wrappable): def __init__(self, space, stream): self.stream = stream -for name, argtypes in EXPOSED_STREAM_METHODS: +for name, argtypes in streamio.STREAM_METHODS: numargs = len(argtypes) args = ", ".join(["v%s" % i for i in range(numargs)]) exec py.code.Source(""" @@ -58,7 +44,7 @@ W_Stream.typedef = TypeDef("Stream", **dict([(name, interp2app(globals()[name])) - for name, _ in EXPOSED_STREAM_METHODS])) + for name, _ in streamio.STREAM_METHODS])) def is_mode_ok(space, mode): Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py ============================================================================== --- pypy/branch/refactor-file/pypy/rlib/streamio.py (original) +++ pypy/branch/refactor-file/pypy/rlib/streamio.py Sat Nov 4 18:12:56 2006 @@ -340,19 +340,37 @@ # ____________________________________________________________ +STREAM_METHODS = [ + ("read", [int]), + ("write", [str]), + ("tell", []), + ("seek", [int, int]), + ("readall", []), + ("readline", []), + ("truncate", [int]), + ("flush", []), + ("close", []), + ("peek", []), + ("try_to_find_file_descriptor", []), + ] def PassThrough(meth_name, flush_buffers): + if meth_name in STREAM_METHODS: + signature = STREAM_METHODS[meth_name] + args = ", ".join(["v%s" % (i, ) for i in range(len(signature))]) + else: + args = "*args" if flush_buffers: - code = """def %s(self, *args): + code = """def %s(self, %s): self.flush_buffers() - return self.base.%s(*args) + return self.base.%s(%s) """ else: - code = """def %s(self, *args): - return self.base.%s(*args) + code = """def %s(self, %s): + return self.base.%s(%s) """ d = {} - exec code % (meth_name, meth_name) in d + exec code % (meth_name, args, meth_name, args) in d return d[meth_name] From santagada at codespeak.net Sat Nov 4 18:19:07 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Sat, 4 Nov 2006 18:19:07 +0100 (CET) Subject: [pypy-svn] r34202 - in pypy/dist/pypy/lang/js: . js test Message-ID: <20061104171907.AE67210093@code0.codespeak.net> Author: santagada Date: Sat Nov 4 18:19:02 2006 New Revision: 34202 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/context.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/js/jsparse.js pypy/dist/pypy/lang/js/test/test_interp.py Log: (santagada) almost everything is working... except prototypes Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Sat Nov 4 18:19:02 2006 @@ -107,6 +107,7 @@ class Script(Node): def __init__(self, nodes, var_decl, func_decl): self.nodes = nodes + [scope_manager.add_variable(id.name, w_Undefined) for id in var_decl] self.var_decl = var_decl self.func_decl = func_decl @@ -139,7 +140,7 @@ class Vars(Node): def __init__(self, nodes): self.nodes = nodes - [scope_manager.add_variable(id.name, w_Undefined) for id in nodes] + #[scope_manager.add_variable(id.name, w_Undefined) for id in nodes] class While(Node): def __init__(self, condition, body): @@ -218,8 +219,12 @@ elif tp == 'RETURN': return Return(from_dict(d['value'])) elif tp == 'SCRIPT': - # XXX: Cannot parse it right now - return Script(getlist(d), [], []) + # TODO: get function names + if isinstance(d['varDecls'], dict): + var_decl = [from_dict(d['varDecls']),] + else: + var_decl = [from_dict(x) for x in d['varDecls']] + return Script(getlist(d), var_decl, []) elif tp == 'SEMICOLON': return Semicolon(from_dict(d['expression'])) elif tp == 'STRING': Modified: pypy/dist/pypy/lang/js/context.py ============================================================================== --- pypy/dist/pypy/lang/js/context.py (original) +++ pypy/dist/pypy/lang/js/context.py Sat Nov 4 18:19:02 2006 @@ -8,11 +8,12 @@ self.globals = {} else: self.globals = parent.globals - #self.locals = {} def assign(self, name, value): - self.locals[name] = value - #self.globals[name] = value + if (name not in self.locals) and (name in self.globals): + self.globals[name] = value + else: + self.locals[name] = value def access(self, name): if name in self.locals: Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sat Nov 4 18:19:02 2006 @@ -25,7 +25,10 @@ class __extend__(Assign): def call(self, context): + #print context.locals.keys(), "|||||", context.globals + #print context.globals['z'] val = self.expr.call(context) + print val self.identifier.put(context,val) class __extend__(Block): @@ -79,14 +82,14 @@ class __extend__(Function): - def call(self, context=None): + def call(self, context): w_obj = W_Object({}, function=self) return w_obj class __extend__(Identifier): - def call(self, context=None): + def call(self, context): if self.initialiser is not None: - scope_manager.set_variable(self.name, self.initialiser.call(context)) + context.assign(self.name, self.initialiser.call(context)) try: return context.access(self.name) except NameError: @@ -197,7 +200,7 @@ return W_Number(num_left + num_right) class __extend__(Script): - def call(self, context=None, args=(), params=[]): + def call(self, context=None, args=(), params=[], first = False): ncontext = ExecutionContext(context) for i, item in enumerate(params): try: @@ -205,6 +208,12 @@ except IndexError: temp = w_Undefined ncontext.assign(item, temp) + + for var in self.var_decl: + if first: + ncontext.globals[var.name] = w_Undefined + else: + ncontext.locals[var.name] = w_Undefined w_Arguments = W_Arguments(dict([(str(x),y) for x,y in enumerate(args)])) ncontext.assign('arguments', w_Arguments) Modified: pypy/dist/pypy/lang/js/js/jsparse.js ============================================================================== --- pypy/dist/pypy/lang/js/js/jsparse.js (original) +++ pypy/dist/pypy/lang/js/js/jsparse.js Sat Nov 4 18:19:02 2006 @@ -284,9 +284,9 @@ var s = "{\n" + INDENTATION.repeat(n) + "'type': '" + tokenstr(this.type) + "'"; for (i = 0; i < a.length; i++) { val = a[i].value + ""; - if (val.search("\\},\\{") != -1) { + if ((val.search("\\},\\{") != -1 )) { s += ",\n" + INDENTATION.repeat(n) + "'" + a[i].id + "': [" + val + "]"; - } else { + } else { if (val.search("\n") != -1) { s += ",\n" + INDENTATION.repeat(n) + "'" + a[i].id + "': " + val + " "; } else { Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Sat Nov 4 18:19:02 2006 @@ -30,7 +30,7 @@ ctx = ExecutionContext() ctx.globals['Object'] = W_Object({}) try: - code.call(ctx) + code.call(ctx, first = True) except ThrowException, excpt: l.append("uncaught exception: "+str(excpt.exception)) assert l == assval @@ -227,4 +227,8 @@ print(o.info); """), ["hello"]) + def test_vars(self): + self.assert_prints(parse_d(""" + var x;x=3; print(x)"""), ["3"]) + From fijal at codespeak.net Sat Nov 4 18:21:30 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 18:21:30 +0100 (CET) Subject: [pypy-svn] r34203 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061104172130.4F672100A0@code0.codespeak.net> Author: fijal Date: Sat Nov 4 18:21:29 2006 New Revision: 34203 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (samuele, fijal) - Test + PyFrame & PyTraceback Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py Sat Nov 4 18:21:29 2006 @@ -86,6 +86,10 @@ from pypy.interpreter.pytraceback import PyTraceback typedef = PyTraceback.typedef +class W_TransparentFrame(W_Transparent): + from pypy.interpreter.pyframe import PyFrame + typedef = PyFrame.typedef + class W_TransparentList(W_TransparentObject): from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sat Nov 4 18:21:29 2006 @@ -39,3 +39,58 @@ raises(ZeroDivisionError, "raise e[0], self.get_proxy(e[1]), tb") import traceback assert len(traceback.format_tb(tb)) == 1 + + def test_simple_frame(self): + import sys + frame = sys._getframe(0) + fp = self.get_proxy(frame) + assert fp.f_locals == frame.f_locals + +class AppTestProxyTracebackController(object): + def test_controller(self): + import types + import sys + import traceback + + def get_proxy(f): + return proxy(type(f), Controller(f).perform) + + class FakeTb(object): + def __init__(self, tb): + self.tb_lasti = tb.tb_lasti + self.tb_lineno = tb.tb_lineno + if tb.tb_next: + self.tb_next = FakeTb(tb.tb_next) + else: + self.tb_next = None + self.tb_frame = get_proxy(tb.tb_frame) + + class Controller(object): + def __init__(self, tb): + if isinstance(tb, types.TracebackType): + self.obj = FakeTb(tb) + else: + self.obj = tb + + def perform(self, name, *args, **kwargs): + return getattr(self.obj, name)(*args, **kwargs) + + def f(): + 1/0 + + def g(): + f() + + try: + g() + except: + e = sys.exc_info() + + last_tb = e[2] + tb = get_proxy(e[2]) + try: + raise e[0], e[1], tb + except: + e = sys.exc_info() + + assert traceback.format_tb(last_tb) == traceback.format_tb(e[2]) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Sat Nov 4 18:21:29 2006 @@ -9,7 +9,7 @@ from pypy.objspace.std.typeobject import W_TypeObject def proxy(space, w_type, w_controller): - from pypy.interpreter.typedef import Function, PyTraceback + from pypy.interpreter.typedef import Function, PyTraceback, PyFrame if not space.is_true(space.callable(w_controller)): raise OperationError(space.w_TypeError, space.wrap("controller should be function")) @@ -23,6 +23,8 @@ return W_TransparentFunction(space, w_type, w_controller) if space.is_true(space.issubtype(w_type, space.gettypeobject(PyTraceback.typedef))): return W_TransparentTraceback(space, w_type, w_controller) + if space.is_true(space.issubtype(w_type, space.gettypeobject(PyFrame.typedef))): + return W_TransparentFrame(space, w_type, w_controller) if w_type.instancetypedef is space.w_object.instancetypedef: return W_Transparent(space, w_type, w_controller) else: From fijal at codespeak.net Sat Nov 4 18:49:51 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Nov 2006 18:49:51 +0100 (CET) Subject: [pypy-svn] r34204 - in pypy/branch/transparent-proxy/pypy: interpreter objspace/std objspace/std/test Message-ID: <20061104174951.76AC51009D@code0.codespeak.net> Author: fijal Date: Sat Nov 4 18:49:49 2006 New Revision: 34204 Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_iter.py (contents, props changed) Modified: pypy/branch/transparent-proxy/pypy/interpreter/typedef.py pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: (pedronis, fijal) - Added GeneratorIterator support. Modified: pypy/branch/transparent-proxy/pypy/interpreter/typedef.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/interpreter/typedef.py (original) +++ pypy/branch/transparent-proxy/pypy/interpreter/typedef.py Sat Nov 4 18:49:49 2006 @@ -668,8 +668,10 @@ GeneratorIterator.typedef = TypeDef("generator", __reduce__ = interp2app(GeneratorIterator.descr__reduce__, unwrap_spec=['self', ObjSpace]), - next = interp2app(GeneratorIterator.descr_next), - __iter__ = interp2app(GeneratorIterator.descr__iter__), + next = interp2app(GeneratorIterator.descr_next, + descrmismatch='next'), + __iter__ = interp2app(GeneratorIterator.descr__iter__, + descrmismatch='__iter__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = interp_attrproperty('frame', cls=GeneratorIterator), __weakref__ = make_weakref_descr(GeneratorIterator), Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py Sat Nov 4 18:49:49 2006 @@ -78,18 +78,20 @@ from pypy.objspace.std.objecttype import object_typedef W_TransparentObject.typedef = object_typedef +from pypy.interpreter.typedef import Function, GeneratorIterator, PyTraceback, PyFrame + class W_TransparentFunction(W_Transparent): - from pypy.interpreter.function import Function typedef = Function.typedef class W_TransparentTraceback(W_Transparent): - from pypy.interpreter.pytraceback import PyTraceback typedef = PyTraceback.typedef class W_TransparentFrame(W_Transparent): - from pypy.interpreter.pyframe import PyFrame typedef = PyFrame.typedef +class W_TransparentGenerator(W_Transparent): + typedef = GeneratorIterator.typedef + class W_TransparentList(W_TransparentObject): from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sat Nov 4 18:49:49 2006 @@ -2,7 +2,7 @@ """ test proxy internals like code, traceback, frame """ -class AppTestProxyInternals(object): +class AppProxy(object): def setup_method(self, meth): self.w_get_proxy = self.space.appexec([], """(): class Controller(object): @@ -16,6 +16,7 @@ return get_proxy """) +class AppTestProxyInternals(AppProxy): def test_traceback_basic(self): try: 1/0 Added: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_iter.py ============================================================================== --- (empty file) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_iter.py Sat Nov 4 18:49:49 2006 @@ -0,0 +1,17 @@ + +""" test of iterators +""" + +from pypy.objspace.std.test.test_proxy_internals import AppProxy + +class AppTestProxyIter(AppProxy): + def test_generator(self): + def some(l): + for i in l: + yield i + + g = self.get_proxy(some([1,2,3])) + assert list(g) == [1,2,3] + g = self.get_proxy(some([1,2,3])) + assert g.next() == 1 + assert g.next() == 2 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Sat Nov 4 18:49:49 2006 @@ -9,7 +9,7 @@ from pypy.objspace.std.typeobject import W_TypeObject def proxy(space, w_type, w_controller): - from pypy.interpreter.typedef import Function, PyTraceback, PyFrame + from pypy.interpreter.typedef import Function, PyTraceback, PyFrame, GeneratorIterator if not space.is_true(space.callable(w_controller)): raise OperationError(space.w_TypeError, space.wrap("controller should be function")) @@ -25,6 +25,8 @@ return W_TransparentTraceback(space, w_type, w_controller) if space.is_true(space.issubtype(w_type, space.gettypeobject(PyFrame.typedef))): return W_TransparentFrame(space, w_type, w_controller) + if space.is_true(space.issubtype(w_type, space.gettypeobject(GeneratorIterator.typedef))): + return W_TransparentGenerator(space, w_type, w_controller) if w_type.instancetypedef is space.w_object.instancetypedef: return W_Transparent(space, w_type, w_controller) else: From cfbolz at codespeak.net Sat Nov 4 18:57:41 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 4 Nov 2006 18:57:41 +0100 (CET) Subject: [pypy-svn] r34205 - in pypy/branch/refactor-file/pypy: module/_file rlib Message-ID: <20061104175741.87C671009F@code0.codespeak.net> Author: cfbolz Date: Sat Nov 4 18:57:40 2006 New Revision: 34205 Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py pypy/branch/refactor-file/pypy/rlib/streamio.py Log: (guido, cfbolz): ouch Modified: pypy/branch/refactor-file/pypy/module/_file/interp_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/interp_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/interp_file.py Sat Nov 4 18:57:40 2006 @@ -27,7 +27,7 @@ def __init__(self, space, stream): self.stream = stream -for name, argtypes in streamio.STREAM_METHODS: +for name, argtypes in streamio.STREAM_METHODS.iteritems(): numargs = len(argtypes) args = ", ".join(["v%s" % i for i in range(numargs)]) exec py.code.Source(""" @@ -44,7 +44,7 @@ W_Stream.typedef = TypeDef("Stream", **dict([(name, interp2app(globals()[name])) - for name, _ in streamio.STREAM_METHODS])) + for name, _ in streamio.STREAM_METHODS.iteritems()])) def is_mode_ok(space, mode): Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py ============================================================================== --- pypy/branch/refactor-file/pypy/rlib/streamio.py (original) +++ pypy/branch/refactor-file/pypy/rlib/streamio.py Sat Nov 4 18:57:40 2006 @@ -340,7 +340,7 @@ # ____________________________________________________________ -STREAM_METHODS = [ +STREAM_METHODS = dict([ ("read", [int]), ("write", [str]), ("tell", []), @@ -352,13 +352,14 @@ ("close", []), ("peek", []), ("try_to_find_file_descriptor", []), - ] + ]) def PassThrough(meth_name, flush_buffers): if meth_name in STREAM_METHODS: signature = STREAM_METHODS[meth_name] args = ", ".join(["v%s" % (i, ) for i in range(len(signature))]) else: + assert 0, "not a good idea" args = "*args" if flush_buffers: code = """def %s(self, %s): From cfbolz at codespeak.net Sun Nov 5 10:29:35 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 10:29:35 +0100 (CET) Subject: [pypy-svn] r34207 - in pypy/branch/refactor-file/pypy/rlib: . test Message-ID: <20061105092935.8F9271007E@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 10:29:33 2006 New Revision: 34207 Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py pypy/branch/refactor-file/pypy/rlib/test/test_streamio.py Log: always supply the whence argument explicitely to seek Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py ============================================================================== --- pypy/branch/refactor-file/pypy/rlib/streamio.py (original) +++ pypy/branch/refactor-file/pypy/rlib/streamio.py Sun Nov 5 10:29:33 2006 @@ -158,7 +158,7 @@ def tell(self): raise NotImplementedError - def seek(self, offset, whence=0): + def seek(self, offset, whence): raise NotImplementedError def readall(self): @@ -214,7 +214,7 @@ def __init__(self, fd): self.fd = fd - def seek(self, offset, whence=0): + def seek(self, offset, whence): os.lseek(self.fd, offset, whence) def tell(self): @@ -267,7 +267,7 @@ def tell(self): return self.pos - def seek(self, offset, whence=0): + def seek(self, offset, whence): if whence == 0: self.pos = max(0, offset) elif whence == 1: @@ -403,7 +403,7 @@ def flush_buffers(self): if self.lines or self.buf: try: - self.do_seek(self.tell()) + self.do_seek(self.tell(), 0) except NotImplementedError: pass else: @@ -418,7 +418,7 @@ assert bytes >= offset #, (locals(), self.__dict__) return bytes - offset - def seek(self, offset, whence=0): + def seek(self, offset, whence): # This may fail on the do_seek() or do_tell() call. # But it won't call either on a relative forward seek. # Nor on a seek to the very end. @@ -818,7 +818,7 @@ break return ''.join(result) - def seek(self, offset, whence=0): + def seek(self, offset, whence): """Seeks based on knowledge that does not come from a tell() may go to the wrong place, since the number of characters seen may not match the number of characters Modified: pypy/branch/refactor-file/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/branch/refactor-file/pypy/rlib/test/test_streamio.py (original) +++ pypy/branch/refactor-file/pypy/rlib/test/test_streamio.py Sun Nov 5 10:29:33 2006 @@ -349,7 +349,7 @@ def test_seek(self): file = self.makeStream(tell=True, seek=True) end = len(file.readall()) - file.seek(0) + file.seek(0, 0) cases = [(readto, seekto, whence) for readto in range(0, end+1) for seekto in range(0, end+1) for whence in [0, 1, 2]] @@ -360,7 +360,7 @@ all = file.readall() assert end == len(all) for readto, seekto, whence in cases: - file.seek(0) + file.seek(0, 0) assert file.tell() == 0 head = file.read(readto) assert head == all[:readto] @@ -461,7 +461,7 @@ base = TWriter() filter = streamio.BufferingOutputStream(base, 4) filter.write("x"*6) - filter.seek(3) + filter.seek(3, 0) filter.write("y"*2) filter.close() assert base.buf == "x"*3 + "y"*2 + "x"*1 @@ -472,7 +472,7 @@ def f(): base = TWriter() filter = streamio.BufferingOutputStream(base, 4) - filter.seek(3) + filter.seek(3, 0) filter.write("y"*2) filter.close() assert base.buf == "\0"*3 + "y"*2 @@ -537,7 +537,7 @@ filter = streamio.BufferingOutputStream(base, 4) def f(): filter.write("x"*6) - filter.seek(3) + filter.seek(3, 0) filter.write("y"*2) filter.close() assert base.buf == "x"*3 + "y"*2 + "x"*1 @@ -620,9 +620,9 @@ file.write("Barf\n") file.writelines(["a\n", "b\n", "c\n"]) assert file.tell() == len("BooHoo\nBarf\na\nb\nc\n") - file.seek(0) + file.seek(0, 0) assert file.read() == "BooHoo\nBarf\na\nb\nc\n" - file.seek(0) + file.seek(0, 0) assert file.readlines() == ( ["BooHoo\n", "Barf\n", "a\n", "b\n", "c\n"]) assert file.tell() == len("BooHoo\nBarf\na\nb\nc\n") @@ -663,7 +663,7 @@ filter = streamio.BufferingInputStream( streamio.BufferingOutputStream(base, 4), 4) def f(): - filter.seek(3) + filter.seek(3, 0) filter.write("y"*2) filter.close() assert base.buf == "\0"*3 + "y"*2 @@ -762,7 +762,7 @@ all = sofar for i in range(len(pairs)): sofar, pos = pairs[i] - filter.seek(pos) + filter.seek(pos, 0) assert filter.tell() == pos assert filter.tell() == pos bufs = [sofar] @@ -850,7 +850,7 @@ base = TWriter() filter = streamio.TextOutputFilter(base, linesep="\n") filter.write("x"*100) - filter.seek(50) + filter.seek(50, 0) filter.write("y"*10) assert base.buf == "x"*50 + "y"*10 + "x"*40 self.interpret(f, []) From cfbolz at codespeak.net Sun Nov 5 10:51:31 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 10:51:31 +0100 (CET) Subject: [pypy-svn] r34208 - pypy/branch/refactor-file/pypy/rlib Message-ID: <20061105095131.747BF1007E@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 10:51:30 2006 New Revision: 34208 Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py Log: hm. supply the missing last argument. Modified: pypy/branch/refactor-file/pypy/rlib/streamio.py ============================================================================== --- pypy/branch/refactor-file/pypy/rlib/streamio.py (original) +++ pypy/branch/refactor-file/pypy/rlib/streamio.py Sun Nov 5 10:51:30 2006 @@ -76,7 +76,7 @@ def open_path_helper(path, os_flags, append): # XXX for now always return DiskFile - fd = os.open(path, os_flags) + fd = os.open(path, os_flags, 0666) if append: try: os.lseek(fd, 0, 2) From pedronis at codespeak.net Sun Nov 5 10:57:03 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 5 Nov 2006 10:57:03 +0100 (CET) Subject: [pypy-svn] r34209 - pypy/dist/pypy/doc Message-ID: <20061105095703.98C4F1007C@code0.codespeak.net> Author: pedronis Date: Sun Nov 5 10:57:02 2006 New Revision: 34209 Modified: pypy/dist/pypy/doc/_ref.txt pypy/dist/pypy/doc/garbage_collection.txt Log: fix reference to objectmodel.py Modified: pypy/dist/pypy/doc/_ref.txt ============================================================================== --- pypy/dist/pypy/doc/_ref.txt (original) +++ pypy/dist/pypy/doc/_ref.txt Sun Nov 5 10:57:02 2006 @@ -47,6 +47,7 @@ .. _`objspace/thunk.py`: ../../pypy/objspace/thunk.py .. _`objspace/trace.py`: .. _`pypy/objspace/trace.py`: ../../pypy/objspace/trace.py +.. _`pypy/rlib/objectmodel.py`: ../../pypy/rlib/objectmodel.py .. _`pypy/rpython`: .. _`pypy/rpython/`: .. _`rpython/`: ../../pypy/rpython @@ -61,7 +62,6 @@ .. _`pypy/rpython/module/`: ../../pypy/rpython/module .. _`pypy/rpython/module/ll_os.py`: ../../pypy/rpython/module/ll_os.py .. _`pypy/rpython/module/test`: ../../pypy/rpython/module/test -.. _`pypy/rpython/objectmodel.py`: ../../pypy/rpython/objectmodel.py .. _`rpython/ootypesystem/ootype.py`: ../../pypy/rpython/ootypesystem/ootype.py .. _`pypy/rpython/rctypes/test/test_ctypes.py`: ../../pypy/rpython/rctypes/test/test_ctypes.py .. _`rpython/rint.py`: ../../pypy/rpython/rint.py Modified: pypy/dist/pypy/doc/garbage_collection.txt ============================================================================== --- pypy/dist/pypy/doc/garbage_collection.txt (original) +++ pypy/dist/pypy/doc/garbage_collection.txt Sun Nov 5 10:57:02 2006 @@ -178,7 +178,7 @@ Instance creation is done the regular way, to free an instance there is a special function ``free_non_gc_object`` defined in -`pypy/rpython/objectmodel.py`_. Trying to access any attribute of the instance +`pypy/rlib/objectmodel.py`_. Trying to access any attribute of the instance after it was freed gives an exception (which is not equivalent to the behaviour after translation: there it would just lead to a crash) Example:: From cfbolz at codespeak.net Sun Nov 5 11:10:52 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 11:10:52 +0100 (CET) Subject: [pypy-svn] r34210 - pypy/branch/refactor-file/pypy/module/_file/test Message-ID: <20061105101052.2E3D01007C@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 11:10:51 2006 New Revision: 34210 Modified: pypy/branch/refactor-file/pypy/module/_file/test/test_file.py Log: check that the mode is set correctly when creating a file Modified: pypy/branch/refactor-file/pypy/module/_file/test/test_file.py ============================================================================== --- pypy/branch/refactor-file/pypy/module/_file/test/test_file.py (original) +++ pypy/branch/refactor-file/pypy/module/_file/test/test_file.py Sun Nov 5 11:10:51 2006 @@ -49,3 +49,15 @@ def test_wraposerror(self): import _file raises(IOError, _file.file, "hopefully/not/existant.bar") + + def test_correct_file_mode(self): + import _file, os + f = _file.file(self.temppath, "w") + umask = os.umask(18) + os.umask(umask) + try: + f.write("foo") + finally: + f.close() + assert oct(os.stat(self.temppath).st_mode & 0777 | umask) == oct(0666) + From cfbolz at codespeak.net Sun Nov 5 11:14:37 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 11:14:37 +0100 (CET) Subject: [pypy-svn] r34211 - pypy/dist/pypy/module/_stackless/test Message-ID: <20061105101437.162901007E@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 11:14:37 2006 New Revision: 34211 Modified: pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py Log: make interp-clonable pass again Modified: pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py Sun Nov 5 11:14:37 2006 @@ -11,6 +11,7 @@ class TestClonableCoroutine(test_transformed_gc.GCTest): + gcname = "stacklessgc" class gcpolicy(gc.StacklessFrameworkGcPolicy): class transformerclass(stacklessframework.StacklessFrameworkGCTransformer): GC_PARAMS = {'start_heap_size': 4096 } From fijal at codespeak.net Sun Nov 5 11:17:07 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 5 Nov 2006 11:17:07 +0100 (CET) Subject: [pypy-svn] r34212 - pypy/dist/pypy/translator/js/test Message-ID: <20061105101707.BD5991007E@code0.codespeak.net> Author: fijal Date: Sun Nov 5 11:17:06 2006 New Revision: 34212 Modified: pypy/dist/pypy/translator/js/test/test_typed.py Log: "How it could ever work" test. Modified: pypy/dist/pypy/translator/js/test/test_typed.py ============================================================================== --- pypy/dist/pypy/translator/js/test/test_typed.py (original) +++ pypy/dist/pypy/translator/js/test/test_typed.py Sun Nov 5 11:17:06 2006 @@ -14,7 +14,7 @@ return res == expected fn = compile_function(wrapper, []) result = fn() - assert result == 0 + assert result == wrapper() def test_get_set_del_slice(): def get_set_del_nonneg_slice(): # no neg slices for now! From arigo at codespeak.net Sun Nov 5 11:29:40 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 5 Nov 2006 11:29:40 +0100 (CET) Subject: [pypy-svn] r34213 - in pypy/dist/pypy: config objspace Message-ID: <20061105102940.DBA981007E@code0.codespeak.net> Author: arigo Date: Sun Nov 5 11:29:38 2006 New Revision: 34213 Added: pypy/dist/pypy/objspace/dump.py Modified: pypy/dist/pypy/config/pypyoption.py Log: Add the 'dump' object space: a quick hack that dumps all space operations to a file 'pypy-space-dump'. It's translatable, so we get a pypy-c version that is maybe useful for debugging small Python programs. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Sun Nov 5 11:29:38 2006 @@ -16,7 +16,7 @@ pypy_optiondescription = OptionDescription("pypy", "All PyPy Options", [ OptionDescription("objspace", "Object Space Option", [ ChoiceOption("name", "Object Space name", - ["std", "flow", "logic", "thunk", "cpy"], "std", + ["std", "flow", "logic", "thunk", "cpy", "dump"], "std", requires = { "thunk": [("objspace.geninterp", False)], "logic": [("objspace.geninterp", False)], Added: pypy/dist/pypy/objspace/dump.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/dump.py Sun Nov 5 11:29:38 2006 @@ -0,0 +1,205 @@ +import os +from pypy.objspace.proxy import patch_space_in_place +from pypy.objspace.std.objspace import StdObjSpace, W_Object +from pypy.interpreter.error import OperationError +from pypy.interpreter import baseobjspace + +DUMP_FILE_NAME = 'pypy-space-dump' +DUMP_FILE_MODE = 0600 + +class Dumper(object): + dump_fd = -1 + + def __init__(self, space): + self.space = space + self.dumpspace_reprs = {} + + def open(self): + space = self.space + self.dumpspace_reprs.update({ + space.w_None: 'None', + space.w_False: 'False', + space.w_True: 'True', + }) + if self.dump_fd < 0: + self.dump_fd = os.open(DUMP_FILE_NAME, + os.O_WRONLY|os.O_CREAT|os.O_TRUNC, + DUMP_FILE_MODE) + + def close(self): + if self.dump_fd >= 0: + os.close(self.dump_fd) + self.dump_fd = -1 + self.dumpspace_reprs.clear() + + def dump_get_repr(self, w_obj): + try: + return self.dumpspace_reprs[w_obj] + except KeyError: + saved_fd = self.dump_fd + try: + self.dump_fd = -1 + space = self.space + if isinstance(w_obj, W_Object): + w_type = space.type(w_obj) + else: + w_type = None + if w_type is space.w_int: + n = space.int_w(w_obj) + s = str(n) + elif w_type is space.w_str: + s = space.str_w(w_obj) + digit2hex = '0123456789abcdef' + lst = ["'"] + for c in s: + if c == '\\': + lst.append('\\') + if c >= ' ': + lst.append(c) + else: + lst.append('\\') + if c == '\n': + lst.append('n') + elif c == '\t': + lst.append('t') + else: + lst.append('x') + lst.append(digit2hex[ord(c) >> 4]) + lst.append(digit2hex[ord(c) & 0xf]) + lst.append("'") + s = ''.join(lst) + elif w_type is space.w_float: + n = space.float_w(w_obj) + s = str(n) + else: + s = '%s at 0x%x' % (w_obj, id(w_obj)) + self.dumpspace_reprs[w_obj] = s + finally: + self.dump_fd = saved_fd + return s + + def dump_enter(self, opname, args_w): + if self.dump_fd >= 0: + text = '\t'.join([self.dump_get_repr(w_arg) for w_arg in args_w]) + os.write(self.dump_fd, '%s CALL %s\n' % (opname, text)) + + def dump_returned_wrapped(self, opname, w_obj): + if self.dump_fd >= 0: + s = self.dump_get_repr(w_obj) + os.write(self.dump_fd, '%s RETURN %s\n' % (opname, s)) + + def dump_returned(self, opname): + if self.dump_fd >= 0: + os.write(self.dump_fd, '%s RETURN\n' % (opname,)) + + def dump_raised(self, opname, e): + if self.dump_fd >= 0: + if isinstance(e, OperationError): + s = e.errorstr(self.space) + else: + s = '%s' % (e,) + os.write(self.dump_fd, '%s RAISE %s\n' % (opname, s)) + + +# for now, always make up a wrapped StdObjSpace +class DumpSpace(StdObjSpace): + + def __init__(self, *args, **kwds): + self.dumper = Dumper(self) + StdObjSpace.__init__(self, *args, **kwds) + patch_space_in_place(self, 'dump', proxymaker) + + def _freeze_(self): + # remove strange things from the caches of self.dumper + # before we annotate + self.dumper.close() + return StdObjSpace._freeze_(self) + + def startup(self): + StdObjSpace.startup(self) + self.dumper.open() + + def finish(self): + self.dumper.close() + StdObjSpace.finish(self) + + def wrap(self, x): + w_res = StdObjSpace.wrap(self, x) + self.dumper.dump_returned_wrapped(' wrap', w_res) + return w_res + wrap._annspecialcase_ = "specialize:wrap" + + +Space = DumpSpace + +# __________________________________________________________________________ + +nb_args = {} +op_returning_wrapped = {} + +def setup(): + nb_args.update({ + # ---- 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, + }) + op_returning_wrapped.update({ + 'wrap': True, + 'newtuple': True, + 'newlist': True, + 'newstring': True, + 'newunicode': True, + 'newdict': True, + 'newslice': True, + 'call_args': True, + }) + for opname, _, arity, _ in baseobjspace.ObjSpace.MethodTable: + nb_args.setdefault(opname, arity) + op_returning_wrapped[opname] = True + for opname in baseobjspace.ObjSpace.IrregularOpTable: + assert opname in nb_args, "missing %r" % opname + +setup() +del setup + +# __________________________________________________________________________ + +def proxymaker(space, opname, parentfn): + if opname == 'wrap': + return None + returns_wrapped = opname in op_returning_wrapped + aligned_opname = '%15s' % opname + n = nb_args[opname] + def proxy(*args): + dumper = space.dumper + args_w = list(args[:n]) + dumper.dump_enter(aligned_opname, args_w) + try: + res = parentfn(*args) + except Exception, e: + dumper.dump_raised(aligned_opname, e) + raise + else: + if returns_wrapped: + dumper.dump_returned_wrapped(aligned_opname, res) + else: + dumper.dump_returned(aligned_opname) + return res + proxy.func_name = 'proxy_%s' % (opname,) + return proxy From fijal at codespeak.net Sun Nov 5 11:35:33 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 5 Nov 2006 11:35:33 +0100 (CET) Subject: [pypy-svn] r34214 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061105103533.98B161007E@code0.codespeak.net> Author: fijal Date: Sun Nov 5 11:35:32 2006 New Revision: 34214 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: Added TypeObject. Not sure what the semantics are altough. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/model.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/model.py Sun Nov 5 11:35:32 2006 @@ -123,6 +123,7 @@ # xxx config self.typeorder[proxyobject.W_TransparentList] = [] self.typeorder[proxyobject.W_TransparentDict] = [] + self.typeorder[proxyobject.W_TransparentType] = [] if config.objspace.std.withstrdict: del self.typeorder[dictobject.W_DictObject] Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py Sun Nov 5 11:35:32 2006 @@ -17,17 +17,17 @@ return s, '__' + mm.name + '__' return s, mm.name -def install_general_args_trampoline(type_, mm, is_local): +def install_general_args_trampoline(type_, mm, is_local, op_name): def function(space, w_transparent_list, __args__): - args = __args__.prepend(space.wrap(mm.name)) + args = __args__.prepend(space.wrap(op_name)) return space.call_args(w_transparent_list.w_controller, args) function.func_name = mm.name mm.register(function, type_) -def install_w_args_trampoline(type_, mm, is_local): +def install_w_args_trampoline(type_, mm, is_local, op_name): def function(space, w_transparent_list, *args_w): - args = Arguments(space, [space.wrap(mm.name)] + list(args_w[:-1]), w_stararg=args_w[-1]) + args = Arguments(space, [space.wrap(op_name)] + list(args_w[:-1]), w_stararg=args_w[-1]) return space.call_args(w_transparent_list.w_controller, args) function.func_name = mm.name @@ -38,9 +38,9 @@ mm_name, op_name = create_mm_names(classname, mm, is_local) if ['__args__'] == mm.argnames_after: - return install_general_args_trampoline(type_, mm, is_local) + return install_general_args_trampoline(type_, mm, is_local, op_name) if ['w_args'] == mm.argnames_after: - return install_w_args_trampoline(type_, mm, is_local) + return install_w_args_trampoline(type_, mm, is_local, op_name) assert not mm.argnames_after # we search here for special-cased stuff def function(space, w_transparent_list, *args_w): Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py Sun Nov 5 11:35:32 2006 @@ -92,6 +92,10 @@ class W_TransparentGenerator(W_Transparent): typedef = GeneratorIterator.typedef +class W_TransparentType(W_TransparentObject): + from pypy.objspace.std.typeobject import W_TypeObject as original + from pypy.objspace.std.typetype import type_typedef as typedef + class W_TransparentList(W_TransparentObject): from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef @@ -102,7 +106,8 @@ registerimplementation(W_TransparentList) registerimplementation(W_TransparentDict) - +registerimplementation(W_TransparentType) register_type(W_TransparentList) register_type(W_TransparentDict) +register_type(W_TransparentType) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sun Nov 5 11:35:32 2006 @@ -95,3 +95,9 @@ e = sys.exc_info() assert traceback.format_tb(last_tb) == traceback.format_tb(e[2]) + +class AppTestProxyType(AppProxy): + def test_filetype(self): + f = self.get_proxy(file) + f("/tmp/sth", "w").write("aaa") + assert open("/tmp/sth").read() == "aaa" Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Sun Nov 5 11:35:32 2006 @@ -27,6 +27,8 @@ return W_TransparentFrame(space, w_type, w_controller) if space.is_true(space.issubtype(w_type, space.gettypeobject(GeneratorIterator.typedef))): return W_TransparentGenerator(space, w_type, w_controller) + if isinstance(w_type, W_TypeObject): + return W_TransparentType(space, w_type, w_controller) if w_type.instancetypedef is space.w_object.instancetypedef: return W_Transparent(space, w_type, w_controller) else: From fijal at codespeak.net Sun Nov 5 11:38:18 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 5 Nov 2006 11:38:18 +0100 (CET) Subject: [pypy-svn] r34215 - pypy/branch/transparent-proxy/pypy/objspace/std/test Message-ID: <20061105103818.7E46910080@code0.codespeak.net> Author: fijal Date: Sun Nov 5 11:38:17 2006 New Revision: 34215 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Log: Added some tests. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sun Nov 5 11:38:17 2006 @@ -101,3 +101,10 @@ f = self.get_proxy(file) f("/tmp/sth", "w").write("aaa") assert open("/tmp/sth").read() == "aaa" + + def test_fileobject(self): + f = open("/tmp/sth", "w") + fp = self.get_proxy(f) + fp.write("aaa") + fp.close() + assert open("/tmp/sth").read() == "aaa" From cfbolz at codespeak.net Sun Nov 5 11:43:01 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 11:43:01 +0100 (CET) Subject: [pypy-svn] r34216 - pypy/extradoc/sprintinfo/ddorf2006b Message-ID: <20061105104301.4EF5B10082@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 11:43:00 2006 New Revision: 34216 Modified: pypy/extradoc/sprintinfo/ddorf2006b/planning.txt Log: (all): status and some small planning for today Modified: pypy/extradoc/sprintinfo/ddorf2006b/planning.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2006b/planning.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2006b/planning.txt Sun Nov 5 11:43:00 2006 @@ -14,12 +14,14 @@ Tasks ===== - - javascript interpreter (leonardo, stephan, guido around) + - javascript interpreter (leonardo, guido around) addition of numbers, strings (with proper, twisted semantics) works integration of the narcissus parser nested scopes, variable declarations, functions without parameters function arguments working, windows support, argument attribute implemented grouping, the comma-operator, mac-os support, exceptions + support for "while", "if" + working on frames and prototypes - jvm backend sharing code between gencli and genjvm @@ -27,12 +29,15 @@ number manipulations, field access more tests running! added support for classes, in-progress: constants - - transparent proxies (maciek, samuele, antonio around) + - transparent proxies (maciek, samuele) lists are working somehow, refactoring in progress dictionaries seem to work somewhat provide a way to implement an object that is of type list, but the behaviour is defined at app-level implemented objects, lists and dictionaries, function calls in an sucky way + mostly DONE. need more experimentation/examples to find what is needed + to be done: check for slow-done, using config to disable it, merging the + branch - apigen tool changes to instance variables after calls to functions @@ -47,7 +52,8 @@ - making streams RPython done -- using the RPython streams for pypy files (guido, carl friedrich) +- using the RPython streams for pypy files + hopefully done - jit code generation lots of documentation about the jit-backend interface, fighting with @@ -59,6 +65,7 @@ - jit ppc code generation (mwh, niko) wrote a simple greedy register allocator, spills work implement links between basic blocks, placing the arguments in the right way + stack manipulation, proper stack handling is done - jit front end (armin, arre, richard) @@ -66,6 +73,7 @@ fixed the last known bug, experimentation needed porting portal tests to run with the backends deepfreezing implemented! hint that a structure is not going to change + deepfreezing dictionaries works - running tests on the translated pypy-cs (related to py.test refactoring?) @@ -76,10 +84,15 @@ - adding the microbenchmark results to the benchmark page DONE - - trying the jit efforts on a regex engine (richard, armin around) + - trying the jit efforts on a regex engine kind of worked, some progress - fixing pypy on windows, adding some more os functions (christian) - unknown amount of progress + trying to fix a problem with greenlets, trying to get back into the action + +- sprint report (carl friedrich, michael) + +- work assessment (people that know what the wp numbers mean (and feel like attending)) - general wizardry (samuele) + found funny bug in the jit stuff From mwh at codespeak.net Sun Nov 5 12:03:42 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sun, 5 Nov 2006 12:03:42 +0100 (CET) Subject: [pypy-svn] r34219 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061105110342.8A6CE1007D@code0.codespeak.net> Author: mwh Date: Sun Nov 5 12:03:40 2006 New Revision: 34219 Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/regalloc.py Log: small cleanups, don't use 'is' on integers Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Sun Nov 5 12:03:40 2006 @@ -15,15 +15,26 @@ _stack_slot_cache = {} def stack_slot(offset): + # because stack slots are put into dictionaries which compare by + # identity, it is important that there's a unique _StackSlot + # object for each offset, at least per function generated or + # something. doing the caching here is easier, though. if offset in _stack_slot_cache: return _stack_slot_cache[offset] _stack_slot_cache[offset] = res = _StackSlot(offset) return res +NO_REGISTER = -1 +GP_REGISTER = 0 +FP_REGISTER = 1 +CR_FIELD = 2 +CT_REGISTER = 3 + class Register(AllocationSlot): is_register = True class GPR(Register): + regclass = GP_REGISTER def __init__(self, number): self.number = number def __repr__(self): @@ -31,28 +42,25 @@ gprs = map(GPR, range(32)) class FPR(Register): + regclass = FP_REGISTER def __init__(self, number): self.number = number fprs = map(GPR, range(32)) class CRF(Register): + regclass = CR_FIELD def __init__(self, number): self.number = number crfs = map(CRF, range(8)) class CTR(Register): + regclass = CT_REGISTER pass ctr = CTR() -NO_REGISTER = -1 -GP_REGISTER = 0 -FP_REGISTER = 1 -CR_FIELD = 2 -CT_REGISTER = 3 - _insn_index = [0] class Insn(object): Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Sun Nov 5 12:03:40 2006 @@ -101,7 +101,7 @@ if not self.var2loc[arg].is_register: # It has no register now because it has been spilled - assert argcls is GP_REGISTER, "uh-oh" + assert argcls == GP_REGISTER, "uh-oh" self._allocate_reg(arg) else: #print "it was in ", self.var2loc[arg] @@ -110,18 +110,18 @@ # Need to allocate a register for the destination assert not insn.result or insn.result not in self.var2loc cand = None - if insn.result_regclass is GP_REGISTER: + if insn.result_regclass == GP_REGISTER: #print "Allocating register for result %r..." % (insn.result,) cand = self._allocate_reg(insn.result) - elif insn.result_regclass is CR_FIELD: + elif insn.result_regclass == CR_FIELD: assert crfs[0] not in self.loc2var assert isinstance(insn, CMPInsn) cand = crfs[0] self.crfinfo[0] = insn.info - elif insn.result_regclass is CT_REGISTER: + elif insn.result_regclass == CT_REGISTER: assert ctr not in self.loc2var cand = ctr - elif insn.result_regclass is not NO_REGISTER: + elif insn.result_regclass != NO_REGISTER: assert 0 if cand is not None and cand not in self.loc2var: self.var2loc[insn.result] = cand From pedronis at codespeak.net Sun Nov 5 12:04:41 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 5 Nov 2006 12:04:41 +0100 (CET) Subject: [pypy-svn] r34220 - pypy/dist/pypy/translator/goal Message-ID: <20061105110441.3B2A81007D@code0.codespeak.net> Author: pedronis Date: Sun Nov 5 12:04:30 2006 New Revision: 34220 Modified: pypy/dist/pypy/translator/goal/bench-unix.py Log: fix alignment and spacing of the output. Modified: pypy/dist/pypy/translator/goal/bench-unix.py ============================================================================== --- pypy/dist/pypy/translator/goal/bench-unix.py (original) +++ pypy/dist/pypy/translator/goal/bench-unix.py Sun Nov 5 12:04:30 2006 @@ -94,7 +94,7 @@ def main(): benchmark_result = BenchmarkResult('bench-unix.benchmark_result') - print 'date size codesize executable richards pystone' + print 'date size codesize executable richards pystone' sys.stdout.flush() ref_rich, ref_stone = None, None @@ -117,7 +117,7 @@ if not ref_stone: ref_stone = stone - fmt = '%-26s %8s %8s %-48s %6dms (%6.1fx) %6d (%6.1fx)' + fmt = '%-26s %8s %8s %-60s %6dms (%6.1fx) %6d (%6.1fx)' print fmt % (time.ctime(), '-', '-', 'python', 'CPython ' + v, rich, rich / ref_rich, stone, stone / ref_stone) sys.stdout.flush() From cfbolz at codespeak.net Sun Nov 5 12:13:10 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 12:13:10 +0100 (CET) Subject: [pypy-svn] r34221 - pypy/branch/refactor-file/lib-python/modified-2.4.1/test Message-ID: <20061105111310.D663E1007D@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 12:13:09 2006 New Revision: 34221 Modified: pypy/branch/refactor-file/lib-python/modified-2.4.1/test/test_file.py Log: weakrefs are working nowadays Modified: pypy/branch/refactor-file/lib-python/modified-2.4.1/test/test_file.py ============================================================================== --- pypy/branch/refactor-file/lib-python/modified-2.4.1/test/test_file.py (original) +++ pypy/branch/refactor-file/lib-python/modified-2.4.1/test/test_file.py Sun Nov 5 12:13:09 2006 @@ -1,24 +1,26 @@ import sys import os +import gc from array import array -#from weakref import proxy +from weakref import proxy from test.test_support import verify, TESTFN, TestFailed from UserList import UserList -# # verify weak references -# f = file(TESTFN, 'w') -# p = proxy(f) -# p.write('teststring') -# verify(f.tell(), p.tell()) -# f.close() -# f = None -# try: -# p.tell() -# except ReferenceError: -# pass -# else: -# raise TestFailed('file proxy still exists when the file is gone') +# verify weak references +f = file(TESTFN, 'w') +p = proxy(f) +p.write('teststring') +verify(f.tell(), p.tell()) +f.close() +f = None +gc.collect() +try: + p.tell() +except ReferenceError: + pass +else: + raise TestFailed('file proxy still exists when the file is gone') # verify expected attributes exist f = file(TESTFN, 'w') From arigo at codespeak.net Sun Nov 5 12:21:53 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 5 Nov 2006 12:21:53 +0100 (CET) Subject: [pypy-svn] r34222 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20061105112153.E12891007D@code0.codespeak.net> Author: arigo Date: Sun Nov 5 12:21:51 2006 New Revision: 34222 Modified: pypy/dist/pypy/objspace/std/objecttype.py pypy/dist/pypy/objspace/std/test/test_typeobject.py pypy/dist/pypy/objspace/std/typeobject.py Log: Assignment to __class__ was too permissive. Fix test and add checks. Modified: pypy/dist/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/objecttype.py (original) +++ pypy/dist/pypy/objspace/std/objecttype.py Sun Nov 5 12:21:51 2006 @@ -28,7 +28,7 @@ raise OperationError(space.w_TypeError, space.wrap("__class__ assignment: only for heap types")) w_oldcls = space.type(w_obj) - if w_oldcls.get_layout() == w_newcls.get_layout() and w_oldcls.hasdict == w_newcls.hasdict: + if w_oldcls.get_full_instance_layout() == w_newcls.get_full_instance_layout(): w_obj.setclass(space, w_newcls) else: raise OperationError(space.w_TypeError, Modified: pypy/dist/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_typeobject.py Sun Nov 5 12:21:51 2006 @@ -404,7 +404,7 @@ class Z1(A): pass class Z2(A): - __slots__ = ['__dict__'] + __slots__ = ['__dict__', '__weakref__'] z1 = Z1() z1.__class__ = Z2 assert z1.__class__ == Z2 Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Sun Nov 5 12:21:51 2006 @@ -225,6 +225,11 @@ return w_bestbase.get_layout() return w_self + # compute a tuple that fully describes the instance layout + def get_full_instance_layout(w_self): + w_layout = w_self.get_layout() + return (w_layout, w_self.hasdict, w_self.needsdel, w_self.weakrefable) + def compute_mro(w_self): return compute_C3_mro(w_self.space, w_self) From cfbolz at codespeak.net Sun Nov 5 12:26:18 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 12:26:18 +0100 (CET) Subject: [pypy-svn] r34224 - in pypy/dist: lib-python/modified-2.4.1/test pypy pypy/config pypy/config/test pypy/lib pypy/lib/test2 pypy/module/__builtin__ pypy/module/_file pypy/module/_file/test pypy/module/posix pypy/module/posix/test pypy/module/sys pypy/objspace/std pypy/rlib pypy/rlib/test pypy/tool Message-ID: <20061105112618.593F11007D@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 12:26:15 2006 New Revision: 34224 Added: pypy/dist/pypy/module/_file/ (props changed) - copied from r34223, pypy/branch/refactor-file/pypy/module/_file/ pypy/dist/pypy/module/_file/__init__.py - copied unchanged from r34223, pypy/branch/refactor-file/pypy/module/_file/__init__.py pypy/dist/pypy/module/_file/app_file.py - copied unchanged from r34223, pypy/branch/refactor-file/pypy/module/_file/app_file.py pypy/dist/pypy/module/_file/interp_file.py - copied unchanged from r34223, pypy/branch/refactor-file/pypy/module/_file/interp_file.py pypy/dist/pypy/module/_file/test/ (props changed) - copied from r34223, pypy/branch/refactor-file/pypy/module/_file/test/ pypy/dist/pypy/module/_file/test/__init__.py - copied unchanged from r34223, pypy/branch/refactor-file/pypy/module/_file/test/__init__.py pypy/dist/pypy/module/_file/test/test_file.py - copied unchanged from r34223, pypy/branch/refactor-file/pypy/module/_file/test/test_file.py pypy/dist/pypy/module/_file/test/test_file_extra.py - copied unchanged from r34223, pypy/branch/refactor-file/pypy/module/_file/test/test_file_extra.py Removed: pypy/dist/pypy/lib/_file.py pypy/dist/pypy/lib/test2/test_file_extra.py Modified: pypy/dist/lib-python/modified-2.4.1/test/test_file.py pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/config/test/test_pypyoption.py pypy/dist/pypy/conftest.py pypy/dist/pypy/module/__builtin__/__init__.py pypy/dist/pypy/module/__builtin__/state.py pypy/dist/pypy/module/posix/app_posix.py pypy/dist/pypy/module/posix/test/test_posix2.py pypy/dist/pypy/module/posix/test/test_posix_libfile.py pypy/dist/pypy/module/sys/__init__.py pypy/dist/pypy/module/sys/state.py pypy/dist/pypy/objspace/std/objspace.py pypy/dist/pypy/rlib/streamio.py pypy/dist/pypy/rlib/test/test_streamio.py pypy/dist/pypy/tool/option.py Log: (guido, cfbolz): new file implementation works! svn merge -r 34171:HEAD http://codespeak.net/svn/pypy/branch/refactor-file Modified: pypy/dist/lib-python/modified-2.4.1/test/test_file.py ============================================================================== --- pypy/dist/lib-python/modified-2.4.1/test/test_file.py (original) +++ pypy/dist/lib-python/modified-2.4.1/test/test_file.py Sun Nov 5 12:26:15 2006 @@ -1,24 +1,26 @@ import sys import os +import gc from array import array -#from weakref import proxy +from weakref import proxy from test.test_support import verify, TESTFN, TestFailed from UserList import UserList -# # verify weak references -# f = file(TESTFN, 'w') -# p = proxy(f) -# p.write('teststring') -# verify(f.tell(), p.tell()) -# f.close() -# f = None -# try: -# p.tell() -# except ReferenceError: -# pass -# else: -# raise TestFailed('file proxy still exists when the file is gone') +# verify weak references +f = file(TESTFN, 'w') +p = proxy(f) +p.write('teststring') +verify(f.tell(), p.tell()) +f.close() +f = None +gc.collect() +try: + p.tell() +except ReferenceError: + pass +else: + raise TestFailed('file proxy still exists when the file is gone') # verify expected attributes exist f = file(TESTFN, 'w') Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Sun Nov 5 12:26:15 2006 @@ -11,7 +11,7 @@ [#"unicodedata", "_codecs", "gc", "_weakref", "array", "marshal", "errno", "math", "_sre", "_pickle_support", "sys", "exceptions", "__builtins__", - "recparser", "symbol", "_random"]) + "recparser", "symbol", "_random", "_file"]) pypy_optiondescription = OptionDescription("pypy", "All PyPy Options", [ OptionDescription("objspace", "Object Space Option", [ @@ -34,16 +34,11 @@ BoolOption("nofaking", "disallow faking in the object space", default=False, requires=[ - ("objspace.uselibfile", True), ("objspace.usemodules.posix", True), ("objspace.usemodules.time", True), ("objspace.usemodules.errno", True)], cmdline='--nofaking'), - BoolOption("uselibfile", "use the applevel file implementation", - default=False, - cmdline='--uselibfile'), - OptionDescription("usemodules", "Which Modules should be used", [ BoolOption(modname, "use module %s" % (modname, ), default=modname in default_modules, Modified: pypy/dist/pypy/config/test/test_pypyoption.py ============================================================================== --- pypy/dist/pypy/config/test/test_pypyoption.py (original) +++ pypy/dist/pypy/config/test/test_pypyoption.py Sun Nov 5 12:26:15 2006 @@ -6,10 +6,6 @@ conf = Config(pypy_optiondescription) assert not conf.translating - conf.objspace.nofaking = True - assert conf.objspace.uselibfile - py.test.raises(ValueError, "conf.objspace.uselibfile = False") - assert conf.objspace.usemodules.gc conf.objspace.std.withsmallint = True Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Sun Nov 5 12:26:15 2006 @@ -28,9 +28,6 @@ help="object space to run tests on."), Option('--oldstyle', action="store_true",dest="oldstyle", default=False, help="enable oldstyle classes as default metaclass"), - Option('--uselibfile', action="store_true", - dest="uselibfile", default=False, - help="enable our applevel file implementation"), Option('--nofaking', action="store_true", dest="nofaking", default=False, help="avoid faking of modules and objects completely."), Modified: pypy/dist/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/__init__.py (original) +++ pypy/dist/pypy/module/__builtin__/__init__.py Sun Nov 5 12:26:15 2006 @@ -72,8 +72,8 @@ 'object' : '(space.w_object)', 'unicode' : '(space.w_unicode)', - 'file' : 'state.get(space).w_file', - 'open' : 'state.get(space).w_file', + 'file' : 'state.get(space).w_file', + 'open' : 'state.get(space).w_file', # old-style classes dummy support '_classobj' : 'space.w_classobj', Modified: pypy/dist/pypy/module/__builtin__/state.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/state.py (original) +++ pypy/dist/pypy/module/__builtin__/state.py Sun Nov 5 12:26:15 2006 @@ -1,10 +1,9 @@ -class State: - def __init__(self, space): - if space.config.objspace.uselibfile: - self.w_file = space.builtin.get('__filestub') - else: - self.w_file = space.wrap(file) +class State: + def __init__(self, space): + self.w_file = space.appexec([], """(): + import _file; + return _file.file""") -def get(space): +def get(space): return space.fromcache(State) Modified: pypy/dist/pypy/module/posix/app_posix.py ============================================================================== --- pypy/dist/pypy/module/posix/app_posix.py (original) +++ pypy/dist/pypy/module/posix/app_posix.py Sun Nov 5 12:26:15 2006 @@ -23,13 +23,10 @@ st_mtime = tuple_item_getter(8) st_ctime = tuple_item_getter(9) -def fdopen(fd, mode='r', buffering=None): +def fdopen(fd, mode='r', buffering=-1): """fdopen(fd [, mode='r' [, buffering]]) -> file_object Return an open file object connected to a file descriptor.""" - try: - return file.fdopen(fd, mode, buffering) - except AttributeError: - raise NotImplementedError, "fdopen only works if you use PyPy's file implementation." + return file.fdopen(fd, mode, buffering) Modified: pypy/dist/pypy/module/posix/test/test_posix2.py ============================================================================== --- pypy/dist/pypy/module/posix/test/test_posix2.py (original) +++ pypy/dist/pypy/module/posix/test/test_posix2.py Sun Nov 5 12:26:15 2006 @@ -72,15 +72,11 @@ ex(self.posix.dup, UNUSEDFD) def test_fdopen(self): - path = self.path - posix = self.posix + path = self.path + posix = self.posix fd = posix.open(path, posix.O_RDONLY, 0777) - try: - f = posix.fdopen(fd, "r") - except NotImplementedError: - pass - else: - raise "did not raise" + f = posix.fdopen(fd, "r") + f.close() def test_listdir(self): pdir = self.pdir Modified: pypy/dist/pypy/module/posix/test/test_posix_libfile.py ============================================================================== --- pypy/dist/pypy/module/posix/test/test_posix_libfile.py (original) +++ pypy/dist/pypy/module/posix/test/test_posix_libfile.py Sun Nov 5 12:26:15 2006 @@ -2,9 +2,9 @@ from pypy.tool.udir import udir import os -def setup_module(mod): - mod.space = gettestobjspace(usemodules=['posix'], uselibfile=True) - mod.path = udir.join('posixtestfile.txt') +def setup_module(mod): + mod.space = gettestobjspace(usemodules=['posix']) + mod.path = udir.join('posixtestfile.txt') mod.path.write("this is a test") class AppTestPosix: Modified: pypy/dist/pypy/module/sys/__init__.py ============================================================================== --- pypy/dist/pypy/module/sys/__init__.py (original) +++ pypy/dist/pypy/module/sys/__init__.py Sun Nov 5 12:26:15 2006 @@ -20,12 +20,12 @@ 'prefix' : 'space.wrap(sys.prefix)', 'maxunicode' : 'space.wrap(sys.maxunicode)', 'maxint' : 'space.wrap(sys.maxint)', - 'stdin' : 'state.getio(space).w_stdin', - '__stdin__' : 'state.getio(space).w_stdin', - 'stdout' : 'state.getio(space).w_stdout', - '__stdout__' : 'state.getio(space).w_stdout', - 'stderr' : 'state.getio(space).w_stderr', - '__stderr__' : 'state.getio(space).w_stderr', + 'stdin' : 'state.getio(space).w_stdin', + '__stdin__' : 'state.getio(space).w_stdin', + 'stdout' : 'state.getio(space).w_stdout', + '__stdout__' : 'state.getio(space).w_stdout', + 'stderr' : 'state.getio(space).w_stderr', + '__stderr__' : 'state.getio(space).w_stderr', 'pypy_objspaceclass' : 'space.wrap(repr(space))', 'path' : 'state.get(space).w_path', Modified: pypy/dist/pypy/module/sys/state.py ============================================================================== --- pypy/dist/pypy/module/sys/state.py (original) +++ pypy/dist/pypy/module/sys/state.py Sun Nov 5 12:26:15 2006 @@ -72,23 +72,33 @@ pypy_initial_path.unwrap_spec = [ObjSpace, str] -def get(space): +def get(space): return space.fromcache(State) -class IOState: - def __init__(self, space): +class IOState: + def __init__(self, space): self.space = space - if space.config.objspace.uselibfile: - self.w_stdout = space.call_function(space.builtin.get('file')) - self.w_stderr = space.call_function(space.builtin.get('file')) - self.w_stdin = space.call_function(space.builtin.get('file')) - else: - self.w_stdout = space.wrap(sys.__stdout__) - self.w_stderr = space.wrap(sys.__stderr__) - self.w_stdin = space.wrap(sys.__stdin__) -def getio(space): - return space.fromcache(IOState) + w_fdopen = space.getattr(space.builtin.get('file'), + space.wrap("fdopen")) + self.w_stdin = space.call_function( + w_fdopen, space.wrap(0), space.wrap("r"), + space.wrap(1)) + space.setattr(self.w_stdin, space.wrap("_name"), + space.wrap("")) + self.w_stdout = space.call_function( + w_fdopen, space.wrap(1), space.wrap("w"), + space.wrap(1)) + space.setattr(self.w_stdout, space.wrap("_name"), + space.wrap("")) + self.w_stderr = space.call_function( + w_fdopen, space.wrap(2), space.wrap("w"), + space.wrap(0)) + space.setattr(self.w_stderr, space.wrap("_name"), + space.wrap("")) + +def getio(space): + return space.fromcache(IOState) def _pypy_getudir(space): """NOT_RPYTHON""" Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Sun Nov 5 12:26:15 2006 @@ -125,12 +125,9 @@ r[s] = value return r dict.fromkeys = classmethod(fromkeys) - """) + """) - if self.config.objspace.uselibfile: - self.inituselibfile() - - if self.config.objspace.std.oldstyle: + if self.config.objspace.std.oldstyle: self.enable_old_style_classes_as_default_metaclass() # final setup @@ -178,36 +175,6 @@ w_mod = self.wrap(mod) return w_mod, w_dic - def inituselibfile(self): - """ NOT_RPYTHON use our application level file implementation - including re-wrapping sys.stdout/err/in - """ - assert self.config.objspace.uselibfile - space = self - # nice print helper if the below does not work - # (we dont have prints working at applevel before - # inituselibfile is complete) - #from pypy.interpreter import gateway - #def printit(space, w_msg): - # s = space.str_w(w_msg) - # print "$", s, - #w_p = space.wrap(gateway.interp2app(printit)) - #self.appexec([w_p], '''(p): - self.appexec([], '''(): - import sys - sys.stdin - sys.stdout - sys.stderr # force unlazifying from mixedmodule - from _file import file as libfile - for name, value in libfile.__dict__.items(): - if (name != '__dict__' and name != '__doc__' - and name != '__module__' and name != '__weakref__'): - setattr(file, name, value) - sys.stdin._fdopen(0, "r", 1, '') - sys.stdout._fdopen(1, "w", 1, '') - sys.stderr._fdopen(2, "w", 0, '') - ''') - def setup_exceptions(self): """NOT_RPYTHON""" ## hacking things in Modified: pypy/dist/pypy/rlib/streamio.py ============================================================================== --- pypy/dist/pypy/rlib/streamio.py (original) +++ pypy/dist/pypy/rlib/streamio.py Sun Nov 5 12:26:15 2006 @@ -29,8 +29,19 @@ import os, sys -# ____________________________________________________________ +from os import O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC +O_BINARY = getattr(os, "O_BINARY", 0) + +# (basemode, plus) +OS_MODE = {('r', False): O_RDONLY, + ('r', True): O_RDWR, + ('w', False): O_WRONLY | O_CREAT | O_TRUNC, + ('w', True): O_RDWR | O_CREAT | O_TRUNC, + ('a', False): O_WRONLY | O_CREAT, + ('a', True): O_RDWR | O_CREAT, + } +# ____________________________________________________________ def replace_crlf_with_lf(s): @@ -49,6 +60,85 @@ return s.join(string.split(c)) +def open_file_as_stream(path, mode="r", buffering=-1): + os_flags, universal, reading, writing, basemode = decode_mode(mode) + stream = open_path_helper(path, os_flags, basemode == "a") + return construct_stream_tower(stream, buffering, universal, reading, + writing) + +def fdopen_as_stream(fd, mode, buffering): + # XXX XXX XXX you want do check whether the modes are compatible + # otherwise you get funny results + os_flags, universal, reading, writing, basemode = decode_mode(mode) + stream = DiskFile(fd) + return construct_stream_tower(stream, buffering, universal, reading, + writing) + +def open_path_helper(path, os_flags, append): + # XXX for now always return DiskFile + fd = os.open(path, os_flags, 0666) + if append: + try: + os.lseek(fd, 0, 2) + except OSError: + # XXX does this pass make sense? + pass + return DiskFile(fd) + +def decode_mode(mode): + if mode[0] == 'U': + mode = 'r' + mode + + basemode = mode[0] # 'r', 'w' or 'a' + plus = False + universal = False + binary = False + + for c in mode[1:]: + if c == '+': + plus = True + elif c == 'U': + universal = True + elif c == 'b': + binary = True + else: + break + + flag = OS_MODE[basemode, plus] + if binary or universal: + flag |= O_BINARY + + reading = basemode == 'r' or plus + writing = basemode != 'r' or plus + + return flag, universal, reading, writing, basemode + + +def construct_stream_tower(stream, buffering, universal, reading, writing): + if buffering == 0: # no buffering + pass + elif buffering == 1: # line-buffering + if writing: + stream = LineBufferingOutputStream(stream) + if reading: + stream = BufferingInputStream(stream) + + else: # default or explicit buffer sizes + if buffering is not None and buffering < 0: + buffering = -1 + if writing: + stream = BufferingOutputStream(stream, buffering) + if reading: + stream = BufferingInputStream(stream, buffering) + + if universal: # Wants universal newlines + if writing and os.linesep != '\n': + stream = TextOutputFilter(stream) + if reading: + stream = TextInputFilter(stream) + return stream + + class StreamError(Exception): def __init__(self, message): self.message = message @@ -68,7 +158,7 @@ def tell(self): raise NotImplementedError - def seek(self, offset, whence=0): + def seek(self, offset, whence): raise NotImplementedError def readall(self): @@ -113,6 +203,9 @@ def peek(self): return '' + def try_to_find_file_descriptor(self): + return -1 + class DiskFile(Stream): @@ -121,11 +214,12 @@ def __init__(self, fd): self.fd = fd - def seek(self, offset, whence=0): + def seek(self, offset, whence): os.lseek(self.fd, offset, whence) def tell(self): - return os.lseek(self.fd, 0, 1) + #XXX for running on top of the cpy objspace. later we want r_longlong + return int(os.lseek(self.fd, 0, 1)) def read(self, n): return os.read(self.fd, n) @@ -145,6 +239,8 @@ def truncate(self, size): os.ftruncate(self.fd, size) + def try_to_find_file_descriptor(self): + return self.fd # next class is not RPython @@ -171,7 +267,7 @@ def tell(self): return self.pos - def seek(self, offset, whence=0): + def seek(self, offset, whence): if whence == 0: self.pos = max(0, offset) elif whence == 1: @@ -239,21 +335,43 @@ def flush(self): self.mm.flush() + def try_to_find_file_descriptor(self): + return self.fd + # ____________________________________________________________ +STREAM_METHODS = dict([ + ("read", [int]), + ("write", [str]), + ("tell", []), + ("seek", [int, int]), + ("readall", []), + ("readline", []), + ("truncate", [int]), + ("flush", []), + ("close", []), + ("peek", []), + ("try_to_find_file_descriptor", []), + ]) def PassThrough(meth_name, flush_buffers): + if meth_name in STREAM_METHODS: + signature = STREAM_METHODS[meth_name] + args = ", ".join(["v%s" % (i, ) for i in range(len(signature))]) + else: + assert 0, "not a good idea" + args = "*args" if flush_buffers: - code = """def %s(self, *args): + code = """def %s(self, %s): self.flush_buffers() - return self.base.%s(*args) + return self.base.%s(%s) """ else: - code = """def %s(self, *args): - return self.base.%s(*args) + code = """def %s(self, %s): + return self.base.%s(%s) """ d = {} - exec code % (meth_name, meth_name) in d + exec code % (meth_name, args, meth_name, args) in d return d[meth_name] @@ -285,7 +403,7 @@ def flush_buffers(self): if self.lines or self.buf: try: - self.do_seek(self.tell()) + self.do_seek(self.tell(), 0) except NotImplementedError: pass else: @@ -300,7 +418,7 @@ assert bytes >= offset #, (locals(), self.__dict__) return bytes - offset - def seek(self, offset, whence=0): + def seek(self, offset, whence): # This may fail on the do_seek() or do_tell() call. # But it won't call either on a relative forward seek. # Nor on a seek to the very end. @@ -493,6 +611,9 @@ flush = PassThrough("flush", flush_buffers=True) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + class BufferingOutputStream(Stream): @@ -545,6 +666,9 @@ flush = PassThrough("flush", flush_buffers=True) close = PassThrough("close", flush_buffers=True) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + class LineBufferingOutputStream(BufferingOutputStream): @@ -560,6 +684,10 @@ self.do_write(self.buf[:p]) self.buf = self.buf[p:] + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + + # ____________________________________________________________ @@ -590,6 +718,8 @@ flush = PassThrough("flush", flush_buffers=False) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() class TextInputFilter(Stream): @@ -688,7 +818,7 @@ break return ''.join(result) - def seek(self, offset, whence=0): + def seek(self, offset, whence): """Seeks based on knowledge that does not come from a tell() may go to the wrong place, since the number of characters seen may not match the number of characters @@ -739,6 +869,9 @@ flush = PassThrough("flush", flush_buffers=True) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + class TextOutputFilter(Stream): @@ -762,6 +895,8 @@ flush = PassThrough("flush", flush_buffers=False) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() # _________________________________________________ @@ -811,6 +946,8 @@ flush = PassThrough("flush", flush_buffers=False) close = PassThrough("close", flush_buffers=False) + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() class EncodingOutputFilter(Stream): @@ -836,3 +973,7 @@ truncate = PassThrough("truncate", flush_buffers=False) flush = PassThrough("flush", flush_buffers=False) close = PassThrough("close", flush_buffers=False) + + def try_to_find_file_descriptor(self): + return self.base.try_to_find_file_descriptor() + Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Sun Nov 5 12:26:15 2006 @@ -188,18 +188,13 @@ def f(): assert file.readline() == "ab\n" assert file.readline() == "def\n" - os.write(1, "3\n") blocks = [] while 1: block = file.read(1) - os.write(1, "XXXX" + block + "YYYY") - os.write(1, "4\n") if not block: break - os.write(1, "5\n") blocks.append(block) assert file.read(0) == "" - os.write(1, "6\n") return "".join(blocks) == "".join(self.lines)[7:] res = self.interpret(f, []) assert res @@ -250,23 +245,16 @@ def test_read_4_after_readline(self): file = self.makeStream() def f(): - os.write(1, "1\n") res = file.readline() assert res == "ab\n" - os.write(1, "2\n") assert file.readline() == "def\n" - os.write(1, "3\n") blocks = [file.read(4)] while 1: block = file.read(4) if not block: break blocks.append(block) - os.write(1, "4\n") assert file.read(0) == "" - os.write(1, "5\n") - for element in blocks: - os.write(1, element + "XXX\n") return blocks == ["xy\np", "q\nuv", "wx"] res = self.interpret(f, []) assert res @@ -361,7 +349,7 @@ def test_seek(self): file = self.makeStream(tell=True, seek=True) end = len(file.readall()) - file.seek(0) + file.seek(0, 0) cases = [(readto, seekto, whence) for readto in range(0, end+1) for seekto in range(0, end+1) for whence in [0, 1, 2]] @@ -372,7 +360,7 @@ all = file.readall() assert end == len(all) for readto, seekto, whence in cases: - file.seek(0) + file.seek(0, 0) assert file.tell() == 0 head = file.read(readto) assert head == all[:readto] @@ -473,7 +461,7 @@ base = TWriter() filter = streamio.BufferingOutputStream(base, 4) filter.write("x"*6) - filter.seek(3) + filter.seek(3, 0) filter.write("y"*2) filter.close() assert base.buf == "x"*3 + "y"*2 + "x"*1 @@ -484,7 +472,7 @@ def f(): base = TWriter() filter = streamio.BufferingOutputStream(base, 4) - filter.seek(3) + filter.seek(3, 0) filter.write("y"*2) filter.close() assert base.buf == "\0"*3 + "y"*2 @@ -549,7 +537,7 @@ filter = streamio.BufferingOutputStream(base, 4) def f(): filter.write("x"*6) - filter.seek(3) + filter.seek(3, 0) filter.write("y"*2) filter.close() assert base.buf == "x"*3 + "y"*2 + "x"*1 @@ -632,9 +620,9 @@ file.write("Barf\n") file.writelines(["a\n", "b\n", "c\n"]) assert file.tell() == len("BooHoo\nBarf\na\nb\nc\n") - file.seek(0) + file.seek(0, 0) assert file.read() == "BooHoo\nBarf\na\nb\nc\n" - file.seek(0) + file.seek(0, 0) assert file.readlines() == ( ["BooHoo\n", "Barf\n", "a\n", "b\n", "c\n"]) assert file.tell() == len("BooHoo\nBarf\na\nb\nc\n") @@ -675,7 +663,7 @@ filter = streamio.BufferingInputStream( streamio.BufferingOutputStream(base, 4), 4) def f(): - filter.seek(3) + filter.seek(3, 0) filter.write("y"*2) filter.close() assert base.buf == "\0"*3 + "y"*2 @@ -774,7 +762,7 @@ all = sofar for i in range(len(pairs)): sofar, pos = pairs[i] - filter.seek(pos) + filter.seek(pos, 0) assert filter.tell() == pos assert filter.tell() == pos bufs = [sofar] @@ -862,7 +850,7 @@ base = TWriter() filter = streamio.TextOutputFilter(base, linesep="\n") filter.write("x"*100) - filter.seek(50) + filter.seek(50, 0) filter.write("y"*10) assert base.buf == "x"*50 + "y"*10 + "x"*40 self.interpret(f, []) Modified: pypy/dist/pypy/tool/option.py ============================================================================== --- pypy/dist/pypy/tool/option.py (original) +++ pypy/dist/pypy/tool/option.py Sun Nov 5 12:26:15 2006 @@ -10,7 +10,6 @@ class Options: objspace = "std" oldstyle = 0 - uselibfile = 0 nofaking = 0 parser = "pypy" # "cpython" / "pypy" compiler = "ast" @@ -71,9 +70,6 @@ setattr(conf.objspace.usemodules, modname, True) if getattr(cmdlineopt, "nofaking", False) or kwds.get("nofaking", False): conf.objspace.nofaking = True - if (getattr(cmdlineopt, "uselibfile", False) or - kwds.get("uselibfile", False)): - conf.objspace.uselibfile = True if getattr(cmdlineopt, "oldstyle", False) or kwds.get("oldstyle", False): conf.objspace.std.oldstyle = True if hasattr(cmdlineopt, "parser") and cmdlineopt.parser is not None: From ac at codespeak.net Sun Nov 5 12:28:25 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Sun, 5 Nov 2006 12:28:25 +0100 (CET) Subject: [pypy-svn] r34225 - in pypy/dist/pypy/rpython/rctypes: . test Message-ID: <20061105112825.12A0D1007D@code0.codespeak.net> Author: ac Date: Sun Nov 5 12:28:21 2006 New Revision: 34225 Modified: pypy/dist/pypy/rpython/rctypes/avoid_p.py pypy/dist/pypy/rpython/rctypes/rchar_p.py pypy/dist/pypy/rpython/rctypes/rmodel.py pypy/dist/pypy/rpython/rctypes/test/test_rvoid_p.py Log: Support ctypes.cast to and from c_char_p. Modified: pypy/dist/pypy/rpython/rctypes/avoid_p.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/avoid_p.py (original) +++ pypy/dist/pypy/rpython/rctypes/avoid_p.py Sun Nov 5 12:28:21 2006 @@ -48,7 +48,8 @@ _about_ = cast def checkptr(self, ctype): - assert (isinstance(ctype, PointerType) or ctype == c_void_p or + assert (isinstance(ctype, PointerType) or + ctype in (c_void_p, c_char_p) or isinstance(ctype, CFuncPtrType)), ( "cast(): can only cast between pointers so far, not %r" % (ctype,)) @@ -67,6 +68,7 @@ def specialize_call(self, hop): from pypy.rpython.rctypes.rpointer import PointerRepr from pypy.rpython.rctypes.rvoid_p import CVoidPRepr + from pypy.rpython.rctypes.rchar_p import CCharPRepr from pypy.rpython.rctypes.rstringbuf import StringBufRepr from pypy.rpython.rctypes.rfunc import CFuncPtrRepr from pypy.rpython.lltypesystem import lltype, llmemory @@ -76,7 +78,7 @@ # to become a general non-constant SomeCTypesObject s_arg = hop.args_s[0].normalized() r_arg = hop.rtyper.getrepr(s_arg) - assert isinstance(r_arg, (PointerRepr, CVoidPRepr, + assert isinstance(r_arg, (PointerRepr, CVoidPRepr, CCharPRepr, StringBufRepr, CFuncPtrRepr)) targetctype = hop.args_s[1].const v_box, c_targetctype = hop.inputargs(r_arg, lltype.Void) @@ -97,4 +99,4 @@ v_result = hop.genop('cast_adr_to_ptr', [v_adr], resulttype = hop.r_result.ll_type) hop.exception_cannot_occur() - return hop.r_result.return_value(hop.llops, v_result) + return hop.r_result.cast_return_value(hop.llops, v_result) Modified: pypy/dist/pypy/rpython/rctypes/rchar_p.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rchar_p.py (original) +++ pypy/dist/pypy/rpython/rctypes/rchar_p.py Sun Nov 5 12:28:21 2006 @@ -24,6 +24,10 @@ # field instead of the c_data pointer return llops.gendirectcall(ll_charp2str, v_value) + def cast_return_value(self, llops, v_value): + # This should not return a string but a char pointer + return CTypesValueRepr.return_value(self, llops, v_value) + def get_content_keepalive_type(self): "An extra keepalive used for the RPython string." return string_repr.lowleveltype Modified: pypy/dist/pypy/rpython/rctypes/rmodel.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/rmodel.py (original) +++ pypy/dist/pypy/rpython/rctypes/rmodel.py Sun Nov 5 12:28:21 2006 @@ -245,6 +245,10 @@ r_temp.setvalue(llops, v_owned_box, v_value) return llops.convertvar(v_owned_box, r_temp, self) + def cast_return_value(self, llops, v_value): + # like return_value(), but used for the cast function + return self.return_value(llops, v_value) + def rtype_is_true(self, hop): [v_box] = hop.inputargs(self) v_value = self.getvalue(hop.llops, v_box) Modified: pypy/dist/pypy/rpython/rctypes/test/test_rvoid_p.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/test/test_rvoid_p.py (original) +++ pypy/dist/pypy/rpython/rctypes/test/test_rvoid_p.py Sun Nov 5 12:28:21 2006 @@ -12,7 +12,7 @@ from pypy.rpython.lltypesystem import lltype, llmemory from pypy.rpython.test.test_llinterp import interpret -from ctypes import c_void_p, c_int, c_long, cast, pointer, POINTER +from ctypes import c_void_p, c_int, c_long, cast, pointer, POINTER, c_ubyte from ctypes import c_char, c_byte, c_char_p, create_string_buffer, CFUNCTYPE class Test_annotation: @@ -53,6 +53,25 @@ s = a.build_types(fn, []) assert s.knowntype == c_void_p + def test_annotate_c_char_p(self): + def fn(): + x = c_int(12) + p1 = cast(pointer(x), c_char_p) + p2 = cast(p1, POINTER(c_int)) + assert p2.contents.value == 12 + return p1, p2 + + t = TranslationContext() + a = t.buildannotator() + s = a.build_types(fn, []) + assert s.items[0].knowntype == c_char_p + assert s.items[1].knowntype == POINTER(c_int) + + if conftest.option.view: + t.view() + + + class Test_specialization: def test_specialize_c_void_p(self): def func(): @@ -65,6 +84,18 @@ assert lltype.typeOf(res.item0.c_data[0]) == llmemory.Address assert res.item1 == 12 + def test_specialize_c_char_p(self): + py.test.skip("LLinterp is grumpy about converting between pointers pointing to different types of data.") + def func(): + x = c_int(12) + p1 = cast(pointer(x), c_char_p) + p2 = cast(p1, POINTER(c_int)) + return p1, p2.contents.value + + res = interpret(func, []) + assert lltype.typeOf(res.item0.c_data[0]) == llmemory.Address + assert res.item1 == 12 + def test_truth_value(self): def func(): assert not c_void_p() @@ -118,7 +149,7 @@ assert lltype.typeOf(res) == lltype.Signed # xxx class Test_compilation: - def test_compile_c_char_p(self): + def test_compile_c_void_p(self): def func(): x = c_int(12) p1 = cast(pointer(x), c_void_p) @@ -128,6 +159,16 @@ fn = compile(func, []) assert fn() == 12 + def test_compile_c_char_p(self): + def func(): + x = c_ubyte(12) + p1 = cast(pointer(x), c_char_p) + p2 = cast(p1, POINTER(c_ubyte)) + return p2.contents.value + + fn = compile(func, []) + assert fn() == 12 + def test_compile_funcptr_as_void_p(self): from pypy.rpython.rctypes.test.test_rfunc import labs UNARYFN = CFUNCTYPE(c_long, c_long) From mwh at codespeak.net Sun Nov 5 12:30:40 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sun, 5 Nov 2006 12:30:40 +0100 (CET) Subject: [pypy-svn] r34226 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061105113040.565F71007D@code0.codespeak.net> Author: mwh Date: Sun Nov 5 12:30:33 2006 New Revision: 34226 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: save and restore the condition register on function entry/exit. some cosmetic and comment cleanups. Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Sun Nov 5 12:30:33 2006 @@ -170,18 +170,30 @@ self.initial_var2loc[arg] = gprs[3+len(self.initial_var2loc)] self.initial_spill_offset = self._var_offset(0) - # Emit standard prologue - # Minimum space = 24+params+lv+4*GPR+8*FPR - # GPR=NSAVEDREGISTERS - # Initially, we allocate only enough space for GPRs, and allow - # each basic block to ensure it has enough space to continue. + # Standard prologue: + + # Minimum stack space = 24+params+lv+4*GPRSAVE+8*FPRSAVE + # params = stack space for parameters for functions we call + # lv = stack space for local variables + # GPRSAVE = the number of callee-save GPRs we save, currently + # NSAVEDREGISTERS which is 19, i.e. all of them + # FPRSAVE = the number of callee-save FPRs we save, currently 0 + # Initially, we set params == lv == 0 and allow each basic block to + # ensure it has enough space to continue. + minspace = self._stack_size(0, self._var_offset(0)) + # save Link Register self.asm.mflr(rSCRATCH) - self.asm.stw(rSCRATCH,rSP,8) - # save all regs from -31 to stack - self.asm.stmw(gprs[32-NSAVEDREGISTERS].number,rSP,-4*(NSAVEDREGISTERS + 1)) - self.asm.mr(rFP, rSP) # set up our frame pointer - self.asm.stwu(rSP,rSP,-minspace) + self.asm.stw(rSCRATCH, rSP, 8) + # save Condition Register + self.asm.mfcr(rSCRATCH) + self.asm.stw(rSCRATCH, rSP, 4) + # save the callee-save GPRs + self.asm.stmw(gprs[32-NSAVEDREGISTERS].number, rSP, -4*(NSAVEDREGISTERS + 1)) + # set up frame pointer + self.asm.mr(rFP, rSP) + # save stack pointer into linkage area and set stack pointer for us. + self.asm.stwu(rSP, rSP, -minspace) return inputargs @@ -222,12 +234,20 @@ self.insns.append(insn.Return(gv_returnvar)) allocator = self.allocate_and_emit() - # Emit standard epilogue: - self.asm.lwz(rSP,rSP,0) # restore old SP - self.asm.lmw(gprs[32-NSAVEDREGISTERS].number,rSP,-4*(NSAVEDREGISTERS+1)) # restore all GPRs - self.asm.lwz(rSCRATCH,rSP,8) # load old Link Register and jump to it - self.asm.mtlr(rSCRATCH) # - self.asm.blr() # + # standard epilogue: + + # restore old SP + self.asm.lwz(rSP, rSP, 0) + # restore all callee-save GPRs + self.asm.lmw(gprs[32-NSAVEDREGISTERS].number, rSP, -4*(NSAVEDREGISTERS+1)) + # restore Condition Register + self.asm.lwz(rSCRATCH, rSP, 4) + self.asm.mtcr(rSCRATCH) + # restore Link Register and jump to it + self.asm.lwz(rSCRATCH, rSP, 8) + self.asm.mtlr(rSCRATCH) + self.asm.blr() + self._close() def finish_and_goto(self, outputargs_gv, target): From fijal at codespeak.net Sun Nov 5 12:38:41 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 5 Nov 2006 12:38:41 +0100 (CET) Subject: [pypy-svn] r34228 - in pypy/branch/transparent-proxy/pypy/objspace/std: . test Message-ID: <20061105113841.9D3611007D@code0.codespeak.net> Author: fijal Date: Sun Nov 5 12:38:38 2006 New Revision: 34228 Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Log: Reverted TransparentType object. Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/model.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/model.py Sun Nov 5 12:38:38 2006 @@ -123,7 +123,6 @@ # xxx config self.typeorder[proxyobject.W_TransparentList] = [] self.typeorder[proxyobject.W_TransparentDict] = [] - self.typeorder[proxyobject.W_TransparentType] = [] if config.objspace.std.withstrdict: del self.typeorder[dictobject.W_DictObject] Modified: pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py Sun Nov 5 12:38:38 2006 @@ -92,10 +92,6 @@ class W_TransparentGenerator(W_Transparent): typedef = GeneratorIterator.typedef -class W_TransparentType(W_TransparentObject): - from pypy.objspace.std.typeobject import W_TypeObject as original - from pypy.objspace.std.typetype import type_typedef as typedef - class W_TransparentList(W_TransparentObject): from pypy.objspace.std.listobject import W_ListObject as original from pypy.objspace.std.listtype import list_typedef as typedef @@ -106,8 +102,6 @@ registerimplementation(W_TransparentList) registerimplementation(W_TransparentDict) -registerimplementation(W_TransparentType) register_type(W_TransparentList) register_type(W_TransparentDict) -register_type(W_TransparentType) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sun Nov 5 12:38:38 2006 @@ -96,7 +96,7 @@ assert traceback.format_tb(last_tb) == traceback.format_tb(e[2]) -class AppTestProxyType(AppProxy): +class DONTAppTestProxyType(AppProxy): def test_filetype(self): f = self.get_proxy(file) f("/tmp/sth", "w").write("aaa") @@ -108,3 +108,16 @@ fp.write("aaa") fp.close() assert open("/tmp/sth").read() == "aaa" + + def test_isinstance(self): + class A: + pass + + a = A() + Ap = self.get_proxy(A) + ap = self.get_proxy(a) + assert isinstance(a, A) + assert isinstance(a, Ap) + assert isinstance(ap, A) + assert isinstance(ap, Ap) + assert type(a) is type(ap) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Sun Nov 5 12:38:38 2006 @@ -27,8 +27,6 @@ return W_TransparentFrame(space, w_type, w_controller) if space.is_true(space.issubtype(w_type, space.gettypeobject(GeneratorIterator.typedef))): return W_TransparentGenerator(space, w_type, w_controller) - if isinstance(w_type, W_TypeObject): - return W_TransparentType(space, w_type, w_controller) if w_type.instancetypedef is space.w_object.instancetypedef: return W_Transparent(space, w_type, w_controller) else: From arigo at codespeak.net Sun Nov 5 12:45:46 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 5 Nov 2006 12:45:46 +0100 (CET) Subject: [pypy-svn] r34229 - in pypy/dist/pypy: annotation/test bin config interpreter interpreter/pyparser/test interpreter/test lib/test2 module/__builtin__/test module/_codecs/test module/_sre/test module/sys/test objspace/flow/test objspace/std objspace/std/test objspace/test rlib rlib/test rpython/rctypes/tool tool tool/algo/test tool/build/bin tool/pytest tool/test translator translator/asm translator/asm/ppcgen translator/asm/ppcgen/test translator/asm/test translator/c translator/c/test translator/cl/test translator/cli/test translator/goal translator/js translator/js/demo/jsdemo translator/js/examples translator/llvm/demo translator/llvm/pyllvm translator/microbench/pybench translator/pyrex translator/pyrex/test translator/test translator/tool translator/tool/pygame Message-ID: <20061105114546.F30A01007D@code0.codespeak.net> Author: arigo Date: Sun Nov 5 12:45:39 2006 New Revision: 34229 Modified: pypy/dist/pypy/annotation/test/autopath.py pypy/dist/pypy/bin/autopath.py pypy/dist/pypy/config/autopath.py pypy/dist/pypy/interpreter/autopath.py pypy/dist/pypy/interpreter/pyparser/test/autopath.py pypy/dist/pypy/interpreter/test/autopath.py pypy/dist/pypy/lib/test2/autopath.py pypy/dist/pypy/module/__builtin__/test/autopath.py pypy/dist/pypy/module/_codecs/test/autopath.py pypy/dist/pypy/module/_sre/test/autopath.py pypy/dist/pypy/module/sys/test/autopath.py pypy/dist/pypy/objspace/flow/test/autopath.py pypy/dist/pypy/objspace/std/autopath.py pypy/dist/pypy/objspace/std/test/autopath.py pypy/dist/pypy/objspace/test/autopath.py pypy/dist/pypy/rlib/autopath.py pypy/dist/pypy/rlib/test/autopath.py pypy/dist/pypy/rpython/rctypes/tool/autopath.py pypy/dist/pypy/tool/algo/test/autopath.py pypy/dist/pypy/tool/autopath.py pypy/dist/pypy/tool/build/bin/autopath.py pypy/dist/pypy/tool/pytest/autopath.py pypy/dist/pypy/tool/test/autopath.py pypy/dist/pypy/translator/asm/autopath.py pypy/dist/pypy/translator/asm/ppcgen/autopath.py pypy/dist/pypy/translator/asm/ppcgen/test/autopath.py pypy/dist/pypy/translator/asm/test/autopath.py pypy/dist/pypy/translator/autopath.py pypy/dist/pypy/translator/c/autopath.py pypy/dist/pypy/translator/c/test/autopath.py pypy/dist/pypy/translator/cl/test/autopath.py pypy/dist/pypy/translator/cli/test/autopath.py pypy/dist/pypy/translator/goal/autopath.py pypy/dist/pypy/translator/js/autopath.py pypy/dist/pypy/translator/js/demo/jsdemo/autopath.py pypy/dist/pypy/translator/js/examples/autopath.py pypy/dist/pypy/translator/llvm/demo/autopath.py pypy/dist/pypy/translator/llvm/pyllvm/autopath.py pypy/dist/pypy/translator/microbench/pybench/autopath.py pypy/dist/pypy/translator/pyrex/autopath.py pypy/dist/pypy/translator/pyrex/test/autopath.py pypy/dist/pypy/translator/test/autopath.py pypy/dist/pypy/translator/tool/autopath.py pypy/dist/pypy/translator/tool/pygame/autopath.py Log: An autopath fix: avoid the getattr(mod, '__file__') if unneeded, because it forces py lib modules to be loaded. Modified: pypy/dist/pypy/annotation/test/autopath.py ============================================================================== --- pypy/dist/pypy/annotation/test/autopath.py (original) +++ pypy/dist/pypy/annotation/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/bin/autopath.py ============================================================================== --- pypy/dist/pypy/bin/autopath.py (original) +++ pypy/dist/pypy/bin/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/config/autopath.py ============================================================================== --- pypy/dist/pypy/config/autopath.py (original) +++ pypy/dist/pypy/config/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/interpreter/autopath.py ============================================================================== --- pypy/dist/pypy/interpreter/autopath.py (original) +++ pypy/dist/pypy/interpreter/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/interpreter/pyparser/test/autopath.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/test/autopath.py (original) +++ pypy/dist/pypy/interpreter/pyparser/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/interpreter/test/autopath.py ============================================================================== --- pypy/dist/pypy/interpreter/test/autopath.py (original) +++ pypy/dist/pypy/interpreter/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/lib/test2/autopath.py ============================================================================== --- pypy/dist/pypy/lib/test2/autopath.py (original) +++ pypy/dist/pypy/lib/test2/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/module/__builtin__/test/autopath.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/autopath.py (original) +++ pypy/dist/pypy/module/__builtin__/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/module/_codecs/test/autopath.py ============================================================================== --- pypy/dist/pypy/module/_codecs/test/autopath.py (original) +++ pypy/dist/pypy/module/_codecs/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/module/_sre/test/autopath.py ============================================================================== --- pypy/dist/pypy/module/_sre/test/autopath.py (original) +++ pypy/dist/pypy/module/_sre/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/module/sys/test/autopath.py ============================================================================== --- pypy/dist/pypy/module/sys/test/autopath.py (original) +++ pypy/dist/pypy/module/sys/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/objspace/flow/test/autopath.py ============================================================================== --- pypy/dist/pypy/objspace/flow/test/autopath.py (original) +++ pypy/dist/pypy/objspace/flow/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/objspace/std/autopath.py ============================================================================== --- pypy/dist/pypy/objspace/std/autopath.py (original) +++ pypy/dist/pypy/objspace/std/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/objspace/std/test/autopath.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/autopath.py (original) +++ pypy/dist/pypy/objspace/std/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/objspace/test/autopath.py ============================================================================== --- pypy/dist/pypy/objspace/test/autopath.py (original) +++ pypy/dist/pypy/objspace/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/rlib/autopath.py ============================================================================== --- pypy/dist/pypy/rlib/autopath.py (original) +++ pypy/dist/pypy/rlib/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/rlib/test/autopath.py ============================================================================== --- pypy/dist/pypy/rlib/test/autopath.py (original) +++ pypy/dist/pypy/rlib/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/rpython/rctypes/tool/autopath.py ============================================================================== --- pypy/dist/pypy/rpython/rctypes/tool/autopath.py (original) +++ pypy/dist/pypy/rpython/rctypes/tool/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/tool/algo/test/autopath.py ============================================================================== --- pypy/dist/pypy/tool/algo/test/autopath.py (original) +++ pypy/dist/pypy/tool/algo/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/tool/autopath.py ============================================================================== --- pypy/dist/pypy/tool/autopath.py (original) +++ pypy/dist/pypy/tool/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/tool/build/bin/autopath.py ============================================================================== --- pypy/dist/pypy/tool/build/bin/autopath.py (original) +++ pypy/dist/pypy/tool/build/bin/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/tool/pytest/autopath.py ============================================================================== --- pypy/dist/pypy/tool/pytest/autopath.py (original) +++ pypy/dist/pypy/tool/pytest/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/tool/test/autopath.py ============================================================================== --- pypy/dist/pypy/tool/test/autopath.py (original) +++ pypy/dist/pypy/tool/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/asm/autopath.py ============================================================================== --- pypy/dist/pypy/translator/asm/autopath.py (original) +++ pypy/dist/pypy/translator/asm/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/asm/ppcgen/autopath.py ============================================================================== --- pypy/dist/pypy/translator/asm/ppcgen/autopath.py (original) +++ pypy/dist/pypy/translator/asm/ppcgen/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/asm/ppcgen/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/asm/ppcgen/test/autopath.py (original) +++ pypy/dist/pypy/translator/asm/ppcgen/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/asm/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/asm/test/autopath.py (original) +++ pypy/dist/pypy/translator/asm/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/autopath.py ============================================================================== --- pypy/dist/pypy/translator/autopath.py (original) +++ pypy/dist/pypy/translator/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/c/autopath.py ============================================================================== --- pypy/dist/pypy/translator/c/autopath.py (original) +++ pypy/dist/pypy/translator/c/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/c/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/c/test/autopath.py (original) +++ pypy/dist/pypy/translator/c/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/cl/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/cl/test/autopath.py (original) +++ pypy/dist/pypy/translator/cl/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/cli/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/autopath.py (original) +++ pypy/dist/pypy/translator/cli/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/goal/autopath.py ============================================================================== --- pypy/dist/pypy/translator/goal/autopath.py (original) +++ pypy/dist/pypy/translator/goal/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/js/autopath.py ============================================================================== --- pypy/dist/pypy/translator/js/autopath.py (original) +++ pypy/dist/pypy/translator/js/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/js/demo/jsdemo/autopath.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/autopath.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/js/examples/autopath.py ============================================================================== --- pypy/dist/pypy/translator/js/examples/autopath.py (original) +++ pypy/dist/pypy/translator/js/examples/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/llvm/demo/autopath.py ============================================================================== --- pypy/dist/pypy/translator/llvm/demo/autopath.py (original) +++ pypy/dist/pypy/translator/llvm/demo/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/llvm/pyllvm/autopath.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/autopath.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/autopath.py Sun Nov 5 12:45:39 2006 @@ -41,15 +41,7 @@ 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: @@ -58,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/microbench/pybench/autopath.py ============================================================================== --- pypy/dist/pypy/translator/microbench/pybench/autopath.py (original) +++ pypy/dist/pypy/translator/microbench/pybench/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/pyrex/autopath.py ============================================================================== --- pypy/dist/pypy/translator/pyrex/autopath.py (original) +++ pypy/dist/pypy/translator/pyrex/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/pyrex/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/pyrex/test/autopath.py (original) +++ pypy/dist/pypy/translator/pyrex/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/test/autopath.py ============================================================================== --- pypy/dist/pypy/translator/test/autopath.py (original) +++ pypy/dist/pypy/translator/test/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/tool/autopath.py ============================================================================== --- pypy/dist/pypy/translator/tool/autopath.py (original) +++ pypy/dist/pypy/translator/tool/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): Modified: pypy/dist/pypy/translator/tool/pygame/autopath.py ============================================================================== --- pypy/dist/pypy/translator/tool/pygame/autopath.py (original) +++ pypy/dist/pypy/translator/tool/pygame/autopath.py Sun Nov 5 12:45:39 2006 @@ -50,8 +50,10 @@ munged = {} for name, mod in sys.modules.items(): + if '.' in name: + continue fn = getattr(mod, '__file__', None) - if '.' in name or not isinstance(fn, str): + if not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] if not newname.startswith(part + '.'): From arigo at codespeak.net Sun Nov 5 12:59:14 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 5 Nov 2006 12:59:14 +0100 (CET) Subject: [pypy-svn] r34230 - pypy/dist/pypy/objspace/std/test Message-ID: <20061105115914.4711A1007D@code0.codespeak.net> Author: arigo Date: Sun Nov 5 12:59:12 2006 New Revision: 34230 Modified: pypy/dist/pypy/objspace/std/test/test_dictproxy.py Log: Fix test to also pass on CPython. Modified: pypy/dist/pypy/objspace/std/test/test_dictproxy.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_dictproxy.py (original) +++ pypy/dist/pypy/objspace/std/test/test_dictproxy.py Sun Nov 5 12:59:12 2006 @@ -21,9 +21,9 @@ def test_dictproxyeq(self): class a(object): pass - class b(object): + class b(a): stuff = 42 - class c(object): + class c(a): stuff = 42 assert a.__dict__ == a.__dict__ assert a.__dict__ != b.__dict__ From pedronis at codespeak.net Sun Nov 5 13:12:16 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 5 Nov 2006 13:12:16 +0100 (CET) Subject: [pypy-svn] r34231 - in pypy/branch/transparent-proxy/pypy: config objspace/std objspace/std/test Message-ID: <20061105121216.6BAF91007C@code0.codespeak.net> Author: pedronis Date: Sun Nov 5 13:12:14 2006 New Revision: 34231 Modified: pypy/branch/transparent-proxy/pypy/config/pypyoption.py pypy/branch/transparent-proxy/pypy/objspace/std/model.py pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Log: adding a --objspace-std-withtproxy option to enable/disable transparent proxy support. Modified: pypy/branch/transparent-proxy/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/config/pypyoption.py (original) +++ pypy/branch/transparent-proxy/pypy/config/pypyoption.py Sun Nov 5 13:12:14 2006 @@ -58,6 +58,9 @@ default=False), OptionDescription("std", "Standard Object Space Options", [ + BoolOption("withtproxy", "support transparent proxies", + default=False), + BoolOption("withsmallint", "use tagged integers", default=False), Modified: pypy/branch/transparent-proxy/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/model.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/model.py Sun Nov 5 13:12:14 2006 @@ -18,6 +18,8 @@ "dictmultiobject.W_DictMultiIterObject"], "withrangelist" : ["rangeobject.W_RangeListObject", "rangeobject.W_RangeIterObject"], + "withtproxy" : ["proxyobject.W_TransparentList", + "proxyobject.W_TransparentDict"], } class StdTypeModel: @@ -66,7 +68,6 @@ from pypy.objspace.std import stringobject from pypy.objspace.std import strsliceobject from pypy.objspace.std import strjoinobject - from pypy.objspace.std import proxyobject from pypy.objspace.std import typeobject from pypy.objspace.std import sliceobject from pypy.objspace.std import longobject @@ -75,6 +76,7 @@ from pypy.objspace.std import unicodeobject from pypy.objspace.std import dictproxyobject from pypy.objspace.std import rangeobject + from pypy.objspace.std import proxyobject from pypy.objspace.std import fake import pypy.objspace.std.default # register a few catch-all multimethods @@ -120,10 +122,6 @@ else: imported_but_not_registered[implcls] = True - # xxx config - self.typeorder[proxyobject.W_TransparentList] = [] - self.typeorder[proxyobject.W_TransparentDict] = [] - if config.objspace.std.withstrdict: del self.typeorder[dictobject.W_DictObject] del self.typeorder[dictobject.W_DictIterObject] Modified: pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/objspace.py Sun Nov 5 13:12:14 2006 @@ -136,10 +136,11 @@ # final setup self.setup_builtin_modules() # Adding transparent proxy call - from pypy.objspace.std.transparent import app_proxy + if self.config.objspace.std.withtproxy: + from pypy.objspace.std.transparent import app_proxy - self.setitem(self.builtin.w_dict, self.wrap('proxy'), - self.wrap(app_proxy)) + self.setitem(self.builtin.w_dict, self.wrap('proxy'), + self.wrap(app_proxy)) def enable_old_style_classes_as_default_metaclass(self): self.setitem(self.builtin.w_dict, self.wrap('__metaclass__'), self.w_classobj) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py Sun Nov 5 13:12:14 2006 @@ -5,6 +5,9 @@ from pypy.conftest import gettestobjspace class AppProxyBasic(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withtproxy": True}) + def setup_method(self, meth): self.w_Controller = self.space.appexec([], """(): class Controller(object): @@ -101,4 +104,5 @@ class AppTestDictStrProxy(AppTestDictProxy): def setup_class(cls): - cls.space = gettestobjspace(**{"objspace.std.withstrdict": True}) + cls.space = gettestobjspace(**{"objspace.std.withstrdict": True, + "objspace.std.withtproxy": True}) Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py Sun Nov 5 13:12:14 2006 @@ -2,9 +2,13 @@ """ test proxy on functions and other crazy goodies """ +from pypy.conftest import gettestobjspace from pypy.objspace.std.test.test_proxy import AppProxyBasic class AppTestProxyFunction(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withtproxy": True}) + def setup_method(self, meth): self.w_get_proxy = self.space.appexec([], """(): class Controller(object): Modified: pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py Sun Nov 5 13:12:14 2006 @@ -1,8 +1,12 @@ """ test proxy internals like code, traceback, frame """ +from pypy.conftest import gettestobjspace class AppProxy(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withtproxy": True}) + def setup_method(self, meth): self.w_get_proxy = self.space.appexec([], """(): class Controller(object): @@ -47,7 +51,7 @@ fp = self.get_proxy(frame) assert fp.f_locals == frame.f_locals -class AppTestProxyTracebackController(object): +class AppTestProxyTracebackController(AppProxy): def test_controller(self): import types import sys From ac at codespeak.net Sun Nov 5 13:14:19 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Sun, 5 Nov 2006 13:14:19 +0100 (CET) Subject: [pypy-svn] r34232 - pypy/dist/pypy/module/rsocket Message-ID: <20061105121419.D06AB1007C@code0.codespeak.net> Author: ac Date: Sun Nov 5 13:14:19 2006 New Revision: 34232 Modified: pypy/dist/pypy/module/rsocket/ctypes_socket.py pypy/dist/pypy/module/rsocket/interp_func.py pypy/dist/pypy/module/rsocket/interp_socket.py pypy/dist/pypy/module/rsocket/rsocket.py Log: Make rsocket translatable. Modified: pypy/dist/pypy/module/rsocket/ctypes_socket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/ctypes_socket.py (original) +++ pypy/dist/pypy/module/rsocket/ctypes_socket.py Sun Nov 5 13:14:19 2006 @@ -8,6 +8,8 @@ from ctypes import c_ushort, c_int, c_uint, c_char_p, c_void_p, c_char, c_ubyte from ctypes import c_short, POINTER, ARRAY, cdll, sizeof, SetPointerType +from pypy.rlib.rarithmetic import intmask, r_uint + # Also not used here, but exported for other code. from ctypes import cast, pointer, create_string_buffer @@ -24,6 +26,7 @@ 'netdb.h', 'arpa/inet.h', 'stdint.h', + 'errno.h', ) cond_includes = [('AF_NETLINK', 'linux/netlink.h')] HEADER = ''.join(['#include <%s>\n' % filename for filename in includes]) @@ -47,6 +50,7 @@ POLLOUT = ctypes_platform.DefinedConstantInteger('POLLOUT') EINPROGRESS = ctypes_platform.DefinedConstantInteger('EINPROGRESS') EWOULDBLOCK = ctypes_platform.DefinedConstantInteger('EWOULDBLOCK') + EAFNOSUPPORT = ctypes_platform.DefinedConstantInteger('EAFNOSUPPORT') constant_names = ''' AF_AAL5 AF_APPLETALK AF_ASH AF_ATMPVC AF_ATMSVC AF_AX25 AF_BLUETOOTH AF_BRIDGE AD_DECnet AF_ECONET AF_INET AF_INET6 AF_IPX AF_IRDA AF_KEY AF_LLC AF_NETBEUI @@ -164,8 +168,9 @@ CConfig.sockaddr_in6 = ctypes_platform.Struct('struct sockaddr_in6', [('sin6_family', c_int), - ('sin6_flowinfo', c_int), + ('sin6_port', c_ushort), ('sin6_addr', CConfig.in6_addr), + ('sin6_flowinfo', c_int), ('sin6_scope_id', c_int)]) CConfig.sockaddr_un = ctypes_platform.Struct('struct sockaddr_un', @@ -235,6 +240,10 @@ constants[name] = default constants['has_ipv6'] = True # This is a configuration option in CPython +for name, value in constants.items(): + if isinstance(value, long): + if r_uint(value) == value: + constants[name] = intmask(value) locals().update(constants) @@ -247,6 +256,7 @@ POLLOUT = cConfig.POLLOUT EINPROGRESS = cConfig.EINPROGRESS EWOULDBLOCK = cConfig.EWOULDBLOCK +EAFNOSUPPORT = cConfig.EAFNOSUPPORT linux = cConfig.linux MS_WINDOWS = cConfig.MS_WINDOWS Modified: pypy/dist/pypy/module/rsocket/interp_func.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_func.py (original) +++ pypy/dist/pypy/module/rsocket/interp_func.py Sun Nov 5 13:14:19 2006 @@ -146,7 +146,7 @@ AF_UNIX if defined on the platform; otherwise, the default is AF_INET. """ try: - sock1, sock2 = rsocket.socketpair(family, type, proto) + sock1, sock2 = rsocket.socketpair(family, type, proto, W_RSocket) except SocketError, e: raise converted_error(space, e) return space.newtuple([space.wrap(sock1), space.wrap(sock2)]) Modified: pypy/dist/pypy/module/rsocket/interp_socket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_socket.py (original) +++ pypy/dist/pypy/module/rsocket/interp_socket.py Sun Nov 5 13:14:19 2006 @@ -16,7 +16,7 @@ info is a pair (hostaddr, port). """ try: - sock, addr = self.accept() + sock, addr = self.accept(W_RSocket) except SocketError, e: raise converted_error(space, e) return space.newtuple([space.wrap(sock), addr.as_object(space)]) @@ -339,7 +339,7 @@ # Error handling def converted_error(space, e): - message = e.__str__() + message = e.get_msg() w_module = space.getbuiltinmodule('_socket') w_exception_class = space.getattr(w_module, space.wrap(e.applevelerrcls)) w_exception = space.call_function(w_exception_class, space.wrap(message)) Modified: pypy/dist/pypy/module/rsocket/rsocket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/rsocket.py (original) +++ pypy/dist/pypy/module/rsocket/rsocket.py Sun Nov 5 13:14:19 2006 @@ -14,8 +14,9 @@ from pypy.rlib.objectmodel import instantiate from pypy.module.rsocket import ctypes_socket as _c from ctypes import cast, POINTER, c_char, c_char_p, pointer, byref, c_void_p -from ctypes import create_string_buffer, sizeof +from ctypes import create_string_buffer, sizeof, cast from pypy.rpython.rctypes.astruct import offsetof +from pypy.rlib.rarithmetic import intmask constants = _c.constants @@ -51,7 +52,7 @@ # exception -- return it as a tuple. family = self.addr.sa_family buf = copy_buffer(cast(pointer(self.addr.sa_data), POINTER(c_char)), - self.addrlen - offsetof(_c.sockaddr_un, 'sa_data')) + self.addrlen - offsetof(_c.sockaddr, 'sa_data')) return space.newtuple([space.wrap(family), space.wrap(buf.raw)]) @@ -94,7 +95,7 @@ # IPv4 also supports the special name "". if name == '': - return makeipv4addr(INADDR_BROADCAST, result) + return makeipv4addr(intmask(INADDR_BROADCAST), result) # "dd.dd.dd.dd" format. digits = name.split('.') @@ -111,8 +112,8 @@ 0 <= d1 <= 255 and 0 <= d2 <= 255 and 0 <= d3 <= 255): - return makeipv4addr(htonl( - (d0 << 24) | (d1 << 16) | (d2 << 8) | (d3 << 0)), + return makeipv4addr(intmask(htonl( + (intmask(d0 << 24)) | (d1 << 16) | (d2 << 8) | (d3 << 0))), result) # generic host name to IP conversion @@ -283,7 +284,7 @@ pieces_w = space.unpackiterable(w_address) if not (2 <= len(pieces_w) <= 4): raise RSocketError("AF_INET6 address must be a tuple of length 2 " - "to 4, not %d" % len(pieces)) + "to 4, not %d" % len(pieces_w)) port = space.int_w(pieces_w[1]) if len(pieces_w) > 2: flowinfo = space.int_w(pieces_w[2]) else: flowinfo = 0 @@ -316,19 +317,19 @@ maxlen = sizeof(struct) def __init__(self, path): - addr = _c.sockaddr_un(sun_family = AF_UNIX) + sun = _c.sockaddr_un(sun_family = AF_UNIX) if _c.linux and path.startswith('\x00'): # Linux abstract namespace extension - if len(path) > sizeof(addr.sun_path): + if len(path) > sizeof(sun.sun_path): raise RSocketError("AF_UNIX path too long") else: # regular NULL-terminated string - if len(path) >= sizeof(addr.sun_path): + if len(path) >= sizeof(sun.sun_path): raise RSocketError("AF_UNIX path too long") - addr.sun_path[len(path)] = 0 + sun.sun_path[len(path)] = 0 for i in range(len(path)): - addr.sun_path[i] = ord(path[i]) - self.addr = cast(pointer(addr), _c.sockaddr_ptr).contents + sun.sun_path[i] = ord(path[i]) + self.addr = cast(pointer(sun), _c.sockaddr_ptr).contents self.addrlen = offsetof(_c.sockaddr_un, 'sun_path') + len(path) def as_sockaddr_un(self): @@ -392,14 +393,15 @@ return '' % (self.get_pid(), self.get_groups()) def as_object(self, space): - return space.wrap(self.get_pid(), self.get_groups()) + return space.newtuple([space.wrap(self.get_pid()), + space.wrap(self.get_groups())]) def from_object(space, w_address): try: w_pid, w_groups = space.unpackiterable(w_address, 2) except ValueError: raise TypeError("AF_NETLINK address must be a tuple of length 2") - return NETLINKAddress(space.int_w(w_pid), space.int_w(w_group)) + return NETLINKAddress(space.int_w(w_pid), space.int_w(w_groups)) from_object = staticmethod(from_object) # ____________________________________________________________ @@ -519,9 +521,11 @@ addr, maxlen = make_null_address(self.family) return addr, _c.socklen_t(maxlen) - def accept(self): + def accept(self, SocketClass=None): """Wait for an incoming connection. Return (new socket object, client address).""" + if SocketClass is None: + SocketClass = RSocket if self._select(False) == 1: raise SocketTimeout address, addrlen = self._addrbuf() @@ -530,7 +534,7 @@ raise self.error_handler() address.addrlen = addrlen.value sock = make_socket(newfd, self.family, self.type, self.proto, - self.__class__) + SocketClass) return (sock, address) def bind(self, address): @@ -625,7 +629,7 @@ buf = _c.create_string_buffer(maxlen) bufsize = _c.socklen_t() bufsize.value = maxlen - res = _c.socketgetsockopt(self.fd, level, option, byref(buf), byref(bufsize)) + res = _c.socketgetsockopt(self.fd, level, option, cast(buf, POINTER(c_char)), byref(bufsize)) if res < 0: raise self.error_handler() return buf.raw[:bufsize.value] @@ -734,7 +738,7 @@ self.settimeout(timeout) def setsockopt(self, level, option, value): - res = _c.socketsetsockopt(self.fd, level, option, value, len(value)) + res = _c.socketsetsockopt(self.fd, level, option, c_char_p(value), len(value)) if res < 0: raise self.error_handler() @@ -772,11 +776,16 @@ result.proto = proto result.timeout = defaults.timeout return result +make_socket._annspecialcase_ = 'specialize:arg(4)' class SocketError(Exception): applevelerrcls = 'error' def __init__(self): pass + def get_msg(self): + return '' + def __str__(self): + return self.get_msg() class SocketErrorWithErrno(SocketError): def __init__(self, errno): @@ -785,11 +794,11 @@ class RSocketError(SocketError): def __init__(self, message): self.message = message - def __str__(self): + def get_msg(self): return self.message class CSocketError(SocketErrorWithErrno): - def __str__(self): + def get_msg(self): return _c.socket_strerror(self.errno) def last_error(): @@ -797,7 +806,7 @@ class GAIError(SocketErrorWithErrno): applevelerrcls = 'gaierror' - def __str__(self): + def get_msg(self): return _c.gai_strerror(self.errno) class HSocketError(SocketError): @@ -806,12 +815,12 @@ self.host = host # XXX h_errno is not easily available, and hstrerror() is # marked as deprecated in the Linux man pages - def __str__(self): + def get_msg(self): return "host lookup failed: '%s'" % (self.host,) class SocketTimeout(SocketError): applevelerrcls = 'timeout' - def __str__(self): + def get_msg(self): return 'timed out' class Defaults: @@ -871,7 +880,7 @@ raise HSocketError(hostname) family = addr.family if hostent.contents.h_addrtype != family: - raise CSocketError(errno.EAFNOSUPPORT) + raise CSocketError(_c.EAFNOSUPPORT) aliases = [] h_aliases = hostent.contents.h_aliases From ac at codespeak.net Sun Nov 5 13:27:40 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Sun, 5 Nov 2006 13:27:40 +0100 (CET) Subject: [pypy-svn] r34233 - in pypy/dist/pypy: module/rsocket module/rsocket/test rlib rlib/test Message-ID: <20061105122740.459DC10079@code0.codespeak.net> Author: ac Date: Sun Nov 5 13:27:39 2006 New Revision: 34233 Added: pypy/dist/pypy/rlib/_rsocket_ctypes.py - copied unchanged from r34232, pypy/dist/pypy/module/rsocket/ctypes_socket.py pypy/dist/pypy/rlib/rsocket.py - copied, changed from r34232, pypy/dist/pypy/module/rsocket/rsocket.py pypy/dist/pypy/rlib/test/test_rsocket.py - copied, changed from r34144, pypy/dist/pypy/module/rsocket/test/test_rsocket.py Removed: pypy/dist/pypy/module/rsocket/ctypes_socket.py pypy/dist/pypy/module/rsocket/rsocket.py pypy/dist/pypy/module/rsocket/test/test_rsocket.py Modified: pypy/dist/pypy/module/rsocket/__init__.py pypy/dist/pypy/module/rsocket/interp_func.py pypy/dist/pypy/module/rsocket/interp_socket.py Log: Move rsocket into rlib. Modified: pypy/dist/pypy/module/rsocket/__init__.py ============================================================================== --- pypy/dist/pypy/module/rsocket/__init__.py (original) +++ pypy/dist/pypy/module/rsocket/__init__.py Sun Nov 5 13:27:39 2006 @@ -18,7 +18,7 @@ } def buildloaders(cls): - from pypy.module.rsocket import rsocket + from pypy.rlib import rsocket for name in """ gethostbyname gethostbyname_ex gethostbyaddr gethostname getservbyname getservbyport getprotobyname Modified: pypy/dist/pypy/module/rsocket/interp_func.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_func.py (original) +++ pypy/dist/pypy/module/rsocket/interp_func.py Sun Nov 5 13:27:39 2006 @@ -1,7 +1,7 @@ from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped from pypy.module.rsocket.interp_socket import converted_error, W_RSocket -from pypy.module.rsocket import rsocket -from pypy.module.rsocket.rsocket import SocketError +from pypy.rlib import rsocket +from pypy.rlib.rsocket import SocketError from pypy.interpreter.error import OperationError def gethostname(space): Modified: pypy/dist/pypy/module/rsocket/interp_socket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_socket.py (original) +++ pypy/dist/pypy/module/rsocket/interp_socket.py Sun Nov 5 13:27:39 2006 @@ -2,8 +2,8 @@ from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped from pypy.interpreter.gateway import interp2app -from pypy.module.rsocket.rsocket import RSocket, AF_INET, SOCK_STREAM -from pypy.module.rsocket.rsocket import SocketError, SocketErrorWithErrno +from pypy.rlib.rsocket import RSocket, AF_INET, SOCK_STREAM +from pypy.rlib.rsocket import SocketError, SocketErrorWithErrno from pypy.interpreter.error import OperationError from pypy.interpreter import gateway From santagada at codespeak.net Sun Nov 5 13:39:46 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Sun, 5 Nov 2006 13:39:46 +0100 (CET) Subject: [pypy-svn] r34234 - in pypy/dist/pypy/lang/js: . test Message-ID: <20061105123946.C876010079@code0.codespeak.net> Author: santagada Date: Sun Nov 5 13:39:44 2006 New Revision: 34234 Modified: pypy/dist/pypy/lang/js/astgen.py pypy/dist/pypy/lang/js/interpreter.py pypy/dist/pypy/lang/js/jsobj.py pypy/dist/pypy/lang/js/test/test_interp.py Log: (santagada, guido around) first version with prototypes Modified: pypy/dist/pypy/lang/js/astgen.py ============================================================================== --- pypy/dist/pypy/lang/js/astgen.py (original) +++ pypy/dist/pypy/lang/js/astgen.py Sun Nov 5 13:39:44 2006 @@ -120,7 +120,6 @@ self.strval = strval class Throw(Node): - """The Throw class.""" def __init__(self, exception): self.exception = exception Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sun Nov 5 13:39:44 2006 @@ -25,8 +25,8 @@ class __extend__(Assign): def call(self, context): - #print context.locals.keys(), "|||||", context.globals - #print context.globals['z'] + print context.locals.keys(), "|||||", context.globals + print context.locals['this'] val = self.expr.call(context) print val self.identifier.put(context,val) @@ -67,14 +67,16 @@ name = self.right.get_literal() return w_obj.Get(name) - def put(self, context, val, obj=None): + def put(self, context, val): + print self.left.name, self.right.name, val if isinstance(self.left,Identifier): - assobj = obj or context - assobj.assign(self.left.name,val) + obj = context.access(self.left.name) + print obj.Class + obj.dict_w[self.right.name] = val elif isinstance(self.left,Dot): - assobj = self.left.put(context, val, obj) + obj = self.left.put(context, val) - return assobj + return obj #w_obj = self.left.put(context).GetValue().ToObject() #name = self.right.get_literal() @@ -91,7 +93,10 @@ if self.initialiser is not None: context.assign(self.name, self.initialiser.call(context)) try: - return context.access(self.name) + print "trying to access", self.name + value = context.access(self.name) + print "value", value + return value except NameError: return scope_manager.get_variable(self.name) @@ -148,16 +153,18 @@ class __extend__(New): def call(self, context=None): - obj = W_Object({}) - obj.Class = 'Object' try: constructor = context.access(self.identifier) except NameError: constructor = scope_manager.get_variable(self.identifier) + obj = W_Object({}) + obj.Class = 'Object' obj.dict_w['prototype'] = constructor.dict_w['prototype'] - nctx = ExecutionContext(context) - nctx.assign('this',obj) - constructor.Call(nctx) + #nctx = ExecutionContext(context) + #nctx.assign('this',obj) + #print nctx.locals.keys() + constructor.Call(context, this = obj) + return obj @@ -200,7 +207,7 @@ return W_Number(num_left + num_right) class __extend__(Script): - def call(self, context=None, args=(), params=[], first = False): + def call(self, context=None, args=(), params=[], this=w_Undefined, first = False): ncontext = ExecutionContext(context) for i, item in enumerate(params): try: @@ -218,6 +225,8 @@ w_Arguments = W_Arguments(dict([(str(x),y) for x,y in enumerate(args)])) ncontext.assign('arguments', w_Arguments) + ncontext.assign('this', this) + try: last = w_Undefined for node in self.nodes: Modified: pypy/dist/pypy/lang/js/jsobj.py ============================================================================== --- pypy/dist/pypy/lang/js/jsobj.py (original) +++ pypy/dist/pypy/lang/js/jsobj.py Sun Nov 5 13:39:44 2006 @@ -39,12 +39,16 @@ self.function = function #self.class_ = None - def Call(self, context=None, args=[]): + def Call(self, context, args=[], this = None): if self.function: return self.function.body.call(context=context, - args=args, - params= self.function.params) + args=args, + + params= self.function.params, + this = this + ) else: + print "returning common object" return W_Object({}) def w_string(self): @@ -60,14 +64,6 @@ retval = valueof_meth.Call(this=self) # XXX: check primitiveness of retval return retval -## else: -## if isinstance(valueof_meth, W_Object): -## retval = valueof_meth.Call(this=self) -## # XXX: check primitiveness of retval -## return retval -## tostring_meth = self.Get("toString") -## if isinstance(tostring_meth, W_Object): -## return tostring_meth.Call(this=self) return w_Undefined def ToPrimitive(self, hint=""): @@ -85,19 +81,15 @@ return w_Undefined - #def ToPrimitive(self, hint=""): - # return DefaultValue(hint) - - #def ToString(self): - # raise SeePage(42) - def CanPut(self, name): return True def Put(self, name, w_obj): # INSANE - raise some exceptions in case of read only and such + print "We are insane" if not self.CanPut(name): return # AAAAAAAAAAAAaaaaaaaaaaaa + print name,"=", w_obj self.dict_w[name] = w_obj def __str__(self): Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Sun Nov 5 13:39:44 2006 @@ -221,11 +221,16 @@ """), ["[object Object]"]) def test_new_with_function(self): - self.assert_prints(parse_d(""" + + + c= parse_d(""" x = function() {this.info = 'hello';}; o = new x(); print(o.info); - """), ["hello"]) + """) + print c + self.assert_prints(c + , ["hello"]) def test_vars(self): self.assert_prints(parse_d(""" From santagada at codespeak.net Sun Nov 5 13:40:18 2006 From: santagada at codespeak.net (santagada at codespeak.net) Date: Sun, 5 Nov 2006 13:40:18 +0100 (CET) Subject: [pypy-svn] r34235 - pypy/dist/pypy/lang/js Message-ID: <20061105124018.2E2811007D@code0.codespeak.net> Author: santagada Date: Sun Nov 5 13:40:15 2006 New Revision: 34235 Modified: pypy/dist/pypy/lang/js/interpreter.py Log: missed a file Modified: pypy/dist/pypy/lang/js/interpreter.py ============================================================================== --- pypy/dist/pypy/lang/js/interpreter.py (original) +++ pypy/dist/pypy/lang/js/interpreter.py Sun Nov 5 13:40:15 2006 @@ -159,13 +159,13 @@ constructor = scope_manager.get_variable(self.identifier) obj = W_Object({}) obj.Class = 'Object' + #it should be undefined... to be completed obj.dict_w['prototype'] = constructor.dict_w['prototype'] #nctx = ExecutionContext(context) #nctx.assign('this',obj) #print nctx.locals.keys() constructor.Call(context, this = obj) - return obj From arigo at codespeak.net Sun Nov 5 13:40:54 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 5 Nov 2006 13:40:54 +0100 (CET) Subject: [pypy-svn] r34236 - pypy/dist/pypy Message-ID: <20061105124054.6D26810079@code0.codespeak.net> Author: arigo Date: Sun Nov 5 13:40:53 2006 New Revision: 34236 Modified: pypy/dist/pypy/conftest.py Log: (pedronis, fijal, arigo) More work on the -A option. Now the setup/teardown work if they are simple enough. Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Sun Nov 5 13:40:53 2006 @@ -59,6 +59,8 @@ try: return _SPACECACHE[key] except KeyError: + if option.runappdirect: + return TinyObjSpace(**kwds) mod = __import__('pypy.objspace.%s' % config.objspace.name, None, None, ['Space']) Space = mod.Space @@ -81,6 +83,17 @@ space.eq_w = appsupport.eq_w.__get__(space) return space +class TinyObjSpace(object): + def __init__(self, **kwds): + if kwds: + py.test.skip("cannot runappdirect test: space needs %s" % (kwds,)) + def appexec(self, args, body): + src = py.code.Source("def anonymous" + body) + d = {} + exec src.compile() in d + return d['anonymous'](*args) + + class OpErrKeyboardInterrupt(KeyboardInterrupt): pass @@ -115,9 +128,18 @@ at the class) ourselves. """ def funcnamefilter(self, name): - return name.startswith('test_') or name.startswith('app_test_') + if name.startswith('test_'): + return not option.runappdirect + if name.startswith('app_test_'): + return True + return False + def classnamefilter(self, name): - return name.startswith('Test') or name.startswith('AppTest') + if name.startswith('Test'): + return not option.runappdirect + if name.startswith('AppTest'): + return True + return False def setup(self): # stick py.test raise in module globals -- carefully @@ -234,24 +256,20 @@ print "executing", func self.execute_appex(space, func, space) - def teardown(self): - if option.runappdirect: - return - return super(AppTestFunction, self).teardown() - class AppTestMethod(AppTestFunction): def setup(self): - if option.runappdirect: - return super(AppTestMethod, self).setup() instance = self.parent.obj w_instance = self.parent.w_instance space = instance.space for name in dir(instance): if name.startswith('w_'): - space.setattr(w_instance, space.wrap(name[2:]), - getattr(instance, name)) + if option.runappdirect: + setattr(w_instance, name[2:], getattr(instance, name)) + else: + space.setattr(w_instance, space.wrap(name[2:]), + getattr(instance, name)) def execute(self, target, *args): assert not args @@ -278,18 +296,15 @@ class AppClassInstance(py.test.collect.Instance): Function = AppTestMethod - def teardown(self): - if not option.runappdirect: - return super(AppClassInstance, self).teardown() - def setup(self): - if option.runappdirect: - return super(AppClassInstance, self).setup() instance = self.obj space = instance.space w_class = self.parent.w_class - self.w_instance = space.call_function(w_class) + if option.runappdirect: + self.w_instance = instance + else: + self.w_instance = space.call_function(w_class) class AppClassCollector(PyPyClassCollector): Instance = AppClassInstance @@ -298,20 +313,16 @@ return keyword == 'applevel' or \ super(AppClassCollector, self).haskeyword(keyword) - def teardown(self): - if not option.runappdirect: - return super(AppClassCollector, self).teardown() - def setup(self): - if option.runappdirect: - #self.class_ = self.obj - return super(AppClassCollector, self).setup() cls = self.obj space = cls.space clsname = cls.__name__ - w_class = space.call_function(space.w_type, - space.wrap(clsname), - space.newtuple([]), - space.newdict()) + if option.runappdirect: + w_class = cls + else: + w_class = space.call_function(space.w_type, + space.wrap(clsname), + space.newtuple([]), + space.newdict()) self.w_class = w_class From ac at codespeak.net Sun Nov 5 15:08:45 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Sun, 5 Nov 2006 15:08:45 +0100 (CET) Subject: [pypy-svn] r34239 - pypy/dist/pypy/module/_socket Message-ID: <20061105140845.6FC021007C@code0.codespeak.net> Author: ac Date: Sun Nov 5 15:08:43 2006 New Revision: 34239 Removed: pypy/dist/pypy/module/_socket/ Log: Remove old implementation of socket. Use rsocket instead. From cfbolz at codespeak.net Sun Nov 5 15:50:42 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 15:50:42 +0100 (CET) Subject: [pypy-svn] r34240 - pypy/extradoc/sprintinfo/ddorf2006b Message-ID: <20061105145042.C4CCB10080@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 15:50:39 2006 New Revision: 34240 Added: pypy/extradoc/sprintinfo/ddorf2006b/report.txt Log: check in the sprint report Added: pypy/extradoc/sprintinfo/ddorf2006b/report.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/ddorf2006b/report.txt Sun Nov 5 15:50:39 2006 @@ -0,0 +1,160 @@ +Hi all! + +it is with a familiar level of tiredness that we bring you these lines. +We are again sitting in one of the rooms of the Institut f?r Informatik, +after 6 days of sprinting. As usual, it has been a busy and productive +(and sometimes strange) sprint. + +One of the new developments of the sprint was the work of Leonardo +Santadaga, our "Summer" of PyPy student from Brazil. Leonardo proposed +to write a JavaScript interpreter, had his proposal accepted and now +gets his travel to sprints funded. This work has seen good progress +every day, so that we now have an interpreter that handles simple +snippet of JavaScript code. Leonardo had help from various other people +changing over the course of the sprint such as Maciek, Guido (the +reluctant Master of JavaScript) and Stephan. The parser is currently +stolen from them Narcissus project, and the interpreter does not +translate yet. For less than a weeks work though we think are doing +pretty well (we are trying not to distract ourselves with crazy thoughts +like translating a JS interpreter to JS or wondering how fast it would +be after applying the magic JIT technology). Although Leonardo will be +flying back to Brazil soon he will continue working on it (at least if +he finds sufficient time between caring for his beloved new MacBook). + +The other PyPy sprint virgin was Niko Matsakis, a graduate student at +ETH Z?rich. To start with he worked with help of Antonio on the +fledgling JVM backend. Antonio and Niko worked on moving code out of the +CLI backend to be shared with other object-oriented backends. They got +as far as supporting nearly everything except constants (which as usual +turns out to be the hardest thing to support). The team was split up +later in the week to work on Other Things. Niko only found out after he +_left_ the sprint that Samuele is one of the authors of Jython, which he +is interested in since some of his students are working on it. + +Another topic that received attention all week was the JIT (dramatic +music). The architecture of the JIT has now crystallized enough to be +able to split up the work into the (for mere mortals largely +incomprehensible) "time shifting" front end and the (much more +straightforward) code generating backends. + +Samuele and Arre started the week by adding some missing pieces for +things called "portals" in the front end. A portal is the part of your +code that marks the entry into JIT-land. For the PyPy interpreter it is +expected to be the bytecode dispatcher (or in general the main loop of +an interpreter). The JIT tests now take so long that they also had time +to work on translating rsocket, which is an RPython-level socket +library, and using it for implementing the socket module. + +For the first few days of the sprint Armin and Richard took a DFA engine +(deterministic finite automaton) that Carl Friedrich wrote to lex Prolog +code and adapted it to be jittable. On Wednesday Armin tried cast some +light on the dark internals of the JIT with a short talk about this +example. The DFA engine is viewed as interpreting the specification of +the automaton and then turned into a compiler by the timeshifter. This +compiler does not work in advance. Instead calls to the compiler are +inserted into the transformed version of the DFA engine. If the DFA +engine is used to match a string against the automaton, the compiler +produces somewhat efficient machine code for doing that. + +Richard's work (with the help of Armin and Arre) for the rest of the +sprint can be summarized as improving the timeshifter to be able to +"un-adapt" this DFA engine until it at least resembled the original +code. This involved adding a new piece of terminology to the +ever-growing JIT jargon "deep-freezing" (something to do with structures +that are so constant that even their contents are constant). + +Concurrently, and with its own set of problems, Michael worked on the +JIT backend all week. He started together with Armin to document all the +sometimes non-intuitively named methods of the backend API, which has +only emerged in the last month or so. They renamed the most strange ones +afterwards. After that Michael and Eric did a little polishing of the +PowerPC backend and began to investigate writing an LLVM backend (C++ is +hard). Eric had to leave mid-sprint so Michael continued with Niko +(another Mac fanatic with insufficient funds to have a MacBook) to +improve the PowerPC backend. This involved fights with the calling +conventions, writing a greedy register allocator and lots of time +waiting for tests (they didn't manage to find a nice side-project). At +the end of the week the PPC backend can actually handle no more programs +than it could at the beginning, but we are very much happier about its +foundations. + +After the break-day Samuele and Maciek started working on the project +that would occupy them for the rest of the sprint: adding "transparent +proxy objects" to the PyPy interpreter. A transparent proxy is something +that claims to be of a specific type (e.g. a list) but all operations +are forwarded to a controller which can choose how to implement those in +an arbitrary way, such as retrieving the values from a database, a +remote host or similar. For most operations the multi-method based +implementation of the standard object space made this relatively +straightforward. For the black-sheep operations this was some more work +but this is still something that, according to Samuele, "if you tried +this with CPython it would take so long that you wouldn't want it +anymore when you're finished". The motivation for writing these proxy +thingies is to experiment with transparent remote objects, orthogonal +persistence and security (there is also a plan to steal the pygame from +CPython by using them). + +There was a little work on the side on the upcoming "apigen" tool, which +is a new part of the py-lib. This is something Maciek, Guido and Brian +Dorsey started before the sprint. It runs all the tests of a package +(currently only the py-lib) and observes the behaviour of the running +code. From this it generates API documentation with additional +information like what types the arguments of the functions had, which +attributes of instances were changed... + +Carl Friedrich spent quite some time on the deeply brain-taxing task of +populating the new rlib directory by moving various files there and +fixing all the imports. The rlib directory is meant to contain a library +useable from RPython programs, so the code in there is all RPython and +is supposed to make up in some way for the lack of a standard library in +RPython. Such modules have been accumulating in various places where +they don't really belong. + +Samuele, Anto and Carl Friedrich had a planning meeting for the +integration of the .NET framework with the Python interpreter that Anto +plans to do. This means being able to call .NET functions and use .NET +classes from pypy.net. Samuele presented the two major approaches: The +simpler, but more annoying one is to write wrapper classes that have the +actual .net object as an attribute. For this you need to do conversions +at the language boundaries and thus suffer a performance penalty. The +other approach is to identify some of the classes of the PyPy +interpreter with .NET classes so that you can pass them around freely. + +Guido and Carl Friedrich worked a small bit on the build tool, which +supposedly gives people a way to build PyPy on remote hosts. This is now +somewhat working modulo lots of annoying real-life details +(error-handling being one of them). Together with Samuele they had a +discussion about what to do in this area in the future. Various +realistic ideas (such as a web frontend) and unrealistic ideas (having a +quake configuration tool where you can hunt down and kill configuration +settings that you don't want) were discussed. + +A very positive aspect of the sprint is that Christian who has been ill +for quite a while is back with us and now finding all the things we have +broken on windows in the meantime. + +Carl Friedrich with the help of Anto and Guido spent a big chunk of time +near the end of the sprint in refactoring PyPy's file implementation. +The first step was converting the stream implementation which was living +at app-level before to be RPython and thus useable by other RPython +programs (such as Prolog interpreters, hint hint). Afterwards they +converted the file implementation to use the new facilities, which +involved the usual fighting with the annotator to make it work. This +should also make it possible to remove some horrendous hacks from the +.NET backend, as the new file implementation should make it easier to +move away from using a POSIX-like model (actually the .NET backend +contained a POSIX compatibility layer written by Anto just for this +purpose). + +Since we cannot seem to come up with a witty closing remark, we just +stop. + +Ade, + +Carl Friedrich & mwh + +-- + "... and the end result of all this is a dating site that matches + people according to the sort of PyPy they compile." + -- Samuele Pedroni + From niko at codespeak.net Sun Nov 5 15:55:08 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Sun, 5 Nov 2006 15:55:08 +0100 (CET) Subject: [pypy-svn] r34241 - in pypy/dist/pypy/translator: jvm jvm/src jvm/test oosupport Message-ID: <20061105145508.7BAA71007C@code0.codespeak.net> Author: niko Date: Sun Nov 5 15:55:06 2006 New Revision: 34241 Added: pypy/dist/pypy/translator/jvm/builtin.py pypy/dist/pypy/translator/jvm/constant.py pypy/dist/pypy/translator/jvm/test/test_class.py pypy/dist/pypy/translator/oosupport/constant.py pypy/dist/pypy/translator/oosupport/database.py Modified: pypy/dist/pypy/translator/jvm/database.py pypy/dist/pypy/translator/jvm/generator.py pypy/dist/pypy/translator/jvm/genjvm.py pypy/dist/pypy/translator/jvm/node.py pypy/dist/pypy/translator/jvm/src/PyPy.java pypy/dist/pypy/translator/jvm/typesystem.py pypy/dist/pypy/translator/oosupport/metavm.py Log: Rather large check-in with JVM restructing. Warning: new code in oosupport will likely change to match CLI more closely as I integrate those. Highlights: 1. Begin the work pulling out constant generation and database code and making it common between CLI and JVM. Right now, it's only used by the JVM. Next check-in will be to integrate with CLI. 2. Unify database nodes and type system both for instances and built-ins. This simplifies JVM code considerably. 3. Implement several other random bug fixes. Added: pypy/dist/pypy/translator/jvm/builtin.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/jvm/builtin.py Sun Nov 5 15:55:06 2006 @@ -0,0 +1,96 @@ +from pypy.translator.jvm import typesystem as jvmtype +from pypy.translator.jvm import generator as jvmgen +from pypy.rpython.ootypesystem import ootype +from pypy.translator.jvm.typesystem import \ + jInt, jVoid, jStringBuilder, jString, jPyPy, jChar + +jStringBuilder = jvmtype.jStringBuilder + +# ______________________________________________________________________ +# Mapping of built-in OOTypes to JVM types + +class JvmBuiltInType(jvmtype.JvmClassType): + + """ + Represents built-in types to JVM. May optionally be associated + with an OOTYPE; if it is, then we will support lookup of the OOTYPE + methods and will re-map them as needed to the JVM equivalents. + """ + + def __init__(self, db, classty, OOTYPE): + jvmtype.JvmClassType.__init__(self, classty.name) + self.db = db + self.OOTYPE = OOTYPE # might be None + + # We need to create a mapping for any generic parameters this + # OOTYPE may have. Other than SELFTYPE_T, we map each generic + # argument to ootype.ROOT. We use a hack here where we assume + # that the only generic parameters are named SELFTYPE_T, + # ITEMTYPE_T, KEYTYPE_T, or VALUETYPE_T. + self.generics = {} + if hasattr(self.OOTYPE, 'SELFTYPE_T'): + self.generics[self.OOTYPE.SELFTYPE_T] = self.OOTYPE + for param in ('ITEMTYPE_T', 'KEYTYPE_T', 'VALUETYPE_T'): + if hasattr(self.OOTYPE, param): + self.generics[getattr(self.OOTYPE, param)] = ootype.ROOT + + def lookup_field(self, fieldnm): + """ Given a field name, returns a jvmgen.Field object """ + _, FIELDTY = self.OOTYPE._lookup_field(fieldnm) + jfieldty = self.db.lltype_to_cts(FIELDTY) + return jvmgen.Field( + self.descriptor.class_name(), fieldnm, jfieldty, False) + + def _map(self, ARG): + """ Maps ootype ARG to a java type. If arg is one of our + generic arguments, substitutes the appropriate type before + performing the mapping. """ + return self.db.lltype_to_cts(self.generics.get(ARG,ARG)) + + def lookup_method(self, methodnm): + """ Given the method name, returns a jvmgen.Method object """ + + # Look for a shortcut method + try: + key = (self.OOTYPE.__class__, methodnm) + print "key=%r" % (key,) + print "hash=%r" % (built_in_methods,) + return built_in_methods[key] + except KeyError: pass + + # Lookup the generic method by name. + GENMETH = self.OOTYPE._GENERIC_METHODS[methodnm] + + # Create an array with the Java version of each type in the + # argument list and return type. + jargtypes = [self._map(P) for P in GENMETH.ARGS] + jrettype = self._map(GENMETH.RESULT) + return jvmgen.Method.v(self, methodnm, jargtypes, jrettype) + +# When we lookup a method on a BuiltInClassNode, we first check +# the 'built_in_methods' table. This allows us to redirect to other +# methods if we like. + +def _ll_build_method(): + # Choose an appropriate ll_build depending on what representation + # we are using for ootype.String: + if True: # XXX db.using_byte_array... + return jvmgen.Method.v( + jStringBuilder, "toString", (),jString) + return jvmgen.Method.s( + jvmgen.PYPYJAVA, "ll_build", (jStringBuilder,), jOOString) + +built_in_methods = { + (ootype.StringBuilder.__class__, "ll_allocate"): + jvmgen.Method.v(jStringBuilder, "ensureCapacity", (jInt,), jVoid), + + (ootype.StringBuilder.__class__, "ll_append_char"): + jvmgen.Method.s(jPyPy, "ll_append_char", (jStringBuilder, jChar), jVoid), + + (ootype.StringBuilder.__class__, "ll_append"): + jvmgen.Method.s(jPyPy, "ll_append", (jStringBuilder, jString), jVoid), + + (ootype.StringBuilder.__class__, "ll_build"): + _ll_build_method() + + } Added: pypy/dist/pypy/translator/jvm/constant.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/jvm/constant.py Sun Nov 5 15:55:06 2006 @@ -0,0 +1,81 @@ +from pypy.translator.jvm.generator import \ + Field, Method, ACONST_NULL, ICONST, LDC, DCONST_0, DCONST_1, LDC2 +from pypy.translator.oosupport.constant import \ + RecordConst, InstanceConst, ClassConst +from pypy.translator.jvm.typesystem import jPyPyConst + +# ___________________________________________________________________________ +# Simple Constants +# +# We create simple dummy constant objects that follow the same +# inteface as the complex constants from oosupport/constant.py. None +# of these requires initialization, so they only support push() and +# they should never find their way into the database's constant list. + +class Const(object): + def push(self, gen): + """ Emits code required to reference a constant. Usually invoked + by generator.emit() """ + raise NotImplementedError + +class VoidConst(object): + def push(self, gen): + pass + +class NullConst(object): + def push(self, gen): + gen.emit(ACONST_NULL) + +class DoubleConst(Const): + def __init__(self, value): + self.value = value + def push(self, gen): + if value == 0.0: + gen.emit(DCONST_0) + elif value == 1.0: + gen.emit(DCONST_1) + else: + gen.emit(LDC2, self.value) + +class UnicodeConst(Const): + def __init__(self, value): + self.value = value + def push(self, gen): + assert isinstance(self.value, unicode) + gen.emit(LDC, res) + +# ___________________________________________________________________________ +# Complex Constants + +class JVMFieldStorage(object): + """ A mix-in for the oosupport constant classes that stores the + pointer for the constant into a field on a class. It implements + the push() and store() methods used by the oosupport classes and + elsewhere.""" + def __init__(self): + # Note that self.name and self.value are set by the oosupport + # constance class: + fieldty = self.db.lltype_to_cts(self.value._TYPE) + self.fieldobj = Field(jPyPyConst.name, self.name, fieldty, True) + + def push(self, gen): + self.fieldobj.load(gen) + + def store(self, gen): + self.fieldobj.store(gen) + +class JVMRecordConst(RecordConst, JVMFieldStorage): + def __init__(self, db, record, count): + RecordConst.__init__(self, db, record, count) + JVMFieldStorage.__init__(self) + +class JVMInstanceConst(InstanceConst, JVMFieldStorage): + def __init__(self, db, obj, record, count): + InstanceConst.__init__(self, db, obj, record, count) + JVMFieldStorage.__init__(self) + +class JVMClassConst(ClassConst, JVMFieldStorage): + def __init__(self, db, class_, count): + ClassConst.__init__(self, db, class_, count) + JVMFieldStorage.__init__(self) + Modified: pypy/dist/pypy/translator/jvm/database.py ============================================================================== --- pypy/dist/pypy/translator/jvm/database.py (original) +++ pypy/dist/pypy/translator/jvm/database.py Sun Nov 5 15:55:06 2006 @@ -1,144 +1,69 @@ """ -The database tracks which graphs have already been generated, and maintains -a worklist. It also contains a pointer to the type system. It is passed -into every node for generation along with the generator. +The database centralizes information about the state of our translation, +and the mapping between the OOTypeSystem and the Java type system. """ + from cStringIO import StringIO from pypy.rpython.lltypesystem import lltype from pypy.rpython.ootypesystem import ootype -from pypy.translator.jvm.typesystem import jvm_method_desc, ootype_to_jvm +from pypy.translator.jvm import typesystem as jvmtype from pypy.translator.jvm import node from pypy.translator.jvm.option import getoption import pypy.translator.jvm.generator as jvmgen +import pypy.translator.jvm.constant as jvmconst from pypy.translator.jvm.typesystem import \ - jStringBuilder, jInt, jVoid, jString, jOOString, jChar + jStringBuilder, jInt, jVoid, jString, jChar, jPyPyConst, jObject +from pypy.translator.jvm.builtin import JvmBuiltInType -# When we lookup a method on a BuiltInClassNode, we first check -# the 'built_in_methods' table. This allows us to redirect to other -# methods if we like. - -def _ll_build_method(): - # Choose an appropriate ll_build depending on what representation - # we are using for ootype.String: - if jOOString == jString: - return jvmgen.Method.v( - jStringBuilder.class_name(), "toString", (),jString) - return jvmgen.Method.s( - jvmgen.PYPYJAVA, "ll_build", (jStringBuilder,), jOOString) - -built_in_methods = { - (ootype.StringBuilder.__class__, "ll_allocate"): - jvmgen.Method.v(jStringBuilder.class_name(), "ensureCapacity", - (jInt,), jVoid), - - (ootype.StringBuilder.__class__, "ll_append_char"): - jvmgen.Method.s(jvmgen.PYPYJAVA, "ll_append_char", - (jStringBuilder, jChar), jVoid), - - (ootype.StringBuilder.__class__, "ll_append"): - jvmgen.Method.s(jvmgen.PYPYJAVA, "ll_append", - (jStringBuilder, jOOString), jVoid), - - # XXX will not work with --byte-arrays - (ootype.StringBuilder.__class__, "ll_build"): - _ll_build_method() - - } +from pypy.translator.oosupport.database import Database as OODatabase -class BuiltInClassNode(object): - """ - This is a fake node that is returned instead of a node.Class object - when pending_class is invoked on a built-in type. It allows other - code to query the fields and methods. - """ - - def __init__(self, db, OOTYPE): - self.db = db - self.OOTYPE = OOTYPE - self.jvmtype = db.lltype_to_cts(OOTYPE) - - # Create a generic mapping. Other than SELFTYPE_T, we map each - # generic argument to ootype.ROOT. We use a hack here where - # we assume that the only generic parameters are named - # SELFTYPE_T, ITEMTYPE_T, KEYTYPE_T, or VALUETYPE_T. - - self.generics = {} - - if hasattr(self.OOTYPE, 'SELFTYPE_T'): - self.generics[self.OOTYPE.SELFTYPE_T] = self.OOTYPE - - for param in ('ITEMTYPE_T', 'KEYTYPE_T', 'VALUETYPE_T'): - if hasattr(self.OOTYPE, param): - self.generics[getattr(self.OOTYPE, param)] = ootype.ROOT - - def jvm_type(self): - return self.jvmtype - - def lookup_field(self, fieldnm): - """ Given a field name, returns a jvmgen.Field object """ - _, FIELDTY = self.OOTYPE._lookup_field(fieldnm) - jfieldty = self.db.lltype_to_cts(FIELDTY) - return jvmgen.Field( - self.jvmtype.class_name(), fieldnm, jfieldty, False) - - def _map(self, ARG): - """ Maps ootype ARG to a java type. If arg is one of our - generic arguments, substitutes the appropriate type before - performing the mapping. """ - return self.db.lltype_to_cts(self.generics.get(ARG,ARG)) - - def lookup_method(self, methodnm): - """ Given the method name, returns a jvmgen.Method object """ - - # Look for a shortcut method - try: - key = (self.OOTYPE.__class__, methodnm) - print "key=%r" % (key,) - print "hash=%r" % (built_in_methods,) - return built_in_methods[key] - except KeyError: pass - - # Lookup the generic method by name. - GENMETH = self.OOTYPE._GENERIC_METHODS[methodnm] - - # Create an array with the Java version of each type in the - # argument list and return type. - jargtypes = [self._map(P) for P in GENMETH.ARGS] - jrettype = self._map(GENMETH.RESULT) - return jvmgen.Method( - self.jvmtype.class_name(), - methodnm, - jvm_method_desc(jargtypes, jrettype), - opcode=jvmgen.INVOKEVIRTUAL) - +# ______________________________________________________________________ +# Database object -class Database: +class Database(OODatabase): def __init__(self, genoo): - # Public attributes: - self.genoo = genoo + OODatabase.__init__(self, genoo) # Private attributes: self._classes = {} # Maps ootype class objects to node.Class objects, # and JvmType objects as well - self._counter = 0 # Used to create unique names self._functions = {} # graph -> jvmgen.Method self._function_names = {} # graph --> function_name self._constants = {} # flowmodel.Variable --> jvmgen.Const - self._pending_nodes = set() # Worklist - self._rendered_nodes = set() + # _________________________________________________________________ + # Java String vs Byte Array + # + # We allow the user to configure whether Python strings are stored + # as Java strings, or as byte arrays. The latter saves space; the + # former may be faster. + using_byte_array = False + + # XXX have to fill this in + + # _________________________________________________________________ + # Miscellaneous + def _uniq(self, nm): - cnt = self._counter - self._counter += 1 - return nm + "_" + str(cnt) + "_" + return nm + "_" + str(self.unique()) def _pkg(self, nm): return "%s.%s" % (getoption('package'), nm) + def class_name(self, TYPE): + jtype = self.lltype_to_cts(TYPE) + assert isinstance(jtype, jvmtype.JvmClassType) + return jtype.name + + # _________________________________________________________________ + # Node Creation + # + # Creates nodes that represents classes, functions, simple constants. + def _function_for_graph(self, classobj, funcnm, is_static, graph): """ @@ -153,46 +78,45 @@ funcobj = node.Function( self, classobj, funcnm, jargtypes, jrettype, graph, is_static) return funcobj - - def pending_node(self, node): - self._pending_nodes.add(node) - - def pending_class(self, OOCLASS): - if not isinstance(OOCLASS, ootype.Instance): - return BuiltInClassNode(self, OOCLASS) + + def _translate_instance(self, OOTYPE): + assert isinstance(OOTYPE, ootype.Instance) + assert OOTYPE is not ootype.ROOT # Create class object if it does not already exist: - if OOCLASS in self._classes: - return self._classes[OOCLASS] + if OOTYPE in self._classes: + return self._classes[OOTYPE] # Resolve super class first - if OOCLASS._superclass: - superclsnm = self.lltype_to_cts(OOCLASS._superclass).class_name() - else: - superclsobj = "java.lang.Object" #? + assert OOTYPE._superclass + supercls = self.pending_class(OOTYPE._superclass) # TODO --- make package of java class reflect the package of the # OO class? clsnm = self._pkg( - self._uniq(OOCLASS._name.replace('.','_'))) - clsobj = node.Class(clsnm, superclsnm) + self._uniq(OOTYPE._name.replace('.','_'))) + clsobj = node.Class(clsnm, supercls) + + print "Class %s has super %s" % ( + clsnm, supercls.name) # Store the class object for future calls - self._classes[OOCLASS] = clsobj - self._classes[clsobj.jvm_type()] = clsobj + self._classes[OOTYPE] = clsobj # TODO --- mangle field and method names? Must be # deterministic, or use hashtable to avoid conflicts between # classes? # Add fields: - for fieldnm, (FIELDOOTY, fielddef) in OOCLASS._fields.iteritems(): + for fieldnm, (FIELDOOTY, fielddef) in OOTYPE._fields.iteritems(): + print "Class %s has field %s of type %s" % ( + clsobj.name, fieldnm, FIELDOOTY) if FIELDOOTY is ootype.Void: continue fieldty = self.lltype_to_cts(FIELDOOTY) clsobj.add_field(jvmgen.Field(clsnm, fieldnm, fieldty, False)) # Add methods: - for mname, mimpl in OOCLASS._methods.iteritems(): + for mname, mimpl in OOTYPE._methods.iteritems(): if not hasattr(mimpl, 'graph'): # Abstract method TODO @@ -203,21 +127,21 @@ # there would be a type mismatch. args = mimpl.graph.getargs() SELF = args[0].concretetype - if not ootype.isSubclass(OOCLASS, SELF): continue + if not ootype.isSubclass(OOTYPE, SELF): continue mobj = self._function_for_graph( clsobj, mname, False, mimpl.graph) clsobj.add_method(mobj) # currently, we always include a special "dump" method for debugging # purposes - dump_method = node.TestDumpMethod(self, OOCLASS, clsobj) + dump_method = node.TestDumpMethod(self, OOTYPE, clsobj) clsobj.add_dump_method(dump_method) self.pending_node(clsobj) return clsobj - def class_obj_for_jvm_type(self, jvmtype): - return self._classes[jvmtype] + def pending_class(self, OOTYPE): + return self.lltype_to_cts(OOTYPE) def pending_function(self, graph): """ @@ -230,48 +154,66 @@ if graph in self._functions: return self._functions[graph] classnm = self._pkg(self._uniq(graph.name)) - classobj = node.Class(classnm, 'java.lang.Object') + classobj = node.Class(classnm, self.pending_class(ootype.ROOT)) funcobj = self._function_for_graph(classobj, "invoke", True, graph) classobj.add_method(funcobj) self.pending_node(classobj) res = self._functions[graph] = funcobj.method() return res - def len_pending(self): - return len(self._pending_nodes) - - def pop(self): - return self._pending_nodes.pop() - - def gen_constants(self, gen): - pass + # _________________________________________________________________ + # Constant Emitting + # + # We place all constants in a special "constant" class + # + # XXX I don't particularly like this code being here. database + # shouldn't be so specific? Guess it's okay... + + RecordConst = jvmconst.JVMRecordConst + InstanceConst = jvmconst.JVMInstanceConst + ClassConst = jvmconst.JVMClassConst + + def _begin_gen_constants(self, gen, all_constants): + gen.begin_class(jPyPyConst, jObject) - def record_const(self, constobj): - TYPE = constobj.concretetype - - # Handle the simple cases: - if TYPE is ootype.Void: - return jvmgen.VoidConst() - elif TYPE in (ootype.Bool, ootype.Signed): - return jvmgen.SignedIntConst(int(constobj.value)) - elif TYPE is ootype.Char or TYPE is ootype.UniChar: - return jvmgen.SignedIntConst(ord(constobj.value)) - elif TYPE is ootype.SignedLongLong: - return jvmgen.SignedLongConst(int(constobj.value)) - elif TYPE is ootype.UnsignedLongLong: - return jvmgen.UnsignedLongConst(int(constobj.value)) - elif TYPE is ootype.Float: - return jvmgen.DoubleConst(constobj.value) - - # Handle the complex cases: - # In this case, we will need to create a method to - # initialize the value and a field. - # For NOW, we create a new class PER constant. - # Clearly this is probably undesirable in the long - # term. - return jvmgen.WarnNullConst() # TODO + for c in all_constants: + assert isinstance(c, jvmconst.JVMFieldStorage) + gen.add_field(c.fieldobj) + + # the constant initialization code is broken up into special + # methods that are then invoked from --- this is to + # prevent the init functions from getting too big + self._constant_steps = 1 + gen.begin_function('constant_init_0', [], [], jVoid, True) + return gen + + def _interrupt_gen_constants(self): + gen.return_val(jVoid) + gen.end_function() # end constant_init_N + + next_nm = "constant_init_%d" % self._constant_steps + self._constant_steps += 1 + gen.begin_function(next_nm, [], [], jVoid, True) + + def _end_gen_constants(self, gen): + gen.return_val(jVoid) + gen.end_function() # end constant_init_N + + # The static init code just needs to call constant_init_1..N + gen.begin_function('', [], [], jVoid, True) + for x in range(self._constant_steps): + m = jvmgen.Method.s(jPyPyConst, "constant_init_%d" % x, [], jVoid) + gen.emit(m) + gen.return_val(jVoid) + gen.end_function() + + gen.end_class() - # Other + # _________________________________________________________________ + # Type printing functions + # + # Returns a method that prints details about the value out to + # stdout. Should generalize to make it allow for stderr as well. _type_printing_methods = { ootype.Signed:jvmgen.PYPYDUMPINT, @@ -282,16 +224,35 @@ ootype.Class:jvmgen.PYPYDUMPOBJECT, ootype.String:jvmgen.PYPYDUMPSTRING, ootype.StringBuilder:jvmgen.PYPYDUMPOBJECT, + ootype.Void:jvmgen.PYPYDUMPVOID, } def generate_dump_method_for_ootype(self, OOTYPE): + """ + Assuming than an instance of type OOTYPE is pushed on the + stack, returns a Method object that you can invoke. This + method will require that you also push an integer (usually 0) + that represents the indentation, and then invoke it. i.e., you + can do something like: + + > gen.load(var) + > mthd = db.generate_dump_method_for_ootype(var.concretetype) + > gen.emit(jvmgen.ICONST, 0) + > mthd.invoke(gen) + + to print the value of 'var'. + """ if OOTYPE in self._type_printing_methods: return self._type_printing_methods[OOTYPE] pclass = self.pending_class(OOTYPE) assert hasattr(pclass, 'dump_method'), "No dump_method for %r" % (OOTYPE, ) return pclass.dump_method.method() + # _________________________________________________________________ # Type translation functions + # + # Functions which translate from OOTypes to JvmType instances. + # FIX --- JvmType and their Class nodes should not be different. def escape_name(self, nm): # invoked by oosupport/function.py; our names don't need escaping? @@ -302,29 +263,56 @@ and name of the given variable""" return self.lltype_to_cts(llv.concretetype), llv.name + # Dictionary for scalar types; in this case, if we see the key, we + # will return the value + ootype_to_scalar = { + ootype.Void: jvmtype.jVoid, + ootype.Signed: jvmtype.jInt, + ootype.Unsigned: jvmtype.jInt, + ootype.SignedLongLong: jvmtype.jLong, + ootype.UnsignedLongLong: jvmtype.jLong, + ootype.Bool: jvmtype.jBool, + ootype.Float: jvmtype.jDouble, + ootype.Char: jvmtype.jByte, + ootype.UniChar: jvmtype.jChar, + ootype.Class: jvmtype.jClass, + ootype.ROOT: jvmtype.jObject, # count this as a scalar... + } + + # Dictionary for non-scalar types; in this case, if we see the key, we + # will return a JvmBuiltInType based on the value + ootype_to_builtin = { + ootype.String: jvmtype.jString, + ootype.StringBuilder: jvmtype.jStringBuilder + } + def lltype_to_cts(self, OOT): """ Returns an instance of JvmType corresponding to - the given OOType""" - - # Check the easy cases - if OOT in ootype_to_jvm: - return ootype_to_jvm[OOT] + the given OOType """ - # Now handle the harder ones + # Handle built-in types: + if OOT in self.ootype_to_scalar: + return self.ootype_to_scalar[OOT] if isinstance(OOT, lltype.Ptr) and isinstance(t.TO, lltype.OpaqueType): return jObject + if OOT in self.ootype_to_builtin: + return JvmBuiltInType(self, self.ootype_to_builtin[OOT], OOT) + + # Handle non-built-in-types: if isinstance(OOT, ootype.Instance): - return self.pending_class(OOT).jvm_type() + return self._translate_instance(OOT) if isinstance(OOT, ootype.Record): - return XXX + return self._translate_record(OOT) if isinstance(OOT, ootype.StaticMethod): return XXX + + assert False, "Untranslatable type %s!" % OOT - # Uh-oh - unhandled_case - - # Invoked by genoo: - # I am not sure that we need them + # _________________________________________________________________ + # Uh.... + # + # These functions are invoked by the code in oosupport, but I + # don't think we need them or use them otherwise. def record_function(self, graph, name): self._function_names[graph] = name Modified: pypy/dist/pypy/translator/jvm/generator.py ============================================================================== --- pypy/dist/pypy/translator/jvm/generator.py (original) +++ pypy/dist/pypy/translator/jvm/generator.py Sun Nov 5 15:55:06 2006 @@ -1,29 +1,49 @@ import os # from pypy.objspace.flow import model as flowmodel from pypy.translator.oosupport.metavm import Generator -from pypy.translator.jvm.typesystem import \ - JvmType, jObject, jPrintStream, jvm_for_class, jVoid, jvm_method_desc, \ - jInt, jByteArray, jOOString, jString, jStringBuilder from pypy.rpython.ootypesystem import ootype +from pypy.translator.oosupport.constant import push_constant +from pypy.translator.jvm.typesystem import \ + JvmType, jString, jInt, jLong, jDouble, jBool, jString, \ + jPyPy, jVoid, jMath, desc_for_method, jPrintStream, jClass, jChar, \ + jObject, jByteArray # ___________________________________________________________________________ # Helper class string constants -PYPYJAVA = "pypy.PyPy" +PYPYJAVA = jPyPy.name # ___________________________________________________________________________ -# JVM Opcode Flags: -# -# Indicates certain properties of each opcode. Used mainly for debugging -# assertions +# Miscellaneous helper functions + +def _isnan(v): + return v != v*1.0 or (v == 1.0 and v == 2.0) -NOFLAGS = 0 -BRANCH = 1 # Opcode is a branching opcode (implies a label argument) -INVOKE = 2 # Opcode is a Method object -CONST5 = 4 # Opcode is specialized for int arguments from -1 to 5 -CONST3 = 8 # Opcode is specialized for int arguments from 0 to 3 -CLASSINM = 16 # Argument is an internal class name -FIELD = 32 # Opcode is a Field object +def _isinf(v): + return v!=0 and (v == v*2) + +def _unsigned_to_signed_32(val): + """ In the JVM, we store unsigned integers in a signed integer slot + (since JVM has no signed integers). This function converts an + unsigned value Python integer (possibly a long) into its corresponding + Python signed integer. """ + if val <= 0x7FFFFFFF: + return int(val) + return int(_two_comp_32(val)) + +def _unsigned_to_signed_64(val): + """ Same as _unsigned_to_signed_32, but for longs. """ + if val <= 0x7FFFFFFFFFFFFFFF: + return val + return _two_comp_64(val) + +def _two_comp_32(val): + """ Returns the 32 bit two's complement. """ + return -((val ^ 0xFFFFFFFF)+1) + +def _two_comp_64(val): + """ Returns the 64 bit two's complement. """ + return -((val ^ 0xFFFFFFFFFFFFFFFF)+1) # ___________________________________________________________________________ # JVM Opcodes: @@ -31,40 +51,49 @@ # Map from symbolic name to an instance of the Opcode class class Opcode(object): - def __init__(self, flags, jvmstr): + def __init__(self, jvmstr): """ flags is a set of flags (see above) that describe opcode jvmstr is the name for jasmin printouts """ - self.flags = flags self.jvmstr = jvmstr def __repr__(self): return "" % (self.jvmstr, self.flags) - - def specialize_opcode(self, args): + + def specialize(self, args): """ Process the argument list according to the various flags. Returns a tuple (OPCODE, ARGS) where OPCODE is a string representing - the new opcode, and ARGS is a list of arguments or empty tuple """ - - if self.flags & CONST5: - assert len(args) == 1 - if args[0] == -1: - return self.jvmstr + "_m1", () - elif args[0] >= 0 and args[0] <= 5: - return self.jvmstr + "_" + str(args[0]), () - else: - return "ldc", args # HACK - - if self.flags & CONST3: - assert len(args) == 1 - if args[0] >= 0 and args[0] <= 3: - return self.jvmstr + "_" + str(args[0]), () - - if self.flags & CLASSINM: - assert len(args) == 1 - args = [args[0].int_class_name()] - + the new opcode, and ARGS is a list of arguments or empty tuple. + Most of these do not do anything. """ + return (self.jvmstr, args) + +class IntConstOpcode(Opcode): + """ The ICONST opcode specializes itself for small integer opcodes. """ + def specialize(self, args): + assert len(args) == 1 + if args[0] == -1: + return self.jvmstr + "_m1", () + elif args[0] >= 0 and args[0] <= 5: + return self.jvmstr + "_" + str(args[0]), () + # Non obvious: convert ICONST to LDC if the constant is out of + # range + return "ldc", args + +class VarOpcode(Opcode): + """ An Opcode which takes a variable index as an argument; specialized + to small integer indices. """ + def specialize(self, args): + assert len(args) == 1 + if args[0] >= 0 and args[0] <= 3: + return self.jvmstr + "_" + str(args[0]), () + return Opcode.specialize(self, args) + +class IntClassNameOpcode(Opcode): + """ An opcode which takes an internal class name as its argument; + the actual argument will be a JvmType instance. """ + def specialize(self, args): + args = [args[0].descriptor.int_class_name()] return self.jvmstr, args class OpcodeFamily(object): @@ -76,12 +105,14 @@ defines one 'family' of opcodes, such as the LOAD family shown above, and produces Opcode objects specific to a particular type. """ - def __init__(self, flags, suffix): + def __init__(self, opcclass, suffix): """ - flags is a set of flags (see above) that describe opcode + opcclass is the opcode subclass to use (see above) when + instantiating a particular opcode + jvmstr is the name for jasmin printouts """ - self.flags = flags + self.opcode_class = opcclass self.suffix = suffix self.cache = {} @@ -89,27 +120,30 @@ try: return self.cache[prefix] except KeyError: - self.cache[prefix] = obj = Opcode(self.flags, prefix+self.suffix) + self.cache[prefix] = obj = self.opcode_class( + prefix+self.suffix) return obj def for_type(self, argtype): """ Returns a customized opcode of this family appropriate to 'argtype', a JvmType object. """ + desc = argtype.descriptor + # These are always true: - if argtype[0] == 'L': return self._o("a") # Objects - if argtype[0] == '[': return self._o("a") # Arrays - if argtype == 'I': return self._o("i") # Integers - if argtype == 'J': return self._o("l") # Integers - if argtype == 'D': return self._o("d") # Doubles - if argtype == 'V': return self._o("") # Void [used by RETURN] + if desc[0] == 'L': return self._o("a") # Objects + if desc[0] == '[': return self._o("a") # Arrays + if desc == 'I': return self._o("i") # Integers + if desc == 'J': return self._o("l") # Integers + if desc == 'D': return self._o("d") # Doubles + if desc == 'V': return self._o("") # Void [used by RETURN] # Chars/Bytes/Booleans are normally represented as ints # in the JVM, but some opcodes are different. They use a # different OpcodeFamily (see ArrayOpcodeFamily for ex) - if argtype == 'C': return self._o("i") # Characters - if argtype == 'B': return self._o("i") # Bytes - if argtype == 'Z': return self._o("i") # Boolean + if desc == 'C': return self._o("i") # Characters + if desc == 'B': return self._o("i") # Bytes + if desc == 'Z': return self._o("i") # Boolean assert False, "Unknown argtype=%s" % repr(argtype) raise NotImplementedError @@ -130,81 +164,83 @@ for cmpop in ('ne', 'eq', 'lt', 'gt', 'le', 'ge'): ifop = "if%s" % cmpop if_icmpop = "if_icmp%s" % cmpop - globals()[ifop.upper()] = Opcode(BRANCH, ifop) - globals()[if_icmpop.upper()] = Opcode(BRANCH, if_icmpop) + globals()[ifop.upper()] = Opcode(ifop) + globals()[if_icmpop.upper()] = Opcode(if_icmpop) # Compare references, either against NULL or against each other -IFNULL = Opcode(BRANCH, 'ifnull') -IFNONNULL = Opcode(BRANCH, 'ifnonnull') -IF_ACMPEQ = Opcode(BRANCH, 'if_acmpeq') -IF_ACMPNE = Opcode(BRANCH, 'if_acmpne') +IFNULL = Opcode('ifnull') +IFNONNULL = Opcode('ifnonnull') +IF_ACMPEQ = Opcode('if_acmpeq') +IF_ACMPNE = Opcode('if_acmpne') # Method invocation -INVOKESTATIC = Opcode(INVOKE, 'invokestatic') -INVOKEVIRTUAL = Opcode(INVOKE, 'invokevirtual') -INVOKESPECIAL = Opcode(INVOKE, 'invokespecial') +INVOKESTATIC = Opcode('invokestatic') +INVOKEVIRTUAL = Opcode('invokevirtual') +INVOKESPECIAL = Opcode('invokespecial') # Other opcodes -LDC = Opcode(NOFLAGS, 'ldc') # single-word types -LDC2 = Opcode(NOFLAGS, 'ldc2_w') # double-word types: doubles and longs -GOTO = Opcode(BRANCH, 'goto') -ICONST = Opcode(CONST5, 'iconst') -ACONST_NULL=Opcode(NOFLAGS, 'aconst_null') -DCONST_0 = Opcode(NOFLAGS, 'dconst_0') -DCONST_1 = Opcode(NOFLAGS, 'dconst_0') -LCONST_0 = Opcode(NOFLAGS, 'lconst_1') -LCONST_1 = Opcode(NOFLAGS, 'lconst_1') -GETFIELD = Opcode(FIELD, 'getfield') -PUTFIELD = Opcode(FIELD, 'putfield') -GETSTATIC = Opcode(FIELD, 'getstatic') -PUTSTATIC = Opcode(FIELD, 'putstatic') -CHECKCAST = Opcode(CLASSINM, 'checkcast') -INEG = Opcode(NOFLAGS, 'ineg') -IXOR = Opcode(NOFLAGS, 'ixor') -IADD = Opcode(NOFLAGS, 'iadd') -ISUB = Opcode(NOFLAGS, 'isub') -IMUL = Opcode(NOFLAGS, 'imul') -IDIV = Opcode(NOFLAGS, 'idiv') -IREM = Opcode(NOFLAGS, 'irem') -IAND = Opcode(NOFLAGS, 'iand') -IOR = Opcode(NOFLAGS, 'ior') -ISHL = Opcode(NOFLAGS, 'ishl') -ISHR = Opcode(NOFLAGS, 'ishr') -IUSHR = Opcode(NOFLAGS, 'iushr') -DCMPG = Opcode(NOFLAGS, 'dcmpg') -DCMPL = Opcode(NOFLAGS, 'dcmpl') -NOP = Opcode(NOFLAGS, 'nop') -I2D = Opcode(NOFLAGS, 'i2d') -I2L = Opcode(NOFLAGS, 'i2l') -D2I= Opcode(NOFLAGS, 'd2i') -L2I = Opcode(NOFLAGS, 'l2i') -ATHROW = Opcode(NOFLAGS, 'athrow') -DNEG = Opcode(NOFLAGS, 'dneg') -DADD = Opcode(NOFLAGS, 'dadd') -DSUB = Opcode(NOFLAGS, 'dsub') -DMUL = Opcode(NOFLAGS, 'dmul') -DDIV = Opcode(NOFLAGS, 'ddiv') -DREM = Opcode(NOFLAGS, 'drem') -LNEG = Opcode(NOFLAGS, 'lneg') -LADD = Opcode(NOFLAGS, 'ladd') -LSUB = Opcode(NOFLAGS, 'lsub') -LMUL = Opcode(NOFLAGS, 'lmul') -LDIV = Opcode(NOFLAGS, 'ldiv') -LREM = Opcode(NOFLAGS, 'lrem') -LAND = Opcode(NOFLAGS, 'land') -LOR = Opcode(NOFLAGS, 'lor') -LXOR = Opcode(NOFLAGS, 'lxor') -LSHL = Opcode(NOFLAGS, 'lshl') -LSHR = Opcode(NOFLAGS, 'lshr') -LUSHR = Opcode(NOFLAGS, 'lushr') -NEW = Opcode(CLASSINM, 'new') -DUP = Opcode(NOFLAGS, 'dup') -POP = Opcode(NOFLAGS, 'pop') -INSTANCEOF= Opcode(CLASSINM, 'instanceof') +LDC = Opcode('ldc') # single-word types +LDC2 = Opcode('ldc2_w') # double-word types: doubles and longs +GOTO = Opcode('goto') +ICONST = IntConstOpcode('iconst') +ACONST_NULL=Opcode('aconst_null') +DCONST_0 = Opcode('dconst_0') +DCONST_1 = Opcode('dconst_0') +LCONST_0 = Opcode('lconst_1') +LCONST_1 = Opcode('lconst_1') +GETFIELD = Opcode('getfield') +PUTFIELD = Opcode('putfield') +GETSTATIC = Opcode('getstatic') +PUTSTATIC = Opcode('putstatic') +CHECKCAST = IntClassNameOpcode('checkcast') +INEG = Opcode('ineg') +IXOR = Opcode('ixor') +IADD = Opcode('iadd') +ISUB = Opcode('isub') +IMUL = Opcode('imul') +IDIV = Opcode('idiv') +IREM = Opcode('irem') +IAND = Opcode('iand') +IOR = Opcode('ior') +ISHL = Opcode('ishl') +ISHR = Opcode('ishr') +IUSHR = Opcode('iushr') +DCMPG = Opcode('dcmpg') +DCMPL = Opcode('dcmpl') +NOP = Opcode('nop') +I2D = Opcode('i2d') +I2L = Opcode('i2l') +D2I= Opcode('d2i') +L2I = Opcode('l2i') +ATHROW = Opcode('athrow') +DNEG = Opcode('dneg') +DADD = Opcode('dadd') +DSUB = Opcode('dsub') +DMUL = Opcode('dmul') +DDIV = Opcode('ddiv') +DREM = Opcode('drem') +LNEG = Opcode('lneg') +LADD = Opcode('ladd') +LSUB = Opcode('lsub') +LMUL = Opcode('lmul') +LDIV = Opcode('ldiv') +LREM = Opcode('lrem') +LAND = Opcode('land') +LOR = Opcode('lor') +LXOR = Opcode('lxor') +LSHL = Opcode('lshl') +LSHR = Opcode('lshr') +LUSHR = Opcode('lushr') +NEW = IntClassNameOpcode('new') +DUP = Opcode('dup') +DUP2 = Opcode('dup2') +POP = Opcode('pop') +POP2 = Opcode('pop2') +INSTANCEOF= IntClassNameOpcode('instanceof') # Loading/storing local variables -LOAD = OpcodeFamily(CONST3, "load") -STORE = OpcodeFamily(CONST3, "store") -RETURN = OpcodeFamily(NOFLAGS, "return") +LOAD = OpcodeFamily(VarOpcode, "load") +STORE = OpcodeFamily(VarOpcode, "store") +RETURN = OpcodeFamily(Opcode, "return") # Loading/storing from arrays # *NOTE*: This family is characterized by the type of the ELEMENT, @@ -213,9 +249,27 @@ # Also: here I break from convention by naming the objects ARRLOAD # rather than ALOAD, even though the suffix is 'aload'. This is to # avoid confusion with the ALOAD opcode. -ARRLOAD = ArrayOpcodeFamily(NOFLAGS, "aload") -ARRSTORE = ArrayOpcodeFamily(NOFLAGS, "astore") +ARRLOAD = ArrayOpcodeFamily(Opcode, "aload") +ARRSTORE = ArrayOpcodeFamily(Opcode, "astore") + +# ___________________________________________________________________________ +# Labels +# +# We use a class here just for sanity checks and debugging print-outs. + +class Label(object): + + def __init__(self, number, desc): + """ number is a unique integer + desc is a short, descriptive string that is a valid java identifier """ + self.label = "%s_%s" % (desc, number) + def __repr__(self): + return "Label(%s)"%self.label + + def jasmin_syntax(self): + return self.label + # ___________________________________________________________________________ # Methods # @@ -227,13 +281,37 @@ class Method(object): - def v(classnm, methnm, argtypes, rettype): - return Method(classnm, methnm, jvm_method_desc(argtypes, rettype), + def v(classty, methnm, argtypes, rettype): + """ + Shorthand to create a virtual method. + 'class' - JvmType object for the class + 'methnm' - name of the method (Python string) + 'argtypes' - list of JvmType objects, one for each argument but + not the this ptr + 'rettype' - JvmType for return type + """ + assert isinstance(classty, JvmType) + classnm = classty.name + argtypes = [a.descriptor for a in argtypes] + rettype = rettype.descriptor + return Method(classnm, methnm, desc_for_method(argtypes, rettype), opcode=INVOKEVIRTUAL) v = staticmethod(v) - def s(classnm, methnm, argtypes, rettype): - return Method(classnm, methnm, jvm_method_desc(argtypes, rettype)) + def s(classty, methnm, argtypes, rettype): + """ + Shorthand to create a static method. + 'class' - JvmType object for the class + 'methnm' - name of the method (Python string) + 'argtypes' - list of JvmType objects, one for each argument but + not the this ptr + 'rettype' - JvmType for return type + """ + assert isinstance(classty, JvmType) + classnm = classty.name + argtypes = [a.descriptor for a in argtypes] + rettype = rettype.descriptor + return Method(classnm, methnm, desc_for_method(argtypes, rettype)) s = staticmethod(s) def __init__(self, classnm, methnm, desc, opcode=INVOKESTATIC): @@ -248,48 +326,35 @@ self.method_name, self.descriptor) -MATHIABS = Method('java.lang.Math', 'abs', '(I)I') -MATHLABS = Method('java.lang.Math', 'abs', '(L)L') -MATHDABS = Method('java.lang.Math', 'abs', '(D)D') -MATHFLOOR = Method('java.lang.Math', 'floor', '(D)D') -PRINTSTREAMPRINTSTR = Method('java.io.PrintStream', 'print', - '(Ljava/lang/String;)V', opcode=INVOKEVIRTUAL) -PYPYUINTCMP = Method(PYPYJAVA, 'uint_cmp', '(II)I') -PYPYULONGCMP = Method(PYPYJAVA, 'ulong', '(LL)I') -PYPYUINTTODOUBLE = Method(PYPYJAVA, 'uint_to_double', '(I)D') -PYPYDOUBLETOUINT = Method(PYPYJAVA, 'double_to_uint', '(D)I') -PYPYLONGBITWISENEGATE = Method(PYPYJAVA, 'long_bitwise_negate', '(L)L') -PYPYARRAYTOLIST = Method(PYPYJAVA, 'array_to_list', - '([Ljava/lang/Object;)Ljava/util/List;') -PYPYSTRTOINT = Method(PYPYJAVA, 'str_to_int', - '(Ljava/lang/String;)I') -PYPYSTRTOUINT = Method(PYPYJAVA, 'str_to_uint', - '(Ljava/lang/String;)I') -PYPYSTRTOLONG = Method(PYPYJAVA, 'str_to_long', - '(Ljava/lang/String;)J') -PYPYSTRTOULONG = Method(PYPYJAVA, 'str_to_ulong', - '(Ljava/lang/String;)J') -PYPYSTRTOBOOL = Method(PYPYJAVA, 'str_to_bool', - '(Ljava/lang/String;)Z') -PYPYSTRTODOUBLE = Method(PYPYJAVA, 'str_to_double', - '(Ljava/lang/String;)D') -PYPYSTRTOCHAR = Method(PYPYJAVA, 'str_to_char', - '(Ljava/lang/String;)C') -PYPYDUMPINDENTED = Method(PYPYJAVA, 'dump_indented', - '(ILjava/lang/String;)V') -PYPYDUMPINT = Method(PYPYJAVA, 'dump_int', '(II)V') -PYPYDUMPUINT = Method(PYPYJAVA, 'dump_uint', '(II)V') -PYPYDUMPLONG = Method(PYPYJAVA, 'dump_long', '(LI)V') -PYPYDUMPDOUBLE = Method(PYPYJAVA, 'dump_double', '(DI)V') -PYPYDUMPSTRING = Method(PYPYJAVA, 'dump_string', - jvm_method_desc((jOOString,jInt),jVoid)) -PYPYDUMPBOOLEAN = Method(PYPYJAVA, 'dump_boolean', '(ZI)V') -PYPYDUMPOBJECT = Method(PYPYJAVA, 'dump_object', - '(Ljava/lang/Object;I)V') -PYPYRUNTIMENEW = Method(PYPYJAVA, 'RuntimeNew', - '(Ljava/lang/Class;)Ljava/lang/Object;') -PYPYSTRING2BYTES = Method(PYPYJAVA, 'string2bytes', - jvm_method_desc((jString),jByteArray)) +MATHIABS = Method.s(jMath, 'abs', (jInt,), jInt) +MATHLABS = Method.s(jMath, 'abs', (jLong,), jLong) +MATHDABS = Method.s(jMath, 'abs', (jDouble,), jDouble) +MATHFLOOR = Method.s(jMath, 'floor', (jDouble,), jDouble) +PRINTSTREAMPRINTSTR = Method.v(jPrintStream, 'print', (jString,), jVoid) +CLASSFORNAME = Method.s(jClass, 'forName', (jString,), jClass) +PYPYUINTCMP = Method.s(jPyPy, 'uint_cmp', (jInt,jInt,), jInt) +PYPYULONGCMP = Method.s(jPyPy, 'ulong_cmp', (jLong,jLong), jInt) +PYPYUINTTODOUBLE = Method.s(jPyPy, 'uint_to_double', (jInt,), jDouble) +PYPYDOUBLETOUINT = Method.s(jPyPy, 'double_to_uint', (jDouble,), jInt) +PYPYLONGBITWISENEGATE = Method.s(jPyPy, 'long_bitwise_negate', (jLong,), jLong) +PYPYSTRTOINT = Method.s(jPyPy, 'str_to_int', (jString,), jInt) +PYPYSTRTOUINT = Method.s(jPyPy, 'str_to_uint', (jString,), jInt) +PYPYSTRTOLONG = Method.s(jPyPy, 'str_to_long', (jString,), jLong) +PYPYSTRTOULONG = Method.s(jPyPy, 'str_to_ulong', (jString,), jLong) +PYPYSTRTOBOOL = Method.s(jPyPy, 'str_to_bool', (jString,), jBool) +PYPYSTRTODOUBLE = Method.s(jPyPy, 'str_to_double', (jString,), jDouble) +PYPYSTRTOCHAR = Method.s(jPyPy, 'str_to_char', (jString,), jChar) +PYPYDUMPINDENTED = Method.s(jPyPy, 'dump_indented', (jInt,jString,), jVoid) +PYPYDUMPINT = Method.s(jPyPy, 'dump_int', (jInt,jInt), jVoid) +PYPYDUMPUINT = Method.s(jPyPy, 'dump_uint', (jInt,jInt), jVoid) +PYPYDUMPLONG = Method.s(jPyPy, 'dump_long', (jLong,jInt), jVoid) +PYPYDUMPDOUBLE = Method.s(jPyPy, 'dump_double', (jDouble,jInt), jVoid) +PYPYDUMPSTRING = Method.s(jPyPy, 'dump_string', (jString,jInt), jVoid) +PYPYDUMPBOOLEAN = Method.s(jPyPy, 'dump_boolean', (jBool,jInt), jVoid) +PYPYDUMPOBJECT = Method.s(jPyPy, 'dump_object', (jObject,jInt,), jVoid) +PYPYDUMPVOID = Method.s(jPyPy, 'dump_void', (jInt,), jVoid) +PYPYRUNTIMENEW = Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject) +PYPYSTRING2BYTES = Method.s(jPyPy, 'string2bytes', (jString,), jByteArray) # ___________________________________________________________________________ @@ -316,135 +381,15 @@ gen._instr(PUTFIELD, self) def jasmin_syntax(self): return "%s/%s %s" % ( - self.class_name.replace('.','/'), self.field_name, self.jtype) - -SYSTEMOUT = Field('java.lang.System', 'out', jPrintStream, True) -SYSTEMERR = Field('java.lang.System', 'err', jPrintStream, True) - -# ___________________________________________________________________________ -# Constants -# -# Constant objects record constants of various types, and can be used -# to emit the required instructions to load their value. - -class Const(object): - def load(self, gen): - """ Emits code required to reference a constant. Usually invoked - by generator.emit() """ - raise NotImplementedError - def initialize(self, gen): - """ Emits code required to DEFINE a constant (if any). Default - version does nothing. """ - pass - -class VoidConst(object): - def load(self, gen): - pass - -class NullConst(object): - def load(self, gen): - gen.emit(ACONST_NULL) - -class WarnNullConst(NullConst): - def load(self, gen): - gen.add_comment(" substituting NULL") - NullConst.load(self, gen) - -class SignedIntConst(Const): - def __init__(self, value): - self.value = value - def load(self, gen): - # In theory, we could get rid of CONST5 flag and do optimization - # here, but then all code would have to use SignedIntConst, and - # that seems uglier - gen.emit(ICONST, self.value) - -class UnsignedIntConst(SignedIntConst): - def __init__(self, value): - assert value >= 0 - if value <= 0x7FFFFFFF: - SignedIntConst.__init__(self, value) - else: - # Find the negative version of the value that will - # represent this constant, and treat it like a signed - # integer: - value = value ^ 0xFFFFFFFF - value += 1 - value *= -1 - assert value < 0 - value = int(value) - SignedIntConst.__init__(self, value) - -class DoubleConst(Const): - def __init__(self, value): - self.value = value - def load(self, gen): - if value == 0.0: - gen.emit(DCONST_0) - elif value == 1.0: - gen.emit(DCONST_1) - else: - gen.emit(LDC2, self.value) - -class SignedLongConst(Const): - def __init__(self, value): - self.value = value - def load(self, gen): - if value == 0: - gen.emit(LCONST_0) - elif value == 1: - gen.emit(LCONST_1) - else: - gen.emit(LDC2, self.value) - -class UnsignedLongConst(SignedLongConst): - def __init__(self, value): - assert value >= 0 - if value <= 0x7FFFFFFFFFFFFFFFL: - SignedIntConst.__init__(self, value) - else: - # Find the negative version of the value that will - # represent this constant, and treat it like a signed - # integer: - value = value ^ 0xFFFFFFFFFFFFFFFF - value += 1 - value *= -1 - assert value < 0 - SignedLongConst.__init__(self, value) - -class UnicodeConst(Const): - def __init__(self, value): - self.value = value - def load(self, gen): - assert isinstance(self.value, unicode) - def escape(char): - if char == '"': return r'\"' - if char == '\n': return r'\n' - return char - res = ('"' + - "".join(escape(c) for c in self.value.encode('utf-8')) + - '"') - gen.emit(LDC, res) - -class ComplexConst(Const): - def __init__(self, fieldinfo, methodinfo): - """ - Stores information about "complex" constants. These are constants - that we cannot embed in the Java file and which require a method - to initialize. They are stored in static fields, and initialized - with static methods that should be embedded in a class's static{} - section. - - fieldinfo --- the static field that will hold the value - methodinfo --- a static method that initializes the value. Should - have no arguments. - """ - self.fieldinfo = fieldinfo - self.methodinfo = methodinfo - def load(self, gen): - self.fieldinfo.load(gen) - def initialize(self, gen): - gen.emit(self.methodinfo) + self.class_name.replace('.','/'), + self.field_name, + self.jtype.descriptor) + +SYSTEMOUT = Field('java.lang.System', 'out', jPrintStream, True) +SYSTEMERR = Field('java.lang.System', 'err', jPrintStream, True) +DOUBLENAN = Field('java.lang.Double', 'NaN', jDouble, True) +DOUBLEPOSINF = Field('java.lang.Double', 'POSITIVE_INFINITY', jDouble, True) +DOUBLENEGINF = Field('java.lang.Double', 'NEGATIVE_INFINITY', jDouble, True) # ___________________________________________________________________________ # Generator State @@ -452,9 +397,9 @@ class ClassState(object): """ When you invoked begin_class(), one of these objects is allocated and tracks the state as we go through the definition process. """ - def __init__(self, classnm, superclassnm): - self.class_name = classnm - self.superclass_name = superclassnm + def __init__(self, classty, superclassty): + self.class_type = classty + self.superclass_type = superclassty def out(self, arg): self.file.write(arg) @@ -468,7 +413,7 @@ def add_var(self, jvar, jtype): """ Adds new entry for variable 'jvar', of java type 'jtype' """ idx = self.next_offset - self.next_offset += jtype.type_width() + self.next_offset += jtype.descriptor.type_width() if jvar: assert jvar not in self.local_vars # never been added before self.local_vars[jvar] = idx @@ -504,7 +449,7 @@ # If the name does not begin with '_', it will be called from # outside the generator. - def begin_class(self, classnm, superclsnm): + def begin_class(self, classty, superclsty): """ Begins a class declaration. Overall flow of class declaration looks like: @@ -517,11 +462,11 @@ Where items in brackets may appear anywhere from 0 to inf times. - classnm --- full Java name of the class (i.e., "java.lang.String") - superclassnm --- full Java name of the super class + classty --- JvmType for the class + superclassty --- JvmType for the superclass """ assert not self.curclass - self.curclass = ClassState(classnm, superclsnm) + self.curclass = ClassState(classty, superclsty) self._begin_class() def end_class(self): @@ -550,10 +495,9 @@ superclsnm --- same Java name of super class as from begin_class """ - jtype = jvm_for_class(self.curclass.class_name) - self.begin_function("", [], [jtype], jVoid) - self.load_jvm_var(jtype, 0) - jmethod = Method(self.curclass.superclass_name, "", "()V", + self.begin_function("", [], [self.curclass.class_type], jVoid) + self.load_jvm_var(self.curclass.class_type, 0) + jmethod = Method(self.curclass.superclass_type.name, "", "()V", opcode=INVOKESPECIAL) jmethod.invoke(self) self.return_val(jVoid) @@ -614,8 +558,19 @@ self._instr(RETURN.for_type(vartype)) def load_string(self, str): - uni = str.decode('utf-8') - UnicodeConst(uni).load(self) + """ Pushes a Java version of a Python string onto the stack. + 'str' should be a Python string encoded in UTF-8 (I think) """ + # Create an escaped version of str: + def escape(char): + if char == '"': return r'\"' + if char == '\n': return r'\n' + return char + res = ('"' + + "".join(escape(c) for c in str) + + '"') + # Use LDC to load the Java version: + # XXX --- support byte arrays here? Would be trickier! + self._instr(LDC, res) def load_jvm_var(self, vartype, varidx): """ Loads from jvm slot #varidx, which is expected to hold a value of @@ -657,9 +612,8 @@ identifier. 'mark' --- if True, then also calls self.mark() with the new lbl """ - labelnum = self.label_counter + res = Label(self.label_counter, desc) self.label_counter += 1 - res = ('Label', labelnum, desc) if mark: self.mark(res) return res @@ -668,7 +622,7 @@ """ Convenience method. Be sure you only call it from a virtual method, not static methods. """ self.load_jvm_var(jObject, 0) - + # __________________________________________________________________ # Exception Handling @@ -749,7 +703,7 @@ return self.load_jvm_var(jty, idx) if isinstance(value, flowmodel.Constant): - return self.db.record_const(value).load(self) + return push_constant(self.db, value.concretetype, value.value, self) raise Exception('Unexpected type for v in load(): '+ repr(value.concretetype) + " v=" + repr(value)) @@ -765,25 +719,14 @@ raise Exception('Unexpected type for v in store(): '+v) def set_field(self, CONCRETETYPE, fieldname): - if fieldname == "meta": - # temporary hack - self.add_comment(" WARNING: emulating meta for now") - self.emit(POP) - self.emit(POP) - else: - clsobj = self.db.pending_class(CONCRETETYPE) - fieldobj = clsobj.lookup_field(fieldname) - fieldobj.store(self) + clsobj = self.db.pending_class(CONCRETETYPE) + fieldobj = clsobj.lookup_field(fieldname) + fieldobj.store(self) def get_field(self, CONCRETETYPE, fieldname): - if fieldname == 'meta': - self.add_comment(" WARNING: emulating meta for now") - self.emit(POP) - self.emit(ACONST_NULL) - else: - clsobj = self.db.pending_class(CONCRETETYPE) - fieldobj = clsobj.lookup_field(fieldname) - fieldobj.load(self) + clsobj = self.db.pending_class(CONCRETETYPE) + fieldobj = clsobj.lookup_field(fieldname) + fieldobj.load(self) def downcast(self, TYPE): jtype = self.db.lltype_to_cts(TYPE) @@ -817,17 +760,17 @@ def call_oostring(self, OOTYPE): cts_type = self.db.lltype_to_cts(OOTYPE) if cts_type != jByteArray: - mthd = Method.s(PYPYJAVA, 'oostring', [cts_type, jInt], jString) + mthd = Method.s(jPyPy, 'oostring', [cts_type, jInt], jString) self.emit(mthd) - if jOOString == jByteArray: + if self.db.using_byte_array: self.emit(PYPYSTRING2BYTES) else: - mthd = Method.s(PYPYJAVA, 'oostring', + mthd = Method.s(jPyPy, 'oostring', [jByteArray, jInt], jByteArray) def new(self, TYPE): jtype = self.db.lltype_to_cts(TYPE) - ctor = Method(jtype.class_name(), "", "()V", opcode=INVOKESPECIAL) + ctor = Method(jtype.name, "", "()V", opcode=INVOKESPECIAL) self.emit(NEW, jtype) self.emit(DUP) self.emit(ctor) @@ -835,6 +778,69 @@ def instantiate(self): self.emit(PYPYRUNTIMENEW) + def getclassobject(self, OOINSTANCE): + jvmtype = self.db.lltype_to_cts(OOINSTANCE) + self.load_string(jvmtype.name) + CLASSFORNAME.invoke(self) + + def dup(self, OOTYPE): + jvmtype = self.db.lltype_to_cts(OOTYPE) + if jvmtype.descriptor.type_width() == 1: + self.emit(DUP) + else: + self.emit(DUP2) + + def pop(self, OOTYPE): + jvmtype = self.db.lltype_to_cts(OOTYPE) + if jvmtype.descriptor.type_width() == 1: + self.emit(POP) + else: + self.emit(POP2) + + def push_null(self, OOTYPE): + self.emit(ACONST_NULL) + + def push_primitive_constant(self, TYPE, value): + if TYPE is ootype.Void: + return + elif TYPE in (ootype.Bool, ootype.Signed): + self.emit(ICONST, int(value)) + elif TYPE is ootype.Unsigned: + # Converts the unsigned int into its corresponding signed value + # and emits it using ICONST. + self.emit(ICONST, _unsigned_to_signed_32(value)) + elif TYPE is ootype.Char or TYPE is ootype.UniChar: + self.emit(ICONST, ord(value)) + elif TYPE is ootype.SignedLongLong: + self._push_long_constant(long(value)) + elif TYPE is ootype.UnsignedLongLong: + self._push_long_constant(_unsigned_to_signed_64(value)) + elif TYPE is ootype.Float: + self._push_double_constant(float(value)) + elif TYPE is ootype.String: + self.load_string(str(value)) + + def _push_long_constant(self, value): + if value == 0: + gen.emit(LCONST_0) + elif value == 1: + gen.emit(LCONST_1) + else: + gen.emit(LDC2, value) + + def _push_double_constant(self, value): + if _isnan(value): + DOUBLENAN.load(self) + elif _isinf(value): + if value > 0: DOUBLEPOSINF.load(self) + else: DOUBLENEGINF.load(self) + elif value == 0.0: + gen.emit(DCONST_0) + elif value == 1.0: + gen.emit(DCONST_1) + else: + gen.emit(LDC2, self.value) + # __________________________________________________________________ # Methods invoked directly by strings in jvm/opcode.py @@ -945,8 +951,8 @@ classnm --- full Java name of the class (i.e., "java.lang.String") """ - iclassnm = self.curclass.class_name.replace('.', '/') - isuper = self.curclass.superclass_name.replace('.', '/') + iclassnm = self.curclass.class_type.descriptor.int_class_name() + isuper = self.curclass.superclass_type.descriptor.int_class_name() jfile = "%s/%s.j" % (self.outdir, iclassnm) @@ -970,8 +976,10 @@ self.curclass.out(" ; %s\n" % comment) def add_field(self, fobj): - self.curclass.out('.field public %s %s\n' % ( - fobj.field_name, fobj.jtype)) + kw = ['public'] + if fobj.is_static: kw.append('static') + self.curclass.out('.field %s %s %s\n' % ( + " ".join(kw), fobj.field_name, fobj.jtype.descriptor)) def _begin_function(self, funcname, argtypes, rettype, static): @@ -981,8 +989,10 @@ kw = ['public'] if static: kw.append('static') self.curclass.out('.method %s %s(%s)%s\n' % ( - " ".join(kw), funcname, - "".join(argtypes), rettype)) + " ".join(kw), + funcname, + "".join([a.descriptor for a in argtypes]), + rettype.descriptor)) def _end_function(self): self.curclass.out('.limit stack 100\n') # HACK, track max offset @@ -991,21 +1001,16 @@ def mark(self, lbl): """ Marks the point that a label indicates. """ - _, lblnum, lbldesc = lbl - assert _ == "Label" - self.curclass.out(' %s_%s:\n' % (lbldesc, lblnum)) + assert isinstance(lbl, Label) + self.curclass.out(' %s:\n' % lbl.jasmin_syntax()) def _instr(self, opcode, *args): - jvmstr, args = opcode.specialize_opcode(args) - # XXX this whole opcode flag things is stupid, redo to be class based - if opcode.flags & BRANCH: - assert len(args) == 1 - _, lblnum, lbldesc = args[0] - args = ('%s_%s' % (lbldesc, lblnum),) - if opcode.flags & (INVOKE|FIELD): - assert len(args) == 1 - args = (args[0].jasmin_syntax(),) - instr_text = ' %s %s' % (jvmstr, " ".join([str(s) for s in args])) + jvmstr, args = opcode.specialize(args) + def jasmin_syntax(arg): + if hasattr(arg, 'jasmin_syntax'): return arg.jasmin_syntax() + return str(arg) + strargs = [jasmin_syntax(arg) for arg in args] + instr_text = '%s %s' % (jvmstr, " ".join(strargs)) self.curclass.out(' %-60s ; %d\n' % ( instr_text, self.curfunc.instr_counter)) self.curfunc.instr_counter+=1 Modified: pypy/dist/pypy/translator/jvm/genjvm.py ============================================================================== --- pypy/dist/pypy/translator/jvm/genjvm.py (original) +++ pypy/dist/pypy/translator/jvm/genjvm.py Sun Nov 5 15:55:06 2006 @@ -193,6 +193,7 @@ """ Creates and returns a Generator object according to the configuration. Right now, however, there is only one kind of generator: JasminGenerator """ + print "Uh...?" return JasminGenerator( self.db, self.jvmsrc.javadir, self.jvmsrc.package) Modified: pypy/dist/pypy/translator/jvm/node.py ============================================================================== --- pypy/dist/pypy/translator/jvm/node.py (original) +++ pypy/dist/pypy/translator/jvm/node.py Sun Nov 5 15:55:06 2006 @@ -1,14 +1,24 @@ """ -Rendering nodes for the JVM. I suspect that a lot of this could be -made to be common between CLR and JVM. +Nodes describe Java structures that we are building. They know how to +render themselves so as to build the java structure they describe. +They are entered onto the database worklist as we go. + +Some nodes describe parts of the JVM structure that already exist --- +for example, there are nodes that are used to describe built-in JVM +types like String, etc. In this case, they are never placed on the +database worklist, and don't know how to render themselves (since they +don't have to). + +Nodes representing classes that we will build also implement the JvmType +interface defined by database.JvmType. """ from pypy.rpython.lltypesystem import lltype from pypy.rpython.ootypesystem import ootype from pypy.translator.jvm.typesystem import \ - jString, jStringArray, jVoid, jThrowable -from pypy.translator.jvm.typesystem import jvm_for_class, jvm_method_desc, jInt + JvmClassType, jString, jStringArray, jVoid, jThrowable, jInt, jPyPyMain, \ + jObject from pypy.translator.jvm.opcodes import opcodes from pypy.translator.jvm.option import getoption from pypy.translator.oosupport.function import Function as OOFunction @@ -62,7 +72,7 @@ } def render(self, gen): - gen.begin_class('pypy.Main', 'java.lang.Object') + gen.begin_class(jPyPyMain, jObject) gen.begin_function( 'main', (), [jStringArray], jVoid, static=True) @@ -105,10 +115,10 @@ """ Represents a function to be emitted. """ - def __init__(self, db, classobj, name, jargtypes, + def __init__(self, db, classty, name, jargtypes, jrettype, graph, is_static): """ - classobj: the Class object this is a part of (even static + classty: the JvmClassType object this is a part of (even static functions have a class) name: the name of the function jargtypes: JvmType of each argument @@ -117,7 +127,7 @@ is_static: boolean flag indicate whether func is static (!) """ OOFunction.__init__(self, db, graph, name, not is_static) - self.classnm = classobj.name + self.classty = classty self.jargtypes = jargtypes self.jrettype = jrettype self._block_labels = {} @@ -125,13 +135,13 @@ def method(self): """ Returns a jvmgen.Method that can invoke this function """ if not self.is_method: - opcode = jvmgen.INVOKESTATIC + ctor = jvmgen.Method.s startidx = 0 else: - opcode = jvmgen.INVOKEVIRTUAL + ctor = jvmgen.Method.v startidx = 1 - mdesc = jvm_method_desc(self.jargtypes[startidx:], self.jrettype) - return jvmgen.Method(self.classnm, self.name, mdesc, opcode=opcode) + return ctor(self.classty, self.name, + self.jargtypes[startidx:], self.jrettype) def begin_render(self): # Prepare argument lists for begin_function call @@ -203,25 +213,22 @@ OOFunction._render_op(self, op) -class Class(Node): +class Class(Node, JvmClassType): """ Represents a class to be emitted. Note that currently, classes are emitted all in one shot, not piecemeal. """ - def __init__(self, name, supername): + def __init__(self, name, supercls): """ - 'name' and 'super_name' should be fully qualified Java class names like - "java.lang.String" + 'name' should be a fully qualified Java class name like + "java.lang.String", supercls is a Class object """ - self.name = name # public attribute - self.super_name = supername # public attribute + JvmClassType.__init__(self, name) + self.super_class = supercls self.fields = {} self.rendered = False self.methods = {} - def jvm_type(self): - return jvm_for_class(self.name) - def add_field(self, fieldobj): """ Creates a new field accessed via the jvmgen.Field descriptor 'fieldobj'. Must be called before render().""" @@ -230,11 +237,15 @@ def lookup_field(self, fieldnm): """ Given a field name, returns a jvmgen.Field object """ - return self.fields[fieldnm] + if fieldnm in self.fields: + return self.fields[fieldnm] + return self.super_class.lookup_field(fieldnm) def lookup_method(self, methodnm): """ Given the method name, returns a jvmgen.Method object """ - return self.methods[methodnm].method() + if methodnm in self.methods: + return self.methods[methodnm].method() + return self.super_class.lookup_method(methodnm) def add_method(self, func): """ Creates a new method in this class, represented by the @@ -249,7 +260,7 @@ def render(self, gen): self.rendered = True - gen.begin_class(self.name, self.super_name) + gen.begin_class(self, self.super_class) for field in self.fields.values(): gen.add_field(field) @@ -268,14 +279,13 @@ self.OOCLASS = OOCLASS self.clsobj = clsobj self.name = "_pypy_dump" - self.jargtypes = [clsobj.jvm_type(), jInt] + self.jargtypes = [clsobj, jInt] self.jrettype = jVoid def method(self): """ Returns a jvmgen.Method that can invoke this function """ - mdesc = jvm_method_desc(self.jargtypes[1:], self.jrettype) - return jvmgen.Method(self.clsobj.name, self.name, mdesc, - opcode=jvmgen.INVOKEVIRTUAL) + return jvmgen.Method.v( + self.clsobj, self.name, self.jargtypes[1:], self.jrettype) def render(self, gen): clsobj = self.clsobj Modified: pypy/dist/pypy/translator/jvm/src/PyPy.java ============================================================================== --- pypy/dist/pypy/translator/jvm/src/PyPy.java (original) +++ pypy/dist/pypy/translator/jvm/src/PyPy.java Sun Nov 5 15:55:06 2006 @@ -194,6 +194,9 @@ System.out.println(text); } + public static void dump_void(int indent) { + } + public static void dump_int(int i, int indent) { dump_indented(indent, Integer.toString(i)); } Added: pypy/dist/pypy/translator/jvm/test/test_class.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/jvm/test/test_class.py Sun Nov 5 15:55:06 2006 @@ -0,0 +1,10 @@ +import py +from pypy.translator.jvm.test.runtest import JvmTest +from pypy.rpython.test.test_rclass import BaseTestRclass +from pypy.rpython.test.test_rspecialcase import BaseTestRspecialcase + +class TestJvmClass(JvmTest, BaseTestRclass): + pass + +#class TestCliSpecialCase(CliTest, BaseTestRspecialcase): +# pass Modified: pypy/dist/pypy/translator/jvm/typesystem.py ============================================================================== --- pypy/dist/pypy/translator/jvm/typesystem.py (original) +++ pypy/dist/pypy/translator/jvm/typesystem.py Sun Nov 5 15:55:06 2006 @@ -34,13 +34,25 @@ from pypy.translator.jvm.option import getoption from pypy.translator.jvm.log import log -class JvmType(str): +# ___________________________________________________________________________ +# Type Descriptors +# +# Internal representations of types for the JVM. Generally speaking, +# only the generator code should deal with these and even it tries to +# avoid them except write before dumping to the output file. + +class JvmTypeDescriptor(str): """ - The class we use to represent JVM types; it is just a string with - the JVM type descriptor at the moment. Using JvmType allows us to - use isinstance, however. The grammar for type descriptors can be - read about here: + An internal class representing JVM type descriptors, which are + essentially Java's short hand for types. This is the lowest level + of our representation for types and are mainly used when defining + the types of fields or arguments to methods. The grammar for type + descriptors can be read about here: + http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html + + We use this class also to represent method descriptors, which define + a set of argument and return types. """ def is_scalar(self): return self[0] != 'L' and self[0] != '[' @@ -48,6 +60,8 @@ return not self.is_scalar() def is_array(self): return self[0] == '[' + def is_method(self): + return self[0] == '(' def class_name(self): """ Converts a descriptor like Ljava/lang/Object; to full class name java.lang.Object """ @@ -68,71 +82,114 @@ # JVM type functions -def jvm_array_of(jtype): +def desc_for_array_of(jdescr): """ Returns a JvmType representing an array of 'jtype', which must be another JvmType """ - assert isinstance(jtype, JvmType) - return JvmType('['+str(jtype)) + assert isinstance(jdescr, JvmTypeDescriptor) + return JvmTypeDescriptor('['+jdescr) -def jvm_for_class(classnm): +def desc_for_class(classnm): """ Returns a JvmType representing a particular class 'classnm', which should be a fully qualified java class name (i.e., 'java.lang.String') """ - return JvmType('L%s;' % classnm.replace('.','/')) - -# Common JVM types -jVoid = JvmType('V') -jInt = JvmType('I') -jLong = JvmType('J') -jBool = JvmType('Z') -jDouble = JvmType('D') -jByte = JvmType('B') -jByteArray = jvm_array_of(jByte) -jChar = JvmType('C') -jThrowable = jvm_for_class('java.lang.Throwable') -jObject = jvm_for_class('java.lang.Object') -jString = jvm_for_class('java.lang.String') -jStringArray = jvm_array_of(jString) -jArrayList = jvm_for_class('java.util.ArrayList') -jHashMap = jvm_for_class('java.util.HashMap') -jIterator = jvm_for_class('java.util.Iterator') -jClass = jvm_for_class('java.lang.Class') -jStringBuilder = jvm_for_class('java.lang.StringBuilder') -jPrintStream = jvm_for_class('java.io.PrintStream') - -# Map from OOType to an internal JVM type descriptor -# only handles the simple cases -ootype_to_jvm = { - ootype.Void: jVoid, - ootype.Signed: jInt, - ootype.Unsigned: jInt, - ootype.SignedLongLong: jLong, - ootype.UnsignedLongLong: jLong, - ootype.Bool: jBool, - ootype.Float: jDouble, - ootype.Char: jByte, - ootype.UniChar: jChar, - ootype.String: jString, - ootype.ROOT: jObject, - - # We may want to use PyPy wrappers here later: - llmemory.WeakGcAddress: jObject, # XXX - ootype.StringBuilder: jStringBuilder, - ootype.Class: jClass, - ootype.List: jArrayList, - ootype.Dict: jHashMap, - ootype.DictItemsIterator:jIterator - } - -# Determine which class we will use to represent strings: -if getoption('byte-arrays'): - ootype_to_jvm[ootype.String] = jByteArray -jOOString = ootype_to_jvm[ootype.String] + return JvmTypeDescriptor('L%s;' % classnm.replace('.','/')) -# Method descriptor construction -def jvm_method_desc(argtypes, rettype): +def desc_for_method(argtypes, rettype): """ A Java method has a descriptor, which is a string specified its argument and return types. This function converts a list of argument types (JvmTypes) and the return type (also a JvmType), into one of these descriptor strings. """ - return "(%s)%s" % ("".join(argtypes), rettype) + return JvmTypeDescriptor("(%s)%s" % ("".join(argtypes), rettype)) + +# ______________________________________________________________________ +# Basic JVM Types + +class JvmType(object): + """ + The JvmType interface defines the interface for type objects + that we return in the database in various places. + """ + def __init__(self, descriptor): + """ 'descriptor' should be a jvm.generator.JvmTypeDescriptor object + for this type """ + self.descriptor = descriptor # public + self.name = None # public, string like "java.lang.Object" + # (None for scalars and arrays) + def lookup_field(self, fieldnm): + """ Returns a jvm.generator.Field object representing the field + with the given name, or raises KeyError if that field does not + exist on this type. """ + raise NotImplementedException + def lookup_method(self, methodnm): + """ Returns a jvm.generator.Method object representing the method + with the given name, or raises KeyError if that field does not + exist on this type. """ + raise NotImplementedException + + def __repr__(self): + return "%s<%s>" % (self.__class__.__name__, self.descriptor) + +class JvmScalarType(JvmType): + """ + Subclass used for all scalar type instances. + """ + def __init__(self, descrstr): + JvmType.__init__(self, JvmTypeDescriptor(descrstr)) + def lookup_field(self, fieldnm): + raise KeyError(fieldnm) # Scalar objects have no fields + def lookup_method(self, methodnm): + raise KeyError(methodnm) # Scalar objects have no methods + +jVoid = JvmScalarType('V') +jInt = JvmScalarType('I') +jLong = JvmScalarType('J') +jBool = JvmScalarType('Z') +jDouble = JvmScalarType('D') +jByte = JvmScalarType('B') +jChar = JvmScalarType('C') +class JvmClassType(JvmType): + """ + Base class used for all class instances. Kind of an abstract class; + instances of this class do not support field or method lookup and + only work to obtain the descriptor. We use it on occasion for classes + like java.lang.Object etc. + """ + def __init__(self, classnm): + JvmType.__init__(self, desc_for_class(classnm)) + self.name = classnm # public String, like 'java.lang.Object' + def lookup_field(self, fieldnm): + raise KeyError(fieldnm) # we treat as opaque type + def lookup_method(self, methodnm): + raise KeyError(fieldnm) # we treat as opaque type + +jThrowable = JvmClassType('java.lang.Throwable') +jObject = JvmClassType('java.lang.Object') +jString = JvmClassType('java.lang.String') +jArrayList = JvmClassType('java.util.ArrayList') +jHashMap = JvmClassType('java.util.HashMap') +jIterator = JvmClassType('java.util.Iterator') +jClass = JvmClassType('java.lang.Class') +jStringBuilder = JvmClassType('java.lang.StringBuilder') +jPrintStream = JvmClassType('java.io.PrintStream') +jMath = JvmClassType('java.lang.Math') +jList = JvmClassType('java.util.List') +jPyPy = JvmClassType('pypy.PyPy') +jPyPyConst = JvmClassType('pypy.Constant') +jPyPyMain = JvmClassType('pypy.Main') + +class JvmArrayType(JvmType): + """ + Subclass used for all array instances. + """ + def __init__(self, elemtype): + JvmType.__init__(self, desc_for_array_of(elemtype.descriptor)) + self.element_type = elemtype + def lookup_field(self, fieldnm): + raise KeyError(fieldnm) # TODO adjust interface to permit opcode here + def lookup_method(self, methodnm): + raise KeyError(methodnm) # Arrays have no methods + +jByteArray = JvmArrayType(jByte) +jObjectArray = JvmArrayType(jObject) +jStringArray = JvmArrayType(jString) + Added: pypy/dist/pypy/translator/oosupport/constant.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/oosupport/constant.py Sun Nov 5 15:55:06 2006 @@ -0,0 +1,332 @@ +""" +___________________________________________________________________________ +Constants + +Complex code for representing constants. For each complex constant, +we create an object and record it in the database. These objects +contain the knowledge about how to access the value of the constant, +as well as the how to initialize it. The constants are initialized in +several phases so that interdependencies do not prevent a problem. + +The initialization process works like this: + +1. create_pointer(): this creates uninitialized pointers, so that + circular references can be handled. + +2. initialize_opaque(): initializes all objects except for + CustomDicts. This basically allows any operation that treats the + object as an opaque pointer. Most initializations complete here. + +3. initialize_full(): initializes custom dicts: objects are inserted + into dicts here because their fields have been initialized. This + assumes that no custom dicts are inserted into any other custom dicts. + +These three methods will be invoked by the database's gen_constants() +routine. +""" + +from pypy.rpython.ootypesystem import ootype + +PRIMITIVE_TYPES = set([ootype.Void, ootype.Bool, ootype.Char, ootype.UniChar, + ootype.Float, ootype.Signed, ootype.Unsigned, + ootype.String, ootype.SignedLongLong, + ootype.UnsignedLongLong]) + +def is_primitive(TYPE): + return TYPE in PRIMITIVE_TYPES + +def push_constant(db, TYPE, value, gen): + """ Class method that pushes the value of the specified + constant onto the stack. May or may not create an abstract constant + object. + + db --- a Database + TYPE --- the ootype of the constant + value --- the ootype instance + gen --- a metavm.Generator + """ + if is_primitive(TYPE): + return gen.push_primitive_constant(TYPE, value) + + const = db.record_const(value) + if const.is_null(): + gen.push_null(TYPE) + else: + const.push(gen) + +# ______________________________________________________________________ +# Constant generator + +class ConstantGenerator(object): + pass + +# ______________________________________________________________________ +# Constant base class + +class AbstractConst(object): + PRIORITY = 0 + + # ____________________________________________________________ + # Hashing, equality comparison, and repr() + # + # Overloaded so that two AbstactConst objects representing + # the same OOValue are equal. Provide a sensible repr() + + def __hash__(self): + return hash(self.value) + + def __eq__(self, other): + return self.value == other.value + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return '' % (self.name, self.value) + + # ____________________________________________________________ + # Simple query routines + + def get_name(self): + pass + + def get_type(self): + pass + + def is_null(self): + return self.value is ootype.null(self.value._TYPE) + + def is_inline(self): + """ + Inline constants are not stored as static fields in the + Constant class, but they are newly created on the stack every + time they are used. Classes overriding is_inline should + override _load too. + """ + return self.is_null() # by default only null constants are inlined + + # ____________________________________________________________ + # Loading and storing the constant + # + # These method are left here as an example. They are commented + # out because they must be implemented by the backend as a mix-in, + # and this way there is no conflict between the two base classes. + + #def push(self, gen): + # """ + # Pushes the value of this constant onto the stack. + # """ + # raise NotImplementedException + + #def store(self, gen): + # """ + # The value of the constant will be pushed onto the stack; + # store places it somewhere so it can later be loaded. + # """ + # raise NotImplementedException + + # ____________________________________________________________ + # Initializing the constant + + def record_dependencies(self): + """ + Ensures that all dependent objects are added to the database, + and any classes that are used are loaded. Called when the + constant object is created. + """ + raise NotImplementedException + + def create_pointer(self, gen): + """ + Creates the pointer representing this object, but does not + initialize its fields. First phase of initialization. + """ + raise NotImplementedException + + def initialize_opaque(self, gen): + """ + Initializes any constants that only use other constants in an + opaque fashion, without relying on them being fully initialized. + The big exception are custom dictionaries. + """ + raise NotImplementedException + + def initialize_full(self, gen): + """ + Initializes all remaining constants, such as custom dicts, + that inspect the fields of their arguments. If it is ever the + case that such constants try to access one another, we'll need + to add a dependence graph, but currently the execution order + of this function between constants is undefined. + """ + raise NotImplementedException + + # ____________________________________________________________ + # Internal helpers + + def _record_const_if_complex(self, TYPE, value): + if not is_primitive(TYPE): + self.db.record_const(value) + + +# ______________________________________________________________________ +# Records + +class RecordConst(AbstractConst): + def __init__(self, db, record, count): + self.db = db + self.cts = db.genoo.TypeSystem(db) + self.value = record + self.name = 'RECORD__%d' % count + + def record_dependencies(self): + if self.value is ootype.null(self.value._TYPE): + return + for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems(): + value = self.value._items[f_name] + self._record_const_if_complex(FIELD_TYPE, value) + + def create_pointer(self, gen): + assert not self.is_null() + gen.new(self.value._TYPE) + self.store(gen) + + def initialize_opaque(self, gen): + assert not self.is_null() + self.push(gen) + SELFTYPE = self.value._TYPE + for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems(): + if FIELD_TYPE is not ootype.Void: + gen.dup(SELFTYPE) + #gen.load(value) + load(self.db, FIELD_TYPE, value, gen) + gen.set_field(SELFTYPE, f_name) + gen.pop(SELFTYPE) + + def initialize_full(self, gen): + pass + +# ______________________________________________________________________ +# Instances + +class InstanceConst(AbstractConst): + def __init__(self, db, obj, static_type, count): + self.db = db + self.value = obj + self.cts = db.genoo.TypeSystem(db) + if static_type is None: + self.static_type = obj._TYPE + else: + self.static_type = static_type + db.genoo.TypeSystem(db).lltype_to_cts( + obj._TYPE) # force scheduling of obj's class + class_name = db.class_name(obj._TYPE).replace('.', '_') + self.name = '%s__%d' % (class_name, count) + + def record_dependencies(self): + if not self.value: + return + + INSTANCE = self.value._TYPE + while INSTANCE is not None: + for name, (TYPE, default) in INSTANCE._fields.iteritems(): + if TYPE is ootype.Void: + continue + type_ = self.cts.lltype_to_cts(TYPE) # record type + value = getattr(self.value, name) # record value + self._record_const_if_complex(TYPE, value) + INSTANCE = INSTANCE._superclass + + def is_null(self): + return not self.value + + def create_pointer(self, gen): + assert not self.is_null() + gen.new(self.value._TYPE) + self.store(gen) + + def _sorted_const_list(self): + # XXX, horrible hack: first collect all consts, then render + # CustomDicts at last because their ll_set could need other + # fields already initialized. We should really think a more + # general way to handle such things. + const_list = [] + INSTANCE = self.value._TYPE + while INSTANCE is not None: + for name, (TYPE, default) in INSTANCE._fields.iteritems(): + if TYPE is ootype.Void: + continue + value = getattr(self.value, name) + const_list.append((TYPE, INSTANCE, name, value)) + INSTANCE = INSTANCE._superclass + + def mycmp(x, y): + if isinstance(x[0], ootype.CustomDict) and not isinstance(y[0], ootype.CustomDict): + return 1 # a CustomDict is always greater than non-CustomDicts + elif isinstance(y[0], ootype.CustomDict) and not isinstance(x[0], ootype.CustomDict): + return -1 # a non-CustomDict is always less than CustomDicts + else: + return cmp(x, y) + const_list.sort(mycmp) + + return const_list + + def initialize_opaque(self, gen): + assert not self.is_null() + + # Get a list of all the constants we'll need to initialize. + # I am not clear on why this needs to be sorted, actually, + # but we sort it. + const_list = self._sorted_const_list() + + # Push ourself on the stack, and cast to our actual type if it + # is not the same as our static type + SELFTYPE = self.value._TYPE + self.push(gen) + if SELFTYPE is not self.static_type: + gen.downcast(SELFTYPE) + + # Store each of our fields in the sorted order + for FIELD_TYPE, INSTANCE, name, value in const_list: + gen.dup(SELFTYPE) + push_constant(self.db, FIELD_TYPE, value, gen) + gen.set_field(INSTANCE, name) + + # Pop selves from stack when done. + gen.pop(SELFTYPE) + + def initialize_full(self, gen): + pass + +# ______________________________________________________________________ +# Class constants + +class ClassConst(AbstractConst): + def __init__(self, db, class_, count): + self.db = db + self.cts = db.genoo.TypeSystem(db) + self.value = class_ + self.name = 'CLASS__%d' % count + + def record_dependencies(self): + INSTANCE = self.value._INSTANCE + if INSTANCE is not None: + self.cts.lltype_to_cts(INSTANCE) # force scheduling class generation + + def is_null(self): + return self.value._INSTANCE is None + + def is_inline(self): + return True + + def create_pointer(self, gen): + assert not self.is_null() + INSTANCE = self.value._INSTANCE + gen.getclassobject(INSTANCE) + self.store(gen) + + def initialize_opaque(self, gen): + pass + + def initialize_full(self, gen): + pass Added: pypy/dist/pypy/translator/oosupport/database.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/oosupport/database.py Sun Nov 5 15:55:06 2006 @@ -0,0 +1,158 @@ +from pypy.translator.oosupport.constant import is_primitive +from pypy.rpython.ootypesystem import ootype + +class Database(object): + + def __init__(self, genoo): + self.genoo = genoo + self.cts = genoo.TypeSystem(self) + self._pending_nodes = set() + self._rendered_nodes = set() + self._const_cache = {} + self._unique_counter = 0 + + # ____________________________________________________________ + # Miscellaneous + + def unique(self): + """ Every time it is called, returns a unique integer. Used in + various places. """ + self._unique_counter+=1 + return self._unique_counter-1 + + def class_name(self, OOINSTANCE): + """ Returns the backend class name of the type corresponding + to OOINSTANCE""" + raise NotImplementedError + + # ____________________________________________________________ + # Generation phases + + def gen_constants(self, ilasm): + """ Renders the constants uncovered during the graph walk""" + + # Now, emit the initialization code: + all_constants = self._const_cache.values() + gen = self._begin_gen_constants(ilasm, all_constants) + gen.add_section("Create Pointer Phase") + ctr = 0 + for const in all_constants: + gen.add_comment("Constant: %s" % const.name) + const.create_pointer(gen) + ctr = self._consider_interrupt(gen, ctr) + gen.add_section("Initialize Opaque Phase") + for const in all_constants: + gen.add_comment("Constant: %s" % const.name) + const.initialize_opaque(gen) + ctr = self._consider_interrupt(gen, ctr) + gen.add_section("Initialize Full Phase") + for const in all_constants: + gen.add_comment("Constant: %s" % const.name) + const.initialize_full(gen) + ctr = self._consider_interrupt(gen, ctr) + self._end_gen_constants(gen) + + def _consider_interrupt(self, gen, ctr): + ctr += 1 + if (ctr % 100) == 0: self._interrupt_gen_constants(gen) + return ctr + + def _begin_gen_constants(self): + # returns a generator + raise NotImplementedError + + def _interrupt_gen_constants(self): + # invoked every so often so as to break up the generated + # code and not create one massive function + pass + + def _end_gen_constants(self, gen): + raise NotImplementedError + + # ____________________________________________________________ + # Node creation + # + # Creates nodes for various kinds of things. + + def pending_class(self, INSTANCE): + """ Returns a Node representing the ootype.Instance provided """ + raise NotImplementedError + + def pending_function(self, graph): + """ Returns a Node representing the graph, which is being used as + a static function """ + raise NotImplementedError + + # ____________________________________________________________ + # Basic Worklist Manipulation + + def pending_node(self, node): + """ Adds a node to the worklist, so long as it is not already there + and has not already been rendered. """ + if node not in self._rendered_nodes: + self._pending_nodes.add(node) + + def len_pending(self): + return len(self._pending_nodes) + + def pop(self): + return self._pending_nodes.pop() + + # ____________________________________________________________ + # Constants + + # Defines the subclasses used to represent complex constants by + # _create_complex_const: + + InstanceConst = None + RecordConst = None + ClassConst = None + + def record_const(self, value): + """ Returns an object representing the constant, remembering also + any details needed to initialize the constant. value should be an + ootype constant value """ + assert not is_primitive(value) + if value in self._const_cache: + return self._const_cache[value] + const = self._create_complex_const(value) + self._const_cache[value] = const + const.record_dependencies() + return const + + def push_primitive_const(self, gen, value): + """ Helper which pushes a primitive constant onto the stack """ + raise NotImplementedException + + def _create_complex_const(self, value): + + """ A helper method which creates a Constant wrapper object for + the given value. Uses the types defined in the sub-class. """ + + # Determine if the static type differs from the dynamic type. + if isinstance(value, ootype._view): + static_type = value._TYPE + value = value._inst + else: + static_type = None + + # Find the appropriate kind of Const object. + if isinstance(value, ootype._instance): + return self.InstanceConst(self, value, static_type, self.unique()) + elif isinstance(value, ootype._record): + return self.RecordConst(self, value, self.unique()) + elif isinstance(value, ootype._class): + return self.ClassConst(self, value, self.unique()) + #elif isinstance(value, ootype._list): + # return ListConst(db, value, count) + #elif isinstance(value, ootype._static_meth): + # return StaticMethodConst(db, value, count) + #elif isinstance(value, ootype._custom_dict): + # return CustomDictConst(db, value, count) + #elif isinstance(value, ootype._dict): + # return DictConst(db, value, count) + #elif isinstance(value, llmemory.fakeweakaddress): + # return WeakRefConst(db, value, count) + else: + assert False, 'Unknown constant: %s' % value + Modified: pypy/dist/pypy/translator/oosupport/metavm.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/metavm.py (original) +++ pypy/dist/pypy/translator/oosupport/metavm.py Sun Nov 5 15:55:06 2006 @@ -23,6 +23,20 @@ """ pass + def add_section(self, text): + """ + Prints a distinguished comment + """ + self.add_comment("_" * 70) + self.add_comment(text) + + def pop(self, TYPE): + """ Pops a value off the top of the stack, which is of the + given TYPE. + + Stack: val, ... -> ...""" + raise NotImplementedError + def dup(self, TYPE): """ Duplicates the top of the stack, which is of the given TYPE. @@ -83,7 +97,14 @@ Stack: obj, ... -> obj, ... """ raise NotImplementedError - + + def getclassobject(self, OOINSTANCE): + """ + Gets the class object for the OOINSTANCE. The type of the class + object will depend on the backend, of course; for example in JVM + it is java.lang.Class. + """ + raise NotImplementedError def instantiate(self): """ @@ -146,9 +167,18 @@ Stack: ... -> newobj, ... """ raise NotImplementedError - def push_null(self): + def push_null(self, TYPE): + """ Push a NULL value onto the stack (the NULL value represents + a pointer to an instance of OOType TYPE, if it matters to you). """ raise NotImplementedError + def push_primitive_constant(self, TYPE, value): + """ Push an instance of TYPE onto the stack with the given + value. TYPE will be one of the types enumerated in + oosupport.constant.PRIMITIVE_TYPES. value will be its + corresponding ootype implementation. """ + raise NotImplementedError + class InstructionList(list): def render(self, generator, op): for instr in self: From arigo at codespeak.net Sun Nov 5 16:34:42 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 5 Nov 2006 16:34:42 +0100 (CET) Subject: [pypy-svn] r34243 - in pypy/dist/pypy: module/_file objspace/std Message-ID: <20061105153442.2EDFC1007C@code0.codespeak.net> Author: arigo Date: Sun Nov 5 16:34:41 2006 New Revision: 34243 Modified: pypy/dist/pypy/module/_file/app_file.py pypy/dist/pypy/objspace/std/objspace.py Log: (cfbolz, pedronis, arigo) Move the 'import os' out of the top-level module. This was causing old-style classes to stop working. Ha ha ha! Better 'assert' to catch this problem. Modified: pypy/dist/pypy/module/_file/app_file.py ============================================================================== --- pypy/dist/pypy/module/_file/app_file.py (original) +++ pypy/dist/pypy/module/_file/app_file.py Sun Nov 5 16:34:41 2006 @@ -1,7 +1,5 @@ """NOT_RPYTHON""" -import os - class file(object): """file(name[, mode[, buffering]]) -> file object @@ -242,6 +240,7 @@ """isatty() -> true or false. True if the file is connected to a tty device.""" if self._closed: raise ValueError('I/O operation on closed file') + import os return os.isatty(self.fd) def __repr__(self): Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Sun Nov 5 16:34:41 2006 @@ -147,13 +147,13 @@ def setup_old_style_classes(self): """NOT_RPYTHON""" # sanity check that this approach is working and is not too late - assert not self.is_true(self.contains(self.builtin.w_dict,self.wrap('_classobj'))),"app-level code has seen dummy old style classes" - assert not self.is_true(self.contains(self.builtin.w_dict,self.wrap('_instance'))),"app-level code has seen dummy old style classes" w_mod, w_dic = self.create_builtin_module('_classobj.py', 'classobj') w_purify = self.getitem(w_dic, self.wrap('purify')) w_classobj = self.getitem(w_dic, self.wrap('classobj')) w_instance = self.getitem(w_dic, self.wrap('instance')) self.call_function(w_purify) + assert not self.is_true(self.contains(self.builtin.w_dict,self.wrap('_classobj'))),"app-level code has seen dummy old style classes" + assert not self.is_true(self.contains(self.builtin.w_dict,self.wrap('_instance'))),"app-level code has seen dummy old style classes" self.w_classobj = w_classobj self.w_instance = w_instance From mwh at codespeak.net Sun Nov 5 16:41:34 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sun, 5 Nov 2006 16:41:34 +0100 (CET) Subject: [pypy-svn] r34245 - pypy/dist/pypy/doc Message-ID: <20061105154134.BF1CA1007C@code0.codespeak.net> Author: mwh Date: Sun Nov 5 16:41:33 2006 New Revision: 34245 Modified: pypy/dist/pypy/doc/sprint-reports.txt Log: link to ddorf2006b sprint report Modified: pypy/dist/pypy/doc/sprint-reports.txt ============================================================================== --- pypy/dist/pypy/doc/sprint-reports.txt (original) +++ pypy/dist/pypy/doc/sprint-reports.txt Sun Nov 5 16:41:33 2006 @@ -27,6 +27,7 @@ * `D?sseldorf (June 2006)`_ * `Europython/Geneva (July 2006)`_ * Limerick (Aug 2006) + * `D?sseldorf (October 2006)`_ .. _Hildesheim (Feb 2003): http://codespeak.net/pypy/extradoc/sprintinfo/HildesheimReport.html .. _Gothenburg (May 2003): http://codespeak.net/pypy/extradoc/sprintinfo/gothenburg-2003-sprintreport.txt @@ -47,5 +48,6 @@ .. _Tokyo (April 2006): http://codespeak.net/pypy/extradoc/sprintinfo/tokyo/sprint-report.txt .. _D?sseldorf (June 2006): http://codespeak.net/pypy/extradoc/sprintinfo/ddorf2006/report1.txt .. _Europython/Geneva (July 2006): http://codespeak.net/pypy/extradoc/sprintinfo/post-ep2006/report.txt + .. _D?sseldorf (October 2006): http://codespeak.net/pypy/extradoc/sprintinfo/ddorf2006b/report.txt From cfbolz at codespeak.net Sun Nov 5 16:44:37 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 16:44:37 +0100 (CET) Subject: [pypy-svn] r34246 - pypy/extradoc/sprintinfo/ddorf2006b Message-ID: <20061105154437.CAC811007F@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 16:44:31 2006 New Revision: 34246 Modified: pypy/extradoc/sprintinfo/ddorf2006b/report.txt Log: rest fix Modified: pypy/extradoc/sprintinfo/ddorf2006b/report.txt ============================================================================== --- pypy/extradoc/sprintinfo/ddorf2006b/report.txt (original) +++ pypy/extradoc/sprintinfo/ddorf2006b/report.txt Sun Nov 5 16:44:31 2006 @@ -153,7 +153,8 @@ Carl Friedrich & mwh --- +--:: + "... and the end result of all this is a dating site that matches people according to the sort of PyPy they compile." -- Samuele Pedroni From pedronis at codespeak.net Sun Nov 5 17:07:37 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 5 Nov 2006 17:07:37 +0100 (CET) Subject: [pypy-svn] r34247 - pypy/dist/pypy/interpreter/pyparser/test Message-ID: <20061105160737.103DD1007E@code0.codespeak.net> Author: pedronis Date: Sun Nov 5 17:07:36 2006 New Revision: 34247 Modified: pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py Log: use something else than '_file.py' 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 Sun Nov 5 17:07:36 2006 @@ -787,8 +787,8 @@ ] LIBSTUFF = [ - '_file.py', - '_sio.py' + '_marshal.py', + '_sio.py' ] def test_snippets(): From pedronis at codespeak.net Sun Nov 5 17:10:55 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 5 Nov 2006 17:10:55 +0100 (CET) Subject: [pypy-svn] r34248 - in pypy/dist/pypy: interpreter objspace objspace/std objspace/std/test Message-ID: <20061105161055.D1F471007E@code0.codespeak.net> Author: pedronis Date: Sun Nov 5 17:10:51 2006 New Revision: 34248 Added: pypy/dist/pypy/objspace/std/proxy_helpers.py - copied unchanged from r34239, pypy/branch/transparent-proxy/pypy/objspace/std/proxy_helpers.py pypy/dist/pypy/objspace/std/proxyobject.py - copied unchanged from r34239, pypy/branch/transparent-proxy/pypy/objspace/std/proxyobject.py pypy/dist/pypy/objspace/std/test/test_proxy.py - copied unchanged from r34239, pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy.py pypy/dist/pypy/objspace/std/test/test_proxy_function.py - copied unchanged from r34239, pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_function.py pypy/dist/pypy/objspace/std/test/test_proxy_internals.py - copied unchanged from r34239, pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_internals.py pypy/dist/pypy/objspace/std/test/test_proxy_iter.py - copied unchanged from r34239, pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_iter.py pypy/dist/pypy/objspace/std/test/test_proxy_object.py - copied unchanged from r34239, pypy/branch/transparent-proxy/pypy/objspace/std/test/test_proxy_object.py pypy/dist/pypy/objspace/std/transparent.py - copied unchanged from r34239, pypy/branch/transparent-proxy/pypy/objspace/std/transparent.py Modified: pypy/dist/pypy/interpreter/argument.py pypy/dist/pypy/interpreter/baseobjspace.py pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/interpreter/typedef.py pypy/dist/pypy/objspace/descroperation.py pypy/dist/pypy/objspace/std/listobject.py pypy/dist/pypy/objspace/std/model.py pypy/dist/pypy/objspace/std/objspace.py pypy/dist/pypy/objspace/std/stdtypedef.py Log: (pedronis, fijal) merge the transparent-proxy branch. Modified: pypy/dist/pypy/interpreter/argument.py ============================================================================== --- pypy/dist/pypy/interpreter/argument.py (original) +++ pypy/dist/pypy/interpreter/argument.py Sun Nov 5 17:10:51 2006 @@ -350,6 +350,11 @@ "Return a ([w1,w2...], {'kw':w3...}) pair." self._unpack() return self.arguments_w, self.kwds_w + + def popfirst(self): + self._unpack() + return self.arguments_w[0], Arguments(self.space, self.arguments_w[1:], + kwds_w = self.kwds_w) def _unpack(self): "unpack the *arg and **kwd into w_arguments and kwds_w" @@ -418,7 +423,7 @@ if not e.match(self.space, self.space.w_StopIteration): raise return None - + ### Parsing for function calls ### def _match_signature(self, scope_w, argnames, has_vararg=False, Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Sun Nov 5 17:10:51 2006 @@ -27,6 +27,24 @@ return space.finditem(w_dict, w_attr) return None + def setdictvalue(self, space, w_attr, w_value): + w_dict = self.getdict() + if w_dict is not None: + space.set_str_keyed_item(w_dict, w_attr, w_value) + return True + return False + + def deldictvalue(self, space, w_name): + w_dict = self.getdict() + if w_dict is not None: + try: + space.delitem(w_dict, w_name) + return True + except OperationError, ex: + if not ex.match(space, space.w_KeyError): + raise + return False + def setdict(self, space, w_dict): typename = space.type(self).getname(space, '?') raise OperationError(space.w_TypeError, @@ -74,6 +92,12 @@ def setslotvalue(self, index, w_val): raise NotImplementedError + def descr_call_mismatch(self, space, opname, RequiredClass, args): + msg = "'%s' object expected, got '%s' instead" % ( + RequiredClass.typedef.name, + self.getclass(space).getname(space, '?')) + raise OperationError(space.w_TypeError, space.wrap(msg)) + # used by _weakref implemenation def getweakref(self): @@ -130,6 +154,9 @@ def __str__(self): return self.msg +class DescrMismatch(Exception): + pass + class ObjSpace(object): """Base class for the interpreter-level implementations of object spaces. http://codespeak.net/pypy/dist/pypy/doc/objspace.html""" @@ -454,6 +481,13 @@ return w_obj return None + def descr_self_interp_w(self, RequiredClass, w_obj): + obj = self.interpclass_w(w_obj) + if not isinstance(obj, RequiredClass): + raise DescrMismatch() + return obj + descr_self_interp_w._annspecialcase_ = 'specialize:arg(1)' + def interp_w(self, RequiredClass, w_obj, can_be_None=False): """ Unwrap w_obj, checking that it is an instance of the required internal Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Sun Nov 5 17:10:51 2006 @@ -16,7 +16,7 @@ from pypy.interpreter import eval from pypy.interpreter.function import Function, Method from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable -from pypy.interpreter.baseobjspace import Wrappable, SpaceCache +from pypy.interpreter.baseobjspace import Wrappable, SpaceCache, DescrMismatch from pypy.interpreter.argument import Arguments, AbstractArguments from pypy.tool.sourcetools import NiceCompile, compile2 @@ -55,7 +55,10 @@ if isinstance(el, str): getattr(self, "visit_%s" % (el,))(el, *args) elif isinstance(el, tuple): - self.visit_function(el, *args) + if el[0] == 'self': + self.visit_self(el[1], *args) + else: + self.visit_function(el, *args) else: for typ in self.bases_order: if issubclass(el, typ): @@ -100,6 +103,9 @@ def visit_function(self, (func, cls), app_sig): self.dispatch(cls, app_sig) + + def visit_self(self, cls, app_sig): + self.visit__Wrappable(cls, app_sig) def visit__Wrappable(self, el, app_sig): name = el.__name__ @@ -170,6 +176,10 @@ self.run_args.append("%s(%s)" % (self.use(func), self.scopenext())) + def visit_self(self, typ): + self.run_args.append("space.descr_self_interp_w(%s, %s)" % + (self.use(typ), self.scopenext())) + def visit__Wrappable(self, typ): self.run_args.append("space.interp_w(%s, %s)" % (self.use(typ), self.scopenext())) @@ -275,6 +285,10 @@ def visit_function(self, (func, cls)): raise FastFuncNotSupported + def visit_self(self, typ): + self.unwrap.append("space.descr_self_interp_w(%s, %s)" % + (self.use(typ), self.nextarg())) + def visit__Wrappable(self, typ): self.unwrap.append("space.interp_w(%s, %s)" % (self.use(typ), self.nextarg())) @@ -334,13 +348,16 @@ class BuiltinCode(eval.Code): "The code object implementing a built-in (interpreter-level) hook." hidden_applevel = True + descrmismatch_op = None + descr_reqcls = None # When a BuiltinCode is stored in a Function object, # you get the functionality of CPython's built-in function type. NOT_RPYTHON_ATTRIBUTES = ['_bltin', '_unwrap_spec'] - def __init__(self, func, unwrap_spec = None, self_type = None): + def __init__(self, func, unwrap_spec = None, self_type = None, + descrmismatch=None): "NOT_RPYTHON" # 'implfunc' is the interpreter-level function. # Note that this uses a lot of (construction-time) introspection. @@ -375,7 +392,17 @@ if self_type: assert unwrap_spec[0] == 'self',"self_type without 'self' spec element" unwrap_spec = list(unwrap_spec) - unwrap_spec[0] = self_type + if descrmismatch is not None: + assert issubclass(self_type, Wrappable) + unwrap_spec[0] = ('self', self_type) + self.descrmismatch_op = descrmismatch + self.descr_reqcls = self_type + else: + unwrap_spec[0] = self_type + else: + assert descrmismatch is None, ( + "descrmismatch without a self-type specified") + orig_sig = Signature(func, argnames, varargname, kwargname) app_sig = Signature(func) @@ -433,7 +460,12 @@ raise OperationError(space.w_MemoryError, space.w_None) except RuntimeError, e: raise OperationError(space.w_RuntimeError, - space.wrap("internal error: " + str(e))) + space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return scope_w[0].descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + args) if w_result is None: w_result = space.w_None return w_result @@ -453,6 +485,11 @@ except RuntimeError, e: raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return args.firstarg().descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + args) if w_result is None: w_result = space.w_None return w_result @@ -475,6 +512,11 @@ except RuntimeError, e: raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return args.firstarg().descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + args) if w_result is None: w_result = space.w_None return w_result @@ -486,8 +528,8 @@ except KeyboardInterrupt: raise OperationError(space.w_KeyboardInterrupt, space.w_None) except MemoryError: - raise OperationError(space.w_MemoryError, space.w_None) - except RuntimeError, e: + raise OperationError(space.w_MemoryError, space.w_None) + except (RuntimeError, DescrMismatch), e: raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) if w_result is None: @@ -504,7 +546,12 @@ raise OperationError(space.w_MemoryError, space.w_None) except RuntimeError, e: raise OperationError(space.w_RuntimeError, - space.wrap("internal error: " + str(e))) + space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return w1.descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + Arguments(space, [w1])) if w_result is None: w_result = space.w_None return w_result @@ -520,6 +567,11 @@ except RuntimeError, e: raise OperationError(space.w_RuntimeError, space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return w1.descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + Arguments(space, [w1, w2])) if w_result is None: w_result = space.w_None return w_result @@ -534,7 +586,12 @@ raise OperationError(space.w_MemoryError, space.w_None) except RuntimeError, e: raise OperationError(space.w_RuntimeError, - space.wrap("internal error: " + str(e))) + space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return w1.descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + Arguments(space, [w1, w2, w3])) if w_result is None: w_result = space.w_None return w_result @@ -549,7 +606,13 @@ raise OperationError(space.w_MemoryError, space.w_None) except RuntimeError, e: raise OperationError(space.w_RuntimeError, - space.wrap("internal error: " + str(e))) + space.wrap("internal error: " + str(e))) + except DescrMismatch, e: + return w1.descr_call_mismatch(space, + self.descrmismatch_op, + self.descr_reqcls, + Arguments(space, + [w1, w2, w3, w4])) if w_result is None: w_result = space.w_None return w_result @@ -569,7 +632,8 @@ NOT_RPYTHON_ATTRIBUTES = ['_staticdefs'] - def __init__(self, f, app_name=None, unwrap_spec = None): + def __init__(self, f, app_name=None, unwrap_spec = None, + descrmismatch=None): "NOT_RPYTHON" Wrappable.__init__(self) # f must be a function whose name does NOT start with 'app_' @@ -584,7 +648,9 @@ raise ValueError, ("function name %r suspiciously starts " "with 'app_'" % f.func_name) app_name = f.func_name - self._code = BuiltinCode(f, unwrap_spec=unwrap_spec, self_type = self_type) + self._code = BuiltinCode(f, unwrap_spec=unwrap_spec, + self_type = self_type, + descrmismatch=descrmismatch) self.__name__ = f.func_name self.name = app_name self._staticdefs = list(f.func_defaults or ()) Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Sun Nov 5 17:10:51 2006 @@ -351,7 +351,8 @@ raise operror else: tb = space.interpclass_w(w_traceback) - if not isinstance(tb, pytraceback.PyTraceback): + if tb is None or not space.is_true(space.isinstance(tb, + space.gettypeobject(pytraceback.PyTraceback.typedef))): raise OperationError(space.w_TypeError, space.wrap("raise: arg 3 must be a traceback or None")) operror.application_traceback = tb Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Sun Nov 5 17:10:51 2006 @@ -5,7 +5,8 @@ import py from pypy.interpreter.gateway import interp2app from pypy.interpreter.argument import Arguments -from pypy.interpreter.baseobjspace import Wrappable, W_Root, ObjSpace +from pypy.interpreter.baseobjspace import Wrappable, W_Root, ObjSpace, \ + DescrMismatch from pypy.interpreter.error import OperationError from pypy.tool.sourcetools import compile2, func_with_new_name from pypy.rlib.objectmodel import instantiate @@ -242,7 +243,7 @@ assert issubclass(cls, Wrappable) source = """ def descr_typecheck_%(name)s(space, w_obj, %(extra)s): - obj = space.interp_w(%(cls_name)s, w_obj) + obj = space.descr_self_interp_w(%(cls_name)s, w_obj) return %(name)s(space, obj, %(extra)s) """ miniglobals[cls_name] = cls @@ -295,6 +296,7 @@ self.fset = fset self.fdel = fdel self.doc = doc + self.reqcls = cls self.name = '' self.objclass_getter = objclass_getter @@ -307,7 +309,12 @@ #print property, w_obj, w_cls return space.wrap(property) else: - return property.fget(space, w_obj) + try: + return property.fget(space, w_obj) + except DescrMismatch, e: + return w_obj.descr_call_mismatch(space, '__getattribute__',\ + property.reqcls, Arguments(space, [w_obj, + space.wrap(property.name)])) def descr_property_set(space, property, w_obj, w_value): """property.__set__(obj, value) @@ -316,7 +323,12 @@ if fset is None: raise OperationError(space.w_TypeError, space.wrap("readonly attribute")) - fset(space, w_obj, w_value) + try: + fset(space, w_obj, w_value) + except DescrMismatch, e: + w_obj.descr_call_mismatch(space, '__setattr__',\ + property.reqcls, Arguments(space, [w_obj, + space.wrap(property.name), w_value])) def descr_property_del(space, property, w_obj): """property.__delete__(obj) @@ -325,7 +337,12 @@ if fdel is None: raise OperationError(space.w_AttributeError, space.wrap("cannot delete attribute")) - fdel(space, w_obj) + try: + fdel(space, w_obj) + except DescrMismatch, e: + w_obj.descr_call_mismatch(space, '__delattr__',\ + property.reqcls, Arguments(space, [w_obj, + space.wrap(property.name)])) def descr_get_objclass(space, property): return property.objclass_getter(space) @@ -583,9 +600,10 @@ Function.typedef = TypeDef("function", __new__ = interp2app(Function.descr_method__new__.im_func), __call__ = interp2app(Function.descr_function_call, - unwrap_spec=['self', Arguments]), + unwrap_spec=['self', Arguments], + descrmismatch='__call__'), __get__ = interp2app(descr_function_get), - __repr__ = interp2app(Function.descr_function_repr), + __repr__ = interp2app(Function.descr_function_repr, descrmismatch='__repr__'), __reduce__ = interp2app(Function.descr_function__reduce__, unwrap_spec=['self', ObjSpace]), __setstate__ = interp2app(Function.descr_function__setstate__, @@ -650,8 +668,10 @@ GeneratorIterator.typedef = TypeDef("generator", __reduce__ = interp2app(GeneratorIterator.descr__reduce__, unwrap_spec=['self', ObjSpace]), - next = interp2app(GeneratorIterator.descr_next), - __iter__ = interp2app(GeneratorIterator.descr__iter__), + next = interp2app(GeneratorIterator.descr_next, + descrmismatch='next'), + __iter__ = interp2app(GeneratorIterator.descr__iter__, + descrmismatch='__iter__'), gi_running = interp_attrproperty('running', cls=GeneratorIterator), gi_frame = interp_attrproperty('frame', cls=GeneratorIterator), __weakref__ = make_weakref_descr(GeneratorIterator), Modified: pypy/dist/pypy/objspace/descroperation.py ============================================================================== --- pypy/dist/pypy/objspace/descroperation.py (original) +++ pypy/dist/pypy/objspace/descroperation.py Sun Nov 5 17:10:51 2006 @@ -35,9 +35,7 @@ if space.is_data_descr(w_descr): space.set(w_descr, w_obj, w_value) return - w_dict = w_obj.getdict() - if w_dict is not None: - space.set_str_keyed_item(w_dict, w_name, w_value) + if w_obj.setdictvalue(space, w_name, w_value): return raiseattrerror(space, w_obj, name, w_descr) @@ -48,14 +46,8 @@ if space.is_data_descr(w_descr): space.delete(w_descr, w_obj) return - w_dict = w_obj.getdict() - if w_dict is not None: - try: - space.delitem(w_dict, w_name) - return - except OperationError, ex: - if not ex.match(space, space.w_KeyError): - raise + if w_obj.deldictvalue(space, w_name): + return raiseattrerror(space, w_obj, name, w_descr) def descr__init__(space, w_obj, __args__): @@ -404,9 +396,11 @@ if space.is_w(w_obj2, space.w_None): return space.wrap(1) if space.is_w(w_typ1, w_typ2): + #print "WARNING, comparison by address!" w_id1 = space.id(w_obj1) w_id2 = space.id(w_obj2) else: + #print "WARNING, comparison by address!" w_id1 = space.id(w_typ1) w_id2 = space.id(w_typ2) if space.is_true(space.lt(w_id1, w_id2)): @@ -451,6 +445,9 @@ left, right = specialnames op = getattr(operator, left) def comparison_impl(space, w_obj1, w_obj2): + #from pypy.objspace.std.tlistobject import W_TransparentList + #if isinstance(w_obj1, W_TransparentList): + # import pdb;pdb.set_trace() w_typ1 = space.type(w_obj1) w_typ2 = space.type(w_obj2) w_left_src, w_left_impl = space.lookup_in_type_where(w_typ1, left) @@ -523,9 +520,9 @@ l = ["space.is_true(space.isinstance(w_result, %s))" % x for x in checkerspec] checker = " or ".join(l) - source = """if 1: + source = """if 1: def %(targetname)s(space, w_obj): - w_impl = space.lookup(w_obj, %(specialname)r) + w_impl = space.lookup(w_obj, %(specialname)r) if w_impl is None: raise OperationError(space.w_TypeError, space.wrap("operand does not support unary %(targetname)s")) Modified: pypy/dist/pypy/objspace/std/listobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/listobject.py (original) +++ pypy/dist/pypy/objspace/std/listobject.py Sun Nov 5 17:10:51 2006 @@ -78,6 +78,16 @@ def add__List_List(space, w_list1, w_list2): return W_ListObject(w_list1.wrappeditems + w_list2.wrappeditems) +#def radd__List_List(space, w_list1, w_list2): +# return W_ListObject(w_list2.wrappeditems + w_list1.wrappeditems) + +##def add__List_ANY(space, w_list, w_any): +## if space.is_true(space.isinstance(w_any, space.w_list)): +## items1_w = w_list.wrappeditems +## items2_w = space.unpackiterable(w_any) +## return W_ListObject(items1_w + items2_w) +## raise FailedToImplement + def inplace_add__List_ANY(space, w_list1, w_iterable2): list_extend__List_ANY(space, w_list1, w_iterable2) return w_list1 @@ -109,26 +119,37 @@ def eq__List_List(space, w_list1, w_list2): # needs to be safe against eq_w() mutating the w_lists behind our back - if len(w_list1.wrappeditems) != len(w_list2.wrappeditems): + items1_w = w_list1.wrappeditems + items2_w = w_list2.wrappeditems + return equal_wrappeditems(space, items1_w, items2_w) + +def equal_wrappeditems(space, items1_w, items2_w): + if len(items1_w) != len(items2_w): return space.w_False i = 0 - while i < len(w_list1.wrappeditems) and i < len(w_list2.wrappeditems): - if not space.eq_w(w_list1.wrappeditems[i], w_list2.wrappeditems[i]): + while i < len(items1_w) and i < len(items2_w): + if not space.eq_w(items1_w[i], items2_w[i]): return space.w_False i += 1 - return space.newbool(len(w_list1.wrappeditems) == len(w_list2.wrappeditems)) + return space.w_True + #return space.newbool(len(w_list1.wrappeditems) == len(w_list2.wrappeditems)) + +##def eq__List_ANY(space, w_list1, w_any): +## if space.is_true(space.isinstance(w_any, space.w_list)): +## items1_w = w_list1.wrappeditems +## items2_w = space.unpackiterable(w_any) +## return equal_wrappeditems(space, items1_w, items2_w) +## raise FailedToImplement def _min(a, b): if a < b: return a return b -def lt__List_List(space, w_list1, w_list2): +def lessthan_unwrappeditems(space, items1_w, items2_w): # needs to be safe against eq_w() mutating the w_lists behind our back # Search for the first index where items are different i = 0 - items1_w = w_list1.wrappeditems - items2_w = w_list2.wrappeditems while i < len(items1_w) and i < len(items2_w): w_item1 = items1_w[i] w_item2 = items2_w[i] @@ -138,13 +159,11 @@ # No more items to compare -- compare sizes return space.newbool(len(items1_w) < len(items2_w)) -def gt__List_List(space, w_list1, w_list2): +def greaterthan_unwrappeditems(space, items1_w, items2_w): # needs to be safe against eq_w() mutating the w_lists behind our back # Search for the first index where items are different i = 0 - items1_w = w_list1.wrappeditems - items2_w = w_list2.wrappeditems - while i < len(w_list1.wrappeditems) and i < len(w_list2.wrappeditems): + while i < len(items1_w) and i < len(items2_w): w_item1 = items1_w[i] w_item2 = items2_w[i] if not space.eq_w(w_item1, w_item2): @@ -153,6 +172,29 @@ # No more items to compare -- compare sizes return space.newbool(len(items1_w) > len(items2_w)) +def lt__List_List(space, w_list1, w_list2): + return lessthan_unwrappeditems(space, w_list1.wrappeditems, + w_list2.wrappeditems) + +##def lt__List_ANY(space, w_list1, w_any): +## # XXX: Implement it not unpacking all the elements +## if space.is_true(space.isinstance(w_any, space.w_list)): +## items1_w = w_list1.wrappeditems +## items2_w = space.unpackiterable(w_any) +## return lessthan_unwrappeditems(space, items1_w, items2_w) +## raise FailedToImplement + +def gt__List_List(space, w_list1, w_list2): + return greaterthan_unwrappeditems(space, w_list1.wrappeditems, + w_list2.wrappeditems) + +##def gt__List_ANY(space, w_list1, w_any): +## # XXX: Implement it not unpacking all the elements +## if space.is_true(space.isinstance(w_any, space.w_list)): +## items1_w = w_list1.wrappeditems +## items2_w = space.unpackiterable(w_any) +## return greaterthan_unwrappeditems(space, items1_w, items2_w) +## raise FailedToImplement def delitem__List_ANY(space, w_list, w_idx): idx = space.int_w(w_idx) Modified: pypy/dist/pypy/objspace/std/model.py ============================================================================== --- pypy/dist/pypy/objspace/std/model.py (original) +++ pypy/dist/pypy/objspace/std/model.py Sun Nov 5 17:10:51 2006 @@ -18,6 +18,8 @@ "dictmultiobject.W_DictMultiIterObject"], "withrangelist" : ["rangeobject.W_RangeListObject", "rangeobject.W_RangeIterObject"], + "withtproxy" : ["proxyobject.W_TransparentList", + "proxyobject.W_TransparentDict"], } class StdTypeModel: @@ -74,6 +76,7 @@ from pypy.objspace.std import unicodeobject from pypy.objspace.std import dictproxyobject from pypy.objspace.std import rangeobject + from pypy.objspace.std import proxyobject from pypy.objspace.std import fake import pypy.objspace.std.default # register a few catch-all multimethods @@ -137,6 +140,7 @@ # register the order in which types are converted into each others # when trying to dispatch multimethods. # XXX build these lists a bit more automatically later + if config.objspace.std.withsmallint: self.typeorder[boolobject.W_BoolObject] += [ (smallintobject.W_SmallIntObject, boolobject.delegate_Bool2SmallInt), @@ -195,6 +199,9 @@ # put W_Root everywhere self.typeorder[W_Root] = [] for type in self.typeorder: + from pypy.objspace.std import stdtypedef + if type is not W_Root and isinstance(type.typedef, stdtypedef.StdTypeDef): + self.typeorder[type].append((type.typedef.any, None)) self.typeorder[type].append((W_Root, None)) # ____________________________________________________________ Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Sun Nov 5 17:10:51 2006 @@ -132,6 +132,12 @@ # final setup self.setup_builtin_modules() + # Adding transparent proxy call + if self.config.objspace.std.withtproxy: + from pypy.objspace.std.transparent import app_proxy + + self.setitem(self.builtin.w_dict, self.wrap('proxy'), + self.wrap(app_proxy)) def enable_old_style_classes_as_default_metaclass(self): self.setitem(self.builtin.w_dict, self.wrap('__metaclass__'), self.w_classobj) Modified: pypy/dist/pypy/objspace/std/stdtypedef.py ============================================================================== --- pypy/dist/pypy/objspace/std/stdtypedef.py (original) +++ pypy/dist/pypy/objspace/std/stdtypedef.py Sun Nov 5 17:10:51 2006 @@ -20,6 +20,7 @@ def __init__(self, __name, __base=None, **rawdict): "NOT_RPYTHON: initialization-time only." TypeDef.__init__(self, __name, __base, **rawdict) + self.any = type("W_Any"+__name.title(), (baseobjspace.W_Root,), {'typedef': self}) self.local_multimethods = [] def registermethods(self, namespace): From pedronis at codespeak.net Sun Nov 5 17:39:05 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 5 Nov 2006 17:39:05 +0100 (CET) Subject: [pypy-svn] r34249 - pypy/dist/pypy/config Message-ID: <20061105163905.56FC11007E@code0.codespeak.net> Author: pedronis Date: Sun Nov 5 17:39:02 2006 New Revision: 34249 Modified: pypy/dist/pypy/config/pypyoption.py Log: oops Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Sun Nov 5 17:39:02 2006 @@ -53,6 +53,9 @@ default=False), OptionDescription("std", "Standard Object Space Options", [ + BoolOption("withtproxy", "support transparent proxies", + default=False), + BoolOption("withsmallint", "use tagged integers", default=False), From ac at codespeak.net Sun Nov 5 18:00:20 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Sun, 5 Nov 2006 18:00:20 +0100 (CET) Subject: [pypy-svn] r34250 - pypy/dist/pypy/module/rsocket Message-ID: <20061105170020.263731007E@code0.codespeak.net> Author: ac Date: Sun Nov 5 17:59:59 2006 New Revision: 34250 Modified: pypy/dist/pypy/module/rsocket/interp_socket.py Log: Release the GIL around some functioncalls. Modified: pypy/dist/pypy/module/rsocket/interp_socket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_socket.py (original) +++ pypy/dist/pypy/module/rsocket/interp_socket.py Sun Nov 5 17:59:59 2006 @@ -16,7 +16,12 @@ info is a pair (hostaddr, port). """ try: - sock, addr = self.accept(W_RSocket) + GIL = space.threadlocals.getGIL() + if GIL is not None: GIL.release() + try: + sock, addr = self.accept(W_RSocket) + finally: + if GIL is not None: GIL.acquire(True) except SocketError, e: raise converted_error(space, e) return space.newtuple([space.wrap(sock), addr.as_object(space)]) @@ -53,7 +58,12 @@ is a pair (host, port). """ try: - self.connect(self.addr_from_object(space, w_addr)) + GIL = space.threadlocals.getGIL() + if GIL is not None: GIL.release() + try: + self.connect(self.addr_from_object(space, w_addr)) + finally: + if GIL is not None: GIL.acquire(True) except SocketError, e: raise converted_error(space, e) except TypeError, e: @@ -67,7 +77,12 @@ This is like connect(address), but returns an error code (the errno value) instead of raising an exception when an error occurs. """ - error = self.connect_ex(self.addr_from_object(space, w_addr)) + GIL = space.threadlocals.getGIL() + if GIL is not None: GIL.release() + try: + error = self.connect_ex(self.addr_from_object(space, w_addr)) + finally: + if GIL is not None: GIL.acquire(True) return space.wrap(error) connect_ex_w.unwrap_spec = ['self', ObjSpace, W_Root] @@ -177,7 +192,13 @@ the remote end is closed and all data is read, return the empty string. """ try: - data = self.recv(buffersize, flags) + GIL = space.threadlocals.getGIL() + if GIL is not None: GIL.release() + try: + data = self.recv(buffersize, flags) + finally: + if GIL is not None: GIL.acquire(True) + except SocketError, e: raise converted_error(space, e) return space.wrap(data) @@ -189,7 +210,12 @@ Like recv(buffersize, flags) but also return the sender's address info. """ try: - data, addr = self.recvfrom(buffersize, flags) + GIL = space.threadlocals.getGIL() + if GIL is not None: GIL.release() + try: + data, addr = self.recvfrom(buffersize, flags) + finally: + if GIL is not None: GIL.acquire(True) except SocketError, e: raise converted_error(space, e) return space.newtuple([space.wrap(data), addr.as_object(space)]) @@ -203,7 +229,12 @@ sent; this may be less than len(data) if the network is busy. """ try: - count = self.send(data, flags) + GIL = space.threadlocals.getGIL() + if GIL is not None: GIL.release() + try: + count = self.send(data, flags) + finally: + if GIL is not None: GIL.acquire(True) except SocketError, e: raise converted_error(space, e) return space.wrap(count) @@ -218,7 +249,12 @@ to tell how much data has been sent. """ try: - self.sendall(data, flags) + GIL = space.threadlocals.getGIL() + if GIL is not None: GIL.release() + try: + count = self.sendall(data, flags) + finally: + if GIL is not None: GIL.acquire(True) except SocketError, e: raise converted_error(space, e) sendall_w.unwrap_spec = ['self', ObjSpace, str, int] @@ -239,7 +275,12 @@ w_addr = w_param3 try: addr = self.addr_from_object(space, w_addr) - count = self.sendto(data, flags, addr) + GIL = space.threadlocals.getGIL() + if GIL is not None: GIL.release() + try: + count = self.sendto(data, flags, addr) + finally: + if GIL is not None: GIL.acquire(True) except SocketError, e: raise converted_error(space, e) return space.wrap(count) From arigo at codespeak.net Sun Nov 5 18:12:43 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 5 Nov 2006 18:12:43 +0100 (CET) Subject: [pypy-svn] r34251 - in pypy/dist/pypy/rpython: . test Message-ID: <20061105171243.8AA3E1007D@code0.codespeak.net> Author: arigo Date: Sun Nov 5 18:12:42 2006 New Revision: 34251 Modified: pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/test/test_rtuple.py Log: Implemented == and != between tuples in RPython. Modified: pypy/dist/pypy/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/dist/pypy/rpython/rtuple.py Sun Nov 5 18:12:42 2006 @@ -7,7 +7,7 @@ from pypy.rpython.rmodel import IteratorRepr from pypy.rpython.rmodel import externalvsinternal from pypy.rpython.rslice import AbstractSliceRepr -from pypy.rpython.lltypesystem.lltype import Void, Signed +from pypy.rpython.lltypesystem.lltype import Void, Signed, Bool from pypy.rlib.rarithmetic import intmask from pypy.rlib.unroll import unrolling_iterable @@ -194,6 +194,16 @@ return r_tup1.newtuple_cached(hop, vlist) rtype_inplace_add = rtype_add + def rtype_eq((r_tup1, r_tup2), hop): + # XXX assumes that r_tup2 is convertible to r_tup1 + v_tuple1, v_tuple2 = hop.inputargs(r_tup1, r_tup1) + ll_eq = r_tup1.get_ll_eq_function() + return hop.gendirectcall(ll_eq, v_tuple1, v_tuple2) + + def rtype_ne(tup1tup2, hop): + v_res = tup1tup2.rtype_eq(hop) + return hop.genop('bool_not', [v_res], resulttype=Bool) + 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: 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 Sun Nov 5 18:12:42 2006 @@ -264,6 +264,28 @@ assert res[5] == "hello" self.interpret(f, [9]) + def test_tuple_eq(self): + def f(n): + return (n, 6) == (3, n*2) + res = self.interpret(f, [3]) + assert res is True + res = self.interpret(f, [2]) + assert res is False + + def test_tuple_ne(self): + def f(n): + return (n, 6) != (3, n*2) + res = self.interpret(f, [3]) + assert res is False + res = self.interpret(f, [2]) + assert res is True + + def test_tuple_hash(self): + def f(n): + return hash((n, 6)) == hash((3, n*2)) + res = self.interpret(f, [3]) + assert res is True + class TestLLtype(BaseTestRtuple, LLRtypeMixin): pass From cfbolz at codespeak.net Sun Nov 5 18:17:58 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 5 Nov 2006 18:17:58 +0100 (CET) Subject: [pypy-svn] r34252 - pypy/branch/transparent-proxy Message-ID: <20061105171758.9BDBF1007D@code0.codespeak.net> Author: cfbolz Date: Sun Nov 5 18:17:57 2006 New Revision: 34252 Removed: pypy/branch/transparent-proxy/ Log: remove merged branch From cfbolz at codespeak.net Mon Nov 6 09:52:15 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 6 Nov 2006 09:52:15 +0100 (CET) Subject: [pypy-svn] r34256 - pypy/dist/pypy/tool/test Message-ID: <20061106085215.395901007B@code0.codespeak.net> Author: cfbolz Date: Mon Nov 6 09:52:13 2006 New Revision: 34256 Removed: pypy/dist/pypy/tool/test/slowtest_run_translation.py Log: remove test file that ran translation a very long time ago From cfbolz at codespeak.net Mon Nov 6 09:52:30 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 6 Nov 2006 09:52:30 +0100 (CET) Subject: [pypy-svn] r34257 - in pypy/dist/pypy: interpreter/pyparser/test lib lib/test2 Message-ID: <20061106085230.4C46410080@code0.codespeak.net> Author: cfbolz Date: Mon Nov 6 09:52:28 2006 New Revision: 34257 Removed: pypy/dist/pypy/lib/_sio.py pypy/dist/pypy/lib/test2/test_sio.py Modified: pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py Log: remove _sio 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 Mon Nov 6 09:52:28 2006 @@ -788,7 +788,6 @@ LIBSTUFF = [ '_marshal.py', - '_sio.py' ] def test_snippets(): From cfbolz at codespeak.net Mon Nov 6 10:07:43 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 6 Nov 2006 10:07:43 +0100 (CET) Subject: [pypy-svn] r34258 - pypy/dist/pypy/translator/c/test Message-ID: <20061106090743.CB48110080@code0.codespeak.net> Author: cfbolz Date: Mon Nov 6 10:07:43 2006 New Revision: 34258 Removed: pypy/dist/pypy/translator/c/test/test_ext__socket.py Log: removing this test that tested the old _socket module From antocuni at codespeak.net Mon Nov 6 12:08:42 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 6 Nov 2006 12:08:42 +0100 (CET) Subject: [pypy-svn] r34262 - pypy/dist/pypy/translator/cli Message-ID: <20061106110842.B05C91006E@code0.codespeak.net> Author: antocuni Date: Mon Nov 6 12:08:42 2006 New Revision: 34262 Modified: pypy/dist/pypy/translator/cli/opcodes.py Log: Ignore debug_assert. Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Mon Nov 6 12:08:42 2006 @@ -56,6 +56,7 @@ 'cast_weakadr_to_ptr': [CastWeakAdrToPtr], 'gc__collect': 'call void class [mscorlib]System.GC::Collect()', 'resume_point': Ignore, + 'debug_assert': Ignore, # __________ numeric operations __________ From mwh at codespeak.net Mon Nov 6 15:20:36 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 6 Nov 2006 15:20:36 +0100 (CET) Subject: [pypy-svn] r34264 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061106142036.C2C0910075@code0.codespeak.net> Author: mwh Date: Mon Nov 6 15:20:35 2006 New Revision: 34264 Removed: pypy/dist/pypy/jit/codegen/ppc/codebuf_posix.py Modified: pypy/dist/pypy/jit/codegen/ppc/codebuf.py Log: de-silly the code layout a bit Modified: pypy/dist/pypy/jit/codegen/ppc/codebuf.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/codebuf.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/codebuf.py Mon Nov 6 15:20:35 2006 @@ -1,5 +1,48 @@ -from pypy.jit.codegen.ppc import codebuf_posix as memhandler -from ctypes import POINTER, cast, c_void_p, c_int +import pypy.rpython.rctypes.implementation # register rctypes types +from pypy.rpython.rctypes.tool import ctypes_platform +from pypy.rpython.rctypes.tool.libc import libc +from ctypes import POINTER, cast, c_void_p, c_int, c_char + +class CConfig: + _includes_ = ("sys/types.h", "sys/mman.h") + size_t = ctypes_platform.SimpleType("size_t", c_int) + off_t = ctypes_platform.SimpleType("off_t", c_int) + + MAP_PRIVATE = ctypes_platform.DefinedConstantInteger("MAP_PRIVATE") + MAP_ANON = ctypes_platform.DefinedConstantInteger("MAP_ANON") + MAP_ANONYMOUS = ctypes_platform.DefinedConstantInteger("MAP_ANONYMOUS") + PROT_READ = ctypes_platform.DefinedConstantInteger("PROT_READ") + PROT_WRITE = ctypes_platform.DefinedConstantInteger("PROT_WRITE") + PROT_EXEC = ctypes_platform.DefinedConstantInteger("PROT_EXEC") + +globals().update(ctypes_platform.configure(CConfig)) +if MAP_ANONYMOUS is None: + MAP_ANONYMOUS = MAP_ANON + assert MAP_ANONYMOUS is not None +del MAP_ANON + +# ____________________________________________________________ + +PTR = POINTER(c_char) # cannot use c_void_p as return value of functions :-( + +mmap_ = libc.mmap +mmap_.argtypes = [PTR, size_t, c_int, c_int, c_int, off_t] +mmap_.restype = PTR +mmap_.includes = ("sys/mman.h",) +munmap_ = libc.munmap +munmap_.argtypes = [PTR, size_t] +munmap_.restype = c_int +munmap_.includes = ("sys/mman.h",) + +def alloc(map_size): + flags = MAP_PRIVATE | MAP_ANONYMOUS + prot = PROT_EXEC | PROT_READ | PROT_WRITE + res = mmap_(PTR(), map_size, prot, flags, -1, 0) + if not res: + raise MemoryError + return res + +free = munmap_ class CodeBlockOverflow(Exception): pass @@ -8,7 +51,7 @@ def __init__(self, map_size): assert map_size % 4 == 0 - res = memhandler.alloc(map_size) + res = alloc(map_size) self._data = cast(res, POINTER(c_int * (map_size / 4))) self._size = map_size/4 self._pos = 0 @@ -25,4 +68,4 @@ return baseaddr + self._pos * 4 def __del__(self): - memhandler.free(cast(self._data, memhandler.PTR), self._size * 4) + free(cast(self._data, PTR), self._size * 4) From fijal at codespeak.net Mon Nov 6 15:38:14 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 6 Nov 2006 15:38:14 +0100 (CET) Subject: [pypy-svn] r34266 - pypy/dist/pypy Message-ID: <20061106143814.169A310075@code0.codespeak.net> Author: fijal Date: Mon Nov 6 15:38:11 2006 New Revision: 34266 Modified: pypy/dist/pypy/conftest.py Log: Killed unused option. Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Mon Nov 6 15:38:11 2006 @@ -31,8 +31,6 @@ Option('--nofaking', action="store_true", dest="nofaking", default=False, help="avoid faking of modules and objects completely."), - Option('--allpypy', action="store_true",dest="allpypy", default=False, - help="run everything possible on top of PyPy."), Option('--usemodules', action="callback", type="string", metavar="NAME", callback=usemodules_callback, default=[], help="(mixed) modules to use."), From mwh at codespeak.net Mon Nov 6 15:46:21 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 6 Nov 2006 15:46:21 +0100 (CET) Subject: [pypy-svn] r34267 - pypy/dist/pypy/rpython/memory Message-ID: <20061106144621.A750D10068@code0.codespeak.net> Author: mwh Date: Mon Nov 6 15:46:19 2006 New Revision: 34267 Modified: pypy/dist/pypy/rpython/memory/gc.py Log: turn off framework spam again (seems like i reactivated this by mistake) Modified: pypy/dist/pypy/rpython/memory/gc.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gc.py (original) +++ pypy/dist/pypy/rpython/memory/gc.py Mon Nov 6 15:46:19 2006 @@ -109,7 +109,7 @@ return init_gc_object_immortal = init_gc_object -DEBUG_PRINT = True +DEBUG_PRINT = False memoryError = MemoryError() class MarkSweepGC(GCBase): _alloc_flavor_ = "raw" From arigo at codespeak.net Mon Nov 6 16:03:02 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 6 Nov 2006 16:03:02 +0100 (CET) Subject: [pypy-svn] r34268 - pypy/dist/pypy/objspace/cpy Message-ID: <20061106150302.2D95C10071@code0.codespeak.net> Author: arigo Date: Mon Nov 6 16:03:00 2006 New Revision: 34268 Modified: pypy/dist/pypy/objspace/cpy/objspace.py Log: Fix test_typedef failures. Modified: pypy/dist/pypy/objspace/cpy/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/cpy/objspace.py (original) +++ pypy/dist/pypy/objspace/cpy/objspace.py Mon Nov 6 16:03:00 2006 @@ -106,6 +106,10 @@ return cpython2rpython(self, RequiredClass, w_obj) interp_w._annspecialcase_ = 'specialize:arg(1)' + def descr_self_interp_w(self, RequiredClass, w_obj): + return self.interp_w(RequiredClass, w_obj) + descr_self_interp_w._annspecialcase_ = 'specialize:arg(1)' + def lookup(self, w_obj, name): w_type = self.type(w_obj) w_name = self.wrap(name) From fijal at codespeak.net Mon Nov 6 16:06:14 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 6 Nov 2006 16:06:14 +0100 (CET) Subject: [pypy-svn] r34269 - pypy/dist/pypy Message-ID: <20061106150614.EBE3110075@code0.codespeak.net> Author: fijal Date: Mon Nov 6 16:06:13 2006 New Revision: 34269 Modified: pypy/dist/pypy/conftest.py Log: Added possibility of creating objspace with keyword options for app-level tests. Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Mon Nov 6 16:06:13 2006 @@ -83,8 +83,13 @@ class TinyObjSpace(object): def __init__(self, **kwds): - if kwds: - py.test.skip("cannot runappdirect test: space needs %s" % (kwds,)) + import sys + for key, val in kwds.iteritems(): + has = sys.pypy_translation_info.get(key, None) + if has != value: + py.test.skip("cannot runappdirect test: space needs %s = %s, "\ + "while pypy-c was built with %s" % (key, value, has)) + def appexec(self, args, body): src = py.code.Source("def anonymous" + body) d = {} From arigo at codespeak.net Mon Nov 6 17:47:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 6 Nov 2006 17:47:29 +0100 (CET) Subject: [pypy-svn] r34295 - in pypy/dist/pypy/module/_stackless: . test Message-ID: <20061106164729.A19E310094@code0.codespeak.net> Author: arigo Date: Mon Nov 6 17:47:28 2006 New Revision: 34295 Modified: pypy/dist/pypy/module/_stackless/coroutine.py pypy/dist/pypy/module/_stackless/interp_coroutine.py pypy/dist/pypy/module/_stackless/test/test_coroutine.py Log: (cfbolz, arigo) - fix a problem with coroutine.kill() killing the interpreter - fix a broken test - add an is_alive flag to app-level coroutines Modified: pypy/dist/pypy/module/_stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/coroutine.py Mon Nov 6 17:47:28 2006 @@ -225,6 +225,10 @@ return space.wrap(self.get_is_zombie()) AppCoroutine.w_get_is_zombie = w_get_is_zombie +def w_get_is_alive(space, self): + return space.wrap(self.is_alive()) +AppCoroutine.w_get_is_alive = w_get_is_alive + def w_descr__framestack(space, self): assert isinstance(self, AppCoroutine) if self.framestack: @@ -258,7 +262,11 @@ switch = interp2app(AppCoroutine.w_switch), kill = interp2app(AppCoroutine.w_kill), finished = interp2app(AppCoroutine.w_finished), - is_zombie = GetSetProperty(AppCoroutine.w_get_is_zombie, doc=AppCoroutine.get_is_zombie.__doc__), + is_alive = GetSetProperty(AppCoroutine.w_get_is_alive), + is_zombie = GetSetProperty(AppCoroutine.w_get_is_zombie, + doc=AppCoroutine.get_is_zombie.__doc__), #--- this flag is a bit obscure + # and not useful (it's totally different from Coroutine.is_zombie(), too) + # but lib/stackless.py uses it _framestack = GetSetProperty(w_descr__framestack), getcurrent = interp2app(AppCoroutine.w_getcurrent), __reduce__ = interp2app(AppCoroutine.descr__reduce__, 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 Mon Nov 6 17:47:28 2006 @@ -208,12 +208,12 @@ return self._execute(incoming_frame) def _execute(self, incoming_frame): - syncstate.switched(incoming_frame) state = self.costate try: try: try: exc = None + syncstate.switched(incoming_frame) self.thunk.call() resume_point("coroutine__bind", self, state) except Exception, e: Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_coroutine.py Mon Nov 6 17:47:28 2006 @@ -106,18 +106,11 @@ raise Exception('co should be a zombie now') def test_kill(self): - skip('should a coroutine be a zombie after killing?') - # running this test actually produces an - # Fatal PyPy error: CoroutineExit (pypy-c) - # or - # some interpreter error when running on py.py - # actually, this looks quite similar to what I (stephan) - # have seen when playing around with the 'finish' routine import _stackless as stackless co = stackless.coroutine() def f(): pass co.bind(f) + assert co.is_alive co.kill() - if not co.is_zombie: - raise Exception('co should be a zombie now') + assert not co.is_alive From arigo at codespeak.net Mon Nov 6 17:50:38 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 6 Nov 2006 17:50:38 +0100 (CET) Subject: [pypy-svn] r34296 - pypy/dist/pypy/module/_stackless/test Message-ID: <20061106165038.C074610094@code0.codespeak.net> Author: arigo Date: Mon Nov 6 17:50:38 2006 New Revision: 34296 Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py Log: Complete a test. Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_coroutine.py Mon Nov 6 17:50:38 2006 @@ -10,15 +10,7 @@ space = gettestobjspace(usemodules=('_stackless',)) cls.space = space - def test_one(self): - import _stackless as stackless - print stackless.__file__ - co = stackless.coroutine() - print co - # not much we can do here without compiling. - # well, we can pickle, at least: - - def test_pickle_coroutine(self): + def test_pickle_coroutine_empty(self): # this test is limited to basic pickling. # real stacks can only tested with a stackless pypy build. import _stackless as stackless @@ -26,7 +18,12 @@ import pickle pckl = pickle.dumps(co) co2 = pickle.loads(pckl) - + # the empty unpickled coroutine can still be used: + result = [] + co2.bind(result.append, 42) + co2.switch() + assert result == [42] + def test_pickle_coroutine_frame(self): #skip('passes in interactive interpreter but not here :/') # this requires py.magic.greenlet! From arigo at codespeak.net Tue Nov 7 04:02:24 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 04:02:24 +0100 (CET) Subject: [pypy-svn] r34302 - in pypy/dist/pypy/module/signal: . test Message-ID: <20061107030224.99EA910075@code0.codespeak.net> Author: arigo Date: Tue Nov 7 04:01:56 2006 New Revision: 34302 Modified: pypy/dist/pypy/module/signal/__init__.py pypy/dist/pypy/module/signal/ctypes_signal.py pypy/dist/pypy/module/signal/interp_signal.py pypy/dist/pypy/module/signal/test/test_signal.py Log: Rewriting the signal module to be translatable to C without rctypes. Modified: pypy/dist/pypy/module/signal/__init__.py ============================================================================== --- pypy/dist/pypy/module/signal/__init__.py (original) +++ pypy/dist/pypy/module/signal/__init__.py Tue Nov 7 04:01:56 2006 @@ -3,16 +3,19 @@ class Module(MixedModule): interpleveldefs = { - 'signal': 'interp_signal.signal', + 'signal': 'interp_signal.signal', + 'NSIG': 'interp_signal.NSIG', + 'SIG_DFL': 'interp_signal.SIG_DFL', + 'SIG_IGN': 'interp_signal.SIG_IGN', } appleveldefs = { } def buildloaders(cls): - from pypy.module.signal import ctypes_signal - for name in ctypes_signal.signal_names: - signum = getattr(ctypes_signal, name) + from pypy.module.signal import interp_signal + for name in interp_signal.signal_names: + signum = getattr(interp_signal, name) if signum is not None: Module.interpleveldefs[name] = 'space.wrap(%d)' % (signum,) super(Module, cls).buildloaders() Modified: pypy/dist/pypy/module/signal/ctypes_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/ctypes_signal.py (original) +++ pypy/dist/pypy/module/signal/ctypes_signal.py Tue Nov 7 04:01:56 2006 @@ -3,6 +3,9 @@ from ctypes import * +assert 0, "not used so far ==============================================" + + signal_names = ['SIGINT', 'SIGTERM', 'SIGKILL', # ... ] Modified: pypy/dist/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/interp_signal.py (original) +++ pypy/dist/pypy/module/signal/interp_signal.py Tue Nov 7 04:01:56 2006 @@ -1,7 +1,19 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace from pypy.interpreter.miscutils import Action -from pypy.module.signal import ctypes_signal +import signal as cpy_signal + + +def setup(): + for key, value in cpy_signal.__dict__.items(): + if key.startswith('SIG') and isinstance(value, int): + globals()[key] = value + yield key + +NSIG = cpy_signal.NSIG +SIG_DFL = cpy_signal.SIG_DFL +SIG_IGN = cpy_signal.SIG_IGN +signal_names = list(setup()) class CheckSignalAction(Action): @@ -12,83 +24,47 @@ def __init__(self, space): self.space = space + self.handlers_w = {} def perform(self): - if flag_queue.signal_occurred: - flag_queue.signal_occurred = 0 - node = flag_queue.head - signum = 0 - while node is not None: - if node.flag: - node.flag = 0 - main_ec = self.space.threadlocals.getmainthreadvalue() - main_ec.add_pending_action(ReportSignal(self.space, - node, signum)) - node = node.next - signum += 1 + while True: + n = pypysig_poll() + if n < 0: + break + main_ec = self.space.threadlocals.getmainthreadvalue() + main_ec.add_pending_action(ReportSignal(self, n)) + + def get(space): + for action in space.pending_actions: + if isinstance(action, CheckSignalAction): + return action + raise OperationError(space.w_RuntimeError, + space.wrap("lost CheckSignalAction")) + get = staticmethod(get) class ReportSignal(Action): """A one-shot action for the main thread's execution context.""" - def __init__(self, space, node, signum): - self.space = space - self.node = node + def __init__(self, action, signum): + self.action = action self.signum = signum def perform(self): - w_handler = self.node.w_handler - if w_handler is not None: - space = self.space - ec = space.getexecutioncontext() - try: - w_frame = ec.framestack.top() - except IndexError: - w_frame = space.w_None - space.call_function(w_handler, space.wrap(self.signum), w_frame) - - -# ____________________________________________________________ -# Global flags set by the signal handler - -# XXX some of these data structures may need to -# use the "volatile" keyword in the generated C code - -class FlagQueueNode(object): - def __init__(self): - self.flag = 0 - self.next = None - self.w_handler = None - -class FlagQueue(object): - signal_occurred = 0 - head = FlagQueueNode() - -flag_queue = FlagQueue() - -def get_flag_queue_signum(signum): - node = flag_queue.head - while signum > 0: - if node.next is None: - node.next = FlagQueueNode() - node = node.next - signum -= 1 - return node - -def generic_signal_handler(signum): - node = flag_queue.head - index = 0 - while index < signum: - node = node.next - index += 1 - node.flag = 1 - flag_queue.signal_occurred = 1 - # XXX may need to set the handler again, in case the OS clears it - -def os_setsig(signum, handler): - return ctypes_signal.signal(signum, handler) - -# ____________________________________________________________ + try: + w_handler = self.action.handlers_w[self.signum] + except KeyError: + return # no handler, ignore signal + # re-install signal handler, for OSes that clear it + pypysig_setflag(self.signum) + # invoke the app-level handler + space = self.action.space + ec = space.getexecutioncontext() + try: + w_frame = ec.framestack.top() + except IndexError: + w_frame = space.w_None + space.call_function(w_handler, space.wrap(self.signum), w_frame) def signal(space, signum, w_handler): ec = space.getexecutioncontext() @@ -97,10 +73,55 @@ raise OperationError(space.w_ValueError, space.wrap("signal() must be called from the " "main thread")) - node = get_flag_queue_signum(signum) - node.w_handler = w_handler - # XXX special values SIG_IGN, SIG_DFL - handler = ctypes_signal.sighandler_t(generic_signal_handler) - os_setsig(signum, handler) - # XXX return value + action = CheckSignalAction.get(space) + if space.eq_w(w_handler, space.wrap(SIG_DFL)): + if signum in action.handlers_w: + del action.handlers_w[signum] + pypysig_default(signum) + elif space.eq_w(w_handler, space.wrap(SIG_IGN)): + if signum in action.handlers_w: + del action.handlers_w[signum] + pypysig_ignore(signum) + else: + if not space.is_true(space.callable(w_handler)): + raise OperationError(space.w_TypeError, + space.wrap("'handler' must be a callable " + "or SIG_DFL or SIG_IGN")) + action.handlers_w[signum] = w_handler + pypysig_setflag(signum) + # XXX return value missing signal.unwrap_spec = [ObjSpace, int, W_Root] + +# ____________________________________________________________ +# CPython and LLTypeSystem implementations + +from pypy.rpython.extregistry import ExtRegistryEntry + +signal_queue = [] # only for py.py, not for translated pypy-c's + +def pypysig_poll(): + "NOT_RPYTHON" + if signal_queue: + return signal_queue.pop(0) + else: + return -1 + +def pypysig_default(signum): + "NOT_RPYTHON" + cpy_signal.signal(signum, cpy_signal.SIG_DFL) # XXX error handling + +def pypysig_ignore(signum): + "NOT_RPYTHON" + cpy_signal.signal(signum, cpy_signal.SIG_IGN) # XXX error handling + +def _queue_handler(signum, frame): + if signum not in signal_queue: + signal_queue.append(signum) + +def pypysig_setflag(signum): + "NOT_RPYTHON" + cpy_signal.signal(signum, _queue_handler) + + +class Entry(ExtRegistryEntry): + pass # in-progress Modified: pypy/dist/pypy/module/signal/test/test_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/test/test_signal.py (original) +++ pypy/dist/pypy/module/signal/test/test_signal.py Tue Nov 7 04:01:56 2006 @@ -1,13 +1,41 @@ +from pypy.conftest import gettestobjspace -##import signal +class AppTestSignal: -##def ya(*args): -## print "ya", args - -##signal.signal(signal.SIGINT, ya) - -##i = 0 -##while 1: -## i += 1 -## if i%1000 == 0: -## print i + def setup_class(cls): + cls.space = gettestobjspace(usemodules=['signal']) + + def test_usr1(self): + import signal, types, posix + received = [] + def myhandler(signum, frame): + assert isinstance(frame, types.FrameType) + received.append(signum) + signal.signal(signal.SIGUSR1, myhandler) + + posix.kill(posix.getpid(), signal.SIGUSR1) + for i in range(10000): + # wait a bit for the signal to be delivered to the handler + if received: + break + assert received == [signal.SIGUSR1] + del received[:] + + posix.kill(posix.getpid(), signal.SIGUSR1) + for i in range(10000): + # wait a bit for the signal to be delivered to the handler + if received: + break + assert received == [signal.SIGUSR1] + del received[:] + + signal.signal(signal.SIGUSR1, signal.SIG_IGN) + + posix.kill(posix.getpid(), signal.SIGUSR1) + for i in range(10000): + # wait a bit - signal should not arrive + if received: + break + assert received == [] + + signal.signal(signal.SIGUSR1, signal.SIG_DFL) From arigo at codespeak.net Tue Nov 7 04:46:10 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 04:46:10 +0100 (CET) Subject: [pypy-svn] r34303 - in pypy/dist/pypy: objspace/std translator/backendopt Message-ID: <20061107034610.5C4AB10071@code0.codespeak.net> Author: arigo Date: Tue Nov 7 04:45:44 2006 New Revision: 34303 Modified: pypy/dist/pypy/objspace/std/proxy_helpers.py pypy/dist/pypy/translator/backendopt/support.py Log: Python 2.3 compatibility Modified: pypy/dist/pypy/objspace/std/proxy_helpers.py ============================================================================== --- pypy/dist/pypy/objspace/std/proxy_helpers.py (original) +++ pypy/dist/pypy/objspace/std/proxy_helpers.py Tue Nov 7 04:45:44 2006 @@ -6,6 +6,7 @@ from pypy.objspace.std.model import W_ANY, W_Object from pypy.interpreter import baseobjspace from pypy.interpreter.argument import Arguments +from pypy.tool.sourcetools import func_with_new_name def create_mm_names(classname, mm, is_local): s = "" @@ -22,7 +23,7 @@ args = __args__.prepend(space.wrap(op_name)) return space.call_args(w_transparent_list.w_controller, args) - function.func_name = mm.name + function = func_with_new_name(function, mm.name) mm.register(function, type_) def install_w_args_trampoline(type_, mm, is_local, op_name): @@ -30,7 +31,7 @@ args = Arguments(space, [space.wrap(op_name)] + list(args_w[:-1]), w_stararg=args_w[-1]) return space.call_args(w_transparent_list.w_controller, args) - function.func_name = mm.name + function = func_with_new_name(function, mm.name) mm.register(function, type_, *([W_ANY] * (mm.arity - 1))) def install_mm_trampoline(type_, mm, is_local): @@ -46,7 +47,7 @@ def function(space, w_transparent_list, *args_w): return space.call_function(w_transparent_list.w_controller, space.wrap\ (op_name), *args_w) - function.func_name = mm_name + function = func_with_new_name(function, mm_name) mm.register(function, type_, *([W_ANY] * (mm.arity - 1))) def is_special_doublearg(mm, type_): @@ -74,7 +75,7 @@ w_any) return retval - function.func_name = mm.specialnames[0] + function = func_with_new_name(function, mm.specialnames[0]) mm.register(function, type_.typedef.any, type_) Modified: pypy/dist/pypy/translator/backendopt/support.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/support.py (original) +++ pypy/dist/pypy/translator/backendopt/support.py Tue Nov 7 04:45:44 2006 @@ -147,7 +147,7 @@ def compute_reachability(graph): reachable = {} blocks = list(graph.iterblocks()) - for block in reversed(blocks): # this order should make the reuse path more likely + for block in py.builtin.reversed(blocks): # this order should make the reuse path more likely reach = {} scheduled = [block] while scheduled: From arigo at codespeak.net Tue Nov 7 04:57:04 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 04:57:04 +0100 (CET) Subject: [pypy-svn] r34304 - in pypy/dist/pypy: module/posix rpython rpython/module translator/c translator/c/src Message-ID: <20061107035704.1E99B10075@code0.codespeak.net> Author: arigo Date: Tue Nov 7 04:56:49 2006 New Revision: 34304 Modified: pypy/dist/pypy/module/posix/__init__.py pypy/dist/pypy/module/posix/interp_posix.py pypy/dist/pypy/rpython/extfunctable.py pypy/dist/pypy/rpython/module/ll_os.py pypy/dist/pypy/translator/c/extfunc.py pypy/dist/pypy/translator/c/src/ll_os.h Log: Added os.kill(). Modified: pypy/dist/pypy/module/posix/__init__.py ============================================================================== --- pypy/dist/pypy/module/posix/__init__.py (original) +++ pypy/dist/pypy/module/posix/__init__.py Tue Nov 7 04:56:49 2006 @@ -47,6 +47,7 @@ 'chmod' : 'interp_posix.chmod', 'rename' : 'interp_posix.rename', '_exit' : 'interp_posix._exit', + 'kill' : 'interp_posix.kill', #'getuid' : 'interp_posix.getuid', #'geteuid' : 'interp_posix.geteuid', } Modified: pypy/dist/pypy/module/posix/interp_posix.py ============================================================================== --- pypy/dist/pypy/module/posix/interp_posix.py (original) +++ pypy/dist/pypy/module/posix/interp_posix.py Tue Nov 7 04:56:49 2006 @@ -344,6 +344,14 @@ return space.wrap(pid) getpid.unwrap_spec = [ObjSpace] +def kill(space, pid, sig): + "Kill a process with a signal." + try: + os.kill(pid, sig) + except OSError, e: + raise wrap_oserror(space, e) +kill.unwrap_spec = [ObjSpace, int, int] + def link(space, src, dst): "Create a hard link to a file." try: Modified: pypy/dist/pypy/rpython/extfunctable.py ============================================================================== --- pypy/dist/pypy/rpython/extfunctable.py (original) +++ pypy/dist/pypy/rpython/extfunctable.py Tue Nov 7 04:56:49 2006 @@ -217,6 +217,7 @@ declare(os.chmod , noneannotation, 'll_os/chmod') declare(os.rename , noneannotation, 'll_os/rename') declare(os._exit , noneannotation, 'll_os/_exit') +declare(os.kill , noneannotation, 'll_os/kill') if hasattr(os, 'getpid'): declare(os.getpid , int, 'll_os/getpid') if hasattr(os, 'link'): Modified: pypy/dist/pypy/rpython/module/ll_os.py ============================================================================== --- pypy/dist/pypy/rpython/module/ll_os.py (original) +++ pypy/dist/pypy/rpython/module/ll_os.py Tue Nov 7 04:56:49 2006 @@ -143,6 +143,10 @@ return os.getpid() ll_os_getpid.suggested_primitive = True + def ll_os_kill(cls, pid, sig): + os.kill(pid, sig) + ll_os_kill.suggested_primitive = True + def ll_os_link(cls, path1, path2): os.link(cls.from_rstr(path1), cls.from_rstr(path2)) ll_os_link.suggested_primitive = True Modified: pypy/dist/pypy/translator/c/extfunc.py ============================================================================== --- pypy/dist/pypy/translator/c/extfunc.py (original) +++ pypy/dist/pypy/translator/c/extfunc.py Tue Nov 7 04:56:49 2006 @@ -52,6 +52,7 @@ impl.ll_os_chmod.im_func: 'LL_os_chmod', impl.ll_os_rename.im_func: 'LL_os_rename', impl.ll_os_getpid.im_func: 'LL_os_getpid', + impl.ll_os_kill.im_func: 'LL_os_kill', impl.ll_os_link.im_func: 'LL_os_link', impl.ll_os_symlink.im_func: 'LL_os_symlink', impl.ll_readlink_into: 'LL_readlink_into', Modified: pypy/dist/pypy/translator/c/src/ll_os.h ============================================================================== --- pypy/dist/pypy/translator/c/src/ll_os.h (original) +++ pypy/dist/pypy/translator/c/src/ll_os.h Tue Nov 7 04:56:49 2006 @@ -9,6 +9,7 @@ #include #include +#include #ifndef PATH_MAX /* assume windows */ # define PATH_MAX 254 @@ -73,6 +74,7 @@ void LL_os_chmod(RPyString * path, int mode); void LL_os_rename(RPyString * path1, RPyString * path2); long LL_os_getpid(void); +void LL_os_kill(int pid, int sig); void LL_os_link(RPyString * path1, RPyString * path2); void LL_os_symlink(RPyString * path1, RPyString * path2); long LL_readlink_into(RPyString *path, RPyString *buffer); @@ -342,6 +344,13 @@ return getpid(); } +void LL_os_kill(int pid, int sig) { + int error = kill(pid, sig); + if (error != 0) { + RPYTHON_RAISE_OSERROR(errno); + } +} + #ifdef HAVE_FILESYSTEM_WITH_LINKS void LL_os_link(RPyString * path1, RPyString * path2) { From arigo at codespeak.net Tue Nov 7 04:59:02 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 04:59:02 +0100 (CET) Subject: [pypy-svn] r34305 - in pypy/dist/pypy: module/signal module/signal/test translator/c/src Message-ID: <20061107035902.E4D3110079@code0.codespeak.net> Author: arigo Date: Tue Nov 7 04:58:52 2006 New Revision: 34305 Added: pypy/dist/pypy/module/signal/test/__init__.py pypy/dist/pypy/module/signal/test/test_interp_signal.py pypy/dist/pypy/translator/c/src/signals.h Modified: pypy/dist/pypy/module/signal/__init__.py pypy/dist/pypy/module/signal/interp_signal.py pypy/dist/pypy/module/signal/test/test_signal.py Log: More hacking at the signal module. Should now be translatable to C. Modified: pypy/dist/pypy/module/signal/__init__.py ============================================================================== --- pypy/dist/pypy/module/signal/__init__.py (original) +++ pypy/dist/pypy/module/signal/__init__.py Tue Nov 7 04:58:52 2006 @@ -4,9 +4,9 @@ class Module(MixedModule): interpleveldefs = { 'signal': 'interp_signal.signal', - 'NSIG': 'interp_signal.NSIG', - 'SIG_DFL': 'interp_signal.SIG_DFL', - 'SIG_IGN': 'interp_signal.SIG_IGN', + 'NSIG': 'space.wrap(interp_signal.NSIG)', + 'SIG_DFL': 'space.wrap(interp_signal.SIG_DFL)', + 'SIG_IGN': 'space.wrap(interp_signal.SIG_IGN)', } appleveldefs = { Modified: pypy/dist/pypy/module/signal/interp_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/interp_signal.py (original) +++ pypy/dist/pypy/module/signal/interp_signal.py Tue Nov 7 04:58:52 2006 @@ -123,5 +123,30 @@ cpy_signal.signal(signum, _queue_handler) +# lltyping - direct mapping to the C functions defined in +# translator/c/src/signals.h + class Entry(ExtRegistryEntry): - pass # in-progress + _about_ = pypysig_poll + def compute_result_annotation(self): + from pypy.annotation import model as annmodel + return annmodel.SomeInteger() + def specialize_call(self, hop): + from pypy.rpython.lltypesystem import lltype + hop.exception_cannot_occur() + return hop.llops.gencapicall("pypysig_poll", [], lltype.Signed, + includes=('src/signals.h',)) + +for _fn in [pypysig_default, pypysig_ignore, pypysig_setflag]: + class Entry(ExtRegistryEntry): + _about_ = _fn + funcname = _fn.func_name + def compute_result_annotation(self, s_signum): + return None + def specialize_call(self, hop): + from pypy.rpython.lltypesystem import lltype + vlist = hop.inputargs(lltype.Signed) + hop.exception_cannot_occur() + hop.llops.gencapicall(self.funcname, vlist, + includes=('src/signals.h',)) +del _fn Added: pypy/dist/pypy/module/signal/test/__init__.py ============================================================================== Added: pypy/dist/pypy/module/signal/test/test_interp_signal.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/signal/test/test_interp_signal.py Tue Nov 7 04:58:52 2006 @@ -0,0 +1,33 @@ +import os +from pypy.translator.c.test.test_genc import compile +from pypy.module.signal import interp_signal + + +def check(expected): + res = interp_signal.pypysig_poll() + os.write(1, "poll() => %d, expected %d\n" % (res, expected)) + assert res == expected + +def test_simple(): + import os + check(-1) + check(-1) + for i in range(3): + interp_signal.pypysig_setflag(interp_signal.SIGUSR1) + os.kill(os.getpid(), interp_signal.SIGUSR1) + check(interp_signal.SIGUSR1) + check(-1) + check(-1) + + interp_signal.pypysig_ignore(interp_signal.SIGUSR1) + os.kill(os.getpid(), interp_signal.SIGUSR1) + check(-1) + check(-1) + + interp_signal.pypysig_default(interp_signal.SIGUSR1) + check(-1) + + +def test_compile(): + fn = compile(test_simple, []) + fn() Modified: pypy/dist/pypy/module/signal/test/test_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/test/test_signal.py (original) +++ pypy/dist/pypy/module/signal/test/test_signal.py Tue Nov 7 04:58:52 2006 @@ -3,10 +3,17 @@ class AppTestSignal: def setup_class(cls): - cls.space = gettestobjspace(usemodules=['signal']) + space = gettestobjspace(usemodules=['signal']) + cls.space = space + cls.w_signal = space.appexec([], "(): import signal; return signal") + + def test_exported_names(self): + self.signal.__dict__ # crashes if the interpleveldefs are invalid def test_usr1(self): - import signal, types, posix + import types, posix + signal = self.signal # the signal module to test + received = [] def myhandler(signum, frame): assert isinstance(frame, types.FrameType) Added: pypy/dist/pypy/translator/c/src/signals.h ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/c/src/signals.h Tue Nov 7 04:58:52 2006 @@ -0,0 +1,94 @@ + +/* some ifdefs from CPython's signalmodule.c... */ + +#ifdef MS_WINDOWS +#include +#endif + +#include + +#ifndef SIG_ERR +#define SIG_ERR ((PyOS_sighandler_t)(-1)) +#endif + +#if defined(PYOS_OS2) && !defined(PYCC_GCC) +#define NSIG 12 +#include +#endif + +#ifndef NSIG +# if defined(_NSIG) +# define NSIG _NSIG /* For BSD/SysV */ +# elif defined(_SIGMAX) +# define NSIG (_SIGMAX + 1) /* For QNX */ +# elif defined(SIGMAX) +# define NSIG (SIGMAX + 1) /* For djgpp */ +# else +# define NSIG 64 /* Use a reasonable default value */ +# endif +#endif + +/************************************************************/ + +/* NOTE: at the moment this file is included by a hack in + module/signal/interp_signal.py, only if one of the pypysig_*() + functions is actually used in the RPython program. */ + + +/* utilities to set a signal handler */ +void pypysig_ignore(int signum); /* signal will be ignored (SIG_IGN) */ +void pypysig_default(int signum); /* signal will do default action (SIG_DFL) */ +void pypysig_setflag(int signum); /* signal will set a flag which can be + queried with pypysig_poll() */ + +/* utility to poll for signals that arrived */ +int pypysig_poll(void); /* => signum or -1 */ + +/************************************************************/ +/* Implementation */ + +#ifndef PYPY_NOT_MAIN_FILE + +static volatile int pypysig_occurred; +static volatile int pypysig_flags[NSIG]; + +void pypysig_ignore(int signum) +{ + signal(signum, SIG_IGN); +} + +void pypysig_default(int signum) +{ + signal(signum, SIG_DFL); +} + +static void signal_setflag_handler(int signum) +{ + pypysig_occurred = 1; + if (0 <= signum && signum < NSIG) + pypysig_flags[signum] = 1; +} + +void pypysig_setflag(int signum) +{ + signal(signum, signal_setflag_handler); +} + +int pypysig_poll(void) +{ + if (pypysig_occurred) + { + int i; + pypysig_occurred = 0; + for (i=0; i Author: fijal Date: Tue Nov 7 10:25:52 2006 New Revision: 34306 Modified: pypy/dist/pypy/translator/goal/bench-cronjob.py Log: (fijal, xoraxax) - Changed march to mtune to avoid problems when copying generated pypy-c somewhere else. Modified: pypy/dist/pypy/translator/goal/bench-cronjob.py ============================================================================== --- pypy/dist/pypy/translator/goal/bench-cronjob.py (original) +++ pypy/dist/pypy/translator/goal/bench-cronjob.py Tue Nov 7 10:25:52 2006 @@ -9,7 +9,7 @@ homedir = os.getenv('HOME') tmpdir = py.std.tempfile.gettempdir() + '/usession-' + os.environ['USER'] + '/' -cflags = "-march=pentium4 -O3 -fomit-frame-pointer" +cflags = "-mtune=pentium4 -O3 -fomit-frame-pointer" lflags = "-lgc -lm -lpthread" dry_run = False From cfbolz at codespeak.net Tue Nov 7 12:40:48 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Nov 2006 12:40:48 +0100 (CET) Subject: [pypy-svn] r34313 - pypy/branch/resume-point-hack Message-ID: <20061107114048.0E3EF10075@code0.codespeak.net> Author: cfbolz Date: Tue Nov 7 12:40:47 2006 New Revision: 34313 Added: pypy/branch/resume-point-hack/ - copied from r34312, pypy/dist/ Log: small private branch to try to implement resume points on top of CPython and thus make testing of coroutine pickling easier. From arigo at codespeak.net Tue Nov 7 13:16:33 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 13:16:33 +0100 (CET) Subject: [pypy-svn] r34315 - in pypy/dist/pypy/module/_stackless: . test Message-ID: <20061107121633.2759510078@code0.codespeak.net> Author: arigo Date: Tue Nov 7 13:16:31 2006 New Revision: 34315 Modified: pypy/dist/pypy/module/_stackless/coroutine.py pypy/dist/pypy/module/_stackless/interp_coroutine.py pypy/dist/pypy/module/_stackless/test/test_coroutine.py Log: Fixes to coroutine pickling (relevant for bound but not running coroutines). Modified: pypy/dist/pypy/module/_stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/coroutine.py Tue Nov 7 13:16:31 2006 @@ -15,7 +15,7 @@ experience to decide where to set the limits. """ -from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.baseobjspace import Wrappable, UnpackValueError from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import GetSetProperty, TypeDef from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w @@ -132,41 +132,62 @@ # this is trying to be simplistic at the moment. # we neither allow to pickle main (which can become a mess # since it has some deep anchestor frames) - # nor we allowto pickle the current coroutine. + # nor we allow to pickle the current coroutine. # rule: switch before pickling. # you cannot construct the tree that you are climbing. - # XXX missing checks! from pypy.interpreter.mixedmodule import MixedModule w_mod = space.getbuiltinmodule('_stackless') mod = space.interp_w(MixedModule, w_mod) w_mod2 = space.getbuiltinmodule('_pickle_support') mod2 = space.interp_w(MixedModule, w_mod2) - new_inst = mod.get('coroutine') + w_new_inst = mod.get('coroutine') w = space.wrap nt = space.newtuple ec = self.space.getexecutioncontext() if self is self._get_state(space).main: - return space.newtuple([mod2.get('return_main'), space.newtuple([])]) + return nt([mod2.get('return_main'), nt([])]) + + thunk = self.thunk + if isinstance(thunk, _AppThunk): + w_args, w_kwds = thunk.args.topacked() + w_thunk = nt([thunk.w_func, w_args, w_kwds]) + else: + w_thunk = space.w_None tup_base = [ ] tup_state = [ w(self.flags), ec.subcontext_getstate(self), + w_thunk, + w(self.parent), ] - return nt([new_inst, nt(tup_base), nt(tup_state)]) + return nt([w_new_inst, nt(tup_base), nt(tup_state)]) def descr__setstate__(self, space, w_args): - args_w = space.unpackiterable(w_args) - w_flags, w_state = args_w + try: + w_flags, w_state, w_thunk, w_parent = space.unpackiterable(w_args, + expected_length=4) + except UnpackValueError, e: + raise OperationError(space.w_ValueError, e.msg) self.flags = space.int_w(w_flags) - self.parent = AppCoroutine._get_state(space).current + self.parent = space.interp_w(AppCoroutine, w_parent, can_be_None=True) ec = self.space.getexecutioncontext() ec.subcontext_setstate(self, w_state) self.reconstruct_framechain() - + if space.is_w(w_thunk, space.w_None): + self.thunk = None + else: + try: + w_func, w_args, w_kwds = space.unpackiterable(w_thunk, + expected_length=3) + except UnpackValueError, e: + raise OperationError(space.w_ValueError, e.msg) + args = Arguments.frompacked(space, w_args, w_kwds) + self.bind(_AppThunk(space, self.costate, w_func, args)) + def reconstruct_framechain(self): from pypy.interpreter.pyframe import PyFrame from pypy.rlib.rstack import resume_state_create 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 Tue Nov 7 13:16:31 2006 @@ -214,14 +214,15 @@ try: exc = None syncstate.switched(incoming_frame) - self.thunk.call() + thunk = self.thunk + self.thunk = None + thunk.call() resume_point("coroutine__bind", self, state) except Exception, e: exc = e raise finally: self.finish(exc) - self.thunk = None except CoroutineExit: # ignore a shutdown exception pass Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_coroutine.py Tue Nov 7 13:16:31 2006 @@ -24,30 +24,18 @@ co2.switch() assert result == [42] - def test_pickle_coroutine_frame(self): - #skip('passes in interactive interpreter but not here :/') - # this requires py.magic.greenlet! - import pickle, sys, new - mod = new.module('mod') - try: - sys.modules['mod'] = mod - exec ''' -import sys, _stackless as stackless - -def f(): - global the_frame - the_frame = sys._getframe() - main_coro.switch() - -co = stackless.coroutine() -main_coro = stackless.coroutine.getcurrent() -co.bind(f) -co.switch() -''' in mod.__dict__ - pckl = pickle.dumps(mod.the_frame) - #co2 = pickle.loads(pckl) - finally: - del sys.modules['mod'] + def test_pickle_coroutine_bound(self): + import pickle + import _stackless + lst = [4] + co = _stackless.coroutine() + co.bind(lst.append, 2) + pckl = pickle.dumps((co, lst)) + + (co2, lst2) = pickle.loads(pckl) + assert lst2 == [4] + co2.switch() + assert lst2 == [4, 2] def test_raise_propagate(self): import _stackless as stackless @@ -111,3 +99,11 @@ assert co.is_alive co.kill() assert not co.is_alive + + def test_bogus_bind(self): + import _stackless as stackless + co = stackless.coroutine() + def f(): + pass + co.bind(f) + raises(ValueError, co.bind, f) From arigo at codespeak.net Tue Nov 7 13:18:57 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 13:18:57 +0100 (CET) Subject: [pypy-svn] r34316 - pypy/dist/pypy/module/_stackless/test Message-ID: <20061107121857.91ADB10078@code0.codespeak.net> Author: arigo Date: Tue Nov 7 13:18:51 2006 New Revision: 34316 Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py Log: Remove broken test. The other skipped test now passes. Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_coroutine.py Tue Nov 7 13:18:51 2006 @@ -51,7 +51,6 @@ raise AssertionError("exception not propagated") def test_strange_test(self): - skip("test is failing for atm unknown reasons") from _stackless import coroutine def f(): print "in new coro" @@ -76,20 +75,6 @@ b.bind(kill) b.switch() - def test_finished(self): - skip('should a coroutine be a zombie after being done?') - import _stackless as stackless - co = stackless.coroutine() - def f(): - pass - co.bind(f) - co.switch() - # doing an assert here runs into some (infinite looking) - # cycle. - # Lots of "GC Warning: Finalization cycle involving xxxx" - if not co.is_zombie: - raise Exception('co should be a zombie now') - def test_kill(self): import _stackless as stackless co = stackless.coroutine() From arigo at codespeak.net Tue Nov 7 13:29:57 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 13:29:57 +0100 (CET) Subject: [pypy-svn] r34317 - pypy/dist/pypy/interpreter Message-ID: <20061107122957.82CCC10078@code0.codespeak.net> Author: arigo Date: Tue Nov 7 13:29:56 2006 New Revision: 34317 Modified: pypy/dist/pypy/interpreter/argument.py Log: Forgot to check this in. Modified: pypy/dist/pypy/interpreter/argument.py ============================================================================== --- pypy/dist/pypy/interpreter/argument.py (original) +++ pypy/dist/pypy/interpreter/argument.py Tue Nov 7 13:29:56 2006 @@ -38,6 +38,16 @@ return Arguments(space, [], w_stararg=w_args, w_starstararg=w_kwds) frompacked = staticmethod(frompacked) + def topacked(self): + """Express the Argument object as a pair of wrapped w_args, w_kwds.""" + space = self.space + args_w, kwds_w = self.unpack() + w_args = space.newtuple(args_w) + w_kwds = space.newdict() + for key, w_value in kwds_w: + space.setitem(w_kwds, space.wrap(key), w_value) + return w_args, w_kwds + def fromshape(space, (shape_cnt,shape_keys,shape_star,shape_stst), data_w): args_w = data_w[:shape_cnt] p = shape_cnt From arigo at codespeak.net Tue Nov 7 13:30:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 13:30:29 +0100 (CET) Subject: [pypy-svn] r34318 - in pypy/dist/pypy: . module/_stackless/test Message-ID: <20061107123029.5F4D51007B@code0.codespeak.net> Author: arigo Date: Tue Nov 7 13:30:28 2006 New Revision: 34318 Modified: pypy/dist/pypy/conftest.py pypy/dist/pypy/module/_stackless/test/test_pickle.py Log: Extending the runappdirect space option processing for this test_pickle. Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Tue Nov 7 13:30:28 2006 @@ -84,9 +84,20 @@ class TinyObjSpace(object): def __init__(self, **kwds): import sys - for key, val in kwds.iteritems(): + for key, value in kwds.iteritems(): + if key == 'usemodules': + for modname in value: + try: + __import__(modname) + except ImportError: + py.test.skip("cannot runappdirect test: " + "module %r required" % (modname,)) + continue + if not hasattr(sys, 'pypy_translation_info'): + py.test.skip("cannot runappdirect this test on top of CPython") has = sys.pypy_translation_info.get(key, None) if has != value: + print sys.pypy_translation_info py.test.skip("cannot runappdirect test: space needs %s = %s, "\ "while pypy-c was built with %s" % (key, value, has)) Modified: pypy/dist/pypy/module/_stackless/test/test_pickle.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_pickle.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_pickle.py Tue Nov 7 13:30:28 2006 @@ -1,12 +1,14 @@ -from pypy.conftest import gettestobjspace, skip_on_missing_buildoption +from pypy.conftest import gettestobjspace, option import py # app-level testing of coroutine pickling -def setup_module(mod): - skip_on_missing_buildoption(stackless=True) +class AppTestPickle: -class TestPickle: + def setup_class(cls): + if not option.runappdirect: + py.test.skip('pure appdirect test (run with -A)') + cls.space = gettestobjspace(usemodules=('_stackless',)) def test_simple_ish(self): From arigo at codespeak.net Tue Nov 7 13:34:58 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 13:34:58 +0100 (CET) Subject: [pypy-svn] r34319 - pypy/dist/pypy/module/_stackless/test Message-ID: <20061107123458.C8EDF10078@code0.codespeak.net> Author: arigo Date: Tue Nov 7 13:34:57 2006 New Revision: 34319 Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py pypy/dist/pypy/module/_stackless/test/test_interp_coroutine.py pypy/dist/pypy/module/_stackless/test/test_stackless.py Log: More small test reorganizations. Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_coroutine.py Tue Nov 7 13:34:57 2006 @@ -1,4 +1,4 @@ -from pypy.conftest import gettestobjspace, skip_on_missing_buildoption +from pypy.conftest import gettestobjspace from py.test import skip # no real testing possible without compiling stackless pypy Modified: pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py Tue Nov 7 13:34:57 2006 @@ -7,7 +7,6 @@ from pypy.rpython.memory.test import test_transformed_gc from pypy.module._stackless.interp_clonable import InterpClonableCoroutine as ClonableCoroutine from pypy.module._stackless.interp_clonable import AbstractThunk, fork -from pypy.conftest import skip_on_missing_buildoption class TestClonableCoroutine(test_transformed_gc.GCTest): 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 Tue Nov 7 13:34:57 2006 @@ -6,7 +6,6 @@ from pypy.module._stackless.interp_coroutine import syncstate, Coroutine, AbstractThunk from pypy.translator.c.test.test_stackless import StacklessTest from pypy.translator.c import gc -from pypy.conftest import skip_on_missing_buildoption def output(stuff): os.write(2, stuff + '\n') Modified: pypy/dist/pypy/module/_stackless/test/test_stackless.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_stackless.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_stackless.py Tue Nov 7 13:34:57 2006 @@ -1,4 +1,4 @@ -from pypy.conftest import gettestobjspace, skip_on_missing_buildoption +from pypy.conftest import gettestobjspace, option from py.test import skip @@ -344,11 +344,12 @@ ('schedule', 1), ('schedule', 2), ('schedule', 1), ('schedule', 2),] -class Test_StacklessPickling: +class AppTest_StacklessPickling: def setup_class(cls): - skip_on_missing_buildoption(stackless=True) - + if not option.runappdirect: + py.test.skip('pure appdirect test (run with -A)') + cls.space = gettestobjspace(usemodules=('_stackless',)) def test_basic_tasklet_pickling(self): import stackless From cfbolz at codespeak.net Tue Nov 7 13:39:11 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Nov 2006 13:39:11 +0100 (CET) Subject: [pypy-svn] r34320 - pypy/dist/pypy/doc Message-ID: <20061107123911.A716210078@code0.codespeak.net> Author: cfbolz Date: Tue Nov 7 13:39:10 2006 New Revision: 34320 Modified: pypy/dist/pypy/doc/project-ideas.txt Log: (cfbolz, mwh, maciek, ?): update project ideas a bit Modified: pypy/dist/pypy/doc/project-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/project-ideas.txt (original) +++ pypy/dist/pypy/doc/project-ideas.txt Tue Nov 7 13:39:10 2006 @@ -1,70 +1,22 @@ Independent project ideas in PyPy ================================= -PyPy allows experimentation in many directions. This page is meant to -collect some ideas of things to try. If you are a student you can -also get inspired for a proposal for our new `Summer of PyPy`_ campaign: -you get a mentor and good funding of travel and accomodation for our -sprints. +PyPy allows experimentation in many directions -- indeed facilitating +experimentation in language implementation was one of the main motivations for +the project. This page is meant to collect some ideas of things to try. + +If you are a student, maybe you will be inspired to make a proposal for our +`Summer of PyPy`_ campaign: you will have an experienced PyPy developer as a +mentor and be invited to attend one or two of our sprints, with travel and +accomodation costs refunded. -Feel free to suggest new ideas and discuss them on IRC or the pypy-dev -list (see the contact_ page). +Feel free to suggest new ideas and discuss them in #pypy on the freenode IRC +network or the pypy-dev mailing list (see the contact_ page). ----------- .. contents:: -Extension modules ------------------ - -Rewrite one or several CPython extension modules to be based on **ctypes** -(newly integrated in Python 2.5): this is generally useful for Python -developers, and it is now the best path to write extension modules that are -compatible with both CPython and PyPy. This is done with the `extension -compiler`_ component of PyPy, which will likely require some attention as -well. - -Modules where some work is already done: - -* ``_socket``, ``os``, ``select`` (unfinished yet, feel free to help; - see e.g. http://codespeak.net/svn/pypy/dist/pypy/module/_socket/). - -* SSL for socket, ``bz2``, ``fcntl``, ``mmap`` and ``time``: part of the - Summer of Code project of Lawrence Oluyede - (http://codespeak.net/svn/user/rhymes/). - -You are free to pick any other CPython module, either standard or third-party -(if relatively well-known). Note that some modules exist in a ctypes version -already, which would be a good start for porting them to PyPy's extension -compiler. We'd particularly appreciate ``readline`` :-) - -Numeric/NumPy/numarray support ------------------------------- - -At the EuroPython sprint, some work was done on making RPython's annotator -recognise Numeric arrays, with the goal of allowing programs using them to be -efficiently translated. It would be a reasonably sized project to finish this -work, i.e. allow RPython programs to use some Numeric facilities. -Additionally, these facilities could be exposed to applications interpreted by -the translated PyPy interpreter. - -Start or improve a back-end ---------------------------- - -PyPy has complete, or nearly so, back-ends for C, LLVM and CLI/.NET and -partial backends for Common Lisp and Squeak. It would be an interesting -project to improve either of these partial backends, or start one for another -platform -- the most obvious of which would be the **Java** Virtual Machine. - -Write a new front end ---------------------- - -Write an interpreter for **another dynamic language** in the PyPy framework. -For example, a Javascript interpreter would be suitable. Ruby too (though -the latter is probably more than two months of work). Or Scheme, or... etc. - -We have a prototype `Prolog interpreter`_ :-) - Experiment with optimizations ----------------------------- @@ -86,6 +38,38 @@ * dictionaries specialized for string-only keys. + + + +Start or improve a back-end +--------------------------- + +PyPy has complete, or nearly so, back-ends for C, LLVM and CLI/.NET and +partial backends for Common Lisp, Squeak and the JVM. It would be an +interesting project to improve either of these partial backends, or start one +for another platform (objective C comes to mind). + +Improve one of the JIT back-ends +-------------------------------- + +PyPy's Just-In-Time compiler relies on two assembler backends for actual code +generation: One for PowerPC and one for i386. Those two backends so far are +mostly working, but nearly no effort was made to make them produce good +assembler. This is an area where quite some improvements could be made. +Another idea in a similar vein would be to use LLVM to re-compile functions +that are particularly often used (LLVM cannot be used for *all* code +generation, since it can only work on function at a time). + +Write a new front end +--------------------- + +Write an interpreter for **another dynamic language** in the PyPy framework. +For example, a Scheme interpreter would be suitable. Ruby too (though +the latter is probably more than two months of work), or Lua, or ... + +We have a somewhat useable `Prolog interpreter`_ and the beginnings of a +`JavaScript interpreter`_ + Investigate restricted execution models --------------------------------------- @@ -101,14 +85,59 @@ objects to be tagged and tracked. The translation of PyPy would also be a good place to insert e.g. systematic checks around all system calls. -Write a new object space ------------------------- -Write **new object spaces** adding features like transparent or -semi-transparent distribution of a program across several machines, and/or -persistence (pickling of program state). This could typically be based on -"proxy" objects, behaving as transparent links to objects located on other -machines. Read more about `object spaces`_... +Experiment with distribution and persistence +-------------------------------------------- + +One of the advantages of PyPy's implementation is that the Python-level type +of an object and its implementation are completely independent. This should +allow a much more intuitive interface to, for example, objects that are backed +by a persistent store, or whose implementation lives on a remote server. + +The recently added "transparent proxy" objects are a key step in this +direction; now all that remains is to implement the interesting bits :-) + +An example project might be to implement functionality akin to the `ZODB's +Persistent class`_, without the need for the _p_changed hacks, and in pure +Python code. + +Numeric/NumPy/numarray support +------------------------------ + +At the EuroPython sprint, some work was done on making RPython's annotator +recognise Numeric arrays, with the goal of allowing programs using them to be +efficiently translated. It would be a reasonably sized project to finish this +work, i.e. allow RPython programs to use some Numeric facilities. +Additionally, these facilities could be exposed to applications interpreted by +the translated PyPy interpreter. + + + +Extension modules +----------------- + +Rewrite one or several CPython extension modules to be based on **ctypes** +(newly integrated in Python 2.5): this is generally useful for Python +developers, and it is now the best path to write extension modules that are +compatible with both CPython and PyPy. This is done with the `extension +compiler`_ component of PyPy, which will likely require some attention as +well. + +Modules where some work is already done: + +* ``_socket``, ``os``, ``select`` (unfinished yet, feel free to help; + see e.g. http://codespeak.net/svn/pypy/dist/pypy/module/_socket/). + +* SSL for socket, ``bz2``, ``fcntl``, ``mmap`` and ``time``: part of the + Summer of Code project of Lawrence Oluyede + (http://codespeak.net/svn/user/rhymes/). + +You are free to pick any other CPython module, either standard or third-party +(if relatively well-known). Note that some modules exist in a ctypes version +already, which would be a good start for porting them to PyPy's extension +compiler. We'd particularly appreciate ``readline`` :-) + + Extend py.execnet to a peer-to-peer model ----------------------------------------- @@ -146,6 +175,7 @@ .. _`py.test`: http://codespeak.net/py/current/doc/test.html .. _`py.execnet`: http://codespeak.net/py/current/doc/execnet.html .. _`Prolog interpreter`: http://codespeak.net/svn/user/cfbolz/hack/prolog/interpreter +.. _`JavaScript interpreter`: ../../../pypy/lang/js .. _`extension compiler`: extcompiler.html .. _`object spaces`: objspace.html .. _`code templating solution`: http://codespeak.net/svn/pypy/extradoc/soc-2006/code-templating.txt @@ -154,3 +184,4 @@ .. _contact: contact.html .. _`pypy-dev mailing list`: http://codespeak.net/mailman/listinfo/pypy-dev .. _`Summer of PyPy`: summer-of-pypy.html +.. _`ZODB's Persistent class`: http://www.zope.org/Documentation/Books/ZDG/current/Persistence.stx From cfbolz at codespeak.net Tue Nov 7 13:42:49 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Nov 2006 13:42:49 +0100 (CET) Subject: [pypy-svn] r34321 - pypy/dist/pypy/doc Message-ID: <20061107124249.6ECAD10078@code0.codespeak.net> Author: cfbolz Date: Tue Nov 7 13:42:48 2006 New Revision: 34321 Modified: pypy/dist/pypy/doc/project-ideas.txt Log: fix link Modified: pypy/dist/pypy/doc/project-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/project-ideas.txt (original) +++ pypy/dist/pypy/doc/project-ideas.txt Tue Nov 7 13:42:48 2006 @@ -175,7 +175,7 @@ .. _`py.test`: http://codespeak.net/py/current/doc/test.html .. _`py.execnet`: http://codespeak.net/py/current/doc/execnet.html .. _`Prolog interpreter`: http://codespeak.net/svn/user/cfbolz/hack/prolog/interpreter -.. _`JavaScript interpreter`: ../../../pypy/lang/js +.. _`JavaScript interpreter`: ../../pypy/lang/js .. _`extension compiler`: extcompiler.html .. _`object spaces`: objspace.html .. _`code templating solution`: http://codespeak.net/svn/pypy/extradoc/soc-2006/code-templating.txt From arigo at codespeak.net Tue Nov 7 13:44:17 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 13:44:17 +0100 (CET) Subject: [pypy-svn] r34322 - in pypy/dist/pypy: lib module/_stackless/test Message-ID: <20061107124417.AD83910078@code0.codespeak.net> Author: arigo Date: Tue Nov 7 13:44:12 2006 New Revision: 34322 Modified: pypy/dist/pypy/lib/stackless.py pypy/dist/pypy/module/_stackless/test/test_coroutine.py Log: Another (skipped) test about kill(), which is not working in app-level coroutines because the interp-level code only knows about a special interp-level CoroutineExit exception which is not visible at app-level. Not sure how to fix it. Modified: pypy/dist/pypy/lib/stackless.py ============================================================================== --- pypy/dist/pypy/lib/stackless.py (original) +++ pypy/dist/pypy/lib/stackless.py Tue Nov 7 13:44:12 2006 @@ -353,7 +353,7 @@ """ if not self.is_zombie: coroutine.kill(self) - return self.raise_excption(TaskletExit) + return self.raise_exception(TaskletExit, TaskletExit()) def raise_exception(self, exc, value): """ Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_coroutine.py Tue Nov 7 13:44:12 2006 @@ -85,6 +85,31 @@ co.kill() assert not co.is_alive + def test_kill_running(self): + skip("kill is not really working (there is only CoroutineExit, " + "which is not an app-level exception)") + import _stackless as stackless + main = stackless.coroutine.getcurrent() + result = [] + co = stackless.coroutine() + def f(): + x = 2 + try: + result.append(1) + main.switch() + x = 3 + finally: + result.append(x) + result.append(4) + co.bind(f) + assert co.is_alive + co.switch() + assert co.is_alive + assert result == [1] + co.kill() + assert not co.is_alive + assert result == [1, 2] + def test_bogus_bind(self): import _stackless as stackless co = stackless.coroutine() From fijal at codespeak.net Tue Nov 7 13:59:18 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 7 Nov 2006 13:59:18 +0100 (CET) Subject: [pypy-svn] r34323 - pypy/dist/pypy/doc Message-ID: <20061107125918.C38E810069@code0.codespeak.net> Author: fijal Date: Tue Nov 7 13:59:17 2006 New Revision: 34323 Modified: pypy/dist/pypy/doc/project-ideas.txt Log: Keeping it a bit more up-to-date, added some JS-specific stuff. Modified: pypy/dist/pypy/doc/project-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/project-ideas.txt (original) +++ pypy/dist/pypy/doc/project-ideas.txt Tue Nov 7 13:59:17 2006 @@ -28,7 +28,7 @@ do this without making the interpreted applications aware of the optimization at all.) -For example, we have started some work on: +For example, we've got working implementations of things like: * lazy string slices (slicing a string gives an object that references a part of the original string). @@ -38,17 +38,31 @@ * dictionaries specialized for string-only keys. +Other interesting ideas might be: - +* lists which are specialised for int-only values (for saving memory). Start or improve a back-end --------------------------- PyPy has complete, or nearly so, back-ends for C, LLVM and CLI/.NET and -partial backends for Common Lisp, Squeak and the JVM. It would be an +partial backends for JS, Common Lisp, Squeak and the JVM. It would be an interesting project to improve either of these partial backends, or start one for another platform (objective C comes to mind). +Improve JS backend +------------------ + +A JS backend is somehow different from other pypy's backends because it does +not try to support all pypy (where it might be run than?), but rather to +compile RPython programs into browser-stuff. Some documents are in a +`JS whatis`_ file and a `JS using`_ file. Some project ideas might be: + +* Write some examples to show different possibilities of using them + +* Improve facilities of testing RPython code on top of CPython, mostly + by improving existing DOM interface. + Improve one of the JIT back-ends -------------------------------- @@ -85,7 +99,6 @@ objects to be tagged and tracked. The translation of PyPy would also be a good place to insert e.g. systematic checks around all system calls. - Experiment with distribution and persistence -------------------------------------------- @@ -111,8 +124,6 @@ Additionally, these facilities could be exposed to applications interpreted by the translated PyPy interpreter. - - Extension modules ----------------- @@ -137,8 +148,6 @@ already, which would be a good start for porting them to PyPy's extension compiler. We'd particularly appreciate ``readline`` :-) - - Extend py.execnet to a peer-to-peer model ----------------------------------------- @@ -185,3 +194,6 @@ .. _`pypy-dev mailing list`: http://codespeak.net/mailman/listinfo/pypy-dev .. _`Summer of PyPy`: summer-of-pypy.html .. _`ZODB's Persistent class`: http://www.zope.org/Documentation/Books/ZDG/current/Persistence.stx +.. _`JS whatis`: js/whatis.html +.. _`JS using`: js/using.html + From fijal at codespeak.net Tue Nov 7 14:06:06 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 7 Nov 2006 14:06:06 +0100 (CET) Subject: [pypy-svn] r34324 - pypy/dist/pypy/doc Message-ID: <20061107130606.76F0F10075@code0.codespeak.net> Author: fijal Date: Tue Nov 7 14:06:05 2006 New Revision: 34324 Modified: pypy/dist/pypy/doc/project-ideas.txt Log: s/JS/JavaScript/g Modified: pypy/dist/pypy/doc/project-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/project-ideas.txt (original) +++ pypy/dist/pypy/doc/project-ideas.txt Tue Nov 7 14:06:05 2006 @@ -46,17 +46,18 @@ --------------------------- PyPy has complete, or nearly so, back-ends for C, LLVM and CLI/.NET and -partial backends for JS, Common Lisp, Squeak and the JVM. It would be an -interesting project to improve either of these partial backends, or start one -for another platform (objective C comes to mind). - -Improve JS backend ------------------- - -A JS backend is somehow different from other pypy's backends because it does -not try to support all pypy (where it might be run than?), but rather to -compile RPython programs into browser-stuff. Some documents are in a -`JS whatis`_ file and a `JS using`_ file. Some project ideas might be: +partial backends for JavaScript, Common Lisp, Squeak and the JVM. It would +be an interesting project to improve either of these partial backends, +or start one for another platform (objective C comes to mind). + +Improve JavaScript backend +-------------------------- + +A JavaScript backend is somehow different from other pypy's backends +because it does not try to support all pypy (where it might be run than?), +but rather to compile RPython programs into browser-stuff. +Some documents are in a `JavaScript whatis`_ file and a `JavaScript using`_ +file. Some project ideas might be: * Write some examples to show different possibilities of using them @@ -194,6 +195,6 @@ .. _`pypy-dev mailing list`: http://codespeak.net/mailman/listinfo/pypy-dev .. _`Summer of PyPy`: summer-of-pypy.html .. _`ZODB's Persistent class`: http://www.zope.org/Documentation/Books/ZDG/current/Persistence.stx -.. _`JS whatis`: js/whatis.html -.. _`JS using`: js/using.html +.. _`JavaScript whatis`: js/whatis.html +.. _`JavaScript using`: js/using.html From arigo at codespeak.net Tue Nov 7 14:55:21 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 14:55:21 +0100 (CET) Subject: [pypy-svn] r34327 - in pypy/dist/pypy/module/_stackless: . test Message-ID: <20061107135521.AEE0A10075@code0.codespeak.net> Author: arigo Date: Tue Nov 7 14:55:19 2006 New Revision: 34327 Added: pypy/dist/pypy/module/_stackless/composable_coroutine.py (contents, props changed) pypy/dist/pypy/module/_stackless/test/test_composable_coroutine.py (contents, props changed) Modified: pypy/dist/pypy/module/_stackless/__init__.py pypy/dist/pypy/module/_stackless/coroutine.py pypy/dist/pypy/module/_stackless/test/test_coroutine.py pypy/dist/pypy/module/_stackless/test/test_stackless.py Log: App-level costate creation, with a test that shows why it is useful in order to avoid various coroutine users tramping on each other's feet. We night need another name that "costate", though. Modified: pypy/dist/pypy/module/_stackless/__init__.py ============================================================================== --- pypy/dist/pypy/module/_stackless/__init__.py (original) +++ pypy/dist/pypy/module/_stackless/__init__.py Tue Nov 7 14:55:19 2006 @@ -16,6 +16,7 @@ 'coroutine' : 'coroutine.AppCoroutine', 'clonable' : 'clonable.ClonableCoroutine', 'greenlet' : 'interp_greenlet.AppGreenlet', + 'usercostate': 'composable_coroutine.W_UserCoState', } def setup_after_space_initialization(self): Added: pypy/dist/pypy/module/_stackless/composable_coroutine.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_stackless/composable_coroutine.py Tue Nov 7 14:55:19 2006 @@ -0,0 +1,33 @@ +from pypy.interpreter.baseobjspace import Wrappable +from pypy.interpreter.typedef import TypeDef, interp2app +from pypy.module._stackless.coroutine import AppCoState, AppCoroutine + + +class W_UserCoState(Wrappable): + def __init__(self, space): + self.costate = AppCoState(space) + self.costate.post_install() + + def descr_method__new__(space, w_subtype): + costate = space.allocate_instance(W_UserCoState, w_subtype) + W_UserCoState.__init__(costate, space) + return space.wrap(costate) + + def w_getcurrent(self): + space = self.costate.space + return space.wrap(self.costate.current) + + def w_spawn(self, w_subtype=None): + space = self.costate.space + if space.is_w(w_subtype, space.w_None): + w_subtype = space.gettypeobject(AppCoroutine.typedef) + co = space.allocate_instance(AppCoroutine, w_subtype) + AppCoroutine.__init__(co, space, state=self.costate) + return space.wrap(co) + +W_UserCoState.typedef = TypeDef("usercostate", + __new__ = interp2app(W_UserCoState.descr_method__new__.im_func), + __module__ = '_stackless', + getcurrent = interp2app(W_UserCoState.w_getcurrent), + spawn = interp2app(W_UserCoState.w_spawn), +) Modified: pypy/dist/pypy/module/_stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/coroutine.py Tue Nov 7 14:55:19 2006 @@ -52,9 +52,10 @@ class AppCoroutine(Coroutine): # XXX, StacklessFlags): - def __init__(self, space, is_main=False): + def __init__(self, space, is_main=False, state=None): self.space = space - state = self._get_state(space) + if state is None: + state = self._get_state(space) Coroutine.__init__(self, state) self.flags = 0 self.framestack = None @@ -145,7 +146,7 @@ nt = space.newtuple ec = self.space.getexecutioncontext() - if self is self._get_state(space).main: + if self is self.costate.main: return nt([mod2.get('return_main'), nt([])]) thunk = self.thunk @@ -304,4 +305,5 @@ self.space = space def post_install(self): - self.current = self.main = AppCoroutine(self.space, is_main=True) + self.current = self.main = AppCoroutine(self.space, is_main=True, + state=self) Added: pypy/dist/pypy/module/_stackless/test/test_composable_coroutine.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_stackless/test/test_composable_coroutine.py Tue Nov 7 14:55:19 2006 @@ -0,0 +1,130 @@ +""" a faith is the connection between past and future that divides the + application into switch-compatible chunks. + -- stakkars +""" +from pypy.conftest import gettestobjspace +from py.test import skip + +class AppTest_ComposableCoroutine: + + def setup_class(cls): + space = gettestobjspace(usemodules=('_stackless',)) + cls.space = space + + cls.w_generator = space.appexec([], """(): + import _stackless + + generators_costate = _stackless.usercostate() + main = generators_costate.getcurrent() + + class generator_iterator(_stackless.coroutine): + + def __iter__(self): + return self + + def next(self): + if self.gi_answer is not None: + raise ValueError('stackless-generator' + ' already executing') + self.gi_answer = [] + self.gi_caller = generators_costate.getcurrent() + self.switch() + answer = self.gi_answer + self.gi_answer = None + if answer: + return answer[0] + else: + raise StopIteration + + def generator(f): + def myfunc(*args, **kwds): + g = generators_costate.spawn(generator_iterator) + g.gi_answer = None + g.bind(f, *args, **kwds) + return g + return myfunc + + def Yield(value): + g = generators_costate.getcurrent() + if g is main: + raise ValueError('Yield() outside any stackless-generator') + assert isinstance(g, generator_iterator) + assert g.gi_answer == [] + g.gi_answer.append(value) + g.gi_caller.switch() + + generator.Yield = Yield + return generator + """) + + def test_simple_costate(self): + import _stackless + costate = _stackless.usercostate() + main = costate.getcurrent() + + result = [] + def f(): + result.append(costate.getcurrent()) + co = costate.spawn() + co.bind(f) + co.switch() + assert result == [co] + + def test_generator(self): + generator = self.generator + + def squares(n): + for i in range(n): + generator.Yield(i*i) + squares = generator(squares) + + lst1 = [i*i for i in range(10)] + for got in squares(10): + expected = lst1.pop(0) + assert got == expected + assert lst1 == [] + + def test_multiple_costates(self): + """Test that two independent costates mix transparently: + + - compute_costate, used for a coroutine that fills a list with + some more items each time it is switched to + + - generators_costate, used interally by self.generator (see above) + """ + + import _stackless + generator = self.generator + + compute_costate = _stackless.usercostate() + compute_main = compute_costate.getcurrent() + lst = [] + + def filler(): # -> 0, 1, 2, 100, 101, 102, 200, 201, 202, 300 ... + for k in range(5): + for j in range(3): + lst.append(100 * k + j) + compute_main.switch() + + filler_co = compute_costate.spawn() + filler_co.bind(filler) + + def grab_next_value(): + while not lst: + #print 'filling more...' + filler_co.switch() + #print 'now lst =', lst + #print 'grabbing', lst[0] + return lst.pop(0) + + def squares(n): + for i in range(n): + #print 'square:', i + generator.Yield(i*grab_next_value()) + squares = generator(squares) + + lst1 = [0, 1, 4, 300, 404, 510, 1200, 1407, 1616, 2700] + for got in squares(10): + expected = lst1.pop(0) + assert got == expected + assert lst1 == [] Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_coroutine.py Tue Nov 7 14:55:19 2006 @@ -1,8 +1,6 @@ from pypy.conftest import gettestobjspace from py.test import skip -# no real testing possible without compiling stackless pypy -# class AppTest_Coroutine: Modified: pypy/dist/pypy/module/_stackless/test/test_stackless.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_stackless.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_stackless.py Tue Nov 7 14:55:19 2006 @@ -348,7 +348,7 @@ def setup_class(cls): if not option.runappdirect: - py.test.skip('pure appdirect test (run with -A)') + skip('pure appdirect test (run with -A)') cls.space = gettestobjspace(usemodules=('_stackless',)) def test_basic_tasklet_pickling(self): From fijal at codespeak.net Tue Nov 7 15:31:34 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 7 Nov 2006 15:31:34 +0100 (CET) Subject: [pypy-svn] r34328 - pypy/dist/pypy/config Message-ID: <20061107143134.4ECCF10078@code0.codespeak.net> Author: fijal Date: Tue Nov 7 15:31:32 2006 New Revision: 34328 Modified: pypy/dist/pypy/config/pypyoption.py Log: Changed transparent proxy option name. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Tue Nov 7 15:31:32 2006 @@ -54,7 +54,7 @@ OptionDescription("std", "Standard Object Space Options", [ BoolOption("withtproxy", "support transparent proxies", - default=False), + default=False, cmdline='--with-transparent-proxy'), BoolOption("withsmallint", "use tagged integers", default=False), From fijal at codespeak.net Tue Nov 7 15:38:01 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 7 Nov 2006 15:38:01 +0100 (CET) Subject: [pypy-svn] r34329 - pypy/dist/pypy/doc Message-ID: <20061107143801.965121007B@code0.codespeak.net> Author: fijal Date: Tue Nov 7 15:38:00 2006 New Revision: 34329 Added: pypy/dist/pypy/doc/proxy.txt (contents, props changed) Log: Added document about transparent proxies. Added: pypy/dist/pypy/doc/proxy.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/proxy.txt Tue Nov 7 15:38:00 2006 @@ -0,0 +1,83 @@ +======================================= +PyPy - transparent proxy implementation +======================================= + +Among the unique features of PyPy, there is as well possibility of +having multiple implementations of builtin types. Multiple performance +optimisations using this features are already implemented, some +hints are in `Object space`_ document. + +Transparent proxy is implementation of some (maybe all at some point) +of objects like functions, objects, lists etc. which forwards all +operations performed on object to app-level function with specific +signature. + +_`Object space`: objspace.html#object-types + +Example: +======== + +Suppose we want to have list which stores all operations performed on +it for later analysis. So we create a list an apropriate controller:: + + class Controller(object): + def __init__(self, l): + self.l = l + self.history = [] + def perform(self, name, *args, **kwargs): + self.history.append(name) + return getattr(self.l, name)(*args, **kwargs) + l = [] + c = Controller(l) + lst = proxy(list, c.perform) + +Here, we've created original list, some random class and called magic +``proxy`` function, which eats operation name and additional arguments. +Important bit is that we do not need some existing object to perform +operations on, it can do whatever we like. And of course +``type(lst) is type(l)`` and ``lst is not l`` (well, the latter is not +"of course", but actually it's true). + +Now we can access all history of operations on ``c.history``, if we +perform something like:: + + lst.append(3) + print lst + lst[:-1] + +it'll be something like ``['__getattribute__', '__repr__', '__getitem__']`` +(not that ``append`` is just an argument to ``__getattribute__``). + +Further points of interest: +=========================== + +A lot of tasks could be performed using transparent proxies. Including, +but not limited to: + +* Remote version of objects, on which we perform operations + (think about transparent distribution) + +* Access to some persistent-storages like databases (imagine + SQL object mapper which looks like real object) + +* Access to external data structures, like other languages as normal + objects. (Of course some will raise exceptions, but it's purely done + in application level, so it's not real problem) + +Random notes: +============= + +Transparent proxy is implemented on top of `standart object space`_, in +`proxy_helpers.py`_, `proxyobject.py`_ and `transparent.py`_. To run it +you need to pass ``--with-transparent-proxy`` option to ``py.py`` or +``translate.py``. It registers implementations like a ``W_TransparentXxx`` +which usually corresponds to an apropriate ``W_XxxObject``, including some +interpreter hacks for objects that are too involved into interpreter +tricks to be implemented in a std objspace. Actually working objects are: +user created classes & functions, lists, dicts, exceptions, tracebacks and +frames. + +_`standart object space`: objspace.html#the-standard-object-space +_`proxy_helpers.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/proxy_helpers.py +_`proxyobject.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/proxyobject.py +_`transparent.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/transparent.py From fijal at codespeak.net Tue Nov 7 15:39:39 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 7 Nov 2006 15:39:39 +0100 (CET) Subject: [pypy-svn] r34330 - pypy/dist/pypy/doc Message-ID: <20061107143939.C88641007D@code0.codespeak.net> Author: fijal Date: Tue Nov 7 15:39:38 2006 New Revision: 34330 Modified: pypy/dist/pypy/doc/project-ideas.txt pypy/dist/pypy/doc/proxy.txt Log: Fixed links. Modified: pypy/dist/pypy/doc/project-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/project-ideas.txt (original) +++ pypy/dist/pypy/doc/project-ideas.txt Tue Nov 7 15:39:38 2006 @@ -108,7 +108,7 @@ allow a much more intuitive interface to, for example, objects that are backed by a persistent store, or whose implementation lives on a remote server. -The recently added "transparent proxy" objects are a key step in this +The recently added `transparent proxy`_ objects are a key step in this direction; now all that remains is to implement the interesting bits :-) An example project might be to implement functionality akin to the `ZODB's @@ -197,4 +197,4 @@ .. _`ZODB's Persistent class`: http://www.zope.org/Documentation/Books/ZDG/current/Persistence.stx .. _`JavaScript whatis`: js/whatis.html .. _`JavaScript using`: js/using.html - +.. _`transparent proxy`: proxy.html \ No newline at end of file Modified: pypy/dist/pypy/doc/proxy.txt ============================================================================== --- pypy/dist/pypy/doc/proxy.txt (original) +++ pypy/dist/pypy/doc/proxy.txt Tue Nov 7 15:39:38 2006 @@ -12,7 +12,7 @@ operations performed on object to app-level function with specific signature. -_`Object space`: objspace.html#object-types +.. _`Object space`: objspace.html#object-types Example: ======== @@ -77,7 +77,7 @@ user created classes & functions, lists, dicts, exceptions, tracebacks and frames. -_`standart object space`: objspace.html#the-standard-object-space -_`proxy_helpers.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/proxy_helpers.py -_`proxyobject.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/proxyobject.py -_`transparent.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/transparent.py +.. _`standart object space`: objspace.html#the-standard-object-space +.. _`proxy_helpers.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/proxy_helpers.py +.. _`proxyobject.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/proxyobject.py +.. _`transparent.py`: http://codespeak.net/svn/pypy/dist/pypy/objspace/std/transparent.py From arigo at codespeak.net Tue Nov 7 15:50:21 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 15:50:21 +0100 (CET) Subject: [pypy-svn] r34331 - in pypy/dist/pypy: interpreter module/_stackless Message-ID: <20061107145021.9E1851007F@code0.codespeak.net> Author: arigo Date: Tue Nov 7 15:50:19 2006 New Revision: 34331 Modified: pypy/dist/pypy/interpreter/argument.py pypy/dist/pypy/module/_stackless/coroutine.py Log: Typos. Modified: pypy/dist/pypy/interpreter/argument.py ============================================================================== --- pypy/dist/pypy/interpreter/argument.py (original) +++ pypy/dist/pypy/interpreter/argument.py Tue Nov 7 15:50:19 2006 @@ -44,7 +44,7 @@ args_w, kwds_w = self.unpack() w_args = space.newtuple(args_w) w_kwds = space.newdict() - for key, w_value in kwds_w: + for key, w_value in kwds_w.items(): space.setitem(w_kwds, space.wrap(key), w_value) return w_args, w_kwds Modified: pypy/dist/pypy/module/_stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/coroutine.py Tue Nov 7 15:50:19 2006 @@ -172,7 +172,7 @@ w_flags, w_state, w_thunk, w_parent = space.unpackiterable(w_args, expected_length=4) except UnpackValueError, e: - raise OperationError(space.w_ValueError, e.msg) + raise OperationError(space.w_ValueError, space.wrap(e.msg)) self.flags = space.int_w(w_flags) self.parent = space.interp_w(AppCoroutine, w_parent, can_be_None=True) ec = self.space.getexecutioncontext() @@ -185,7 +185,7 @@ w_func, w_args, w_kwds = space.unpackiterable(w_thunk, expected_length=3) except UnpackValueError, e: - raise OperationError(space.w_ValueError, e.msg) + raise OperationError(space.w_ValueError, space.wrap(e.msg)) args = Arguments.frompacked(space, w_args, w_kwds) self.bind(_AppThunk(space, self.costate, w_func, args)) From cfbolz at codespeak.net Tue Nov 7 15:57:54 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Nov 2006 15:57:54 +0100 (CET) Subject: [pypy-svn] r34333 - in pypy/branch/resume-point-hack/pypy/rlib: . test Message-ID: <20061107145754.AF70C10082@code0.codespeak.net> Author: cfbolz Date: Tue Nov 7 15:57:52 2006 New Revision: 34333 Added: pypy/branch/resume-point-hack/pypy/rlib/test/test_rstack.py Modified: pypy/branch/resume-point-hack/pypy/rlib/rstack.py Log: hacks to support resume_point, resume_state_create and resume_state_invoke on top of CPython. Modified: pypy/branch/resume-point-hack/pypy/rlib/rstack.py ============================================================================== --- pypy/branch/resume-point-hack/pypy/rlib/rstack.py (original) +++ pypy/branch/resume-point-hack/pypy/rlib/rstack.py Tue Nov 7 15:57:52 2006 @@ -2,8 +2,8 @@ This file defines utilities for manipulating the stack in an RPython-compliant way, intended mostly for use by the Stackless PyPy. """ - -import inspect +import py +import inspect, random, sys, dis def stack_unwind(): raise RuntimeError("cannot unwind stack in non-translated versions") @@ -36,8 +36,46 @@ from pypy.rpython.extregistry import ExtRegistryEntry -def resume_point(label, *args, **kwds): - pass +def resume_point(name, *args, **kwargs): + if not isinstance(name, str): + raise TypeError("resume point name has to be a string") + assert len(kwargs) <= 1 + #print " resume_point", name + resume_data = ResumeData.current_resume_data + if resume_data is None or not resume_data.is_resuming(name): + #print " not resuming" + return + frame = sys._getframe(1) + print " ", frame, frame.f_locals + setvals = {} + assert len(resume_data.args) == len(args), ( + "resume state for %s created with wrong number of arguments" % + (name, )) + for name, val in frame.f_locals.iteritems(): + for i, arg in enumerate(args): + if val is arg: + if name in setvals: + raise ValueError( + "Could not reliably determine value of %s" % name) + setvals[name] = val + resume_data.set_local(name, resume_data.args[i], 1) + if kwargs: + if val is kwargs["returns"]: + if resume_data.returning is NOTHING: + assert resume_data.raising is not NOTHING + continue + if name in setvals: + raise ValueError( + "Could not reliably determine value of %s" % name) + setvals[name] = val + resume_data.set_local(name, resume_data.returning, 1) + if resume_data.raising is not NOTHING: + print "raising..." + e = resume_data.raising + resume_data.resuming_finished() + raise e + resume_data.resuming_finished() + class ResumePointFnEntry(ExtRegistryEntry): _about_ = resume_point @@ -70,8 +108,8 @@ return hop.genop('resume_point', [c_label, v_return] + args_v, hop.r_result) -def resume_state_create(prevstate, label, *args): - raise RuntimeError("cannot resume states in non-translated versions") +def resume_state_create(prevstate, label, func, *args): + return ResumeData(prevstate, label, func, *args) def concretify_argument(hop, index): from pypy.objspace.flow import model @@ -86,7 +124,7 @@ class ResumeStateCreateFnEntry(ExtRegistryEntry): _about_ = resume_state_create - def compute_result_annotation(self, s_prevstate, s_label, *args_s): + def compute_result_annotation(self, s_prevstate, s_label, s_ignore, *args_s): from pypy.annotation import model as annmodel return annmodel.SomeExternalObject(frame_stack_top) @@ -97,6 +135,7 @@ assert hop.args_s[1].is_constant() c_label = hop.inputconst(lltype.Void, hop.args_s[1].const) + c_func = hop.inputconst(lltype.Void, hop.args_s[2].const) v_state = hop.inputarg(hop.r_result, arg=0) @@ -109,7 +148,7 @@ hop.r_result) def resume_state_invoke(type, state, **kwds): - raise NotImplementedError("only works in translated versions") + return state.resume(**kwds) class ResumeStateInvokeFnEntry(ExtRegistryEntry): _about_ = resume_state_invoke @@ -143,3 +182,351 @@ hop.r_result) +# __________________________________________________________________ +# the following code is used for the (quite hackish) implementation +# of resume states on top of CPython + + + +operations = [ + ('operator.pos', 'pos', 1, ['__pos__']), + ('operator.neg', 'neg', 1, ['__neg__']), + ('abs', 'abs', 1, ['__abs__']), + ('operator.invert', '~', 1, ['__invert__']), + ('getattr', 'getattr', 2, ['__getattr__']), + ('operator.getitem', 'getitem', 2, ['__getitem__']), + ('operator.add', '+', 2, ['__add__', '__radd__']), + ('operator.sub', '-', 2, ['__sub__', '__rsub__']), + ('operator.mul', '*', 2, ['__mul__', '__rmul__']), + ('operator.truediv', '/', 2, ['__truediv__', '__rtruediv__']), + ('operator.floordiv', '//', 2, ['__floordiv__', '__rfloordiv__']), + ('operator.div', 'div', 2, ['__div__', '__rdiv__']), + ('operator.mod', '%', 2, ['__mod__', '__rmod__']), + ('operator.divmod', 'divmod', 2, ['__divmod__', '__rdivmod__']), + ('operator.lshift', '<<', 2, ['__lshift__', '__rlshift__']), + ('operator.rshift', '>>', 2, ['__rshift__', '__rrshift__']), + ('operator.and_', '&', 2, ['__and__', '__rand__']), + ('operator.or_', '|', 2, ['__or__', '__ror__']), + ('operator.xor', '^', 2, ['__xor__', '__rxor__']), + ('operator.lt', '<', 2, ['__lt__', '__gt__']), + ('operator.le', '<=', 2, ['__le__', '__ge__']), + ('operator.eq', '==', 2, ['__eq__', '__eq__']), + ('operator.ne', '!=', 2, ['__ne__', '__ne__']), + ('operator.gt', '>', 2, ['__gt__', '__lt__']), + ('operator.ge', '>=', 2, ['__ge__', '__le__']), + ('cmp', 'cmp', 2, ['__cmp__']), +] + +class Blackhole(object): + for impl, _, arity, names in operations: + args = ", ".join(["v%s" % i for i in range(arity)]) + for name in names: + exec py.code.Source(""" + def %s(%s): + return v0.__class__() + """ % (name, args)).compile() + + def __pow__(self, *args): + return self.__class__() + + def __call__(self, *args): + return self.__class__() + + +class HomingBlackhole(Blackhole): + def __nonzero__(self): + print "taking decision", + decision = ResumeData.current_resume_data.pop_next_decision("bool")[1] + print decision + return decision + + def next(self): + print "taking decision" + decision = ResumeData.current_resume_data.pop_next_decision("next")[1] + print decision + if decision == "stop": + raise StopIteration + return self.__class__() + + def __iter__(self): + return self.__class__() + + def _freeze_(self): + assert 0 # a HomingBlackhole was left!!! + + + +NOTHING = object() + +class ResumeData(object): + current_resume_data = None + + def __init__(self, goto_after, name, func, *args): + self.local_changes = [] + self.goto_after = goto_after + self.name = name + self.func = func + self.args = args + self.decision_stack = None + self.likely_frame = None + self.previous_globals = None + self.returning = NOTHING + self.raising = NOTHING + + def register_local_change(self, frame, name, value): + assert frame is self.likely_frame + self.local_changes.append((name, value)) + + def pop_local_changes(self, frame): + assert frame is self.likely_frame + res = self.local_changes + self.local_changes = [] + return res + + def is_resuming(self, name): + return self.name == name + + def resume(self, returning=NOTHING, raising=NOTHING): + assert returning is NOTHING or raising is NOTHING + try: + ResumeData.current_resume_data = self + self.returning = returning + self.raising = raising + dummy_args = [HomingBlackhole()] * self.func.func_code.co_argcount + paths, other_globals = find_path_to_resume_point(self.func) + self.fix_globals = [g for g, val in other_globals.items() if val] + decisions = paths[self.name][:] + decisions.reverse() + self.decision_stack = decisions + sys.settrace(self.resume_tracer) + try: + result = self.func(*dummy_args) + except Exception, e: + if self.goto_after is not None: + print "caught something, handing it on..." + return self.goto_after.resume(raising=e) + raise + finally: + sys.settrace(None) + if self.goto_after is not None: + return self.goto_after.resume(returning=result) + return result + + def pop_next_decision(self, what): + assert self.decision_stack[-1][0] == what + return self.decision_stack.pop() + + def resuming_finished(self): + self.decisions = None + ResumeData.current_resume_data = None + self.returning = NOTHING + self.raising = NOTHING + + def possible_frame(self, frame): + if self.likely_frame is None: + self.likely_frame = frame + return True + return frame is self.likely_frame + + def set_local(self, local, val, levels=0): + frame = sys._getframe(levels + 1) + self.register_local_change(frame, local, val) + + def resume_tracer(self, frame, what, x): + is_resume_frame = self.possible_frame(frame) +# print frame, what, x, is_resume_frame + if not is_resume_frame: + return None + # still waiting for resume_point? + if ResumeData.current_resume_data is self: + newlocals = {} + for name, val in frame.f_locals.iteritems(): + if not isinstance(val, HomingBlackhole): + val = HomingBlackhole() + newlocals[name] = val + if newlocals: +# print "fixing locals", newlocals + frame.f_locals.update(newlocals) + if self.fix_globals: + self.previous_globals = {} + print "fixing globals", self.fix_globals + for gl in self.fix_globals: + try: + oldvalue = frame.f_globals[gl] + except KeyError: + oldvalue = NOTHING + frame.f_globals[gl] = HomingBlackhole() + self.previous_globals[gl] = oldvalue + assert gl in frame.f_globals + self.fix_globals = None + else: + print "restore correct globals" + if self.previous_globals is not None: + for gl, oldvalue in self.previous_globals.iteritems(): + if oldvalue is NOTHING: + if gl in frame.f_globals: + del frame.f_globals[gl] + else: + frame.f_globals[gl] = oldvalue + changes = self.pop_local_changes(frame) + if changes: + print 'changes', dict(changes), changes + frame.f_locals.update(dict(changes)) + return self.resume_tracer + + +# _________________________________________________________________________ +# Functions to analyze bytecode to find a way to reach resume_points + +def find_basic_blocks(code): + labels = [] + n = len(code) + i = 0 + while i < n: + c = code[i] + op = ord(c) + i = i + 1 + if op >= dis.HAVE_ARGUMENT: + oparg = ord(code[i]) + ord(code[i+1])*256 + i = i+2 + label = -1 + if op in dis.hasjrel: + label = i+oparg + elif op in dis.hasjabs: + label = oparg + if label >= 0: + if label not in labels: + labels.append(label) + if i - 3 not in labels: + labels.append(i - 3) + return labels + +def split_opcode_args(code): + ops_args = [] + n = len(code) + i = 0 + while i < n: + c = code[i] + op = ord(c) + i = i + 1 + if op >= dis.HAVE_ARGUMENT: + oparg = ord(code[i]) + ord(code[i+1])*256 + ops_args.append((i - 1, dis.opname[op], oparg)) + i = i+2 + else: + ops_args.append((i - 1, dis.opname[op], None)) + return ops_args + +def find_resume_points_and_other_globals(func): + code_obj = func.func_code + code = code_obj.co_code + ops_args = split_opcode_args(code) + globals = func.func_globals + loaded_global = None + loaded_global_name = None + positions = [] + other_globals = {} + for i, (pos, opname, arg) in enumerate(ops_args): + resume_pos = -1 + if opname == "LOAD_GLOBAL": + loaded_global_name = code_obj.co_names[arg] + try: + loaded_global = globals[loaded_global_name] + except KeyError: + loaded_global = None + if loaded_global is resume_point: + resume_pos = pos + loaded_global = None + other_globals[loaded_global_name] = False + else: + if (loaded_global_name not in other_globals and + loaded_global_name is not None): + other_globals[loaded_global_name] = True + elif opname == "LOAD_ATTR": + if getattr(loaded_global, + code_obj.co_names[arg], None) is resume_point: + resume_pos = pos + loaded_global = None + other_globals[loaded_global_name] = False + else: + if (loaded_global_name not in other_globals and + loaded_global_name is not None): + other_globals[loaded_global_name] = True + else: + loaded_global = None + if resume_pos >= 0: + if i + 1 >= len(ops_args) or ops_args[i + 1][1] != "LOAD_CONST": + raise TypeError( + "could not statically determine resume point names") + else: + positions.append((pos, code_obj.co_consts[ops_args[i + 1][2]])) + if len(dict.fromkeys(positions)) != len(positions): + raise TypeError("duplicate resume point name") + return positions, other_globals + +def _get_targets_with_condition(pos, name, arg): + op = dis.opname.index(name) + if op in dis.hasjrel: + target = pos + arg + 3 + if name == "JUMP_IF_FALSE": + return [(target, "bool", False), (pos + 3, "bool", True)] + elif name == "JUMP_IF_TRUE": + return [(target, "bool", True), (pos + 3, "bool", False)] + elif name == "JUMP_FORWARD": + return [(target, None, None)] + elif name == "SETUP_LOOP" or name == "SETUP_EXCEPT": + return [(pos + 3, None, None)] #XXX not sure + elif name == "FOR_ITER": + return [(target, "next", "stop")] + assert 0, "not implemented" + elif op in dis.hasjabs: + if name == "JUMP_ABSOLUTE": + return [(arg, None, None)] + assert 0, "not implemented" + else: + if op > dis.HAVE_ARGUMENT: + return [(pos + 3, None, None)] + else: + return [(pos + 1, None, None)] + assert 0, "not implemented" + +def find_path_to_resume_point(func): + resume_points, other_globals = find_resume_points_and_other_globals(func) + ops_args = split_opcode_args(func.func_code.co_code) + paths = {ops_args[0][0]: []} + last_unknown = None + while 1: + flip_boolean = False + num_nots = 0 + unknown = {} + for i, (pos, name, arg) in enumerate(ops_args): + path = paths.get(pos, None) + if path is None: + unknown[path] = True + continue + targets = _get_targets_with_condition(pos, name, arg) + if name == "UNARY_NOT": + flip_boolean = not flip_boolean + num_nots += 1 + elif num_nots: + num_nots = 0 + for i in range(len(targets)): + target, what, value = targets[i] + if what is None: + flip_boolean = False + targets[i] = target, "bool", False + for target, what, value in targets: + oldpath = paths.get(target, None) + if oldpath is None or len(oldpath) > len(path) + 1: + if what == "bool" and flip_boolean: + value = not value + paths[target] = path + [(what, value)] + if not unknown or unknown == last_unknown: + break + last_unknown = unknown + result = {} + for pos, name in resume_points: + if pos in paths: + result[name] = [(how, what) for how, what in paths[pos] + if how is not None] + return result, other_globals Added: pypy/branch/resume-point-hack/pypy/rlib/test/test_rstack.py ============================================================================== --- (empty file) +++ pypy/branch/resume-point-hack/pypy/rlib/test/test_rstack.py Tue Nov 7 15:57:52 2006 @@ -0,0 +1,427 @@ +import py +import sys, dis +from pypy.rlib.rstack import Blackhole, resume_point +from pypy.rlib.rstack import find_basic_blocks, split_opcode_args +from pypy.rlib.rstack import find_resume_points_and_other_globals +from pypy.rlib.rstack import find_path_to_resume_point, ResumeData +from pypy.rlib.rstack import resume_state_create, resume_state_invoke +from pypy.rlib import rstack + +def test_blackhole_simple(): + b = Blackhole() + assert isinstance(b + b, Blackhole) + assert isinstance(b.whatever, Blackhole) + assert isinstance(b(b, b, 1), Blackhole) + assert isinstance(b ** b, Blackhole) + +def test_set_local_direct(): + try: + def f(x): + resume_data.set_local('x', 42) + a = 1 + return x + resume_data = ResumeData(None, "...", f) + sys.settrace(resume_data.resume_tracer) + res = f(1) + finally: + sys.settrace(None) + assert res == 42 + +def test_set_local_direct_several(): + try: + def f(x, y): + resume_data.set_local('x', 42) + resume_data.set_local('y', 42) + return x + y + resume_data = ResumeData(None, "...", f) + sys.settrace(resume_data.resume_tracer) + res = f(1, 1) + finally: + sys.settrace(None) + assert res == 84 + +def test_set_local_nested(): + try: + def f(x): + g() + return x + def g(): + resume_data.set_local('x', 42, 1) + resume_data = ResumeData(None, "...", f) + sys.settrace(resume_data.resume_tracer) + res = f(1) + finally: + sys.settrace(None) + assert res == 42 + +def test_set_local_nested_several(): + try: + def f(x, y): + g() + return x + y + def g(): + resume_data.set_local('y', 22, 1) + resume_data.set_local('x', 20, 1) + resume_data = ResumeData(None, "...", f) + sys.settrace(resume_data.resume_tracer) + res = f(1, 1) + finally: + sys.settrace(None) + assert res == 42 + + +def test_resume_simple(): + def f(x): + x += 1 + print 1, x + resume_point("r1", x) + print 2, x + return x + assert f(1) == 2 + s1 = resume_state_create(None, "r1", f, 1) + r = resume_state_invoke(int, s1) + assert r == 1 + +def test_resume_simple_module_attribute(): + def f(x): + x += 1 + print 1, x + rstack.resume_point("r1", x) + print 2, x + return x + assert f(1) == 2 + s1 = resume_state_create(None, "r1", f, 1) + r = resume_state_invoke(int, s1) + assert r == 1 + +def test_normal_gettatr(): + def f(out): + out.append(3) + rstack.resume_point("r1", out) + return out[-1] + s1 = resume_state_create(None, "r1", f, [4]) + r = resume_state_invoke(int, s1) + assert r == 4 + + +def test_resume_many_args(): + def f(x, y, z): + x += 1 + y += 2 + z += 3 + resume_point("r1", x, y, z) + return x + y + z + assert f(1, 2, 3) == 12 + s1 = resume_state_create(None, "r1", f, 1, 2, 3) + res = resume_state_invoke(int, s1) + assert res == 6 + +def test_several_resume_points(): + def f(x, y, z): + x += 1 + y += 2 + resume_point("r1", x, y, returns=z) + z += 3 + resume_point("r2", x, y, returns=z) + return x + y + z + assert f(1, 2, 3) == 12 + s1 = resume_state_create(None, "r1", f, 1, 2) + res = resume_state_invoke(int, s1, returning=3) + assert res == 9 + s2 = resume_state_create(None, "r2", f, 1, 2) + res = resume_state_invoke(int, s2, returning=3) + assert res == 6 + +def test_resume_in_branch(): + def f(cond, x): + x += 1 + if cond: + resume_point("r1", x) + return x + else: + resume_point("r2", x) + x += 1 + return x + assert f(True, 1) == 2 + assert f(False, 2) == 4 + resume_data = resume_state_create(None, "r2", f, 2) + res = resume_state_invoke(int, resume_data) + assert res == 3 + resume_data = resume_state_create(None, "r1", f, 1) + res = resume_state_invoke(int, resume_data) + assert res == 1 + +def test_resume_branches_nested(): + def f(c1, c2, x): + if c1: + if c2: + resume_point("r1", x) + return x + 1 + else: + resume_point("r2", x) + return x + 2 + else: + if c2: + resume_point("r3", x) + return x + 3 + else: + resume_point("r4", x) + return x + 4 + for i, name in enumerate("r1 r2 r3 r4".split()): + s1 = resume_state_create(None, name, f, 2) + res = resume_state_invoke(int, s1) + assert res == 3 + i + +def test_resume_while_simple(): + def f(x): + a = 1 + result = 0 + while a <= x: + resume_point("r", a, x, result) + print result, a, x + result += a + a += 1 + return result + s1 = resume_state_create(None, "r", f, 4, 6, 10) + res = resume_state_invoke(int, s1) + assert res == 25 + +def test_resume_while_non_unique(): + def f(x): + a = 0 + result = 0 + while a <= x: + resume_point("r", a, x, result) + print result, a, x + result += a + a += 1 + return result + s1 = resume_state_create(None, "r", f, 4, 6, 10) + res = resume_state_invoke(int, s1) + assert res == 25 + +def test_resume_function_call(): + def g(x): + while 1: + x += 1 + return x + def f(x): + x = g(x) + resume_point("r", x) + return x + s1 = resume_state_create(None, "r", f, 1) + res = resume_state_invoke(int, s1) + assert res == 1 + +def forever(x): + if x: + while 1: + print "bad idea!" + return 41 + +def test_resume_global_function_call(): + old_forever = forever + def f(x): + forever(1) + resume_point("r", x) + x += forever(0) + return x + s1 = resume_state_create(None, "r", f, 1) + res = resume_state_invoke(int, s1) + assert res == 42 + assert forever is old_forever # make sure the globals were restored + +def test_chained_states(): + def g(x, y): + x += 1 + resume_point("rp1", x, y) + return x + y + def f(x, y, z): + y += 1 + r = g(x, y) + resume_point("rp2", z, returns=r) + return r + z + def example(): + v1 = f(1, 2, 3) + s2 = resume_state_create(None, "rp2", f, 2) + s1 = resume_state_create(s2, "rp1", g, 4, 5) + return 100*v1 + resume_state_invoke(int, s1) + res = example() + assert res == 811 + +def test_resume_and_raise_and_catch(): + def g(x): + x += 1 + resume_point("rp0", x) + if x == 0: + raise KeyError + return x + 1 + def f(x): + x = x - 1 + try: + r = g(x) + resume_point("rp1", returns=r) + except KeyError: + r = 42 + return r - 1 + def example(): + v1 = f(2) + s1 = resume_state_create(None, "rp1", f) + s0 = resume_state_create(s1, "rp0", g, 0) + v2 = resume_state_invoke(int, s0) + return v1*100 + v2 + res = example() + assert res == 241 + +def DONOTtest_resume_in_except_block(): # probably not necessary + def g(x): + if x: + raise KeyError + def f(x): + x += 1 + try: + g(x) + except KeyError: + resume_point("r1", x) + return x + s = resume_state_create(None, "r1", f, 42) + res = resume_state_invoke(int, s) + assert res == 42 + +def test_jump_over_for(): + def f(x): + result = 0 + for i in range(x): + print "bad idea" + result += i + resume_point("r1", result) + return result + s = resume_state_create(None, "r1", f, 42) + res = resume_state_invoke(int, s) + assert res == 42 + +def test_resume_point_guarded_by_complex_condition(): + def f(x): + x += 5 + if (x >> 8) & 0xff == 0: + resume_point("r1", x) + else: + x += 8 + return x + s = resume_state_create(None, "r1", f, 42) + res = resume_state_invoke(int, s) + assert res == 42 + +def test_function_with_bool(): + def f(x): + x = bool(x) + if x: + resume_point("r1", x) + else: + x += 8 + return x + dis.dis(f) + s = resume_state_create(None, "r1", f, 42) + res = resume_state_invoke(int, s) + assert res == 42 + +def test_function_with_and(): + def f(x, y): + if x and not y: + resume_point("r1", x) + else: + x += 8 + return x + s = resume_state_create(None, "r1", f, 42) + res = resume_state_invoke(int, s) + assert res == 42 + +def test_function_with_not(): + def f(x, y): + x = not x + if x: + resume_point("r1", x) + else: + x += 8 + return x + dis.dis(f) + s = resume_state_create(None, "r1", f, 42) + res = resume_state_invoke(int, s) + assert res == 42 + +# _________________________________________________________________________ +# test for bytecode analyzing functions + +def test_find_basic_blocks(): + def f(cond, x): + x += 1 + if cond: + return x + else: + x += 1 + return x + code = f.func_code.co_code + res = find_basic_blocks(code) + assert len(res) == 4 + +def test_split_opcode_args(): + def f(x): + return x + 1 + dis.dis(f) + res = split_opcode_args(f.func_code.co_code) + assert len(res) == 4 + assert [op for pos, op, const in res] == [ + "LOAD_FAST", "LOAD_CONST", "BINARY_ADD", "RETURN_VALUE"] + assert [pos for pos, op, const in res] == [0, 3, 6, 7] + assert res[0][2] == 0 # LOAD_FAST + assert res[1][2] == 1 # LOAD_CONST + assert res[2][2] is None # BINARY_ADD + assert res[3][2] is None # RETURN_VALUE + +def test_find_resume_points(): + def f(cond, x): + forever(x) + x += 1 + if cond: + resume_point("r1", x) + return x + else: + resume_point("r2", x) + x += 1 + return x + rps, other_globals = find_resume_points_and_other_globals(f) + assert len(rps) == 2 + assert rps[0][1] == "r1" + assert rps[1][1] == "r2" + assert not other_globals['resume_point'] + assert other_globals['forever'] + +def test_find_path_to_resume_point(): + def f(cond, x): + x += 1 + if cond: + resume_point("r1", x) + return x + else: + resume_point("r2", x) + x += 1 + return x + paths, other_globals = find_path_to_resume_point(f) + assert paths["r1"] == [("bool", True)] + assert paths["r2"] == [("bool", False)] + +def test_find_path_with_not(): + def f(x, y): + y = not y + resume_point("r2", x) + if not not x: + resume_point("r1", x) + else: + x += 8 + return x + dis.dis(f) + paths, other_globals = find_path_to_resume_point(f) + assert paths["r1"][0][0] == "bool" + assert paths["r1"][1] == ("bool", True) + assert paths["r2"][0][0] == "bool" + From cfbolz at codespeak.net Tue Nov 7 15:58:59 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Nov 2006 15:58:59 +0100 (CET) Subject: [pypy-svn] r34334 - pypy/branch/resume-point-hack/pypy/translator/stackless/test Message-ID: <20061107145859.8E7C710081@code0.codespeak.net> Author: cfbolz Date: Tue Nov 7 15:58:58 2006 New Revision: 34334 Modified: pypy/branch/resume-point-hack/pypy/translator/stackless/test/test_resume_point.py Log: run most of the resume_point tests on top of CPython too Modified: pypy/branch/resume-point-hack/pypy/translator/stackless/test/test_resume_point.py ============================================================================== --- pypy/branch/resume-point-hack/pypy/translator/stackless/test/test_resume_point.py (original) +++ pypy/branch/resume-point-hack/pypy/translator/stackless/test/test_resume_point.py Tue Nov 7 15:58:58 2006 @@ -30,13 +30,14 @@ def test_no_call(): def f(x, y): x = x-1 - rstack.resume_point("rp0", x, y) + rstack.resume_point("rp0", x, y) r = x+y rstack.stack_unwind() return r def example(): v1 = f(one(),one()+one()) - state = rstack.resume_state_create(None, "rp0", one(), one()+one()+one()) + state = rstack.resume_state_create(None, "rp0", f, + one(), one()+one()+one()) v2 = rstack.resume_state_invoke(int, state) return v1*10 + v2 ## transform_stackless_function(example) @@ -46,14 +47,16 @@ def test_bogus_restart_state_create(): def f(x, y): x = x-1 - rstack.resume_point("rp0", x, y) + rstack.resume_point("rp0", x, y) return x+y def example(): v1 = f(one(),one()+one()) - state = rstack.resume_state_create(None, "rp0", one()) - return v1 + state = rstack.resume_state_create(None, "rp0", f, one()) + v2 = rstack.resume_state_invoke(int, state) + return v1 + v2 info = py.test.raises(AssertionError, "transform_stackless_function(example)") assert 'rp0' in str(info.value) + py.test.raises(AssertionError, example) def test_call(): @@ -65,13 +68,15 @@ return z+y def example(): v1 = f(one(),one()+one()) - s = rstack.resume_state_create(None, "rp1", 5*one()) + s = rstack.resume_state_create(None, "rp1", f, 5*one()) v2 = rstack.resume_state_invoke(int, s, returning=one()*7) return v1*100 + v2 res = llinterp_stackless_function(example) assert res == 412 res = run_stackless_function(example) assert res == 412 + res = example() + assert res == 412 def test_returns_with_instance(): class C: @@ -85,13 +90,15 @@ return r.x + y def example(): v1 = f(one(),one()+one()) - s = rstack.resume_state_create(None, "rp1", 5*one()) + s = rstack.resume_state_create(None, "rp1", f, 5*one()) v2 = rstack.resume_state_invoke(int, s, returning=C(one()*3)) return v1*100 + v2 res = llinterp_stackless_function(example, assert_unwind=False) assert res == 408 res = run_stackless_function(example) assert res == 408 + res = example() + assert res == 408 def test_call_uncovered(): def g(x,y): @@ -119,13 +126,15 @@ return r + z def example(): v1 = f(one(), 2*one(), 3*one()) - s2 = rstack.resume_state_create(None, "rp2", 2*one()) - s1 = rstack.resume_state_create(s2, "rp1", 4*one(), 5*one()) + s2 = rstack.resume_state_create(None, "rp2", f, 2*one()) + s1 = rstack.resume_state_create(s2, "rp1", g, 4*one(), 5*one()) return 100*v1 + rstack.resume_state_invoke(int, s1) res = llinterp_stackless_function(example) assert res == 811 res = run_stackless_function(example) assert res == 811 + res = example() + assert res == 811 def test_return_instance(): class C: @@ -141,15 +150,17 @@ return r.x + y def example(): v1 = f(one(), 2*one()) - s2 = rstack.resume_state_create(None, "rp2", 2*one()) + s2 = rstack.resume_state_create(None, "rp2", f, 2*one()) c = C() c.x = 4*one() - s1 = rstack.resume_state_create(s2, "rp1", c) + s1 = rstack.resume_state_create(s2, "rp1", g, c) return v1*100 + rstack.resume_state_invoke(int, s1) res = llinterp_stackless_function(example) assert res == 406 res = run_stackless_function(example) assert res == 406 + res = example() + assert res == 406 def test_really_return_instance(): class C: @@ -163,12 +174,14 @@ v1 = g(one()).x c = C() c.x = 4*one() - s1 = rstack.resume_state_create(None, "rp1", c) + s1 = rstack.resume_state_create(None, "rp1", g, c) return v1*100 + rstack.resume_state_invoke(C, s1).x res = llinterp_stackless_function(example) assert res == 204 res = run_stackless_function(example) assert res == 204 + res = example() + assert res == 204 def test_resume_and_raise(): def g(x): @@ -178,7 +191,7 @@ return x + 1 def example(): v1 = g(one()) - s = rstack.resume_state_create(None, "rp0", one()-1) + s = rstack.resume_state_create(None, "rp0", g, one()-1) try: v2 = rstack.resume_state_invoke(int, s) except KeyError: @@ -188,6 +201,8 @@ assert res == 242 res = run_stackless_function(example) assert res == 242 + res = example() + assert res == 242 def test_resume_and_raise_and_catch(): def g(x): @@ -205,14 +220,16 @@ return r - 1 def example(): v1 = f(one()+one()) - s1 = rstack.resume_state_create(None, "rp1") - s0 = rstack.resume_state_create(s1, "rp0", one()-1) + s1 = rstack.resume_state_create(None, "rp1", f) + s0 = rstack.resume_state_create(s1, "rp0", g, one()-1) v2 = rstack.resume_state_invoke(int, s0) return v1*100 + v2 res = llinterp_stackless_function(example) assert res == 141 res = run_stackless_function(example) assert res == 141 + res = example() + assert res == 141 def test_invoke_raising(): def g(x): @@ -228,21 +245,23 @@ return r - 1 def example(): v1 = f(one()+one()) - s1 = rstack.resume_state_create(None, "rp1") - s0 = rstack.resume_state_create(s1, "rp0", 0) + s1 = rstack.resume_state_create(None, "rp1", f) + s0 = rstack.resume_state_create(s1, "rp0", g, 0) v2 = rstack.resume_state_invoke(int, s0, raising=KeyError()) return v1*100 + v2 res = llinterp_stackless_function(example) assert res == 141 res = run_stackless_function(example) assert res == 141 + res = example() + assert res == 141 def test_finally(): def f(x): - rstack.resume_point("rp1", x) + rstack.resume_point("rp1", x) return 1/x - def in_finally(x): + def in_finally(x): rstack.resume_point("rp1.5", x) return 2/x def g(x): @@ -257,6 +276,7 @@ def example(): return g(one()) transform_stackless_function(example) + res = example() def test_except(): py.test.skip("please don't write code like this") @@ -340,8 +360,8 @@ out = [] x = h(out) l = len(out) - chain = rstack.resume_state_create(None, 'h', out) - chain = rstack.resume_state_create(chain, 'g') + chain = rstack.resume_state_create(None, 'h', h, out) + chain = rstack.resume_state_create(chain, 'g', g) x += rstack.resume_state_invoke(int, chain) l += len(out) return l*100+x @@ -350,6 +370,8 @@ assert res == 200 res = run_stackless_function(example) assert res == 200 + res = example() + assert res == 200 def test_more_mess(): from pypy.interpreter.miscutils import Stack From arigo at codespeak.net Tue Nov 7 16:32:26 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 16:32:26 +0100 (CET) Subject: [pypy-svn] r34335 - in pypy/dist/pypy: . annotation module/_stackless/test Message-ID: <20061107153226.70F4610078@code0.codespeak.net> Author: arigo Date: Tue Nov 7 16:32:23 2006 New Revision: 34335 Modified: pypy/dist/pypy/annotation/builtin.py pypy/dist/pypy/conftest.py pypy/dist/pypy/module/_stackless/test/test_composable_coroutine.py Log: Small fixes. Now all the app-level _stackless tests work on top of a compiled pypy-c-stackless with py.test -A. Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Tue Nov 7 16:32:23 2006 @@ -376,8 +376,12 @@ OSError_init) BUILTIN_ANALYZERS[sys.getdefaultencoding] = conf -import unicodedata -BUILTIN_ANALYZERS[unicodedata.decimal] = unicodedata_decimal # xxx +try: + import unicodedata +except ImportError: + pass +else: + BUILTIN_ANALYZERS[unicodedata.decimal] = unicodedata_decimal # xxx # object - just ignore object.__init__ BUILTIN_ANALYZERS[object.__init__] = object_init Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Tue Nov 7 16:32:23 2006 @@ -3,7 +3,7 @@ from pypy.interpreter.error import OperationError from pypy.tool.pytest import appsupport from pypy.tool.option import make_config -from inspect import isclass +from inspect import isclass, getmro rootdir = py.magic.autopath().dirpath() @@ -199,6 +199,16 @@ py.test.skip("need translated pypy with: %s, got %s" %(ropts,options)) +def getwithoutbinding(x, name): + try: + return x.__dict__[name] + except (AttributeError, KeyError): + for cls in getmro(x.__class__): + if name in cls.__dict__: + return cls.__dict__[name] + # uh? not found anywhere, fall back (which might raise AttributeError) + return getattr(x, name) + class LazyObjSpaceGetter(object): def __get__(self, obj, cls=None): space = gettestobjspace() @@ -280,7 +290,10 @@ for name in dir(instance): if name.startswith('w_'): if option.runappdirect: - setattr(w_instance, name[2:], getattr(instance, name)) + # if the value is a function living on the class, + # don't turn it into a bound method here + obj = getwithoutbinding(instance, name) + setattr(w_instance, name[2:], obj) else: space.setattr(w_instance, space.wrap(name[2:]), getattr(instance, name)) Modified: pypy/dist/pypy/module/_stackless/test/test_composable_coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_composable_coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_composable_coroutine.py Tue Nov 7 16:32:23 2006 @@ -54,6 +54,7 @@ g.gi_caller.switch() generator.Yield = Yield + generator._costate = generators_costate return generator """) @@ -96,6 +97,8 @@ import _stackless generator = self.generator + # you can see how it fails if we don't have two different costates + # by setting compute_costate to generator._costate instead compute_costate = _stackless.usercostate() compute_main = compute_costate.getcurrent() lst = [] From arigo at codespeak.net Tue Nov 7 16:52:02 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 16:52:02 +0100 (CET) Subject: [pypy-svn] r34336 - pypy/dist/pypy/module/_stackless/test Message-ID: <20061107155202.B76ED10078@code0.codespeak.net> Author: arigo Date: Tue Nov 7 16:52:01 2006 New Revision: 34336 Modified: pypy/dist/pypy/module/_stackless/test/test_pickle.py Log: A new test that passes out of the box on pypy-c-stackless. It's the same as the coroutine cloning demo, but done with pickling instead (so it doesn't require a stacklessgc). Modified: pypy/dist/pypy/module/_stackless/test/test_pickle.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_pickle.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_pickle.py Tue Nov 7 16:52:01 2006 @@ -224,3 +224,71 @@ ''' in mod.__dict__ finally: del sys.modules['mod'] + + + def test_solver(self): + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +import _stackless, pickle + +class Fail(Exception): + pass + +class Success(Exception): + pass + +def first_solution(func): + global next_answer + co = _stackless.coroutine() + co.bind(func) + pending = [(co, None)] + while pending: + co, next_answer = pending.pop() + try: + co.switch() + except Fail: + pass + except Success, e: + return e.args[0] + else: + # zero_or_one() called, clone the coroutine + # NB. this seems to be quite slow + co2 = pickle.loads(pickle.dumps(co)) + pending.append((co2, 1)) + pending.append((co, 0)) + raise Fail("no solution") + +pending = [] +main = _stackless.coroutine.getcurrent() + +def zero_or_one(): + main.switch() + return next_answer + +# ____________________________________________________________ + +invalid_prefixes = { + (0, 0): True, + (0, 1, 0): True, + (0, 1, 1): True, + (1, 0): True, + (1, 1, 0, 0): True, + } + +def example(): + test = [] + for n in range(5): + test.append(zero_or_one()) + if tuple(test) in invalid_prefixes: + raise Fail + raise Success(test) + +res = first_solution(example) +assert res == [1, 1, 0, 1, 0] +''' in mod.__dict__ + finally: + del sys.modules['mod'] From mwh at codespeak.net Tue Nov 7 16:56:29 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Nov 2006 16:56:29 +0100 (CET) Subject: [pypy-svn] r34337 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061107155629.0170E1007B@code0.codespeak.net> Author: mwh Date: Tue Nov 7 16:56:29 2006 New Revision: 34337 Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/regalloc.py Log: make details of register allocation more generic Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Tue Nov 7 16:56:29 2006 @@ -211,7 +211,7 @@ BO = 12 # jump if relavent bit is set in the CR else: BO = 4 # jump if relavent bit is NOT set in the CR - asm.bcctr(BO, self.bit) + asm.bcctr(BO, self.crf.number*4 + self.bit) class Unspill(Insn): """ A special instruction inserted by our register "allocator." It Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Tue Nov 7 16:56:29 2006 @@ -1,5 +1,7 @@ -from pypy.jit.codegen.ppc.instruction import gprs, NO_REGISTER, GP_REGISTER, \ - FP_REGISTER, CR_FIELD, CT_REGISTER, CMPInsn, Spill, Unspill, crfs, ctr, stack_slot +from pypy.jit.codegen.ppc.instruction import \ + gprs, fprs, crfs, ctr, \ + NO_REGISTER, GP_REGISTER, FP_REGISTER, CR_FIELD, CT_REGISTER, \ + CMPInsn, Spill, Unspill, stack_slot class RegisterAllocation: def __init__(self, minreg, initial_mapping, initial_spill_offset): @@ -7,7 +9,11 @@ #print "RegisterAllocation __init__", initial_mapping self.insns = [] # Output list of instructions - self.freeregs = gprs[minreg:] # Registers with dead values + # Registers with dead values + self.freeregs = {GP_REGISTER:gprs[minreg:], + FP_REGISTER:fprs[:], + CR_FIELD:crfs[:], + CT_REGISTER:[ctr]} self.var2loc = {} # Maps a Var to an AllocationSlot self.loc2var = {} # Maps an AllocationSlot to a Var self.lru = [] # Least-recently-used list of vars; first is oldest. @@ -20,8 +26,8 @@ for var, loc in initial_mapping.iteritems(): self.loc2var[loc] = var self.var2loc[var] = loc - if loc in self.freeregs: - self.freeregs.remove(loc) + if loc.is_register and loc in self.freeregs[loc.regclass]: + self.freeregs[loc.regclass].remove(loc) self.lru.append(var) self.crfinfo = [(0, 0)] * 8 @@ -31,20 +37,28 @@ self.spill_offset -= 4 return self.spill_offset - def _allocate_reg(self, newarg): + def _allocate_reg(self, regclass, newarg): # check if there is a register available - if self.freeregs: - reg = self.freeregs.pop() + freeregs = self.freeregs[regclass] + + if freeregs: + reg = freeregs.pop() self.loc2var[reg] = newarg self.var2loc[newarg] = reg #print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) return reg # if not, find something to spill - argtospill = self.lru.pop(0) - reg = self.var2loc[argtospill] - assert reg.is_register + for i in range(len(self.lru)): + argtospill = self.lru[i] + reg = self.var2loc[argtospill] + assert reg.is_register + if reg.regclass == regclass: + del self.lru[i] + break + else: + assert 0 # Move the value we are spilling onto the stack, both in the # data structures and in the instructions: @@ -85,10 +99,8 @@ # put things into the lru for i in range(len(insn.reg_args)): arg = insn.reg_args[i] - argcls = insn.reg_arg_regclasses[i] - if argcls == GP_REGISTER: - self._promote(arg) - if insn.result and insn.result_regclass == GP_REGISTER: + self._promote(arg) + if insn.result: self._promote(insn.result) #print "LRU list is now: %r" % (self.lru,) @@ -101,28 +113,20 @@ if not self.var2loc[arg].is_register: # It has no register now because it has been spilled - assert argcls == GP_REGISTER, "uh-oh" - self._allocate_reg(arg) + self._allocate_reg(argcls, arg) else: #print "it was in ", self.var2loc[arg] pass # Need to allocate a register for the destination assert not insn.result or insn.result not in self.var2loc - cand = None - if insn.result_regclass == GP_REGISTER: + if insn.result_regclass != NO_REGISTER: #print "Allocating register for result %r..." % (insn.result,) - cand = self._allocate_reg(insn.result) - elif insn.result_regclass == CR_FIELD: - assert crfs[0] not in self.loc2var - assert isinstance(insn, CMPInsn) - cand = crfs[0] - self.crfinfo[0] = insn.info - elif insn.result_regclass == CT_REGISTER: - assert ctr not in self.loc2var - cand = ctr - elif insn.result_regclass != NO_REGISTER: - assert 0 + cand = self._allocate_reg(insn.result_regclass, insn.result) + if isinstance(insn, CMPInsn): + self.crfinfo[cand.number] = insn.info + else: + cand = None if cand is not None and cand not in self.loc2var: self.var2loc[insn.result] = cand self.loc2var[cand] = insn.result From cfbolz at codespeak.net Tue Nov 7 17:01:06 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 7 Nov 2006 17:01:06 +0100 (CET) Subject: [pypy-svn] r34338 - in pypy/branch/resume-point-hack/pypy/rlib: . test Message-ID: <20061107160106.7FBDB1007F@code0.codespeak.net> Author: cfbolz Date: Tue Nov 7 17:01:04 2006 New Revision: 34338 Modified: pypy/branch/resume-point-hack/pypy/rlib/rstack.py pypy/branch/resume-point-hack/pypy/rlib/test/test_rstack.py Log: make it possible to resume into a try... finally block Modified: pypy/branch/resume-point-hack/pypy/rlib/rstack.py ============================================================================== --- pypy/branch/resume-point-hack/pypy/rlib/rstack.py (original) +++ pypy/branch/resume-point-hack/pypy/rlib/rstack.py Tue Nov 7 17:01:04 2006 @@ -109,6 +109,9 @@ hop.r_result) def resume_state_create(prevstate, label, func, *args): + if label == "yield_current_frame_to_caller_1": + assert func is None + XXX return ResumeData(prevstate, label, func, *args) def concretify_argument(hop, index): @@ -265,6 +268,8 @@ self.local_changes = [] self.goto_after = goto_after self.name = name + if isinstance(func, type(self.__init__)): + func = func.im_func self.func = func self.args = args self.decision_stack = None @@ -303,7 +308,7 @@ result = self.func(*dummy_args) except Exception, e: if self.goto_after is not None: - print "caught something, handing it on..." + print "caught %s, handing it on..." % (e, ) return self.goto_after.resume(raising=e) raise finally: @@ -345,7 +350,7 @@ val = HomingBlackhole() newlocals[name] = val if newlocals: -# print "fixing locals", newlocals + print "fixing locals", newlocals frame.f_locals.update(newlocals) if self.fix_globals: self.previous_globals = {} @@ -374,6 +379,9 @@ frame.f_locals.update(dict(changes)) return self.resume_tracer + def switch(self): + return self.resume() + # _________________________________________________________________________ # Functions to analyze bytecode to find a way to reach resume_points @@ -474,7 +482,7 @@ return [(target, "bool", True), (pos + 3, "bool", False)] elif name == "JUMP_FORWARD": return [(target, None, None)] - elif name == "SETUP_LOOP" or name == "SETUP_EXCEPT": + elif name in ("SETUP_LOOP", "SETUP_FINALLY", "SETUP_EXCEPT"): return [(pos + 3, None, None)] #XXX not sure elif name == "FOR_ITER": return [(target, "next", "stop")] Modified: pypy/branch/resume-point-hack/pypy/rlib/test/test_rstack.py ============================================================================== --- pypy/branch/resume-point-hack/pypy/rlib/test/test_rstack.py (original) +++ pypy/branch/resume-point-hack/pypy/rlib/test/test_rstack.py Tue Nov 7 17:01:04 2006 @@ -288,6 +288,28 @@ res = resume_state_invoke(int, s) assert res == 42 +def test_resume_in_finally_block(): + def g(x): + x += 1 + resume_point("rp0", x) + return x + 1 + def f(x): + x = x - 1 + try: + r = g(x) + resume_point("rp1", returns=r) + finally: + r = 42 + r + return r - 1 + def example(): + s1 = resume_state_create(None, "rp1", f) + s0 = resume_state_create(s1, "rp0", g, 0) + v2 = resume_state_invoke(int, s0) + return v2 + res = example() + assert res == 42 + + def test_jump_over_for(): def f(x): result = 0 From mwh at codespeak.net Tue Nov 7 19:17:10 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Nov 2006 19:17:10 +0100 (CET) Subject: [pypy-svn] r34340 - in pypy/dist/pypy/jit/codegen/ppc: . test Message-ID: <20061107181710.4A82710071@code0.codespeak.net> Author: mwh Date: Tue Nov 7 19:17:09 2006 New Revision: 34340 Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/regalloc.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Log: add a test that uses all the int_* comparison functions. implement all of them plus a little support code also support for moving such results from the condition register to a general purpose register. Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Tue Nov 7 19:17:09 2006 @@ -52,6 +52,9 @@ regclass = CR_FIELD def __init__(self, number): self.number = number + def move_to_gpr(self, allocator, gpr): + bit, negated = allocator.crfinfo[self.number] + return _CRF2GPR(gpr, self.number*4 + bit, negated) crfs = map(CRF, range(8)) @@ -213,7 +216,15 @@ BO = 4 # jump if relavent bit is NOT set in the CR asm.bcctr(BO, self.crf.number*4 + self.bit) -class Unspill(Insn): +class AllocTimeInsn(Insn): + def __init__(self): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result_regclass = NO_REGISTER + self.result = None + +class Unspill(AllocTimeInsn): """ A special instruction inserted by our register "allocator." It indicates that we need to load a value from the stack into a register because we spilled a particular value. """ @@ -223,14 +234,14 @@ reg --- the reg we spilled it from (an integer) offset --- the offset on the stack we spilled it to (an integer) """ - Insn.__init__(self) + AllocTimeInsn.__init__(self) self.var = var self.reg = reg self.stack = stack def emit(self, asm): asm.lwz(self.reg.number, rFP, self.stack.offset) -class Spill(Insn): +class Spill(AllocTimeInsn): """ A special instruction inserted by our register "allocator." It indicates that we need to store a value from the register into the stack because we spilled a particular value.""" @@ -240,13 +251,25 @@ reg --- the reg we are spilling it from (an integer) offset --- the offset on the stack we are spilling it to (an integer) """ - Insn.__init__(self) + AllocTimeInsn.__init__(self) self.var = var self.reg = reg self.stack = stack def emit(self, asm): asm.stw(self.reg.number, rFP, self.stack.offset) +class _CRF2GPR(AllocTimeInsn): + def __init__(self, targetreg, bit, negated): + AllocTimeInsn.__init__(self) + self.targetreg = targetreg + self.bit = bit + self.negated = negated + def emit(self, asm): + asm.mfcr(self.targetreg) + asm.extrwi(self.targetreg, self.targetreg, 1, self.bit) + if self.negated: + asm.xori(self.targetreg, self.targetreg, 1) + class Return(Insn): """ Ensures the return value is in r3 """ def __init__(self, var): Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Tue Nov 7 19:17:09 2006 @@ -110,10 +110,20 @@ arg = insn.reg_args[i] argcls = insn.reg_arg_regclasses[i] #print "Allocating register for %r..." % (arg,) + argloc = self.var2loc[arg] - if not self.var2loc[arg].is_register: + if not argloc.is_register: # It has no register now because it has been spilled self._allocate_reg(argcls, arg) + elif argloc.regclass != argcls: + if argcls == GP_REGISTER: + del self.var2loc[arg] + del self.loc2var[argloc] + newloc = self._allocate_reg(GP_REGISTER, arg) + self.insns.append( + argloc.move_to_gpr(self, newloc.number)) + else: + assert 0 else: #print "it was in ", self.var2loc[arg] pass Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Tue Nov 7 19:17:09 2006 @@ -395,21 +395,59 @@ return gv_result def _compare(self, op, gv_x, gv_y): - assert op == 'gt' + cmp2info = { + # bit-in-crf negated + 'gt': ( 1, 0 ), + 'lt': ( 0, 0 ), + 'le': ( 1, 1 ), + 'ge': ( 0, 1 ), + 'eq': ( 2, 0 ), + 'ne': ( 2, 1 ), + } + cmp2info_flipped = { + # bit-in-crf negated + 'gt': ( 1, 1 ), + 'lt': ( 0, 1 ), + 'le': ( 1, 0 ), + 'ge': ( 0, 0 ), + 'eq': ( 2, 0 ), + 'ne': ( 2, 1 ), + } result = self.newvar() if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2*16: gv_x = gv_x.load(self) - self.insns.append(insn.CMPWI((1, 0), result, [gv_x, gv_y])) + self.insns.append( + insn.CMPWI(cmp2info[op], result, + [gv_x, gv_y])) elif isinstance(gv_x, IntConst) and abs(gv_x.value) < 2*16: gv_y = gv_y.load(self) - self.insns.append(insn.CMPWI((1, 1), result, [gv_y, gv_x])) + self.insns.append( + insn.CMPWI(cmp2info_flipped[op], result, + [gv_y, gv_x])) else: - self.insns.append(insn.CMPW((1, 0), result, [gv_x.load(self), gv_y.load(self)])) + self.insns.append( + insn.CMPW(cmp2info[op], result, + [gv_x.load(self), gv_y.load(self)])) return result def op_int_gt(self, gv_x, gv_y): return self._compare('gt', gv_x, gv_y) + def op_int_lt(self, gv_x, gv_y): + return self._compare('lt', gv_x, gv_y) + + def op_int_ge(self, gv_x, gv_y): + return self._compare('ge', gv_x, gv_y) + + def op_int_le(self, gv_x, gv_y): + return self._compare('le', gv_x, gv_y) + + def op_int_eq(self, gv_x, gv_y): + return self._compare('eq', gv_x, gv_y) + + def op_int_ne(self, gv_x, gv_y): + return self._compare('ne', gv_x, gv_y) + def _jump(self, gv_condition, if_true): targetbuilder = self._fork() Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Tue Nov 7 19:17:09 2006 @@ -1,6 +1,8 @@ import py from pypy.jit.codegen.ppc.rgenop import RPPCGenOp -from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTests +from pypy.rpython.lltypesystem import lltype +from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTests, FUNC2 +from ctypes import cast, c_int, c_void_p, CFUNCTYPE class FewRegisters(RPPCGenOp): MINUSERREG = 29 @@ -8,7 +10,50 @@ class TestRPPCGenop(AbstractRGenOpTests): RGenOp = RPPCGenOp -class TestRPPCGenopNoRegs(AbstractRGenOpTests): + def test_multiple_cmps(self): + # return x>y + 10*x=y + 10000*x==y + 100000*x!=y + rgenop = self.RGenOp() + signed_kind = rgenop.kindToken(lltype.Signed) + sigtoken = rgenop.sigToken(FUNC2) + builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) + + args_gv = [gv_x, gv_y] + builder.enter_next_block([signed_kind, signed_kind], args_gv) + [gv_x, gv_y] = args_gv + + gv_gt = builder.genop2("int_gt", gv_x, gv_y) + gv_lt = builder.genop2("int_lt", gv_x, gv_y) + gv_ge = builder.genop2("int_ge", gv_x, gv_y) + gv_le = builder.genop2("int_le", gv_x, gv_y) + gv_eq = builder.genop2("int_eq", gv_x, gv_y) + gv_ne = builder.genop2("int_ne", gv_x, gv_y) + + gv_gt2 = gv_gt + gv_lt2 = builder.genop2("int_mul", rgenop.genconst(10), gv_lt) + gv_ge2 = builder.genop2("int_mul", rgenop.genconst(100), gv_ge) + gv_le2 = builder.genop2("int_mul", rgenop.genconst(1000), gv_le) + gv_eq2 = builder.genop2("int_mul", rgenop.genconst(10000), gv_eq) + gv_ne2 = builder.genop2("int_mul", rgenop.genconst(100000), gv_ne) + + gv_r0 = gv_gt + gv_r1 = builder.genop2("int_add", gv_r0, gv_lt2) + gv_r2 = builder.genop2("int_add", gv_r1, gv_ge2) + gv_r3 = builder.genop2("int_add", gv_r2, gv_le2) + gv_r4 = builder.genop2("int_add", gv_r3, gv_eq2) + gv_r5 = builder.genop2("int_add", gv_r4, gv_ne2) + + builder.finish_and_return(sigtoken, gv_r5) + gv_callable = rgenop.gencallableconst(sigtoken, "multicmp", entrypoint) + fnptr = cast(c_void_p(gv_callable.value), CFUNCTYPE(c_int, c_int)) + res = fnptr(1, 2) + assert res == 101010 + res = fnptr(1, 1) + assert res == 11100 + res = fnptr(2, 1) + assert res == 100101 + + +class TestRPPCGenopNoRegs(TestRPPCGenop): RGenOp = FewRegisters def compile(self, runner, argtypes): From mwh at codespeak.net Tue Nov 7 19:54:08 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Nov 2006 19:54:08 +0100 (CET) Subject: [pypy-svn] r34341 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061107185408.6E14E10078@code0.codespeak.net> Author: mwh Date: Tue Nov 7 19:54:06 2006 New Revision: 34341 Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: do the constant -> var promotion for register operands just before register allocation. makes code in rgenop less tedious. Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Tue Nov 7 19:54:06 2006 @@ -89,8 +89,21 @@ self.lru.append(arg) def allocate_for_insns(self, insns): - # Walk through instructions in forward order + from pypy.jit.codegen.ppc.rgenop import IntConst, Var + + insns2 = [] + for insn in insns: + for i in range(len(insn.reg_args)): + arg = insn.reg_args[i] + if not isinstance(arg, Var): + v = Var() + arg.load(insns2, v) + insn.reg_args[i] = v + insns2.append(insn) + + # Walk through instructions in forward order + for insn in insns2: #print "Processing instruction %r with args %r and result %r:" % (insn, insn.reg_args, insn.result) Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Tue Nov 7 19:54:06 2006 @@ -27,8 +27,6 @@ def __init__(self): self.__magic_index = _var_index[0] _var_index[0] += 1 - def load(self, builder): - return self def __repr__(self): return "" % self.__magic_index @@ -46,12 +44,10 @@ else: return lltype.cast_primitive(T, self.value) - def load(self, builder): - var = builder.newvar() - builder.insns.append( + def load(self, insns, var): + insns.append( insn.Insn_GPR__IMM(RPPCAssembler.load_word, - var, [self])) - return var + var, [self])) def load_now(self, asm, loc): if loc.is_register: @@ -163,7 +159,7 @@ numargs = sigtoken # for now if not we_are_translated() and option.trap: self.asm.trap() - inputargs = [self.newvar() for i in range(numargs)] + inputargs = [Var() for i in range(numargs)] assert self.initial_var2loc is None self.initial_var2loc = {} for arg in inputargs: @@ -230,7 +226,6 @@ return allocator def finish_and_return(self, sigtoken, gv_returnvar): - gv_returnvar = gv_returnvar.load(self) self.insns.append(insn.Return(gv_returnvar)) allocator = self.allocate_and_emit() @@ -345,20 +340,8 @@ self.emit_stack_adjustment() return Label(target_addr, arg_locations, min_stack_offset) - def newvar(self): - gv = Var() - return gv - - def new_and_load_2(self, gv_x, gv_y): - gv_result = self.newvar() - return (gv_result, gv_x.load(self), gv_y.load(self)) - - def new_and_load_1(self, gv_x): - gv_result = self.newvar() - return (gv_result, gv_x.load(self)) - def op_int_mul(self, gv_x, gv_y): - gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y) + gv_result = Var() self.insns.append( insn.Insn_GPR__GPR_GPR(RPPCAssembler.mullw, gv_result, [gv_x, gv_y])) @@ -366,32 +349,32 @@ def op_int_add(self, gv_x, gv_y): if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2**16: - gv_result = self.newvar() + gv_result = Var() self.insns.append( insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, - gv_result, [gv_x.load(self), gv_y])) + gv_result, [gv_x, gv_y])) return gv_result elif isinstance(gv_x, IntConst): return self.op_int_add(gv_y, gv_x) else: - gv_result = self.newvar() + gv_result = Var() self.insns.append( insn.Insn_GPR__GPR_GPR(RPPCAssembler.add, - gv_result, [gv_x.load(self), gv_y.load(self)])) + gv_result, [gv_x, gv_y])) return gv_result def op_int_sub(self, gv_x, gv_y): - gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y) + gv_result = Var() self.insns.append( insn.Insn_GPR__GPR_GPR(RPPCAssembler.sub, gv_result, [gv_x, gv_y])) return gv_result def op_int_floordiv(self, gv_x, gv_y): - gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y) + gv_result = Var() self.insns.append( insn.Insn_GPR__GPR_GPR(RPPCAssembler.divw, - gv_result, [gv_x.load(self), gv_y.load(self)])) + gv_result, [gv_x, gv_y])) return gv_result def _compare(self, op, gv_x, gv_y): @@ -413,22 +396,17 @@ 'eq': ( 2, 0 ), 'ne': ( 2, 1 ), } - result = self.newvar() + gv_result = Var() if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2*16: - gv_x = gv_x.load(self) self.insns.append( - insn.CMPWI(cmp2info[op], result, - [gv_x, gv_y])) + insn.CMPWI(cmp2info[op], gv_result, [gv_x, gv_y])) elif isinstance(gv_x, IntConst) and abs(gv_x.value) < 2*16: - gv_y = gv_y.load(self) self.insns.append( - insn.CMPWI(cmp2info_flipped[op], result, - [gv_y, gv_x])) + insn.CMPWI(cmp2info_flipped[op], gv_result, [gv_y, gv_x])) else: self.insns.append( - insn.CMPW(cmp2info[op], result, - [gv_x.load(self), gv_y.load(self)])) - return result + insn.CMPW(cmp2info[op], gv_result, [gv_x, gv_y])) + return gv_result def op_int_gt(self, gv_x, gv_y): return self._compare('gt', gv_x, gv_y) @@ -451,11 +429,11 @@ def _jump(self, gv_condition, if_true): targetbuilder = self._fork() - gv = self.newvar() + gv = Var() self.insns.append( insn.Insn_GPR__IMM(RPPCAssembler.load_word, gv, [IntConst(targetbuilder.asm.mc.tell())])) - gv2 = self.newvar() + gv2 = Var() self.insns.append( insn.MTCTR(gv2, [gv])) self.insns.append( From arigo at codespeak.net Tue Nov 7 19:54:20 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 19:54:20 +0100 (CET) Subject: [pypy-svn] r34342 - pypy/dist/pypy/doc Message-ID: <20061107185420.A7CE81007D@code0.codespeak.net> Author: arigo Date: Tue Nov 7 19:54:19 2006 New Revision: 34342 Modified: pypy/dist/pypy/doc/stackless.txt Log: Progress on documenting the app-level stackless interface. This contains some paragraphs that really sound like an EU deliverable, which we should probably rephrase after they get copied into the deliverable body. Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Tue Nov 7 19:54:19 2006 @@ -2,9 +2,6 @@ Application-level Stackless features ========================================================== -.. contents:: -.. sectnum:: - Introduction ================ @@ -13,149 +10,275 @@ concurrent style. It actually exposes three different paradigms to choose from: -* Tasklets and channels; +* `Tasklets and channels`_; -* Greenlets; +* Greenlets_; -* Plain coroutines. +* Plain coroutines_. All of them are extremely light-weight, which means that PyPy should be -able to handle programs containing large amounts of -coroutines/tasklet/greenlets. +able to handle programs containing large amounts of coroutines, tasklets +and greenlets. Requirements -================= +++++++++++++++++ If you are running py.py on top of CPython, then you need to enable the _stackless module by running it as follows:: - py.py --usemodules=_stackless + py.py --withmod-_stackless This is implemented internally using greenlets, so it only works on a -platform where greenlets_ are supported. +platform where greenlets_ are supported. A few features do not work in +this way, though, and really require a translated ``pypy-c``. -To translate a version of ``pypy-c`` that includes Stackless support, -run translate.py as follows:: +To obtained a translated version of ``pypy-c`` that includes Stackless +support, run translate.py as follows:: cd pypy/translator/goal python translate.py --stackless -Quick reference -========================== +Application level interface +============================= + +A stackless PyPy contains a module called ``stackless``. The interface +exposed by this module has not been much refined, so it should be +considered in-flux (as of 2006). + +So far, PyPy does not provide support for ``stackless`` in a threaded +environment. This limitation is not fundamental, as previous experience +has shown, so supporting this would probably be reasonably easy. + +An interesting point is that the same ``stackless`` module can provide +three different concurrency paradigms at the same time. From a +theoretical point of view, none of these three paradigms considered +alone is new: two of them are from previous Python work, and the third +one is a quite classical coroutine variant. The new part is that the +PyPy implementation manages to provide all of them and let the user +implement more. Moreover - and this might be an important theoretical +contribution of this work - we manage to provide these concurrency +concepts in a "composable" way. In other words, it is possible to +naturally mix in a single application multiple concurrency paradigms, +and multiple unrelated usages of the same paradigm. This is detailed in +the Composability_ section below. + + +Coroutines +++++++++++ + +A Coroutine is similar to a microthread, with no preemptive scheduling. +Within a family of coroutines, the execution can be explicitly +transferred from one to another by the user. When execution is +transferred to a coroutine, it starts executing some Python code. When +execution is transferred away from it, it is temporarily suspended. +When the execution comes back to it, it resumes its execution from the +point where it was suspend. Conceptually, only one coroutine is +actively running at any given time (but see Composability_ below). + +The ``stackless.coroutine`` class is instantiated with no argument. +It provides the following methods and attributes: + +* ``stackless.coroutine.getcurrent()`` -The new features are exposed in a module called ``stackless``. + Static method returning the currently running coroutine. There is a + so-called "main" coroutine object that represents the "outer" + execution context, where your main program started and where it runs + as long as it does not switch to another coroutine. + +* ``coro.bind(callable, *args, **kwds)`` + + Bind the coroutine so that it will execute ``callable(*args, + **kwds)``. The call is not performed immediately, but only the + first time we call the ``coro.switch()`` method. A coroutine must + be bound before it is switched to. When the coroutine finishes + (because the call to the callable returns), the coroutine exits and + implicitly switches back to another coroutine (its "parent"); after + this point, it is possible to bind it again and switch to it again. + (Which coroutine is the parent of which is not documented, as it is + likely to change when the interface is refined.) + +* ``coro.switch()`` + + Suspend the current (caller) coroutine, and resume execution in the + target coroutine ``coro``. + +* ``coro.kill()`` + + Kill ``coro`` by sending an exception to it. (At the moment, the + exception is not visible to app-level, which means that you cannot + catch it, and that ``try: finally:`` clauses are not honored. This + will be fixed in the future.) Tasklets and channels +++++++++++++++++++++ -The ``stackless`` module provides an interface that is roughly +The ``stackless`` module also provides an interface that is roughly compatible with the interface of the ``stackless`` module in `Stackless Python`_: it contains ``stackless.tasklet`` and ``stackless.channel`` -classes. Tasklets are similar to microthreads, but don't actually run -in parallel with other microthreads; instead, they synchronize and -exchange data with each other over Channels, and these exchanges -determine which Tasklet run next. +classes. Tasklets are similar to microthreads, but (like coroutines) +they don't actually run in parallel with other microthreads; instead, +they synchronize and exchange data with each other over Channels, and +these exchanges determine which Tasklet runs next. For usage reference, see the documentation on the `Stackless Python`_ website. Note that Tasklets and Channels are implemented at application-level in -`pypy/lib/stackless.py`_ on top of coroutines. You can refer to this +`pypy/lib/stackless.py`_ on top of coroutines_. You can refer to this module for more details and the actual documentation. -The current ``stackless`` module (pypy 0.9) is not yet feature complete and -may fail in spectacular ways. Just be warned. - -There is no support for stackless in a threaded environment whatsoever. - The stackless.py code tries to resemble the stackless C code as much as possible. This makes the code somewhat unpythonic. Bird eyes view of tasklets and channels ---------------------------------------- -tasklets are a bit like threads: they capsulate a function in such a way that +Tasklets are a bit like threads: they encapsulate a function in such a way that they can be suspended/restarted any time. Unlike threads, they won't -run concurrently, but must be quite cooperative. When using stackless +run concurrently, but must be cooperative. When using stackless features, it is vitaly important that no action is performed that blocks -everything else. +everything else. In particular, blocking input/output should be centralized +to a single tasklet. Communication between tasklets is done via channels. - There are three ways for a tasklet to give up control: 1. call ``schedule()`` 2. send something over a channel 3. receive something from a channel -A (living) tasklet can be either running, or wait to get scheduled, or be +A (living) tasklet can either be running, or wait to get scheduled, or be blocked by a channel. -Scheduling is done strictly round-robin. A blocked tasklet is removed from -the scheduling queue and a blocked tasklet will be reinserted into the -queue when it becomes unblocked. +Scheduling is done in strictly round-robin manner. A blocked tasklet is +removed from the scheduling queue and a blocked tasklet will be +reinserted into the queue when it becomes unblocked. + Greenlets +++++++++ -Greenlets are primitive Tasklets with a lower-level interface and -with exact control over the execution order. For usage reference, -see the greenlets_ documentation. - - -Coroutines -++++++++++ - -Coroutines are similar to greenlets, with a slightly different -interface. One way to see the difference is to note that greenlets put -more emphasis on a tree structure: the various greenlets of a program -form a precise tree, which controls the order of execution. - -The ``stackless.coroutine`` class is instantiated with no argument. -Such a coroutine object is similar to a microthread. When execution is -transferred to it, it starts to execute some Python code. When -execution is transferred away from it, it is temporarily suspended. -When the execution comes back to it, it resumes its execution from the -point where it was suspend. Only one coroutine is actively running at -any given time. - -The class ``stackless.coroutine`` has the following methods and -attributes: - -* ``stackless.coroutine.getcurrent()`` - - Static method returning the currently running coroutine. There is a - so-called "main" coroutine object that represents the "outer" - execution context, where your main program started and where it runs - as long as it does not switch to another coroutine. - -* ``coro.bind(callable, *args, **kwds)`` - - Bind the coroutine so that it will execute ``callable(*args, - **kwds)``. The call is not performed immediately, but only the - first time we call the ``coro.switch()`` method. A coroutine must - be bound before it is switched to. When the coroutine finishes - (because the call to the callable returns), the coroutine exits and - implicitly switches back to its parent coroutine; after this point, - it is possible to bind it again and switch to it again. - -* ``coro.switch()`` - - Suspend the current (caller) coroutine, and resume execution in the - target coroutine ``coro``. - -* ``coro.kill()`` - - Kill ``coro`` by sending an exception to it. (At the moment, the - exception is not visible to app-level, which means that you cannot - catch it, and that ``try: finally:`` clauses are not honored. This - will be fixed in the future.) +A Greenlet is a kind of primitive Tasklet with a lower-level interface +and with exact control over the execution order. Greenlets are similar +to Coroutines, with a slightly different interface: greenlets put more +emphasis on a tree structure. The various greenlets of a program form a +precise tree, which fully determines their order of execution. + +For usage reference, see the greenlet_ documentation in the Py lib. The +PyPy interface is identical, except that the `greenlet` class is in the +``stackless`` module instead of in the ``py.magic`` module. + + +Coroutine Pickling +++++++++++++++++++ + +Coroutines and tasklets can be pickled and unpickled, i.e. serialized to +a string of bytes for the purpose of storage or transmission. This +allows "live" coroutines or tasklets to be made persistent, moved to +other machines, or cloned in any way. The standard ``pickle`` module +works with coroutines and tasklets (at least in a translated ``pypy-c``; +unpickling live coroutines or tasklets cannot be easily implemented on +top of CPython). + +To be able to achieve this result, we have to consider many objects that +are not normally picklable in CPython. Here again, the `Stackless +Python`_ implementation has paved the way, and we follow the same +general design decisions: simple internal objects like bound method +objects and various kind of iterators are supported; frame objects can +be fully pickled and unpickled (by serializing the bytecode they are +running in addition to all the local variables). References to globals +and modules are pickled by name, like references to functions and +classes in the traditional CPython ``pickle``. + +The "magic" part of this process is the implementation of the unpickling +of a chain of frames. The Python interpreter of PyPy uses +interpreter-level recursion to represent application-level calls. The +reason for this is that it tremendously simplifies the implementation of +the interpreter itself. Indeed, in Python, almost any operation can +potentially result in a non-tail-recursive call to another Python +function. This makes writing an non-recursive interpreter extremely +tedious. For this reason, the interpreter is recursive, and we rely on +lower-level transformations during the translation process to control +this recursion - the `Stackless Transform`_. + +At any point in time, a chain of Python-level frames corresponds to a +chain of interpreter-level frames (e.g. C frames in pypy-c), where each +single Python-level frame corresponds to one or a few interpreter-level +frames - depending on the length of the interpreter-level call chain +from one bytecode evaluation loop to the next recursively invoked one. + +This means that it is not sufficient to simply create a chain of Python +frame objects in the heap of a process before we can resume execution of +these newly built frames. We must recreate a corresponding chain of +interpreter-level frames. To this end, we have inserted a few *named +resume points* (see XXX) in the Python interpreter of PyPy. This is the +motivation for implementing the interpreter-level primitives +``resume_state_create()`` and ``resume_state_invoke()``, a powerful +interface that allows an RPython program to artifically rebuild a chain +of calls in a reflective way, completely from scratch, and jump to it. + + +Coroutine Cloning ++++++++++++++++++ + +In theory, coroutine pickling is general enough to allow coroutines to +be *cloned* in-process; i.e. from one suspended coroutine, a copy can be +made (by pickling and immediately unpickling it). Both the original and +the copy can then continue execution from the same point on. Cloning +gives much of the expressive power of full *continuations*. + +However, pickling has many problems in practice. It is not a completely +general solution because not all kinds of objects can be pickled; +moreover, which objects are pickled by value or by reference only +depends on the type of the object. For the purpose of cloning, this +means that coroutines cannot be pickled/unpickled in all situations, and +even when they can, the user does not have full control over which of +the objects currently reachable from a coroutine will be duplicated, and +which will be shared with the original coroutine. + +For this reason, we implemented a direct cloning operation. After some +experiments, we determined that the following behavior is usually +considered correct: when cloning a coroutine C, we duplicate exactly +those objects that were created by C (i.e. while C was running). The +objects not created by C (e.g. pre-existing, or created outside) are not +duplicated, but directly shared between C and its new copy. This +heuristic generally matches the intuition that the objects created by C +are also often the ones "owned" by C, in the sense that if C is cloned, +the clone needs its own copy to avoid mutating the same shared objects +in conflicit ways. Conversely, objects of a more "global" nature, like +modules and functions, which are typically created before the coroutine +C started, should not be duplicated; this would result in unexpectedly +invisible side-effects if they are mutated by the clone of C. + +The implementation of the above heuristic is based on support from the +garbage collector. For this reason, it is only available if both +stackless and our own framework GC are compiled together in pypy-c (use +``translate.py --stackless --framework=gc``). In this mode, our garbage +collector is extended to support the notion of "pool": a pool is a +linked list of allocated objects. All objects allocated go to a +"current" pool. When the stackless module switches execution between +two ClonableCoroutine objects, it switches the GC's current pool as +well, so that the allocated objects end up segregated by coroutine. +Cloning is implemented by another GC extension which makes byte-level +copies of allocated by following all references. References that point +to objects inside the current pool cause the objects to be recursively +copied; other references are simply shared. + + +Composability ++++++++++++++ + +XXX, without having to complicate each part of the +application with explicit knowledge about the other part's usage of +concurrency. Many traditional concurrency concepts cannot be composed +in this way. XXX .. _`Stackless Python`: http://www.stackless.com -.. _greenlets: http://codespeak.net/py/current/doc/greenlet.html +.. _greenlet: http://codespeak.net/py/current/doc/greenlet.html +.. _`Stackless Transform`: translation.html#the-stackless-transform .. include:: _ref.txt From mwh at codespeak.net Tue Nov 7 20:01:37 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Nov 2006 20:01:37 +0100 (CET) Subject: [pypy-svn] r34343 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061107190137.AE6101007B@code0.codespeak.net> Author: mwh Date: Tue Nov 7 20:01:35 2006 New Revision: 34343 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: factor the "fits in an immediate" calculation into a couple of methods. Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Tue Nov 7 20:01:35 2006 @@ -29,6 +29,8 @@ _var_index[0] += 1 def __repr__(self): return "" % self.__magic_index + def fits_in_immediate(self): + return False class IntConst(GenConst): @@ -56,6 +58,9 @@ asm.load_word(rSCRATCH, self.value) asm.stw(rSCRATCH, rFP, loc.offset) + def fits_in_immediate(self): + return abs(self.value) < 2**16 + class JumpPatchupGenerator(object): def __init__(self, asm, min_offset): @@ -348,20 +353,20 @@ return gv_result def op_int_add(self, gv_x, gv_y): - if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2**16: - gv_result = Var() + gv_result = Var() + if gv_y.fits_in_immediate(): self.insns.append( insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, gv_result, [gv_x, gv_y])) - return gv_result - elif isinstance(gv_x, IntConst): - return self.op_int_add(gv_y, gv_x) + elif gv_x.fits_in_immediate(): + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_result, [gv_y, gv_x])) else: - gv_result = Var() self.insns.append( insn.Insn_GPR__GPR_GPR(RPPCAssembler.add, gv_result, [gv_x, gv_y])) - return gv_result + return gv_result def op_int_sub(self, gv_x, gv_y): gv_result = Var() @@ -397,10 +402,10 @@ 'ne': ( 2, 1 ), } gv_result = Var() - if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2*16: + if gv_y.fits_in_immediate(): self.insns.append( insn.CMPWI(cmp2info[op], gv_result, [gv_x, gv_y])) - elif isinstance(gv_x, IntConst) and abs(gv_x.value) < 2*16: + elif gv_x.fits_in_immediate(): self.insns.append( insn.CMPWI(cmp2info_flipped[op], gv_result, [gv_y, gv_x])) else: From arigo at codespeak.net Tue Nov 7 20:09:23 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 20:09:23 +0100 (CET) Subject: [pypy-svn] r34344 - pypy/dist/pypy/doc Message-ID: <20061107190923.D182010071@code0.codespeak.net> Author: arigo Date: Tue Nov 7 20:09:22 2006 New Revision: 34344 Modified: pypy/dist/pypy/doc/stackless.txt Log: Typos. Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Tue Nov 7 20:09:22 2006 @@ -30,8 +30,9 @@ py.py --withmod-_stackless This is implemented internally using greenlets, so it only works on a -platform where greenlets_ are supported. A few features do not work in -this way, though, and really require a translated ``pypy-c``. +platform where the `Py lib greenlets`_ are supported. A few features do +not work in this way, though, and really require a translated +``pypy-c``. To obtained a translated version of ``pypy-c`` that includes Stackless support, run translate.py as follows:: @@ -167,9 +168,9 @@ emphasis on a tree structure. The various greenlets of a program form a precise tree, which fully determines their order of execution. -For usage reference, see the greenlet_ documentation in the Py lib. The -PyPy interface is identical, except that the `greenlet` class is in the -``stackless`` module instead of in the ``py.magic`` module. +For usage reference, see the documentation of the `Py lib greenlets`_. +The PyPy interface is identical, except that the ``greenlet`` class is +in the ``stackless`` module instead of in the ``py.magic`` module. Coroutine Pickling @@ -190,8 +191,8 @@ objects and various kind of iterators are supported; frame objects can be fully pickled and unpickled (by serializing the bytecode they are running in addition to all the local variables). References to globals -and modules are pickled by name, like references to functions and -classes in the traditional CPython ``pickle``. +and modules are pickled by name, similarly to references to functions +and classes in the traditional CPython ``pickle``. The "magic" part of this process is the implementation of the unpickling of a chain of frames. The Python interpreter of PyPy uses @@ -199,16 +200,17 @@ reason for this is that it tremendously simplifies the implementation of the interpreter itself. Indeed, in Python, almost any operation can potentially result in a non-tail-recursive call to another Python -function. This makes writing an non-recursive interpreter extremely -tedious. For this reason, the interpreter is recursive, and we rely on -lower-level transformations during the translation process to control -this recursion - the `Stackless Transform`_. +function. This makes writing a non-recursive interpreter extremely +tedious; instead, we rely on lower-level transformations during the +translation process to control this recursion. This is the `Stackless +Transform`_, which is at the heart of PyPy's support for stackless-style +concurrency. At any point in time, a chain of Python-level frames corresponds to a chain of interpreter-level frames (e.g. C frames in pypy-c), where each single Python-level frame corresponds to one or a few interpreter-level frames - depending on the length of the interpreter-level call chain -from one bytecode evaluation loop to the next recursively invoked one. +from one bytecode evaluation loop to the next (recursively invoked) one. This means that it is not sufficient to simply create a chain of Python frame objects in the heap of a process before we can resume execution of @@ -216,7 +218,7 @@ interpreter-level frames. To this end, we have inserted a few *named resume points* (see XXX) in the Python interpreter of PyPy. This is the motivation for implementing the interpreter-level primitives -``resume_state_create()`` and ``resume_state_invoke()``, a powerful +``resume_state_create()`` and ``resume_state_invoke()``, the powerful interface that allows an RPython program to artifically rebuild a chain of calls in a reflective way, completely from scratch, and jump to it. @@ -225,19 +227,21 @@ +++++++++++++++++ In theory, coroutine pickling is general enough to allow coroutines to -be *cloned* in-process; i.e. from one suspended coroutine, a copy can be -made (by pickling and immediately unpickling it). Both the original and -the copy can then continue execution from the same point on. Cloning -gives much of the expressive power of full *continuations*. - -However, pickling has many problems in practice. It is not a completely -general solution because not all kinds of objects can be pickled; -moreover, which objects are pickled by value or by reference only -depends on the type of the object. For the purpose of cloning, this -means that coroutines cannot be pickled/unpickled in all situations, and -even when they can, the user does not have full control over which of -the objects currently reachable from a coroutine will be duplicated, and -which will be shared with the original coroutine. +be *cloned* within a process; i.e. from one suspended coroutine, a copy +can be made - simply by pickling and immediately unpickling it. Both +the original and the copy can then continue execution from the same +point on. Cloning gives much of the expressive power of full +*continuations*. + +However, pickling has several problems in practice (besides a relatively +high overhead). It is not a completely general solution because not all +kinds of objects can be pickled; moreover, which objects are pickled by +value or by reference only depends on the type of the object. For the +purpose of cloning, this means that coroutines cannot be +pickled/unpickled in all situations, and even when they can, the user +does not have full control over which of the objects currently reachable +from a coroutine will be duplicated, and which will be shared with the +original coroutine. For this reason, we implemented a direct cloning operation. After some experiments, we determined that the following behavior is usually @@ -246,26 +250,29 @@ objects not created by C (e.g. pre-existing, or created outside) are not duplicated, but directly shared between C and its new copy. This heuristic generally matches the intuition that the objects created by C -are also often the ones "owned" by C, in the sense that if C is cloned, -the clone needs its own copy to avoid mutating the same shared objects -in conflicit ways. Conversely, objects of a more "global" nature, like +are also the ones "owned" by C, in the sense that if C is cloned, +the clone needs its own copy - to avoid mutating the same shared object +in confliciting ways. Conversely, objects of a more "global" nature, like modules and functions, which are typically created before the coroutine C started, should not be duplicated; this would result in unexpectedly invisible side-effects if they are mutated by the clone of C. The implementation of the above heuristic is based on support from the garbage collector. For this reason, it is only available if both -stackless and our own framework GC are compiled together in pypy-c (use -``translate.py --stackless --framework=gc``). In this mode, our garbage -collector is extended to support the notion of "pool": a pool is a -linked list of allocated objects. All objects allocated go to a -"current" pool. When the stackless module switches execution between -two ClonableCoroutine objects, it switches the GC's current pool as -well, so that the allocated objects end up segregated by coroutine. -Cloning is implemented by another GC extension which makes byte-level -copies of allocated by following all references. References that point -to objects inside the current pool cause the objects to be recursively -copied; other references are simply shared. +stackless and our own framework GC are compiled together in pypy-c:: + + cd pypy/translator/goal + python translate.py --stackless --framework=gc + +In this mode, our garbage collector is extended to support the notion of +"pool": a pool is a linked list of allocated objects. All objects +allocated go to a "current" pool. When the stackless module switches +execution between two ClonableCoroutine objects, it switches the GC's +current pool as well, so that the allocated objects end up segregated by +coroutine. Cloning is implemented by another GC extension which makes +byte-level copies of allocated objects. Pointers to objects inside the +current pool cause the target objects to be recursively copied; pointers +outside the current pool are simply shared. Composability @@ -278,7 +285,7 @@ .. _`Stackless Python`: http://www.stackless.com -.. _greenlet: http://codespeak.net/py/current/doc/greenlet.html +.. _`Py lib greenlets`: http://codespeak.net/py/current/doc/greenlet.html .. _`Stackless Transform`: translation.html#the-stackless-transform .. include:: _ref.txt From mwh at codespeak.net Tue Nov 7 20:17:56 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Nov 2006 20:17:56 +0100 (CET) Subject: [pypy-svn] r34345 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061107191756.E0BCB10071@code0.codespeak.net> Author: mwh Date: Tue Nov 7 20:17:53 2006 New Revision: 34345 Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/regalloc.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: more doing more in the register allocator to enable more doing less in rgenop. Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Tue Nov 7 20:17:53 2006 @@ -60,7 +60,8 @@ class CTR(Register): regclass = CT_REGISTER - pass + def move_from_gpr(self, allocator, gpr): + return _GPR2CTR(gpr) ctr = CTR() @@ -270,6 +271,13 @@ if self.negated: asm.xori(self.targetreg, self.targetreg, 1) +class _GPR2CTR(AllocTimeInsn): + def __init__(self, fromreg): + AllocTimeInsn.__init__(self) + self.fromreg = fromreg + def emit(self, asm): + asm.mtctr(self.fromreg) + class Return(Insn): """ Ensures the return value is in r3 """ def __init__(self, var): Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Tue Nov 7 20:17:53 2006 @@ -1,7 +1,8 @@ from pypy.jit.codegen.ppc.instruction import \ gprs, fprs, crfs, ctr, \ NO_REGISTER, GP_REGISTER, FP_REGISTER, CR_FIELD, CT_REGISTER, \ - CMPInsn, Spill, Unspill, stack_slot + CMPInsn, Spill, Unspill, stack_slot, \ + rSCRATCH class RegisterAllocation: def __init__(self, minreg, initial_mapping, initial_spill_offset): @@ -129,14 +130,21 @@ # It has no register now because it has been spilled self._allocate_reg(argcls, arg) elif argloc.regclass != argcls: - if argcls == GP_REGISTER: - del self.var2loc[arg] - del self.loc2var[argloc] - newloc = self._allocate_reg(GP_REGISTER, arg) + del self.var2loc[arg] + del self.loc2var[argloc] + if argloc.regclass != GP_REGISTER: + if argcls == GP_REGISTER: + gpr = self._allocate_reg(GP_REGISTER, arg).number + else: + gpr = rSCRATCH self.insns.append( - argloc.move_to_gpr(self, newloc.number)) + argloc.move_to_gpr(self, gpr)) else: - assert 0 + gpr = argloc.number + if argcls != GP_REGISTER: + newargloc = self._allocate_reg(argcls, arg) + self.insns.append( + newargloc.move_from_gpr(self, gpr)) else: #print "it was in ", self.var2loc[arg] pass Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Tue Nov 7 20:17:53 2006 @@ -434,15 +434,10 @@ def _jump(self, gv_condition, if_true): targetbuilder = self._fork() - gv = Var() - self.insns.append( - insn.Insn_GPR__IMM(RPPCAssembler.load_word, - gv, [IntConst(targetbuilder.asm.mc.tell())])) - gv2 = Var() - self.insns.append( - insn.MTCTR(gv2, [gv])) + targetaddr = targetbuilder.asm.mc.tell() + self.insns.append( - insn.Jump(gv_condition, gv2, if_true)) + insn.Jump(gv_condition, self.rgenop.genconst(targetaddr), if_true)) allocator = self.allocate_and_emit() self.make_fresh_from_jump(allocator.var2loc) From mwh at codespeak.net Tue Nov 7 20:22:38 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Nov 2006 20:22:38 +0100 (CET) Subject: [pypy-svn] r34346 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061107192238.4E10710071@code0.codespeak.net> Author: mwh Date: Tue Nov 7 20:22:37 2006 New Revision: 34346 Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py Log: these asserts seem like a good idea for now. Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Tue Nov 7 20:22:37 2006 @@ -180,20 +180,20 @@ def emit(self, asm): asm.cmpwi(self.result_reg.number, self.arg_reg.number, self.imm.value) -class MTCTR(Insn): - def __init__(self, result, args): - Insn.__init__(self) - self.result = result - self.result_regclass = CT_REGISTER +## class MTCTR(Insn): +## def __init__(self, result, args): +## Insn.__init__(self) +## self.result = result +## self.result_regclass = CT_REGISTER - self.reg_args = args - self.reg_arg_regclasses = [GP_REGISTER] +## self.reg_args = args +## self.reg_arg_regclasses = [GP_REGISTER] - def allocate(self, allocator): - self.arg_reg = allocator.var2loc[self.reg_args[0]] +## def allocate(self, allocator): +## self.arg_reg = allocator.var2loc[self.reg_args[0]] - def emit(self, asm): - asm.mtctr(self.arg_reg.number) +## def emit(self, asm): +## asm.mtctr(self.arg_reg.number) class Jump(Insn): def __init__(self, gv_cond, gv_target, jump_if_true): @@ -237,6 +237,7 @@ """ AllocTimeInsn.__init__(self) self.var = var + assert isinstance(reg, GPR) self.reg = reg self.stack = stack def emit(self, asm): @@ -254,6 +255,7 @@ """ AllocTimeInsn.__init__(self) self.var = var + assert isinstance(reg, GPR) self.reg = reg self.stack = stack def emit(self, asm): From mwh at codespeak.net Tue Nov 7 20:36:45 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 7 Nov 2006 20:36:45 +0100 (CET) Subject: [pypy-svn] r34347 - in pypy/dist/pypy/jit/codegen/ppc: . test Message-ID: <20061107193645.3B5461007B@code0.codespeak.net> Author: mwh Date: Tue Nov 7 20:36:42 2006 New Revision: 34347 Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Log: reorganize the way we list the registers we consider for allocation. Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Tue Nov 7 20:36:42 2006 @@ -5,16 +5,15 @@ rSCRATCH class RegisterAllocation: - def __init__(self, minreg, initial_mapping, initial_spill_offset): + def __init__(self, freeregs, initial_mapping, initial_spill_offset): #print #print "RegisterAllocation __init__", initial_mapping self.insns = [] # Output list of instructions # Registers with dead values - self.freeregs = {GP_REGISTER:gprs[minreg:], - FP_REGISTER:fprs[:], - CR_FIELD:crfs[:], - CT_REGISTER:[ctr]} + self.freeregs = {} + for regcls in freeregs: + self.freeregs[regcls] = freeregs[regcls][:] self.var2loc = {} # Maps a Var to an AllocationSlot self.loc2var = {} # Maps an AllocationSlot to a Var self.lru = [] # Least-recently-used list of vars; first is oldest. Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Tue Nov 7 20:36:42 2006 @@ -222,7 +222,7 @@ def allocate_and_emit(self): assert self.initial_var2loc is not None allocator = RegisterAllocation( - self.rgenop.MINUSERREG, self.initial_var2loc, self.initial_spill_offset) + self.rgenop.freeregs, self.initial_var2loc, self.initial_spill_offset) self.insns = allocator.allocate_for_insns(self.insns) if self.insns: self.patch_stack_adjustment(self._stack_size(0, allocator.spill_offset)) @@ -318,7 +318,7 @@ else: usedregs[loc] = None # XXX use this - unusedregs = [loc for loc in gprs[self.rgenop.MINUSERREG:] if loc not in usedregs] + unusedregs = [loc for loc in self.rgenop.freeregs[insn.GP_REGISTER] if loc not in usedregs] arg_locations = [] for i in range(len(args_gv)): @@ -457,9 +457,13 @@ class RPPCGenOp(AbstractRGenOp): - # minimum register we will use for register allocation + # the set of registers we consider available for allocation # we can artifically restrict it for testing purposes - MINUSERREG = 3 + freeregs = { + insn.GP_REGISTER:insn.gprs[3:], + insn.FP_REGISTER:insn.fprs, + insn.CR_FIELD:insn.crfs, + insn.CT_REGISTER:[insn.ctr]} def __init__(self): self.mcs = [] # machine code blocks where no-one is currently writing Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Tue Nov 7 20:36:42 2006 @@ -3,9 +3,14 @@ from pypy.rpython.lltypesystem import lltype from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTests, FUNC2 from ctypes import cast, c_int, c_void_p, CFUNCTYPE +from pypy.jit.codegen.ppc import instruction as insn class FewRegisters(RPPCGenOp): - MINUSERREG = 29 + freeregs = { + insn.GP_REGISTER:insn.gprs[29:], + insn.FP_REGISTER:insn.fprs, + insn.CR_FIELD:insn.crfs, + insn.CT_REGISTER:[insn.ctr]} class TestRPPCGenop(AbstractRGenOpTests): RGenOp = RPPCGenOp From arigo at codespeak.net Tue Nov 7 20:44:26 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 7 Nov 2006 20:44:26 +0100 (CET) Subject: [pypy-svn] r34348 - pypy/dist/pypy/doc Message-ID: <20061107194426.2C6CA1007B@code0.codespeak.net> Author: arigo Date: Tue Nov 7 20:44:25 2006 New Revision: 34348 Modified: pypy/dist/pypy/doc/_ref.txt pypy/dist/pypy/doc/stackless.txt Log: Start talking about composability. Modified: pypy/dist/pypy/doc/_ref.txt ============================================================================== --- pypy/dist/pypy/doc/_ref.txt (original) +++ pypy/dist/pypy/doc/_ref.txt Tue Nov 7 20:44:25 2006 @@ -36,6 +36,7 @@ .. _`module/_sre/`: .. _`pypy/module/_sre`: ../../pypy/module/_sre .. _`pypy/module/_sre/interp_sre.py`: ../../pypy/module/_sre/interp_sre.py +.. _`pypy/module/_stackless/test/test_composable_coroutine.py`: ../../pypy/module/_stackless/test/test_composable_coroutine.py .. _`pypy/module/readline`: ../../pypy/module/readline .. _`module/recparser/`: ../../pypy/module/recparser .. _`module/sys/`: ../../pypy/module/sys Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Tue Nov 7 20:44:25 2006 @@ -278,10 +278,141 @@ Composability +++++++++++++ -XXX, without having to complicate each part of the -application with explicit knowledge about the other part's usage of -concurrency. Many traditional concurrency concepts cannot be composed -in this way. XXX +Although coroutines exist since a long time, they have not been +generally integrated into mainstream languages, or only in limited form +(like generators in Python and iterators C#). We can argue that a +possible reason for that is that they do not scale well when a program's +complexity increases: they look attractive in small examples, but the +models that require explicit switching, by naming the target coroutine, +do not compose naturally. This means that a program that uses +coroutines for two unrelated purposes may run into conflits caused by +unexpected interactions. + +To illustrate the problem, consider the following example (simplified +code; see the full source in +`pypy/module/_stackless/test/test_composable_coroutine.py`_). First, a +simple usage of coroutine:: + + main_coro = coroutine.getcurrent() # the main (outer) coroutine + data = [] + + def data_producer(): + for i in range(10): + # add some numbers to the list 'data' ... + data.append(i) + data.append(i * 5) + data.append(i * 25) + # and then switch back to main to continue processing + main_coro.switch() + + producer_coro = coroutine() + producer_coro.bind(data_producer) + + def grab_next_value(): + if not data: + # put some more numbers in the 'data' list if needed + producer_coro.switch() + # then grab the next value from the list + return data.pop(0) + +Every call to grab_next_value() returns a single value, but if necessary +it switches into the producer function (and back) to give it a chance to +put some more numbers in it. + +Now consider a simple reimplementation of Python's generators in term of +coroutines:: + + def generator(f): + """Wrap a function 'f' so that it behaves like a generator.""" + def wrappedfunc(*args, **kwds): + g = generator_iterator() + g.bind(f, *args, **kwds) + return g + return wrappedfunc + + class generator_iterator(coroutine): + def __iter__(self): + return self + def next(self): + self.caller = coroutine.getcurrent() + self.switch() + return self.answer + + def Yield(value): + """Yield the value from the current generator.""" + g = coroutine.getcurrent() + g.answer = value + g.caller.switch() + + def squares(n): + """Demo generator, producing square numbers.""" + for i in range(n): + Yield(i * i) + squares = generator(squares) + + for x in squares(5): + print x # this prints 0, 1, 4, 9, 16 + +Both these examples are attractively elegant. However, they cannot be +composed. If we try to write the following generator:: + + def grab_values(n): + for i in range(n): + Yield(grab_next_value()) + grab_values = generator(grab_values) + +then the program does not behave as expected. The reason is the +following. The generator coroutine that executes ``grab_values()`` +calls ``grab_next_value()``, which may switch to the ``producer_coro`` +coroutine. This works so far, but the switching back from +``data_producer()`` to ``main_coro`` lands in the wrong coroutine: it +resumes execution in the main coroutine, which is not the one from which +it comes. We expect ``data_producer()`` to switch back to the +``grab_next_values()`` call, but the latter lives in the generator +coroutine ``g`` created in ``wrappedfunc``, which is totally unknown to +the ``data_producer()`` code. Instead, we really switch back to the +main coroutine, which confuses the ``generator_iterator.next()`` method +(it gets resumed, but not as a result of a call to ``Yield()``). + +As part of trying to combine multiple different paradigms into a single +application-level module, we have built a way to solve this problem. +The idea is to avoid the notion of a single, global "main" coroutine (or +a single main greenlet, or a single main tasklet). Instead, each +conceptually separated user of one of these concurrency interfaces can +create its own "view" on what the main coroutine/greenlet/tasklet is, +which other coroutine/greenlet/tasklets there are, and which of these is +the currently running one. Each "view" is orthogonal to the others. In +particular, each view has one (and exactly one) "current" +coroutine/greenlet/tasklet at any point in time. When the user switches +to a coroutine/greenlet/tasklet, it implicitly means that he wants to +switch away from the current coroutine/greenlet/tasklet *that belongs to +the same view as the target*. + +The precise application-level interface has not been fixed yet; so far, +"views" in the above sense are objects of the type +``stackless.usercostate``. The above two examples can be rewritten in +the following way:: + + producer_view = stackless.usercostate() # a local view + main_coro = producer_view.getcurrent() # the main (outer) coroutine + ... + producer_coro = producer_view.newcoroutine() + ... + +and:: + + generators_view = stackless.usercostate() + + def generator(f): + def wrappedfunc(*args, **kwds): + g = generators_view.newcoroutine(generator_iterator) + ... + + ...generators_view.getcurrent()... + +Then the composition ``grab_values()`` works as expected. + +XXX a few words about how .. _`Stackless Python`: http://www.stackless.com From niko at codespeak.net Tue Nov 7 22:24:22 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Tue, 7 Nov 2006 22:24:22 +0100 (CET) Subject: [pypy-svn] r34349 - in pypy/dist/pypy/translator: cli jvm oosupport Message-ID: <20061107212422.242B410075@code0.codespeak.net> Author: niko Date: Tue Nov 7 22:24:19 2006 New Revision: 34349 Added: pypy/dist/pypy/translator/cli/constant.py Removed: pypy/dist/pypy/translator/cli/constgenerator.py Modified: pypy/dist/pypy/translator/cli/class_.py pypy/dist/pypy/translator/cli/database.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/gencli.py pypy/dist/pypy/translator/cli/ilgenerator.py pypy/dist/pypy/translator/jvm/constant.py pypy/dist/pypy/translator/jvm/database.py pypy/dist/pypy/translator/jvm/genjvm.py pypy/dist/pypy/translator/oosupport/constant.py pypy/dist/pypy/translator/oosupport/database.py pypy/dist/pypy/translator/oosupport/function.py pypy/dist/pypy/translator/oosupport/genoo.py Log: Next iteration of unified JVM/CLI constant support. In this version, the CLI code uses the same constant code as JVM, but the CLI has its own version of the methods which generate bytecode. Final iteration is to remove those methods by implementing them generically in oosupport and implementing the required methods in the "metavm" generator interface. Towards that end, this check-in also includes a "CLIBaseGenerator" class that includes most of the metavm generator implementation, but not those parts that are specific to a particular function (like loading a variable). All tests continue to pass in CLI and JS on my machine. Modified: pypy/dist/pypy/translator/cli/class_.py ============================================================================== --- pypy/dist/pypy/translator/cli/class_.py (original) +++ pypy/dist/pypy/translator/cli/class_.py Tue Nov 7 22:24:19 2006 @@ -1,6 +1,8 @@ from pypy.rpython.ootypesystem import ootype from pypy.translator.cli.node import Node from pypy.translator.cli.cts import CTS +from pypy.translator.oosupport.constant import push_constant +from pypy.translator.cli.ilgenerator import CLIBaseGenerator try: set @@ -73,6 +75,8 @@ return self.ilasm = ilasm + + gen = CLIBaseGenerator(self.db, ilasm) if self.namespace: ilasm.begin_namespace(self.namespace) @@ -109,8 +113,7 @@ if isinstance(METH.RESULT, ootype.OOType): ilasm.opcode('ldnull') else: - from pypy.translator.cli.database import AbstractConst - AbstractConst.load(self.db, METH.RESULT, 0, ilasm) + push_constant(self.db, METH.RESULT, 0, gen) ilasm.opcode('ret') ilasm.end_function() @@ -120,7 +123,6 @@ ilasm.end_namespace() def _ctor(self): - from pypy.translator.cli.database import AbstractConst self.ilasm.begin_function('.ctor', [], 'void', False, 'specialname', 'rtspecialname', 'instance') self.ilasm.opcode('ldarg.0') self.ilasm.call('instance void %s::.ctor()' % self.get_base_class()) @@ -130,7 +132,7 @@ f_name = self.cts.escape_name(f_name) if cts_type != 'void': self.ilasm.opcode('ldarg.0') - AbstractConst.load(self.db, F_TYPE, f_default, self.ilasm) + push_constant(self.db, F_TYPE, f_default, self) class_name = self.db.class_name(self.INSTANCE) self.ilasm.set_field((cts_type, class_name, f_name)) Added: pypy/dist/pypy/translator/cli/constant.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/cli/constant.py Tue Nov 7 22:24:19 2006 @@ -0,0 +1,616 @@ +""" +___________________________________________________________________________ +CLI Constants + +This module extends the oosupport/constant.py to be specific to the +CLI. + +Currently, it is not terribly well integrated with the constant +framework. In particular, each kind of constant overloads the +create_pointer() and initialize_data() methods with some CLI-specific +stuff, rather than implementing the more general generator interface. +This allowed me to cut and paste from the old CLI code, but should +eventually be changed. I have included some commented routines +showing how the code should eventually look. + +The CLI implementation is broken into three sections: + +* Constant Generators: different generators implementing different + techniques for loading constants (Static fields, singleton fields, etc) + +* Mixins: mixins are used to add a few CLI-specific methods to each + constant class. Basically, any time I wanted to extend a base class + (such as AbstractConst or DictConst), I created a mixin, and then + mixed it in to each sub-class of that base-class. + +* Subclasses: here are the CLI specific classes. Eventually, these + probably wouldn't need to exist at all (the JVM doesn't have any, + for example), or could simply have empty bodies and exist to + combine a mixin and the generic base class. For now, though, they + contain the create_pointer() and initialize_data() routines. +""" + +from pypy.translator.oosupport.constant import \ + push_constant, WeakRefConst, StaticMethodConst, CustomDictConst, \ + ListConst, ClassConst, InstanceConst, RecordConst, DictConst, \ + BaseConstantGenerator +from pypy.translator.cli.support import string_literal +from pypy.rpython.ootypesystem import ootype +from pypy.rlib.objectmodel import CDefinedIntSymbolic +from pypy.translator.cli.comparer import EqualityComparer +from pypy.rpython.lltypesystem import lltype +from pypy.translator.cli.cts import PYPY_DICT_OF_VOID, WEAKREF + +CONST_NAMESPACE = 'pypy.runtime' +CONST_CLASSNAME = 'Constants' +CONST_CLASS = '%s.%s' % (CONST_NAMESPACE, CONST_CLASSNAME) + +DEBUG_CONST_INIT = False +DEBUG_CONST_INIT_VERBOSE = False +MAX_CONST_PER_STEP = 100 +SERIALIZE = False + +DEFINED_INT_SYMBOLICS = {'MALLOC_ZERO_FILLED':1} + +def isnan(v): + return v != v*1.0 or (v == 1.0 and v == 2.0) + +def isinf(v): + return v!=0 and (v == v*2) + +# ______________________________________________________________________ +# MetaVM Generator interface + +class CLIGeneratorForConstants(object): + + ''' Very minimal "implementation" of oosupport.metavm.Generator + interface. Just what is actually used. ''' + + def __init__(self, ilasm): + self.ilasm = ilasm + + def add_section(self, text): + return + + def add_comment(self, text): + return + + def pop(self, OOTYPE): + self.ilasm.pop() + +# ______________________________________________________________________ +# Constant Generators +# +# Different generators implementing different techniques for loading +# constants (Static fields, singleton fields, etc) + +class CLIBaseConstGenerator(BaseConstantGenerator): + """ + Base of all CLI constant generators. It implements the oosupport + constant generator in terms of the CLI interface. + """ + + def __init__(self, db): + BaseConstantGenerator.__init__(self, db) + self.cts = db.genoo.TypeSystem(db) + + def _begin_gen_constants(self, ilasm, all_constants): + self.ilasm = ilasm + self.begin_class() + gen = CLIGeneratorForConstants(ilasm) + return gen + + def _end_gen_constants(self, gen, numsteps): + assert gen.ilasm is self.ilasm + self.end_class() + + def begin_class(self): + self.ilasm.begin_namespace(CONST_NAMESPACE) + self.ilasm.begin_class(CONST_CLASSNAME, beforefieldinit=True) + + def end_class(self): + self.ilasm.end_class() + self.ilasm.end_namespace() + + def _declare_const(self, gen, const): + self.ilasm.field(const.name, const.get_type(), static=True) + + def push_primitive_constant(self, gen, TYPE, value): + ilasm = gen.ilasm + if TYPE is ootype.Void: + pass + elif TYPE is ootype.Bool: + ilasm.opcode('ldc.i4', str(int(value))) + elif TYPE is ootype.Char or TYPE is ootype.UniChar: + ilasm.opcode('ldc.i4', ord(value)) + elif TYPE is ootype.Float: + if isinf(value): + ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f0 7f)') + elif isnan(value): + ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f8 ff)') + else: + ilasm.opcode('ldc.r8', repr(value)) + elif isinstance(value, CDefinedIntSymbolic): + ilasm.opcode('ldc.i4', DEFINED_INT_SYMBOLICS[value.expr]) + elif TYPE in (ootype.Signed, ootype.Unsigned): + ilasm.opcode('ldc.i4', str(value)) + elif TYPE in (ootype.SignedLongLong, ootype.UnsignedLongLong): + ilasm.opcode('ldc.i8', str(value)) + elif TYPE is ootype.String: + if value._str is None: + ilasm.opcode('ldnull') + else: + ilasm.opcode("ldstr", string_literal(value._str)) + else: + assert False, "Unexpected constant type" + + def downcast_constant(self, gen, const, EXPECTED_TYPE): + type = self.cts.lltype_to_cts(EXPECTED_TYPE) + gen.ilasm.opcode('castclass', type) + +class FieldConstGenerator(CLIBaseConstGenerator): + pass + +class StaticFieldConstGenerator(FieldConstGenerator): + + # _________________________________________________________________ + # OOSupport interface + + def push_constant(self, gen, const): + type_ = const.get_type() + gen.ilasm.load_static_constant(type_, CONST_NAMESPACE, CONST_CLASSNAME, const.name) + + def _push_constant_during_init(self, gen, const): + full_name = '%s::%s' % (CONST_CLASS, const.name) + gen.ilasm.opcode('ldsfld %s %s' % (const.get_type(), full_name)) + + def _store_constant(self, gen, const): + type_ = const.get_type() + gen.ilasm.store_static_constant(type_, CONST_NAMESPACE, CONST_CLASSNAME, const.name) + + # _________________________________________________________________ + # CLI interface + + def _declare_step(self, gen, stepnum): + gen.ilasm.begin_function( + 'step%d' % stepnum, [], 'void', False, 'static') + + def _close_step(self, gen, stepnum): + gen.ilasm.ret() + gen.ilasm.end_function() + + def _end_gen_constants(self, gen, numsteps): + + self.ilasm.begin_function('.cctor', [], 'void', False, 'static', + 'specialname', 'rtspecialname', 'default') + self.ilasm.stderr('CONST: initialization starts', DEBUG_CONST_INIT) + for i in range(numsteps): + self.ilasm.stderr('CONST: step %d of %d' % (i, numsteps), + DEBUG_CONST_INIT) + step_name = 'step%d' % i + self.ilasm.call('void %s::%s()' % (CONST_CLASS, step_name)) + self.ilasm.stderr('CONST: initialization completed', DEBUG_CONST_INIT) + self.ilasm.ret() + self.ilasm.end_function() + + super(StaticFieldConstGenerator, self)._end_gen_constants( + gen, numsteps) + +class InstanceFieldConstGenerator(FieldConstGenerator): + + # _________________________________________________________________ + # OOSupport interface + + def push_constant(self, gen, const): + # load the singleton instance + gen.ilasm.opcode('ldsfld class %s %s::Singleton' % (CONST_CLASS, CONST_CLASS)) + gen.ilasm.opcode('ldfld %s %s::%s' % (const.get_type(), CONST_CLASS, const.name)) + + def _push_constant_during_init(self, gen, const): + # during initialization, we load the 'this' pointer from our + # argument rather than the singleton argument + gen.ilasm.opcode('ldarg.0') + gen.ilasm.opcode('ldfld %s %s::%s' % (const.get_type(), CONST_CLASS, const.name)) + + def _pre_store_constant(self, gen, const): + gen.ilasm.opcode('ldarg.0') + + def _store_constant(self, gen, const): + gen.ilasm.set_field((const.get_type(), CONST_CLASS, const.name)) + + # _________________________________________________________________ + # CLI interface + + def _declare_const(self, gen, all_constants): + gen.ilasm.field(const.name, const.get_type(), static=False) + + def _declare_step(self, gen, stepnum): + gen.ilasm.begin_function('step%d' % stepnum, [], 'void', False) + + def _close_step(self, gen, stepnum): + gen.ilasm.ret() + gen.ilasm.end_function() + + def _end_gen_constants(self, gen, numsteps): + + ilasm = gen.ilasm + + ilasm.begin_function('.ctor', [], 'void', False, 'specialname', 'rtspecialname', 'instance') + ilasm.opcode('ldarg.0') + ilasm.call('instance void object::.ctor()') + + ilasm.opcode('ldarg.0') + ilasm.opcode('stsfld class %s %s::Singleton' % (CONST_CLASS, CONST_CLASS)) + + for i in range(numsteps): + step_name = 'step%d' % i + ilasm.opcode('ldarg.0') + ilasm.call('instance void %s::%s()' % (CONST_CLASS, step_name)) + ilasm.ret() + ilasm.end_function() + + # declare&init the Singleton containing the constants + ilasm.field('Singleton', 'class %s' % CONST_CLASS, static=True) + ilasm.begin_function('.cctor', [], 'void', False, 'static', 'specialname', 'rtspecialname', 'default') + if SERIALIZE: + self._serialize_ctor() + else: + self._plain_ctor() + ilasm.end_function() + + super(StaticFieldConstGenerator, self)._end_gen_constants(gen, numsteps) + + def _plain_ctor(self): + self.ilasm.new('instance void class %s::.ctor()' % CONST_CLASS) + self.ilasm.pop() + self.ilasm.ret() + + def _serialize_ctor(self): + self.ilasm.opcode('ldstr "constants.dat"') + self.ilasm.call('object [pypylib]pypy.runtime.Utils::Deserialize(string)') + self.ilasm.opcode('dup') + self.ilasm.opcode('brfalse initialize') + self.ilasm.stderr('Constants deserialized successfully') + self.ilasm.opcode('stsfld class %s %s::Singleton' % (CONST_CLASS, CONST_CLASS)) + self.ilasm.ret() + self.ilasm.label('initialize') + self.ilasm.pop() + self.ilasm.stderr('Cannot deserialize constants... initialize them!') + self.ilasm.new('instance void class %s::.ctor()' % CONST_CLASS) + self.ilasm.opcode('ldstr "constants.dat"') + self.ilasm.call('void [pypylib]pypy.runtime.Utils::Serialize(object, string)') + self.ilasm.ret() + +class LazyConstGenerator(StaticFieldConstGenerator): + def push_constant(self, ilasm, const): + getter_name = '%s::%s' % (CONST_CLASS, 'get_%s' % const.name) + ilasm.call('%s %s()' % (const.get_type(), getter_name)) + + def _create_pointers(self, gen, all_constants): + # overload to do nothing since we handle everything in lazy fashion + pass + + def _initialize_data(self, gen, all_constants): + # overload to do nothing since we handle everything in lazy fashion + pass + + def _declare_const(self, gen, const): + # Declare the field + super(LazyConstGenerator, self)._declare_const(gen, const) + + # Create the method for accessing the field + getter_name = 'get_%s' % const.name + type_ = const.get_type() + self.ilasm.begin_function(getter_name, [], type_, False, 'static') + self.ilasm.load_static_constant(type_, CONST_NAMESPACE, CONST_CLASS, const.name) + # if it's already initialized, just return it + self.ilasm.opcode('dup') + self.ilasm.opcode('brfalse', 'initialize') + self.ilasm.opcode('ret') + # else, initialize! + self.ilasm.label('initialize') + self.ilasm.opcode('pop') # discard the null value we know is on the stack + const.instantiate(ilasm) + self.ilasm.opcode('dup') # two dups because const.init pops the value at the end + self.ilasm.opcode('dup') + self.ilasm.store_static_constant(type_, CONST_NAMESPACE, CONST_CLASS, const.name) + const.init(ilasm) + self.ilasm.opcode('ret') + self.ilasm.end_function() + +# ______________________________________________________________________ +# Mixins +# +# Mixins are used to add a few CLI-specific methods to each constant +# class. Basically, any time I wanted to extend a base class (such as +# AbstractConst or DictConst), I created a mixin, and then mixed it in +# to each sub-class of that base-class. Kind of awkward. + +class CLIBaseConstMixin(object): + """ A mix-in with a few extra methods the CLI backend uses """ + + def get_type(self, include_class=True): + """ Returns the CLI type for this constant's representation """ + return self.cts.lltype_to_cts(self.value._TYPE, include_class) + + def push_inline(self, gen, TYPE): + """ Overload the oosupport version so that we use the CLI opcode + for pushing NULL """ + assert self.is_null() + gen.ilasm.opcode('ldnull') + +class CLIDictMixin(CLIBaseConstMixin): + # Eventually code should look more like this: + #def _check_for_void_dict(self, gen): + # KEYTYPE = self.value._TYPE._KEYTYPE + # keytype = self.cts.lltype_to_cts(KEYTYPE) + # keytype_T = self.cts.lltype_to_cts(self.value._TYPE.KEYTYPE_T) + # VALUETYPE = self.value._TYPE._VALUETYPE + # valuetype = self.cts.lltype_to_cts(VALUETYPE) + # valuetype_T = self.cts.lltype_to_cts(self.value._TYPE.VALUETYPE_T) + # if VALUETYPE is ootype.Void: + # class_name = PYPY_DICT_OF_VOID % keytype + # for key in self.value._dict: + # gen.ilasm.opcode('dup') + # push_constant(self.db, KEYTYPE, key, gen) + # meth = 'void class %s::ll_set(%s)' % (class_name, keytype_T) + # gen.ilasm.call_method(meth, False) + # gen.ilasm.opcode('pop') + # return True + # return False + # + #def initialize_data(self, gen): + # # special case: dict of void, ignore the values + # if _check_for_void_dict(self, gen): + # return + # return super(CLIDictMixin, self).record_dependencies() + + def initialize_data(self, gen): + assert not self.is_null() + class_name = self.get_type(False) + KEYTYPE = self.value._TYPE._KEYTYPE + keytype = self.cts.lltype_to_cts(KEYTYPE) + keytype_T = self.cts.lltype_to_cts(self.value._TYPE.KEYTYPE_T) + + VALUETYPE = self.value._TYPE._VALUETYPE + valuetype = self.cts.lltype_to_cts(VALUETYPE) + valuetype_T = self.cts.lltype_to_cts(self.value._TYPE.VALUETYPE_T) + + if KEYTYPE is ootype.Void: + assert VALUETYPE is ootype.Void + return + + # special case: dict of void, ignore the values + if VALUETYPE is ootype.Void: + class_name = PYPY_DICT_OF_VOID % keytype + for key in self.value._dict: + gen.ilasm.opcode('dup') + push_constant(self.db, KEYTYPE, key, gen) + meth = 'void class %s::ll_set(%s)' % (class_name, keytype_T) + gen.ilasm.call_method(meth, False) + return + + for key, value in self.value._dict.iteritems(): + gen.ilasm.opcode('dup') + push_constant(self.db, KEYTYPE, key, gen) + push_constant(self.db, VALUETYPE, value, gen) + meth = 'void class [pypylib]pypy.runtime.Dict`2<%s, %s>::ll_set(%s, %s)' %\ + (keytype, valuetype, keytype_T, valuetype_T) + gen.ilasm.call_method(meth, False) + + +# ______________________________________________________________________ +# Constant Classes +# +# Here we overload a few methods, and mix in the base classes above. +# Note that the mix-ins go first so that they overload methods where +# required. +# +# Eventually, these probably wouldn't need to exist at all (the JVM +# doesn't have any, for example), or could simply have empty bodies +# and exist to combine a mixin and the generic base class. For now, +# though, they contain the create_pointer() and initialize_data() +# routines. In order to get rid of them, we would need to implement +# the generator interface in the CLI. + +class CLIRecordConst(CLIBaseConstMixin, RecordConst): + # Eventually code should look more like this: + #def create_pointer(self, gen): + # self.db.const_count.inc('Record') + # super(CLIRecordConst, self).create_pointer(gen) + + def create_pointer(self, gen): + assert not self.is_null() + class_name = self.get_type(False) + gen.ilasm.new('instance void class %s::.ctor()' % class_name) + self.db.const_count.inc('Record') + + def initialize_data(self, gen): + assert not self.is_null() + class_name = self.get_type(False) + for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems(): + if FIELD_TYPE is not ootype.Void: + f_type = self.cts.lltype_to_cts(FIELD_TYPE) + value = self.value._items[f_name] + gen.ilasm.opcode('dup') + push_constant(self.db, FIELD_TYPE, value, gen) + gen.ilasm.set_field((f_type, class_name, f_name)) + +class CLIInstanceConst(CLIBaseConstMixin, InstanceConst): + # Eventually code should look more like this: + #def create_pointer(self, gen): + # self.db.const_count.inc('Instance') + # self.db.const_count.inc('Instance', INSTANCE) + # super(CLIInstanceConst, self).create_pointer(gen) + + def create_pointer(self, gen): + assert not self.is_null() + INSTANCE = self.value._TYPE + gen.ilasm.new('instance void class %s::.ctor()' % self.db.class_name(INSTANCE)) + self.db.const_count.inc('Instance') + self.db.const_count.inc('Instance', INSTANCE) + + def initialize_data(self, gen): + assert not self.is_null() + INSTANCE = self.value._TYPE + if INSTANCE is not self.static_type: + gen.ilasm.opcode('castclass', self.cts.lltype_to_cts(INSTANCE, include_class=False)) + + # XXX, horrible hack: first collect all consts, then render + # CustomDicts at last because their ll_set could need other + # fields already initialized. We should really think a more + # general way to handle such things. + const_list = [] + while INSTANCE is not None: + for name, (TYPE, default) in INSTANCE._fields.iteritems(): + if TYPE is ootype.Void: + continue + value = getattr(self.value, name) + const_list.append((TYPE, INSTANCE, name, value)) + INSTANCE = INSTANCE._superclass + + def mycmp(x, y): + if isinstance(x[0], ootype.CustomDict) and not isinstance(y[0], ootype.CustomDict): + return 1 # a CustomDict is always greater than non-CustomDicts + elif isinstance(y[0], ootype.CustomDict) and not isinstance(x[0], ootype.CustomDict): + return -1 # a non-CustomDict is always less than CustomDicts + else: + return cmp(x, y) + const_list.sort(mycmp) + + for TYPE, INSTANCE, name, value in const_list: + type_ = self.cts.lltype_to_cts(TYPE) + gen.ilasm.opcode('dup') + push_constant(self.db, TYPE, value, gen) + gen.ilasm.opcode('stfld %s %s::%s' % (type_, self.db.class_name(INSTANCE), name)) + +class CLIClassConst(CLIBaseConstMixin, ClassConst): + def is_inline(self): + return True + + def push_inline(self, gen, EXPECTED_TYPE): + if not self.is_null(): + INSTANCE = self.value._INSTANCE + gen.ilasm.opcode('ldtoken', self.db.class_name(INSTANCE)) + gen.ilasm.call('class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)') + return + super(CLIClassConst, self).push_inline(gen, EXPECTED_TYPE) + pass + +class CLIListConst(CLIBaseConstMixin, ListConst): + + # Eventually code should look more like this: + #def _do_not_initialize(self): + # # Check if it is a list of all zeroes: + # try: + # if self.value._list == [0] * len(self.value._list): + # return True + # except: + # pass + # return super(CLIListConst, self)._do_not_initialize(self) + # + #def create_pointer(self, gen): + # self.db.const_count.inc('List') + # self.db.const_count.inc('List', self.value._TYPE._ITEMTYPE) + # self.db.const_count.inc('List', len(self.value._list)) + # super(CLIListConst, self).create_pointer(gen) + + def create_pointer(self, gen): + assert not self.is_null() + class_name = self.get_type(False) + push_constant(self.db, ootype.Signed, len(self.value._list), gen) + gen.ilasm.new('instance void class %s::.ctor(int32)' % class_name) + self.db.const_count.inc('List') + self.db.const_count.inc('List', self.value._TYPE._ITEMTYPE) + self.db.const_count.inc('List', len(self.value._list)) + + def _list_of_zeroes(self): + try: + return self.value._list == [0] * len(self.value._list) + except: + return False + + def initialize_data(self, gen): + assert not self.is_null() + ITEMTYPE = self.value._TYPE._ITEMTYPE + itemtype = self.cts.lltype_to_cts(ITEMTYPE) + itemtype_T = self.cts.lltype_to_cts(self.value._TYPE.ITEMTYPE_T) + + # special case: List(Void); only resize it, don't care of the contents + # special case: list of zeroes, don't need to initialize every item + if ITEMTYPE is ootype.Void or self._list_of_zeroes(): + push_constant(self.db, ootype.Signed, len(self.value._list), gen) + meth = 'void class %s::_ll_resize(int32)' % self.get_type(False) #PYPY_LIST_OF_VOID + gen.ilasm.call_method(meth, False) + return True + + for item in self.value._list: + gen.ilasm.opcode('dup') + push_constant(self.db, ITEMTYPE, item, gen) + meth = 'void class [pypylib]pypy.runtime.List`1<%s>::Add(%s)' % (itemtype, itemtype_T) + gen.ilasm.call_method(meth, False) + +class CLIDictConst(CLIDictMixin, DictConst): + + # Eventually code should look more like this: + #def create_pointer(self, gen): + # self.db.const_count.inc('Dict') + # self.db.const_count.inc('Dict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE) + # super(CLIDictConst, self).create_pointer(gen) + + def create_pointer(self, gen): + assert not self.is_null() + class_name = self.get_type(False) + gen.ilasm.new('instance void class %s::.ctor()' % class_name) + self.db.const_count.inc('Dict') + self.db.const_count.inc('Dict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE) + +class CLICustomDictConst(CLIDictMixin, CustomDictConst): + def record_dependencies(self): + if not self.value: + return + eq = self.value._dict.key_eq + hash = self.value._dict.key_hash + self.comparer = EqualityComparer(self.db, self.value._TYPE._KEYTYPE, eq, hash) + self.db.pending_node(self.comparer) + super(CLICustomDictConst, self).record_dependencies() + + def create_pointer(self, gen): + assert not self.is_null() + gen.ilasm.new(self.comparer.get_ctor()) + class_name = self.get_type() + gen.ilasm.new('instance void %s::.ctor(class ' + '[mscorlib]System.Collections.Generic.IEqualityComparer`1)' + % class_name) + self.db.const_count.inc('CustomDict') + self.db.const_count.inc('CustomDict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE) + +class CLIStaticMethodConst(CLIBaseConstMixin, StaticMethodConst): + def create_pointer(self, gen): + assert not self.is_null() + signature = self.cts.graph_to_signature(self.value.graph) + gen.ilasm.opcode('ldnull') + gen.ilasm.opcode('ldftn', signature) + gen.ilasm.new('instance void class %s::.ctor(object, native int)' % self.delegate_type) + self.db.const_count.inc('StaticMethod') + + def initialize_data(self, gen): + return + + +class CLIWeakRefConst(CLIBaseConstMixin, WeakRefConst): + def create_pointer(self, gen): + gen.ilasm.opcode('ldnull') + gen.ilasm.new('instance void %s::.ctor(object)' % self.get_type()) + self.db.const_count.inc('WeakRef') + + def get_type(self, include_class=True): + return 'class ' + WEAKREF + + def initialize_data(self, gen): + if self.value is not None: + push_constant(self.db, self.value._TYPE, self.value, gen) + gen.ilasm.call_method( + 'void %s::set_Target(object)' % self.get_type(), True) + return True + Modified: pypy/dist/pypy/translator/cli/database.py ============================================================================== --- pypy/dist/pypy/translator/cli/database.py (original) +++ pypy/dist/pypy/translator/cli/database.py Tue Nov 7 22:24:19 2006 @@ -1,6 +1,5 @@ import operator import string -from pypy.translator.cli.cts import CTS, PYPY_LIST_OF_VOID, PYPY_DICT_OF_VOID, WEAKREF from pypy.translator.cli.function import Function, log from pypy.translator.cli.class_ import Class from pypy.translator.cli.record import Record @@ -8,25 +7,18 @@ from pypy.translator.cli.comparer import EqualityComparer from pypy.translator.cli.node import Node from pypy.translator.cli.support import string_literal, Counter -from pypy.translator.cli.constgenerator import StaticFieldConstGenerator, InstanceFieldConstGenerator, LazyConstGenerator from pypy.rpython.ootypesystem import ootype from pypy.rpython.ootypesystem.module import ll_os -from pypy.rpython.lltypesystem import lltype -from pypy.rpython.lltypesystem import llmemory from pypy.translator.cli.opcodes import opcodes from pypy.translator.cli import dotnet from pypy.rlib.objectmodel import CDefinedIntSymbolic +from pypy.translator.oosupport.database import Database as OODatabase try: set except NameError: from sets import Set as set -#CONST_GENERATOR = InstanceFieldConstGenerator -CONST_GENERATOR = StaticFieldConstGenerator -#CONST_GENERATOR = LazyConstGenerator - - BUILTIN_RECORDS = { ootype.Record({"item0": ootype.Signed, "item1": ootype.Signed}): '[pypylib]pypy.runtime.Record_Signed_Signed', @@ -40,20 +32,9 @@ ll_os.STAT_RESULT: '[pypylib]pypy.runtime.Record_Stat_Result', } -DEFINED_INT_SYMBOLICS = {'MALLOC_ZERO_FILLED':1} - -def isnan(v): - return v != v*1.0 or (v == 1.0 and v == 2.0) - -def isinf(v): - return v!=0 and (v == v*2) - -class LowLevelDatabase(object): +class LowLevelDatabase(OODatabase): def __init__(self, genoo): - self._pending_nodes = set() - self._rendered_nodes = set() - self.genoo = genoo - self.cts = genoo.TypeSystem(self) + OODatabase.__init__(self, genoo) self.classes = {} # INSTANCE --> class_name self.classnames = set() # (namespace, name) self.recordnames = {} # RECORD --> name @@ -62,13 +43,9 @@ self.consts = {} # value --> AbstractConst self.delegates = {} # StaticMethod --> type_name self.const_count = Counter() # store statistics about constants - self.const_names = set() - self.name_count = 0 - self.locked = False def next_count(self): - self.name_count += 1 - return self.name_count + return self.unique() def _default_record_name(self, RECORD): trans = string.maketrans('<>(), :', '_______') @@ -133,14 +110,6 @@ self.pending_node(r) return name - def pending_node(self, node): - if node in self._pending_nodes or node in self._rendered_nodes: - return - - assert not self.locked # sanity check - self._pending_nodes.add(node) - node.dependencies() - def record_function(self, graph, name): self.functions[graph] = name @@ -166,16 +135,6 @@ except KeyError: return self.recordnames[RECORD] - def record_const(self, value): - if value in self.consts: - const = self.consts[value] - else: - const = AbstractConst.make(self, value, self.next_count()) - self.consts[value] = const - self.pending_node(const) - - return const - def record_delegate(self, TYPE): try: return self.delegates[TYPE] @@ -184,497 +143,3 @@ self.delegates[TYPE] = name self.pending_node(Delegate(self, TYPE, name)) return name - - - def gen_constants(self, ilasm): - self.locked = True # new pending nodes are not allowed here - generator = CONST_GENERATOR(ilasm) - generator.begin_class() - - const_list = [const for const in self.consts.itervalues() if not const.is_inline()] - const_list.sort(key=operator.attrgetter('PRIORITY')) - num_const = len(const_list) - - # render field definitions - for const in const_list: - assert not const.is_null() - generator.declare_const(const) - - generator.generate_consts(const_list) - generator.end_class() - log.INFO("%d constants rendered" % num_const) - self.locked = False - - - -class AbstractConst(Node): - PRIORITY = 0 - - def make(db, value, count): - if isinstance(value, ootype._view): - static_type = value._TYPE - value = value._inst - else: - static_type = None - - if isinstance(value, ootype._instance): - return InstanceConst(db, value, static_type, count) - elif isinstance(value, ootype._record): - return RecordConst(db, value, count) - elif isinstance(value, ootype._list): - return ListConst(db, value, count) - elif isinstance(value, ootype._static_meth): - return StaticMethodConst(db, value, count) - elif isinstance(value, ootype._class): - return ClassConst(db, value, count) - elif isinstance(value, ootype._custom_dict): - return CustomDictConst(db, value, count) - elif isinstance(value, ootype._dict): - return DictConst(db, value, count) - elif isinstance(value, llmemory.fakeweakaddress): - return WeakRefConst(db, value, count) - else: - assert False, 'Unknown constant: %s' % value - make = staticmethod(make) - - PRIMITIVE_TYPES = set([ootype.Void, ootype.Bool, ootype.Char, ootype.UniChar, - ootype.Float, ootype.Signed, ootype.Unsigned, ootype.String, - lltype.SignedLongLong, lltype.UnsignedLongLong]) - - def is_primitive(cls, TYPE): - return TYPE in cls.PRIMITIVE_TYPES - is_primitive = classmethod(is_primitive) - - def load(cls, db, TYPE, value, ilasm): - if TYPE is ootype.Void: - pass - elif TYPE is ootype.Bool: - ilasm.opcode('ldc.i4', str(int(value))) - elif TYPE is ootype.Char or TYPE is ootype.UniChar: - ilasm.opcode('ldc.i4', ord(value)) - elif TYPE is ootype.Float: - if isinf(value): - ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f0 7f)') - elif isnan(value): - ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f8 ff)') - else: - ilasm.opcode('ldc.r8', repr(value)) - elif isinstance(value, CDefinedIntSymbolic): - ilasm.opcode('ldc.i4', DEFINED_INT_SYMBOLICS[value.expr]) - elif TYPE in (ootype.Signed, ootype.Unsigned): - ilasm.opcode('ldc.i4', str(value)) - elif TYPE in (lltype.SignedLongLong, lltype.UnsignedLongLong): - ilasm.opcode('ldc.i8', str(value)) - elif TYPE is ootype.String: - if value._str is None: - ilasm.opcode('ldnull') - else: - ilasm.opcode("ldstr", string_literal(value._str)) - else: - assert TYPE not in cls.PRIMITIVE_TYPES - const = db.record_const(value) - if const.is_null(): - ilasm.opcode('ldnull') - else: - const._load(ilasm, TYPE) - load = classmethod(load) - - def __hash__(self): - return hash(self.value) - - def __eq__(self, other): - return self.value == other.value - - def __ne__(self, other): - return not self == other - - def __repr__(self): - return '' % (self.name, self.value) - - def get_name(self): - pass - - def get_type(self): - pass - - def is_null(self): - return self.value is ootype.null(self.value._TYPE) - - def is_inline(self): - """ - Inline constants are not stored as static fields in the - Constant class, but they are newly created on the stack every - time they are used. Classes overriding is_inline should - override _load too. - """ - return self.is_null() # by default only null constants are inlined - - def _load(self, ilasm, EXPECTED_TYPE): - """ - Load the constant onto the stack. - """ - cts = CTS(self.db) - cts_static_type = self.get_type() - CONST_GENERATOR.load_const(ilasm, self) - - if cts_static_type != cts.lltype_to_cts(EXPECTED_TYPE): - ilasm.opcode('castclass', cts.lltype_to_cts(EXPECTED_TYPE, include_class=False)) - - def record_const_maybe(self, TYPE, value): - if AbstractConst.is_primitive(TYPE): - return - self.db.record_const(value) - - def render(self, ilasm): - pass - - def dependencies(self): - """ - Record all constants that are needed to correctly initialize - the object. - """ - - def instantiate(self, ilasm): - """ - Instantiate the the object which represent the constant and - leave a reference to it on the stack. - """ - raise NotImplementedError - - def init(self, ilasm): - """ - Do some sort of extra initialization, if needed. It assume the - object to be initialized is on the stack. Don't leave anything - on the stack. - """ - assert not self.is_null() - ilasm.opcode('pop') - - -class RecordConst(AbstractConst): - def __init__(self, db, record, count): - self.db = db - self.cts = CTS(db) - self.value = record - self.name = 'RECORD__%d' % count - - def get_type(self, include_class=True): - return self.cts.lltype_to_cts(self.value._TYPE, include_class) - - def dependencies(self): - if self.value is ootype.null(self.value._TYPE): - return - for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems(): - value = self.value._items[f_name] - self.record_const_maybe(FIELD_TYPE, value) - - def instantiate(self, ilasm): - assert not self.is_null() - class_name = self.get_type(False) - ilasm.new('instance void class %s::.ctor()' % class_name) - self.db.const_count.inc('Record') - - def init(self, ilasm): - assert not self.is_null() - class_name = self.get_type(False) - for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems(): - if FIELD_TYPE is not ootype.Void: - f_type = self.cts.lltype_to_cts(FIELD_TYPE) - value = self.value._items[f_name] - ilasm.opcode('dup') - AbstractConst.load(self.db, FIELD_TYPE, value, ilasm) - ilasm.set_field((f_type, class_name, f_name)) - ilasm.opcode('pop') - -class StaticMethodConst(AbstractConst): - def __init__(self, db, sm, count): - self.db = db - self.cts = CTS(db) - self.value = sm - self.name = 'DELEGATE__%d' % count - - def get_type(self, include_class=True): - return self.cts.lltype_to_cts(self.value._TYPE, include_class) - - def dependencies(self): - if self.value is ootype.null(self.value._TYPE): - return - self.db.pending_function(self.value.graph) - self.delegate_type = self.db.record_delegate(self.value._TYPE) - - def instantiate(self, ilasm): - assert not self.is_null() - signature = self.cts.graph_to_signature(self.value.graph) - ilasm.opcode('ldnull') - ilasm.opcode('ldftn', signature) - ilasm.new('instance void class %s::.ctor(object, native int)' % self.delegate_type) - self.db.const_count.inc('StaticMethod') - -class ClassConst(AbstractConst): - def __init__(self, db, class_, count): - self.db = db - self.cts = CTS(db) - self.value = class_ - self.name = 'CLASS__%d' % count - - def get_type(self, include_class=True): - return self.cts.lltype_to_cts(self.value._TYPE, include_class) - - def dependencies(self): - INSTANCE = self.value._INSTANCE - if INSTANCE is not None: - self.cts.lltype_to_cts(INSTANCE) # force scheduling class generation - - def is_null(self): - return self.value._INSTANCE is None - - def is_inline(self): - return True - - def _load(self, ilasm, EXPECTED_TYPE): - assert not self.is_null() - INSTANCE = self.value._INSTANCE - ilasm.opcode('ldtoken', self.db.class_name(INSTANCE)) - ilasm.call('class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)') - -class ListConst(AbstractConst): - def __init__(self, db, list_, count): - self.db = db - self.cts = CTS(db) - self.value = list_ - self.name = 'LIST__%d' % count - - def get_type(self, include_class=True): - return self.cts.lltype_to_cts(self.value._TYPE, include_class) - - def dependencies(self): - if not self.value: - return - for item in self.value._list: - self.record_const_maybe(self.value._TYPE._ITEMTYPE, item) - - def instantiate(self, ilasm): - assert not self.is_null() - class_name = self.get_type(False) - AbstractConst.load(self.db, ootype.Signed, len(self.value._list), ilasm) - ilasm.new('instance void class %s::.ctor(int32)' % class_name) - self.db.const_count.inc('List') - self.db.const_count.inc('List', self.value._TYPE._ITEMTYPE) - self.db.const_count.inc('List', len(self.value._list)) - - def _list_of_zeroes(self): - try: - return self.value._list == [0] * len(self.value._list) - except: - return False - - def init(self, ilasm): - assert not self.is_null() - ITEMTYPE = self.value._TYPE._ITEMTYPE - itemtype = self.cts.lltype_to_cts(ITEMTYPE) - itemtype_T = self.cts.lltype_to_cts(self.value._TYPE.ITEMTYPE_T) - - # special case: List(Void); only resize it, don't care of the contents - # special case: list of zeroes, don't need to initialize every item - if ITEMTYPE is ootype.Void or self._list_of_zeroes(): - AbstractConst.load(self.db, ootype.Signed, len(self.value._list), ilasm) - meth = 'void class %s::_ll_resize(int32)' % self.get_type(False) #PYPY_LIST_OF_VOID - ilasm.call_method(meth, False) - return - - for item in self.value._list: - ilasm.opcode('dup') - AbstractConst.load(self.db, ITEMTYPE, item, ilasm) - meth = 'void class [pypylib]pypy.runtime.List`1<%s>::Add(%s)' % (itemtype, itemtype_T) - ilasm.call_method(meth, False) - ilasm.opcode('pop') - -class DictConst(AbstractConst): - def __init__(self, db, dict_, count): - self.db = db - self.cts = CTS(db) - self.value = dict_ - self.name = 'DICT__%d' % count - - def get_type(self, include_class=True): - return self.cts.lltype_to_cts(self.value._TYPE, include_class) - - def dependencies(self): - if not self.value: - return - - for key, value in self.value._dict.iteritems(): - self.record_const_maybe(self.value._TYPE._KEYTYPE, key) - self.record_const_maybe(self.value._TYPE._VALUETYPE, value) - - def instantiate(self, ilasm): - assert not self.is_null() - class_name = self.get_type(False) - ilasm.new('instance void class %s::.ctor()' % class_name) - self.db.const_count.inc('Dict') - self.db.const_count.inc('Dict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE) - - def init(self, ilasm): - assert not self.is_null() - class_name = self.get_type(False) - KEYTYPE = self.value._TYPE._KEYTYPE - keytype = self.cts.lltype_to_cts(KEYTYPE) - keytype_T = self.cts.lltype_to_cts(self.value._TYPE.KEYTYPE_T) - - VALUETYPE = self.value._TYPE._VALUETYPE - valuetype = self.cts.lltype_to_cts(VALUETYPE) - valuetype_T = self.cts.lltype_to_cts(self.value._TYPE.VALUETYPE_T) - - if KEYTYPE is ootype.Void: - assert VALUETYPE is ootype.Void - ilasm.opcode('pop') - return - - # special case: dict of void, ignore the values - if VALUETYPE is ootype.Void: - class_name = PYPY_DICT_OF_VOID % keytype - for key in self.value._dict: - ilasm.opcode('dup') - AbstractConst.load(self.db, KEYTYPE, key, ilasm) - meth = 'void class %s::ll_set(%s)' % (class_name, keytype_T) - ilasm.call_method(meth, False) - ilasm.opcode('pop') - return - - for key, value in self.value._dict.iteritems(): - ilasm.opcode('dup') - AbstractConst.load(self.db, KEYTYPE, key, ilasm) - AbstractConst.load(self.db, VALUETYPE, value, ilasm) - meth = 'void class [pypylib]pypy.runtime.Dict`2<%s, %s>::ll_set(%s, %s)' %\ - (keytype, valuetype, keytype_T, valuetype_T) - ilasm.call_method(meth, False) - ilasm.opcode('pop') - -class CustomDictConst(DictConst): - PRIORITY = 100 - - def dependencies(self): - if not self.value: - return - - eq = self.value._dict.key_eq - hash = self.value._dict.key_hash - self.comparer = EqualityComparer(self.db, self.value._TYPE._KEYTYPE, eq, hash) - self.db.pending_node(self.comparer) - DictConst.dependencies(self) - - def instantiate(self, ilasm): - assert not self.is_null() - ilasm.new(self.comparer.get_ctor()) - class_name = self.get_type() - ilasm.new('instance void %s::.ctor(class ' - '[mscorlib]System.Collections.Generic.IEqualityComparer`1)' - % class_name) - self.db.const_count.inc('CustomDict') - self.db.const_count.inc('CustomDict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE) - - -class InstanceConst(AbstractConst): - def __init__(self, db, obj, static_type, count): - self.db = db - self.cts = CTS(db) - self.value = obj - if static_type is None: - self.static_type = obj._TYPE - else: - self.static_type = static_type - self.cts.lltype_to_cts(obj._TYPE) # force scheduling of obj's class - class_name = db.class_name(obj._TYPE).replace('.', '_') - self.name = '%s__%d' % (class_name, count) - - def get_type(self): - return self.cts.lltype_to_cts(self.static_type) - - def dependencies(self): - if not self.value: - return - - INSTANCE = self.value._TYPE - while INSTANCE is not None: - for name, (TYPE, default) in INSTANCE._fields.iteritems(): - if TYPE is ootype.Void: - continue - type_ = self.cts.lltype_to_cts(TYPE) # record type - value = getattr(self.value, name) # record value - self.record_const_maybe(TYPE, value) - INSTANCE = INSTANCE._superclass - - def is_null(self): - return not self.value - - def instantiate(self, ilasm): - assert not self.is_null() - INSTANCE = self.value._TYPE - ilasm.new('instance void class %s::.ctor()' % self.db.class_name(INSTANCE)) - self.db.const_count.inc('Instance') - self.db.const_count.inc('Instance', INSTANCE) - - def init(self, ilasm): - assert not self.is_null() - INSTANCE = self.value._TYPE - if INSTANCE is not self.static_type: - ilasm.opcode('castclass', self.cts.lltype_to_cts(INSTANCE, include_class=False)) - - # XXX, horrible hack: first collect all consts, then render - # CustomDicts at last because their ll_set could need other - # fields already initialized. We should really think a more - # general way to handle such things. - const_list = [] - while INSTANCE is not None: - for name, (TYPE, default) in INSTANCE._fields.iteritems(): - if TYPE is ootype.Void: - continue - value = getattr(self.value, name) - const_list.append((TYPE, INSTANCE, name, value)) - INSTANCE = INSTANCE._superclass - - def mycmp(x, y): - if isinstance(x[0], ootype.CustomDict) and not isinstance(y[0], ootype.CustomDict): - return 1 # a CustomDict is always greater than non-CustomDicts - elif isinstance(y[0], ootype.CustomDict) and not isinstance(x[0], ootype.CustomDict): - return -1 # a non-CustomDict is always less than CustomDicts - else: - return cmp(x, y) - const_list.sort(mycmp) - - for TYPE, INSTANCE, name, value in const_list: - type_ = self.cts.lltype_to_cts(TYPE) - ilasm.opcode('dup') - AbstractConst.load(self.db, TYPE, value, ilasm) - ilasm.opcode('stfld %s %s::%s' % (type_, self.db.class_name(INSTANCE), name)) - - ilasm.opcode('pop') - -class WeakRefConst(AbstractConst): - def __init__(self, db, fakeaddr, count): - self.db = db - self.cts = CTS(db) - self.value = fakeaddr.get() - self.name = 'WEAKREF__%d' % count - - def get_type(self, include_class=True): - return 'class ' + WEAKREF - - def is_null(self): - return False - - def dependencies(self): - if self.value is not None: - self.db.record_const(self.value) - - def instantiate(self, ilasm): - ilasm.opcode('ldnull') - ilasm.new('instance void %s::.ctor(object)' % self.get_type()) - self.db.const_count.inc('WeakRef') - - def init(self, ilasm): - if self.value is not None: - AbstractConst.load(self.db, self.value._TYPE, self.value, ilasm) - ilasm.call_method('void %s::set_Target(object)' % self.get_type(), True) - else: - ilasm.opcode('pop') Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Tue Nov 7 22:24:19 2006 @@ -4,9 +4,7 @@ from sets import Set as set from pypy.objspace.flow import model as flowmodel -from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float -from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong -from pypy.rpython.ootypesystem import ootype +from pypy.rpython.lltypesystem.lltype import Void from pypy.translator.oosupport.function import Function as OOFunction from pypy.translator.cli.option import getoption from pypy.translator.cli.cts import CTS @@ -15,8 +13,9 @@ from pypy.translator.cli.node import Node from pypy.translator.cli.class_ import Class from pypy.translator.cli.support import log +from pypy.translator.cli.ilgenerator import CLIBaseGenerator -class Function(OOFunction, Node, Generator): +class Function(OOFunction, Node, CLIBaseGenerator): def __init__(self, *args, **kwargs): OOFunction.__init__(self, *args, **kwargs) @@ -98,56 +97,8 @@ self.ilasm.opcode('throw') - # Generator interface - - def add_comment(self, text): - pass - - def function_signature(self, graph, func_name=None): - return self.cts.graph_to_signature(graph, False, func_name) - - def class_name(self, TYPE): - if isinstance(TYPE, ootype.Instance): - return self.db.class_name(TYPE) - elif isinstance(TYPE, ootype.Record): - return self.db.get_record_name(TYPE) - - def emit(self, instr, *args): - self.ilasm.opcode(instr, *args) - - def call_graph(self, graph, func_name=None): - if func_name is None: # else it is a suggested primitive - self.db.pending_function(graph) - func_sig = self.function_signature(graph, func_name) - self.ilasm.call(func_sig) - - def call_signature(self, signature): - self.ilasm.call(signature) - - def cast_to(self, lltype): - cts_type = self.cts.lltype_to_cts(lltype, False) - self.ilasm.opcode('castclass', cts_type) - - def new(self, obj): - self.ilasm.new(self.cts.ctor_name(obj)) - - def set_field(self, obj, name): - self.ilasm.opcode('stfld ' + self.field_name(obj, name)) - - def get_field(self, obj, name): - self.ilasm.opcode('ldfld ' + self.field_name(obj, name)) - - def call_method(self, obj, name): - # TODO: use callvirt only when strictly necessary - signature, virtual = self.cts.method_signature(obj, name) - self.ilasm.call_method(signature, virtual) - - def downcast(self, TYPE): - type = self.cts.lltype_to_cts(TYPE) - return self.ilasm.opcode('castclass', type) - - def instantiate(self): - self.call_signature('object [pypylib]pypy.runtime.Utils::RuntimeNew(class [mscorlib]System.Type)') + # Those parts of the generator interface that are function + # specific def load(self, v): if isinstance(v, flowmodel.Variable): @@ -160,14 +111,8 @@ else: self.ilasm.load_local(v) - elif isinstance(v, flowmodel.Constant): - self._load_const(v) else: - assert False - - def _load_const(self, const): - from pypy.translator.cli.database import AbstractConst - AbstractConst.load(self.db, const.concretetype, const.value, self.ilasm) + super(Function, self).load(v) def store(self, v): if isinstance(v, flowmodel.Variable): @@ -175,12 +120,3 @@ self.ilasm.store_local(v) else: assert False - - def isinstance(self, class_name): - self.ilasm.opcode('isinst', class_name) - - def branch_unconditionally(self, target_label): - self.ilasm.branch(target_label) - - def branch_conditionally(self, cond, target_label): - self.ilasm.branch_if(cond, target_label) Modified: pypy/dist/pypy/translator/cli/gencli.py ============================================================================== --- pypy/dist/pypy/translator/cli/gencli.py (original) +++ pypy/dist/pypy/translator/cli/gencli.py Tue Nov 7 22:24:19 2006 @@ -20,6 +20,7 @@ from pypy.translator.cli.prebuiltnodes import get_prebuilt_nodes from pypy.translator.cli.stackopt import StackOptGenerator from pypy.translator.cli import query +from pypy.translator.cli import constant try: set @@ -36,6 +37,16 @@ opcodes = opcodes Database = LowLevelDatabase log = log + + ConstantGenerator = constant.StaticFieldConstGenerator + InstanceConst = constant.CLIInstanceConst + RecordConst = constant.CLIRecordConst + ClassConst = constant.CLIClassConst + ListConst = constant.CLIListConst + StaticMethodConst = constant.CLIStaticMethodConst + CustomDictConst = constant.CLICustomDictConst + DictConst = constant.CLIDictConst + WeakRefConst = constant.CLIWeakRefConst def __init__(self, tmpdir, translator, entrypoint, config=None): GenOO.__init__(self, tmpdir, translator, entrypoint, config) Modified: pypy/dist/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/dist/pypy/translator/cli/ilgenerator.py (original) +++ pypy/dist/pypy/translator/cli/ilgenerator.py Tue Nov 7 22:24:19 2006 @@ -1,5 +1,9 @@ from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong +from pypy.rpython.ootypesystem import ootype +from pypy.translator.oosupport.metavm import Generator +from pypy.translator.oosupport.constant import push_constant +from pypy.objspace.flow import model as flowmodel class CodeGenerator(object): def __init__(self, out, indentstep = 4, startblock = '{', endblock = '}'): @@ -239,5 +243,82 @@ self.opcode('ldstr', string_literal(msg)) self.call_method('void class [mscorlib]System.IO.TextWriter::WriteLine(string)', virtual=True) + def add_comment(self, text): + self.out.write('// %s\n' % text) + def flush(self): pass + +class CLIBaseGenerator(Generator): + + """ Implements those parts of the metavm generator that are not + tied to any particular function.""" + + def __init__(self, db, ilasm): + self.ilasm = ilasm + self.db = db + self.cts = db.genoo.TypeSystem(db) + + def add_comment(self, text): + pass + + def function_signature(self, graph, func_name=None): + return self.cts.graph_to_signature(graph, False, func_name) + + def class_name(self, TYPE): + if isinstance(TYPE, ootype.Instance): + return self.db.class_name(TYPE) + elif isinstance(TYPE, ootype.Record): + return self.db.get_record_name(TYPE) + + def emit(self, instr, *args): + self.ilasm.opcode(instr, *args) + + def call_graph(self, graph, func_name=None): + if func_name is None: # else it is a suggested primitive + self.db.pending_function(graph) + func_sig = self.function_signature(graph, func_name) + self.ilasm.call(func_sig) + + def call_signature(self, signature): + self.ilasm.call(signature) + + def cast_to(self, lltype): + cts_type = self.cts.lltype_to_cts(lltype, False) + self.ilasm.opcode('castclass', cts_type) + + def new(self, obj): + self.ilasm.new(self.cts.ctor_name(obj)) + + def set_field(self, obj, name): + self.ilasm.opcode('stfld ' + self.field_name(obj, name)) + + def get_field(self, obj, name): + self.ilasm.opcode('ldfld ' + self.field_name(obj, name)) + + def call_method(self, obj, name): + # TODO: use callvirt only when strictly necessary + signature, virtual = self.cts.method_signature(obj, name) + self.ilasm.call_method(signature, virtual) + + def downcast(self, TYPE): + type = self.cts.lltype_to_cts(TYPE) + return self.ilasm.opcode('castclass', type) + + def instantiate(self): + self.call_signature('object [pypylib]pypy.runtime.Utils::RuntimeNew(class [mscorlib]System.Type)') + + def load(self, v): + if isinstance(v, flowmodel.Constant): + push_constant(self.db, v.concretetype, v.value, self) + else: + assert False + + def isinstance(self, class_name): + self.ilasm.opcode('isinst', class_name) + + def branch_unconditionally(self, target_label): + self.ilasm.branch(target_label) + + def branch_conditionally(self, cond, target_label): + self.ilasm.branch_if(cond, target_label) Modified: pypy/dist/pypy/translator/jvm/constant.py ============================================================================== --- pypy/dist/pypy/translator/jvm/constant.py (original) +++ pypy/dist/pypy/translator/jvm/constant.py Tue Nov 7 22:24:19 2006 @@ -2,80 +2,54 @@ Field, Method, ACONST_NULL, ICONST, LDC, DCONST_0, DCONST_1, LDC2 from pypy.translator.oosupport.constant import \ RecordConst, InstanceConst, ClassConst -from pypy.translator.jvm.typesystem import jPyPyConst +from pypy.translator.jvm.typesystem import \ + jPyPyConst, jObject # ___________________________________________________________________________ -# Simple Constants -# -# We create simple dummy constant objects that follow the same -# inteface as the complex constants from oosupport/constant.py. None -# of these requires initialization, so they only support push() and -# they should never find their way into the database's constant list. - -class Const(object): - def push(self, gen): - """ Emits code required to reference a constant. Usually invoked - by generator.emit() """ - raise NotImplementedError - -class VoidConst(object): - def push(self, gen): - pass - -class NullConst(object): - def push(self, gen): - gen.emit(ACONST_NULL) - -class DoubleConst(Const): - def __init__(self, value): - self.value = value - def push(self, gen): - if value == 0.0: - gen.emit(DCONST_0) - elif value == 1.0: - gen.emit(DCONST_1) - else: - gen.emit(LDC2, self.value) - -class UnicodeConst(Const): - def __init__(self, value): - self.value = value - def push(self, gen): - assert isinstance(self.value, unicode) - gen.emit(LDC, res) +# Constant Generator -# ___________________________________________________________________________ -# Complex Constants +class JVMConstantGenerator(BaseConstantGenerator): -class JVMFieldStorage(object): - """ A mix-in for the oosupport constant classes that stores the - pointer for the constant into a field on a class. It implements - the push() and store() methods used by the oosupport classes and - elsewhere.""" - def __init__(self): - # Note that self.name and self.value are set by the oosupport - # constance class: - fieldty = self.db.lltype_to_cts(self.value._TYPE) - self.fieldobj = Field(jPyPyConst.name, self.name, fieldty, True) + # _________________________________________________________________ + # Constant Operations + # + # We store constants in static fields of the jPyPyConst class. + + def _init_constant(self, const): + fieldty = self.db.lltype_to_cts(const.OOTYPE()) + const.fieldobj = Field(jPyPyConst.name, const.name, fieldty, True) + + def push_constant(self, gen, const): + const.fieldobj.load(gen) + + def _store_constant(self, gen, const): + const.fieldobj.store(gen) + + # _________________________________________________________________ + # Constant Generation + + def _begin_gen_constants(self, gen, all_constants): + gen.begin_class(jPyPyConst, jObject) + + def _declare_const(self, gen, const): + gen.add_field(c.fieldobj) + + def _declare_step(self, gen, stepnum): + next_nm = "constant_init_%d" % stepnum + gen.begin_function(next_nm, [], [], jVoid, True) + + def _close_step(self, gen, stepnum): + gen.return_val(jVoid) + gen.end_function() # end constant_init_N where N == stepnum + + def _end_gen_constants(self, gen, numsteps): + # The static init code just needs to call constant_init_1..N + gen.begin_function('', [], [], jVoid, True) + for x in range(numsteps): + m = jvmgen.Method.s(jPyPyConst, "constant_init_%d" % x, [], jVoid) + gen.emit(m) + gen.return_val(jVoid) + gen.end_function() - def push(self, gen): - self.fieldobj.load(gen) - - def store(self, gen): - self.fieldobj.store(gen) - -class JVMRecordConst(RecordConst, JVMFieldStorage): - def __init__(self, db, record, count): - RecordConst.__init__(self, db, record, count) - JVMFieldStorage.__init__(self) - -class JVMInstanceConst(InstanceConst, JVMFieldStorage): - def __init__(self, db, obj, record, count): - InstanceConst.__init__(self, db, obj, record, count) - JVMFieldStorage.__init__(self) - -class JVMClassConst(ClassConst, JVMFieldStorage): - def __init__(self, db, class_, count): - ClassConst.__init__(self, db, class_, count) - JVMFieldStorage.__init__(self) - + gen.end_class() + Modified: pypy/dist/pypy/translator/jvm/database.py ============================================================================== --- pypy/dist/pypy/translator/jvm/database.py (original) +++ pypy/dist/pypy/translator/jvm/database.py Tue Nov 7 22:24:19 2006 @@ -162,54 +162,6 @@ return res # _________________________________________________________________ - # Constant Emitting - # - # We place all constants in a special "constant" class - # - # XXX I don't particularly like this code being here. database - # shouldn't be so specific? Guess it's okay... - - RecordConst = jvmconst.JVMRecordConst - InstanceConst = jvmconst.JVMInstanceConst - ClassConst = jvmconst.JVMClassConst - - def _begin_gen_constants(self, gen, all_constants): - gen.begin_class(jPyPyConst, jObject) - - for c in all_constants: - assert isinstance(c, jvmconst.JVMFieldStorage) - gen.add_field(c.fieldobj) - - # the constant initialization code is broken up into special - # methods that are then invoked from --- this is to - # prevent the init functions from getting too big - self._constant_steps = 1 - gen.begin_function('constant_init_0', [], [], jVoid, True) - return gen - - def _interrupt_gen_constants(self): - gen.return_val(jVoid) - gen.end_function() # end constant_init_N - - next_nm = "constant_init_%d" % self._constant_steps - self._constant_steps += 1 - gen.begin_function(next_nm, [], [], jVoid, True) - - def _end_gen_constants(self, gen): - gen.return_val(jVoid) - gen.end_function() # end constant_init_N - - # The static init code just needs to call constant_init_1..N - gen.begin_function('', [], [], jVoid, True) - for x in range(self._constant_steps): - m = jvmgen.Method.s(jPyPyConst, "constant_init_%d" % x, [], jVoid) - gen.emit(m) - gen.return_val(jVoid) - gen.end_function() - - gen.end_class() - - # _________________________________________________________________ # Type printing functions # # Returns a method that prints details about the value out to Modified: pypy/dist/pypy/translator/jvm/genjvm.py ============================================================================== --- pypy/dist/pypy/translator/jvm/genjvm.py (original) +++ pypy/dist/pypy/translator/jvm/genjvm.py Tue Nov 7 22:24:19 2006 @@ -172,6 +172,10 @@ Database = Database opcodes = opcodes log = log + + RecordConst = jvmconst.JVMRecordConst + InstanceConst = jvmconst.JVMInstanceConst + ClassConst = jvmconst.JVMClassConst def __init__(self, tmpdir, translator, entrypoint): """ Modified: pypy/dist/pypy/translator/oosupport/constant.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/constant.py (original) +++ pypy/dist/pypy/translator/oosupport/constant.py Tue Nov 7 22:24:19 2006 @@ -6,26 +6,28 @@ we create an object and record it in the database. These objects contain the knowledge about how to access the value of the constant, as well as the how to initialize it. The constants are initialized in -several phases so that interdependencies do not prevent a problem. +two phases so that interdependencies do not prevent a problem. -The initialization process works like this: +The initialization process works in two phases: 1. create_pointer(): this creates uninitialized pointers, so that circular references can be handled. -2. initialize_opaque(): initializes all objects except for - CustomDicts. This basically allows any operation that treats the - object as an opaque pointer. Most initializations complete here. - -3. initialize_full(): initializes custom dicts: objects are inserted - into dicts here because their fields have been initialized. This - assumes that no custom dicts are inserted into any other custom dicts. +2. initialize_data(): initializes everything else. The constants are + first sorted by PRIORITY so that CustomDicts are initialized last. -These three methods will be invoked by the database's gen_constants() +These two methods will be invoked by the ConstantGenerator's gen_constants() routine. + +A backend will typically create its own version of each kind of Const class, +adding at minimum a push() and store() method. A custom variant of +BaseConstantGenerator is also needed. These classes can also be chosen +by the genoo.py subclass of the backend """ +from pypy.rpython.lltypesystem import llmemory from pypy.rpython.ootypesystem import ootype +import operator PRIMITIVE_TYPES = set([ootype.Void, ootype.Bool, ootype.Char, ootype.UniChar, ootype.Float, ootype.Signed, ootype.Unsigned, @@ -36,29 +38,273 @@ return TYPE in PRIMITIVE_TYPES def push_constant(db, TYPE, value, gen): - """ Class method that pushes the value of the specified - constant onto the stack. May or may not create an abstract constant - object. + """ General method that pushes the value of the specified constant + onto the stack. Use this when you want to load a constant value. + May or may not create an abstract constant object. db --- a Database TYPE --- the ootype of the constant - value --- the ootype instance + value --- the ootype instance (ootype._list, int, etc) gen --- a metavm.Generator """ + + constgen = db.constant_generator + if is_primitive(TYPE): - return gen.push_primitive_constant(TYPE, value) + return constgen.push_primitive_constant(gen, TYPE, value) - const = db.record_const(value) - if const.is_null(): - gen.push_null(TYPE) + const = constgen.record_const(value) + if const.is_inline(): + const.push_inline(gen, TYPE) else: - const.push(gen) + constgen.push_constant(gen, const) + if TYPE is not const.OOTYPE(): + constgen.downcast_constant(gen, value, TYPE) # ______________________________________________________________________ # Constant generator +# +# The back-end can specify which constant generator to use by setting +# genoo.ConstantGenerator to the appropriate class. The +# ConstantGenerator handles invoking the constant's initialization +# routines, as well as loading and storing them. +# +# For the most part, no code needs to interact with the constant +# generator --- the rest of the code base should always invoke +# push_constant(), which may delegate to the constant generator if +# needed. + +class BaseConstantGenerator(object): + + def __init__(self, db): + self.db = db + self.genoo = db.genoo + self.cache = {} + + # _________________________________________________________________ + # Constant Operations + # + # Methods for loading and storing the value of constants. Clearly, + # storing the value of a constant is only done internally. These + # must be overloaded by the specific backend. Note that there + # are some more specific variants below that do not have to be overloaded + # but may be. + + def push_constant(self, gen, const): + """ + gen --- a generator + const --- an AbstractConst object + + Loads the constant onto the stack. Can be invoked at any time. + """ + raise NotImplementedError + + def _store_constant(self, gen, const): + """ + gen --- a generator + const --- an AbstractConst object + + stores the constant from the stack + """ + raise NotImplementedError + + # _________________________________________________________________ + # Optional Constant Operations + # + # These allow various hooks at convenient times. All of them are + # already implemented and you don't need to overload them. + + def push_primitive_constant(self, gen, TYPE, value): + """ Invoked when an attempt is made to push a primitive + constant. Normally just passes the call onto the code + generator. """ + gen.push_primitive_constant(TYPE, value) + + def downcast_constant(self, gen, const, EXPECTED_TYPE): + """ Invoked when the expected type of a const does not match + const.OOTYPE(). The constant has been pushed. Normally just + invokes gen.downcast. When it finishes, constant should still + be on the stack. """ + gen.downcast(EXPECTED_TYPE) + + def _init_constant(self, const): + """ + const --- a freshly created AbstractConst object + + Gives the generator a chance to set any fields it wants on the + constant just after the object is first created. Not invoked + while generating constant initialization code, but before. + """ + pass + + def _push_constant_during_init(self, gen, const): + """ + gen --- a generator + const --- an AbstractConst object + + Just like push_constant, but only invoked during + initialization. By default simply invokes push_constant(). + """ + return self.push_constant(gen, const) + + def _pre_store_constant(self, gen, const): + """ + gen --- a generator + const --- an AbstractConst object + + invoked before the constant's create_pointer() routine is + called, to prepare the stack in any way needed. Typically + does nothing, but sometimes pushes the 'this' pointer if the + constant will be stored in the field of a singleton object. + """ + pass + + # _________________________________________________________________ + # Constant Object Creation + # + # Code that deals with creating AbstractConst objects and recording + # them. You should not need to change anything here. + + def record_const(self, value): + """ Returns an object representing the constant, remembering + also any details needed to initialize the constant. value + should be an ootype constant value. Not generally called + directly, but it can be if desired. """ + assert not is_primitive(value) + if value in self.cache: + return self.cache[value] + const = self._create_complex_const(value) + self.cache[value] = const + self._init_constant(const) + const.record_dependencies() + return const -class ConstantGenerator(object): - pass + def _create_complex_const(self, value): + + """ A helper method which creates a Constant wrapper object for + the given value. Uses the types defined in the sub-class. """ + + # Determine if the static type differs from the dynamic type. + if isinstance(value, ootype._view): + static_type = value._TYPE + value = value._inst + else: + static_type = None + + # Find the appropriate kind of Const object. + genoo = self.genoo + uniq = self.db.unique() + if isinstance(value, ootype._instance): + return genoo.InstanceConst(self.db, value, static_type, uniq) + elif isinstance(value, ootype._record): + return genoo.RecordConst(self.db, value, uniq) + elif isinstance(value, ootype._class): + return genoo.ClassConst(self.db, value, uniq) + elif isinstance(value, ootype._list): + return genoo.ListConst(self.db, value, uniq) + elif isinstance(value, ootype._static_meth): + return genoo.StaticMethodConst(self.db, value, uniq) + elif isinstance(value, ootype._custom_dict): + return genoo.CustomDictConst(self.db, value, uniq) + elif isinstance(value, ootype._dict): + return genoo.DictConst(self.db, value, uniq) + elif isinstance(value, llmemory.fakeweakaddress): + return genoo.WeakRefConst(self.db, value, uniq) + else: + assert False, 'Unknown constant: %s' % value + + # _________________________________________________________________ + # Constant Generation + # + # You will not generally need to overload any of the functions + # in this section. + + def gen_constants(self, ilasm): + + # Sort constants by priority. Don't bother with inline + # constants. + all_constants = [c for c in self.cache.values() if not c.is_inline()] + all_constants.sort(key=lambda c: (c.PRIORITY, c.count)) + + # Counters to track how many steps we have emitted so far, etc. + # See _consider_step() for more information. + self._step_counter = 0 + self._all_counter = 0 + + # Now, emit the initialization code: + gen = self._begin_gen_constants(ilasm, all_constants) + for const in all_constants: + self._declare_const(gen, const) + self._create_pointers(gen, all_constants) + self._initialize_data(gen, all_constants) + self._end_step(gen) + self._end_gen_constants(gen, self._step_counter) + + def _create_pointers(self, gen, all_constants): + """ Iterates through each constant, creating the pointer for it + and storing it. """ + gen.add_section("Create Pointer Phase") + for const in all_constants: + gen.add_comment("Constant: %s" % const.name) + self._pre_store_constant(gen, const) + self._consider_step(gen) + const.create_pointer(gen) + self._store_constant(gen, const) + + def _initialize_data(self, gen, all_constants): + """ Iterates through each constant, initializing its data. """ + gen.add_section("Initialize Data Phase") + for const in all_constants: + gen.add_comment("Constant: %s" % const.name) + self._push_constant_during_init(gen, const) + self._consider_step(gen) + if not const.initialize_data(gen): + gen.pop(const.OOTYPE()) + + def _consider_step(self, gen): + """ Considers whether to start a new step at this point. We + start a new step every so often to ensure the initialization + functions don't get too large and upset mono or the JVM or + what have you. """ + if (self._all_counter % 100) == 0: + self._end_step(gen) + self._declare_step(gen, self._step_counter) # open the next step + self._all_counter += 1 + + def _end_step(self, gen): + """ Ends the current step if one has begun. """ + if self._all_counter != 0: + self._close_step(gen, self._step_counter) # close previous step + self._step_counter += 1 + + # _________________________________________________________________ + # Abstract functions you must overload + + def _begin_gen_constants(self, ilasm, all_constants): + """ Invoked with the assembler and sorted list of constants + before anything else. Expected to return a generator that will + be passed around after that (the parameter named 'gen'). """ + raise NotImplementedError + + def _declare_const(self, gen, const): + """ Invoked once for each constant before any steps are created. """ + raise NotImplementedError + + def _declare_step(self, gen, stepnum): + """ Invoked to begin step #stepnum. stepnum starts with 0 (!) + and proceeds monotonically. If _declare_step() is invoked, + there will always be a corresponding call to _close_step(). """ + raise NotImplementedError + + def _close_step(self, gen, stepnum): + """ Invoked to end step #stepnum. Never invoked without a + corresponding call from _declare_step() first. """ + raise NotImplementedError + + def _end_gen_constants(self, gen, numsteps): + """ Invoked as the very last thing. numsteps is the total number + of steps that were created. """ + raise NotImplementedError # ______________________________________________________________________ # Constant base class @@ -66,6 +312,12 @@ class AbstractConst(object): PRIORITY = 0 + def __init__(self, db, value, count): + self.db = db + self.cts = db.genoo.TypeSystem(db) + self.value = value + self.count = count + # ____________________________________________________________ # Hashing, equality comparison, and repr() # @@ -86,13 +338,13 @@ # ____________________________________________________________ # Simple query routines + + def OOTYPE(self): + return self.value._TYPE def get_name(self): pass - def get_type(self): - pass - def is_null(self): return self.value is ootype.null(self.value._TYPE) @@ -101,29 +353,20 @@ Inline constants are not stored as static fields in the Constant class, but they are newly created on the stack every time they are used. Classes overriding is_inline should - override _load too. + override push_inline too. By default only NULL constants are + inlined. """ - return self.is_null() # by default only null constants are inlined + return self.is_null() - # ____________________________________________________________ - # Loading and storing the constant - # - # These method are left here as an example. They are commented - # out because they must be implemented by the backend as a mix-in, - # and this way there is no conflict between the two base classes. - - #def push(self, gen): - # """ - # Pushes the value of this constant onto the stack. - # """ - # raise NotImplementedException - - #def store(self, gen): - # """ - # The value of the constant will be pushed onto the stack; - # store places it somewhere so it can later be loaded. - # """ - # raise NotImplementedException + def push_inline(self, gen, EXPECTED_TYPE): + """ + Invoked by push_constant() when is_inline() returns true. + By default, just pushes NULL as only NULL constants are inlined. + If you overload this, overload is_inline() too. + """ + assert self.is_inline() and self.is_null() + return gen.push_null(EXPECTED_TYPE) + # ____________________________________________________________ # Initializing the constant @@ -141,23 +384,16 @@ Creates the pointer representing this object, but does not initialize its fields. First phase of initialization. """ - raise NotImplementedException - - def initialize_opaque(self, gen): - """ - Initializes any constants that only use other constants in an - opaque fashion, without relying on them being fully initialized. - The big exception are custom dictionaries. - """ - raise NotImplementedException + assert not self.is_null() + gen.new(self.value._TYPE) - def initialize_full(self, gen): + def initialize_data(self, gen): """ - Initializes all remaining constants, such as custom dicts, - that inspect the fields of their arguments. If it is ever the - case that such constants try to access one another, we'll need - to add a dependence graph, but currently the execution order - of this function between constants is undefined. + Initializes the internal data. Begins with a pointer to + the constant on the stack. Normally returns something + false (like, say, None) --- but returns True if it consumes + the pointer from the stack in the process; otherwise, a pop + is automatically inserted afterwards. """ raise NotImplementedException @@ -166,7 +402,7 @@ def _record_const_if_complex(self, TYPE, value): if not is_primitive(TYPE): - self.db.record_const(value) + self.db.constant_generator.record_const(value) # ______________________________________________________________________ @@ -174,9 +410,7 @@ class RecordConst(AbstractConst): def __init__(self, db, record, count): - self.db = db - self.cts = db.genoo.TypeSystem(db) - self.value = record + AbstractConst.__init__(self, db, record, count) self.name = 'RECORD__%d' % count def record_dependencies(self): @@ -186,34 +420,22 @@ value = self.value._items[f_name] self._record_const_if_complex(FIELD_TYPE, value) - def create_pointer(self, gen): - assert not self.is_null() - gen.new(self.value._TYPE) - self.store(gen) - - def initialize_opaque(self, gen): + def initialize_data(self, gen): assert not self.is_null() - self.push(gen) SELFTYPE = self.value._TYPE for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems(): if FIELD_TYPE is not ootype.Void: gen.dup(SELFTYPE) - #gen.load(value) - load(self.db, FIELD_TYPE, value, gen) + push_constant(self.db, FIELD_TYPE, value, gen) gen.set_field(SELFTYPE, f_name) gen.pop(SELFTYPE) - def initialize_full(self, gen): - pass - # ______________________________________________________________________ # Instances class InstanceConst(AbstractConst): def __init__(self, db, obj, static_type, count): - self.db = db - self.value = obj - self.cts = db.genoo.TypeSystem(db) + AbstractConst.__init__(self, db, obj, count) if static_type is None: self.static_type = obj._TYPE else: @@ -240,11 +462,6 @@ def is_null(self): return not self.value - def create_pointer(self, gen): - assert not self.is_null() - gen.new(self.value._TYPE) - self.store(gen) - def _sorted_const_list(self): # XXX, horrible hack: first collect all consts, then render # CustomDicts at last because their ll_set could need other @@ -271,7 +488,7 @@ return const_list - def initialize_opaque(self, gen): + def initialize_data(self, gen): assert not self.is_null() # Get a list of all the constants we'll need to initialize. @@ -282,7 +499,6 @@ # Push ourself on the stack, and cast to our actual type if it # is not the same as our static type SELFTYPE = self.value._TYPE - self.push(gen) if SELFTYPE is not self.static_type: gen.downcast(SELFTYPE) @@ -295,17 +511,12 @@ # Pop selves from stack when done. gen.pop(SELFTYPE) - def initialize_full(self, gen): - pass - # ______________________________________________________________________ # Class constants class ClassConst(AbstractConst): def __init__(self, db, class_, count): - self.db = db - self.cts = db.genoo.TypeSystem(db) - self.value = class_ + AbstractConst.__init__(self, db, class_, count) self.name = 'CLASS__%d' % count def record_dependencies(self): @@ -316,17 +527,144 @@ def is_null(self): return self.value._INSTANCE is None - def is_inline(self): - return True - def create_pointer(self, gen): assert not self.is_null() INSTANCE = self.value._INSTANCE gen.getclassobject(INSTANCE) - self.store(gen) - def initialize_opaque(self, gen): + def initialize_data(self, gen): pass - def initialize_full(self, gen): - pass +# ______________________________________________________________________ +# List constants + +class ListConst(AbstractConst): + def __init__(self, db, list, count): + AbstractConst.__init__(self, db, list, count) + self.name = 'LIST__%d' % count + + def record_dependencies(self): + if not self.value: + return + for item in self.value._list: + self._record_const_if_complex(self.value._TYPE._ITEMTYPE, item) + + def create_pointer(self, gen): + assert not self.is_null() + SELFTYPE = self.value._TYPE + + # XXX --- should we add something special to the generator for + # this? I want it to look exactly like it would in normal + # opcodes...but of course under current system I can't know + # what normal opcodes would look like as they fall under the + # perview of each backend rather than oosupport + + # Create the list + gen.new(SELFTYPE) + + # And then resize it to the correct size + gen.dup() + push_constant(self.db, ootype.Signed, len(self.value._list), gen) + gen.call_method(SELFTYPE, '_ll_resize') + + def _do_not_initialize(self): + """ Returns True if the list should not be initialized; this + can be overloaded by the backend if your conditions are wider. + The default is not to initialize if the list is a list of + Void. """ + return self.value._TYPE._ITEMTYPE is ootype.Void + try: + return self.value._list == [0] * len(self.value._list) + except: + return False + + def initialize_data(self, gen): + assert not self.is_null() + SELFTYPE = self.value._TYPE + ITEMTYPE = self.value._TYPE._ITEMTYPE + + # check for special cases and avoid initialization + if self._do_not_initialize(): + return + + # set each item in the list using the OOTYPE methods + for idx, item in enumerate(self.value._list): + gen.dup(SELFTYPE) + push_constant(self.db, ootype.Signed, idx, gen) + push_constant(self.db, ITEMTYPE, item, gen) + gen.call_method(SELFFTYPE, 'll_setitem_fast') + +# ______________________________________________________________________ +# Dictionary constants + +class DictConst(AbstractConst): + def __init__(self, db, dict, count): + AbstractConst.__init__(self, db, dict, count) + self.name = 'DICT__%d' % count + + def record_dependencies(self): + if not self.value: + return + + for key, value in self.value._dict.iteritems(): + self._record_const_if_complex(self.value._TYPE._KEYTYPE, key) + self._record_const_if_complex(self.value._TYPE._VALUETYPE, value) + + def initialize_data(self, gen): + assert not self.is_null() + SELFTYPE = self.value._TYPE + KEYTYPE = self.value._TYPE._KEYTYPE + VALUETYPE = self.value._TYPE._VALUETYPE + + if KEYTYPE is ootype.Void: + assert VALUETYPE is ootype.Void + return + + for key, value in self.value._dict.iteritems(): + gen.dup(SELFTYPE) + push_constant(self.db, KEYTYPE, key, gen) + if VALUETYPE is ootype.Void: + # special case dict of Void + gen.dup(KEYTYPE) + else: + push_constant(self.db, VALUETYPE, value, gen) + gen.call_method(SELFTYPE, 'll_set') + +class CustomDictConst(DictConst): + PRIORITY = 100 + +# ______________________________________________________________________ +# Static method constants + +class StaticMethodConst(AbstractConst): + def __init__(self, db, sm, count): + AbstractConst.__init__(self, db, sm, count) + self.name = 'DELEGATE__%d' % count + + def record_dependencies(self): + if self.value is ootype.null(self.value._TYPE): + return + self.db.pending_function(self.value.graph) + self.delegate_type = self.db.record_delegate(self.value._TYPE) + + def initialize_data(self, ilasm): + raise NotImplementedError + +# ______________________________________________________________________ +# Weak Reference constants + +class WeakRefConst(AbstractConst): + def __init__(self, db, fakeaddr, count): + AbstractConst.__init__(self, db, fakeaddr.get(), count) + self.name = 'WEAKREF__%d' % count + + def OOTYPE(self): + # Not sure what goes here...? + return None + + def is_null(self): + return False + + def record_dependencies(self): + if self.value is not None: + self.db.constant_generator.record_const(self.value) Modified: pypy/dist/pypy/translator/oosupport/database.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/database.py (original) +++ pypy/dist/pypy/translator/oosupport/database.py Tue Nov 7 22:24:19 2006 @@ -8,8 +8,9 @@ self.cts = genoo.TypeSystem(self) self._pending_nodes = set() self._rendered_nodes = set() - self._const_cache = {} self._unique_counter = 0 + self.constant_generator = genoo.ConstantGenerator(self) + self.locked = False # new pending nodes are not allowed here # ____________________________________________________________ # Miscellaneous @@ -30,45 +31,18 @@ def gen_constants(self, ilasm): """ Renders the constants uncovered during the graph walk""" + self.locked = True # new pending nodes are not allowed here + self.constant_generator.gen_constants(ilasm) + self.locked = False - # Now, emit the initialization code: - all_constants = self._const_cache.values() - gen = self._begin_gen_constants(ilasm, all_constants) - gen.add_section("Create Pointer Phase") - ctr = 0 - for const in all_constants: - gen.add_comment("Constant: %s" % const.name) - const.create_pointer(gen) - ctr = self._consider_interrupt(gen, ctr) - gen.add_section("Initialize Opaque Phase") - for const in all_constants: - gen.add_comment("Constant: %s" % const.name) - const.initialize_opaque(gen) - ctr = self._consider_interrupt(gen, ctr) - gen.add_section("Initialize Full Phase") - for const in all_constants: - gen.add_comment("Constant: %s" % const.name) - const.initialize_full(gen) - ctr = self._consider_interrupt(gen, ctr) - self._end_gen_constants(gen) - - def _consider_interrupt(self, gen, ctr): - ctr += 1 - if (ctr % 100) == 0: self._interrupt_gen_constants(gen) - return ctr + # ____________________________________________________________ + # Generation phases - def _begin_gen_constants(self): - # returns a generator + def record_delegate(self, OOTYPE): + """ Returns a backend-specific type for a delegate class... + details currently undefined. """ raise NotImplementedError - def _interrupt_gen_constants(self): - # invoked every so often so as to break up the generated - # code and not create one massive function - pass - - def _end_gen_constants(self, gen): - raise NotImplementedError - # ____________________________________________________________ # Node creation # @@ -89,8 +63,11 @@ def pending_node(self, node): """ Adds a node to the worklist, so long as it is not already there and has not already been rendered. """ - if node not in self._rendered_nodes: - self._pending_nodes.add(node) + assert not self.locked # sanity check + if node in self._pending_nodes or node in self._rendered_nodes: + return + self._pending_nodes.add(node) + node.dependencies() def len_pending(self): return len(self._pending_nodes) @@ -98,61 +75,3 @@ def pop(self): return self._pending_nodes.pop() - # ____________________________________________________________ - # Constants - - # Defines the subclasses used to represent complex constants by - # _create_complex_const: - - InstanceConst = None - RecordConst = None - ClassConst = None - - def record_const(self, value): - """ Returns an object representing the constant, remembering also - any details needed to initialize the constant. value should be an - ootype constant value """ - assert not is_primitive(value) - if value in self._const_cache: - return self._const_cache[value] - const = self._create_complex_const(value) - self._const_cache[value] = const - const.record_dependencies() - return const - - def push_primitive_const(self, gen, value): - """ Helper which pushes a primitive constant onto the stack """ - raise NotImplementedException - - def _create_complex_const(self, value): - - """ A helper method which creates a Constant wrapper object for - the given value. Uses the types defined in the sub-class. """ - - # Determine if the static type differs from the dynamic type. - if isinstance(value, ootype._view): - static_type = value._TYPE - value = value._inst - else: - static_type = None - - # Find the appropriate kind of Const object. - if isinstance(value, ootype._instance): - return self.InstanceConst(self, value, static_type, self.unique()) - elif isinstance(value, ootype._record): - return self.RecordConst(self, value, self.unique()) - elif isinstance(value, ootype._class): - return self.ClassConst(self, value, self.unique()) - #elif isinstance(value, ootype._list): - # return ListConst(db, value, count) - #elif isinstance(value, ootype._static_meth): - # return StaticMethodConst(db, value, count) - #elif isinstance(value, ootype._custom_dict): - # return CustomDictConst(db, value, count) - #elif isinstance(value, ootype._dict): - # return DictConst(db, value, count) - #elif isinstance(value, llmemory.fakeweakaddress): - # return WeakRefConst(db, value, count) - else: - assert False, 'Unknown constant: %s' % value - Modified: pypy/dist/pypy/translator/oosupport/function.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/function.py (original) +++ pypy/dist/pypy/translator/oosupport/function.py Tue Nov 7 22:24:19 2006 @@ -132,7 +132,7 @@ continue # see above assert issubclass(link.exitcase, Exception) ll_meta_exc = link.llexitcase - self.db.record_const(ll_meta_exc) + self.db.constant_generator.record_const(ll_meta_exc) self.begin_catch(link.llexitcase) self.store_exception_and_link(link) target_label = self._get_block_name(link.target) Modified: pypy/dist/pypy/translator/oosupport/genoo.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/genoo.py (original) +++ pypy/dist/pypy/translator/oosupport/genoo.py Tue Nov 7 22:24:19 2006 @@ -11,6 +11,19 @@ opcodes = None log = None + # Defines the subclasses used to represent complex constants by + # _create_complex_const: + + ConstantGenerator = None + InstanceConst = None + RecordConst = None + ClassConst = None + ListConst = None + StaticMethodConst = None + CustomDictConst = None + DictConst = None + WeakRefConst = None + def __init__(self, tmpdir, translator, entrypoint, config=None): self.tmpdir = tmpdir self.translator = translator From ac at codespeak.net Wed Nov 8 10:33:03 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 8 Nov 2006 10:33:03 +0100 (CET) Subject: [pypy-svn] r34358 - pypy/dist/pypy/module/rsocket Message-ID: <20061108093303.6855310078@code0.codespeak.net> Author: ac Date: Wed Nov 8 10:33:02 2006 New Revision: 34358 Modified: pypy/dist/pypy/module/rsocket/interp_socket.py Log: Convert exceptions from calls to addr.as_object(). Modified: pypy/dist/pypy/module/rsocket/interp_socket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_socket.py (original) +++ pypy/dist/pypy/module/rsocket/interp_socket.py Wed Nov 8 10:33:02 2006 @@ -22,9 +22,10 @@ sock, addr = self.accept(W_RSocket) finally: if GIL is not None: GIL.acquire(True) + return space.newtuple([space.wrap(sock), + addr.as_object(space)]) except SocketError, e: raise converted_error(space, e) - return space.newtuple([space.wrap(sock), addr.as_object(space)]) accept_w.unwrap_spec = ['self', ObjSpace] def bind_w(self, space, w_addr): @@ -113,9 +114,9 @@ """ try: addr = self.getpeername() + return addr.as_object(space) except SocketError, e: raise converted_error(space, e) - return addr.as_object(space) getpeername_w.unwrap_spec = ['self', ObjSpace] def getsockname_w(self, space): @@ -126,9 +127,9 @@ """ try: addr = self.getsockname() + return addr.as_object(space) except SocketError, e: raise converted_error(space, e) - return addr.as_object(space) getsockname_w.unwrap_spec = ['self', ObjSpace] def getsockopt_w(self, space, level, optname, w_buflen=NoneNotWrapped): @@ -216,9 +217,10 @@ data, addr = self.recvfrom(buffersize, flags) finally: if GIL is not None: GIL.acquire(True) + return space.newtuple([space.wrap(data), + addr.as_object(space)]) except SocketError, e: raise converted_error(space, e) - return space.newtuple([space.wrap(data), addr.as_object(space)]) recvfrom_w.unwrap_spec = ['self', ObjSpace, int, int] def send_w(self, space, data, flags=0): From ac at codespeak.net Wed Nov 8 10:34:52 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 8 Nov 2006 10:34:52 +0100 (CET) Subject: [pypy-svn] r34359 - pypy/dist/lib-python/modified-2.4.1/test Message-ID: <20061108093452.894C110079@code0.codespeak.net> Author: ac Date: Wed Nov 8 10:34:52 2006 New Revision: 34359 Removed: pypy/dist/lib-python/modified-2.4.1/test/test_socket.py Log: Start with a new modified test. From fijal at codespeak.net Wed Nov 8 10:41:24 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 8 Nov 2006 10:41:24 +0100 (CET) Subject: [pypy-svn] r34360 - pypy/dist/pypy/doc Message-ID: <20061108094124.9F1151007C@code0.codespeak.net> Author: fijal Date: Wed Nov 8 10:41:23 2006 New Revision: 34360 Modified: pypy/dist/pypy/doc/index.txt Log: Added link to transparent proxy document. Modified: pypy/dist/pypy/doc/index.txt ============================================================================== --- pypy/dist/pypy/doc/index.txt (original) +++ pypy/dist/pypy/doc/index.txt Wed Nov 8 10:41:23 2006 @@ -96,9 +96,12 @@ `Logic and Constraint`_ programming features +`Transparent proxy`_ implementation + .. _Thunk: getting-started.html#lazily-computed-objects .. _Stackless: stackless.html .. _`Logic and Constraint`: howto-logicobjspace-0.9.html +.. _`Transparent proxy`: proxy.html Status From cfbolz at codespeak.net Wed Nov 8 12:21:02 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 8 Nov 2006 12:21:02 +0100 (CET) Subject: [pypy-svn] r34361 - pypy/dist/pypy/doc Message-ID: <20061108112102.7E27F10036@code0.codespeak.net> Author: cfbolz Date: Wed Nov 8 12:21:00 2006 New Revision: 34361 Modified: pypy/dist/pypy/doc/stackless.txt Log: two typos, one of them slightly funny Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Wed Nov 8 12:21:00 2006 @@ -262,7 +262,7 @@ stackless and our own framework GC are compiled together in pypy-c:: cd pypy/translator/goal - python translate.py --stackless --framework=gc + python translate.py --stackless --gc=framework In this mode, our garbage collector is extended to support the notion of "pool": a pool is a linked list of allocated objects. All objects @@ -285,7 +285,7 @@ complexity increases: they look attractive in small examples, but the models that require explicit switching, by naming the target coroutine, do not compose naturally. This means that a program that uses -coroutines for two unrelated purposes may run into conflits caused by +coroutines for two unrelated purposes may run into conflicts caused by unexpected interactions. To illustrate the problem, consider the following example (simplified From niko at codespeak.net Wed Nov 8 12:52:55 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Wed, 8 Nov 2006 12:52:55 +0100 (CET) Subject: [pypy-svn] r34362 - in pypy/dist/pypy/translator: cli jvm oosupport Message-ID: <20061108115255.9140010050@code0.codespeak.net> Author: niko Date: Wed Nov 8 12:52:54 2006 New Revision: 34362 Modified: pypy/dist/pypy/translator/cli/class_.py pypy/dist/pypy/translator/cli/constant.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/ilgenerator.py pypy/dist/pypy/translator/jvm/constant.py pypy/dist/pypy/translator/jvm/genjvm.py pypy/dist/pypy/translator/jvm/node.py pypy/dist/pypy/translator/oosupport/constant.py pypy/dist/pypy/translator/oosupport/function.py pypy/dist/pypy/translator/oosupport/genoo.py Log: 1. adapt the JVM code to the changes I made in cli/oosupport; though I checked this in before, but apparently not. 2. make the CLI constants for Records and Instances rely only upon the generic setup code in oosupport; others remain the same Modified: pypy/dist/pypy/translator/cli/class_.py ============================================================================== --- pypy/dist/pypy/translator/cli/class_.py (original) +++ pypy/dist/pypy/translator/cli/class_.py Wed Nov 8 12:52:54 2006 @@ -75,8 +75,8 @@ return self.ilasm = ilasm + self.gen = CLIBaseGenerator(self.db, ilasm) - gen = CLIBaseGenerator(self.db, ilasm) if self.namespace: ilasm.begin_namespace(self.namespace) @@ -113,7 +113,7 @@ if isinstance(METH.RESULT, ootype.OOType): ilasm.opcode('ldnull') else: - push_constant(self.db, METH.RESULT, 0, gen) + push_constant(self.db, METH.RESULT, 0, self.gen) ilasm.opcode('ret') ilasm.end_function() @@ -132,7 +132,7 @@ f_name = self.cts.escape_name(f_name) if cts_type != 'void': self.ilasm.opcode('ldarg.0') - push_constant(self.db, F_TYPE, f_default, self) + push_constant(self.db, F_TYPE, f_default, self.gen) class_name = self.db.class_name(self.INSTANCE) self.ilasm.set_field((cts_type, class_name, f_name)) Modified: pypy/dist/pypy/translator/cli/constant.py ============================================================================== --- pypy/dist/pypy/translator/cli/constant.py (original) +++ pypy/dist/pypy/translator/cli/constant.py Wed Nov 8 12:52:54 2006 @@ -34,9 +34,8 @@ push_constant, WeakRefConst, StaticMethodConst, CustomDictConst, \ ListConst, ClassConst, InstanceConst, RecordConst, DictConst, \ BaseConstantGenerator -from pypy.translator.cli.support import string_literal +from pypy.translator.cli.ilgenerator import CLIBaseGenerator from pypy.rpython.ootypesystem import ootype -from pypy.rlib.objectmodel import CDefinedIntSymbolic from pypy.translator.cli.comparer import EqualityComparer from pypy.rpython.lltypesystem import lltype from pypy.translator.cli.cts import PYPY_DICT_OF_VOID, WEAKREF @@ -50,8 +49,6 @@ MAX_CONST_PER_STEP = 100 SERIALIZE = False -DEFINED_INT_SYMBOLICS = {'MALLOC_ZERO_FILLED':1} - def isnan(v): return v != v*1.0 or (v == 1.0 and v == 2.0) @@ -59,26 +56,6 @@ return v!=0 and (v == v*2) # ______________________________________________________________________ -# MetaVM Generator interface - -class CLIGeneratorForConstants(object): - - ''' Very minimal "implementation" of oosupport.metavm.Generator - interface. Just what is actually used. ''' - - def __init__(self, ilasm): - self.ilasm = ilasm - - def add_section(self, text): - return - - def add_comment(self, text): - return - - def pop(self, OOTYPE): - self.ilasm.pop() - -# ______________________________________________________________________ # Constant Generators # # Different generators implementing different techniques for loading @@ -97,7 +74,7 @@ def _begin_gen_constants(self, ilasm, all_constants): self.ilasm = ilasm self.begin_class() - gen = CLIGeneratorForConstants(ilasm) + gen = CLIBaseGenerator(self.db, ilasm) return gen def _end_gen_constants(self, gen, numsteps): @@ -115,35 +92,6 @@ def _declare_const(self, gen, const): self.ilasm.field(const.name, const.get_type(), static=True) - def push_primitive_constant(self, gen, TYPE, value): - ilasm = gen.ilasm - if TYPE is ootype.Void: - pass - elif TYPE is ootype.Bool: - ilasm.opcode('ldc.i4', str(int(value))) - elif TYPE is ootype.Char or TYPE is ootype.UniChar: - ilasm.opcode('ldc.i4', ord(value)) - elif TYPE is ootype.Float: - if isinf(value): - ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f0 7f)') - elif isnan(value): - ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f8 ff)') - else: - ilasm.opcode('ldc.r8', repr(value)) - elif isinstance(value, CDefinedIntSymbolic): - ilasm.opcode('ldc.i4', DEFINED_INT_SYMBOLICS[value.expr]) - elif TYPE in (ootype.Signed, ootype.Unsigned): - ilasm.opcode('ldc.i4', str(value)) - elif TYPE in (ootype.SignedLongLong, ootype.UnsignedLongLong): - ilasm.opcode('ldc.i8', str(value)) - elif TYPE is ootype.String: - if value._str is None: - ilasm.opcode('ldnull') - else: - ilasm.opcode("ldstr", string_literal(value._str)) - else: - assert False, "Unexpected constant type" - def downcast_constant(self, gen, const, EXPECTED_TYPE): type = self.cts.lltype_to_cts(EXPECTED_TYPE) gen.ilasm.opcode('castclass', type) @@ -414,75 +362,17 @@ # the generator interface in the CLI. class CLIRecordConst(CLIBaseConstMixin, RecordConst): - # Eventually code should look more like this: - #def create_pointer(self, gen): - # self.db.const_count.inc('Record') - # super(CLIRecordConst, self).create_pointer(gen) - def create_pointer(self, gen): - assert not self.is_null() - class_name = self.get_type(False) - gen.ilasm.new('instance void class %s::.ctor()' % class_name) self.db.const_count.inc('Record') - - def initialize_data(self, gen): - assert not self.is_null() - class_name = self.get_type(False) - for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems(): - if FIELD_TYPE is not ootype.Void: - f_type = self.cts.lltype_to_cts(FIELD_TYPE) - value = self.value._items[f_name] - gen.ilasm.opcode('dup') - push_constant(self.db, FIELD_TYPE, value, gen) - gen.ilasm.set_field((f_type, class_name, f_name)) + super(CLIRecordConst, self).create_pointer(gen) class CLIInstanceConst(CLIBaseConstMixin, InstanceConst): # Eventually code should look more like this: - #def create_pointer(self, gen): - # self.db.const_count.inc('Instance') - # self.db.const_count.inc('Instance', INSTANCE) - # super(CLIInstanceConst, self).create_pointer(gen) - def create_pointer(self, gen): - assert not self.is_null() - INSTANCE = self.value._TYPE - gen.ilasm.new('instance void class %s::.ctor()' % self.db.class_name(INSTANCE)) self.db.const_count.inc('Instance') - self.db.const_count.inc('Instance', INSTANCE) + self.db.const_count.inc('Instance', self.OOTYPE()) + super(CLIInstanceConst, self).create_pointer(gen) - def initialize_data(self, gen): - assert not self.is_null() - INSTANCE = self.value._TYPE - if INSTANCE is not self.static_type: - gen.ilasm.opcode('castclass', self.cts.lltype_to_cts(INSTANCE, include_class=False)) - - # XXX, horrible hack: first collect all consts, then render - # CustomDicts at last because their ll_set could need other - # fields already initialized. We should really think a more - # general way to handle such things. - const_list = [] - while INSTANCE is not None: - for name, (TYPE, default) in INSTANCE._fields.iteritems(): - if TYPE is ootype.Void: - continue - value = getattr(self.value, name) - const_list.append((TYPE, INSTANCE, name, value)) - INSTANCE = INSTANCE._superclass - - def mycmp(x, y): - if isinstance(x[0], ootype.CustomDict) and not isinstance(y[0], ootype.CustomDict): - return 1 # a CustomDict is always greater than non-CustomDicts - elif isinstance(y[0], ootype.CustomDict) and not isinstance(x[0], ootype.CustomDict): - return -1 # a non-CustomDict is always less than CustomDicts - else: - return cmp(x, y) - const_list.sort(mycmp) - - for TYPE, INSTANCE, name, value in const_list: - type_ = self.cts.lltype_to_cts(TYPE) - gen.ilasm.opcode('dup') - push_constant(self.db, TYPE, value, gen) - gen.ilasm.opcode('stfld %s %s::%s' % (type_, self.db.class_name(INSTANCE), name)) class CLIClassConst(CLIBaseConstMixin, ClassConst): def is_inline(self): @@ -495,7 +385,6 @@ gen.ilasm.call('class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)') return super(CLIClassConst, self).push_inline(gen, EXPECTED_TYPE) - pass class CLIListConst(CLIBaseConstMixin, ListConst): Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Wed Nov 8 12:52:54 2006 @@ -59,15 +59,6 @@ self.store(link.last_exc_value) self._setup_link(link) - def field_name(self, obj, field): - INSTANCE, type_ = obj._lookup_field(field) - assert type_ is not None, 'Cannot find the field %s in the object %s' % (field, obj) - - class_name = self.class_name(INSTANCE) - field_type = self.cts.lltype_to_cts(type_) - field = self.cts.escape_name(field) - return '%s %s::%s' % (field_type, class_name, field) - def begin_render(self): returntype, returnvar = self.cts.llvar_to_cts(self.graph.getreturnvar()) if self.is_method: Modified: pypy/dist/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/dist/pypy/translator/cli/ilgenerator.py (original) +++ pypy/dist/pypy/translator/cli/ilgenerator.py Wed Nov 8 12:52:54 2006 @@ -1,9 +1,11 @@ from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong +from pypy.rlib.objectmodel import CDefinedIntSymbolic from pypy.rpython.ootypesystem import ootype from pypy.translator.oosupport.metavm import Generator from pypy.translator.oosupport.constant import push_constant from pypy.objspace.flow import model as flowmodel +from pypy.translator.cli.support import string_literal class CodeGenerator(object): def __init__(self, out, indentstep = 4, startblock = '{', endblock = '}'): @@ -249,6 +251,8 @@ def flush(self): pass +DEFINED_INT_SYMBOLICS = {'MALLOC_ZERO_FILLED':1} + class CLIBaseGenerator(Generator): """ Implements those parts of the metavm generator that are not @@ -259,6 +263,9 @@ self.db = db self.cts = db.genoo.TypeSystem(db) + def pop(self, TYPE): + self.ilasm.opcode('pop') + def add_comment(self, text): pass @@ -290,6 +297,15 @@ def new(self, obj): self.ilasm.new(self.cts.ctor_name(obj)) + def field_name(self, obj, field): + INSTANCE, type_ = obj._lookup_field(field) + assert type_ is not None, 'Cannot find the field %s in the object %s' % (field, obj) + + class_name = self.class_name(INSTANCE) + field_type = self.cts.lltype_to_cts(type_) + field = self.cts.escape_name(field) + return '%s %s::%s' % (field_type, class_name, field) + def set_field(self, obj, name): self.ilasm.opcode('stfld ' + self.field_name(obj, name)) @@ -322,3 +338,35 @@ def branch_conditionally(self, cond, target_label): self.ilasm.branch_if(cond, target_label) + + def push_primitive_constant(self, TYPE, value): + ilasm = self.ilasm + if TYPE is ootype.Void: + pass + elif TYPE is ootype.Bool: + ilasm.opcode('ldc.i4', str(int(value))) + elif TYPE is ootype.Char or TYPE is ootype.UniChar: + ilasm.opcode('ldc.i4', ord(value)) + elif TYPE is ootype.Float: + if isinf(value): + ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f0 7f)') + elif isnan(value): + ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f8 ff)') + else: + ilasm.opcode('ldc.r8', repr(value)) + elif isinstance(value, CDefinedIntSymbolic): + ilasm.opcode('ldc.i4', DEFINED_INT_SYMBOLICS[value.expr]) + elif TYPE in (ootype.Signed, ootype.Unsigned): + ilasm.opcode('ldc.i4', str(value)) + elif TYPE in (ootype.SignedLongLong, ootype.UnsignedLongLong): + ilasm.opcode('ldc.i8', str(value)) + elif TYPE is ootype.String: + if value._str is None: + ilasm.opcode('ldnull') + else: + ilasm.opcode("ldstr", string_literal(value._str)) + else: + assert False, "Unexpected constant type" + + def dup(self, TYPE): + self.ilasm.opcode('dup') Modified: pypy/dist/pypy/translator/jvm/constant.py ============================================================================== --- pypy/dist/pypy/translator/jvm/constant.py (original) +++ pypy/dist/pypy/translator/jvm/constant.py Wed Nov 8 12:52:54 2006 @@ -1,9 +1,9 @@ from pypy.translator.jvm.generator import \ - Field, Method, ACONST_NULL, ICONST, LDC, DCONST_0, DCONST_1, LDC2 + Field, Method from pypy.translator.oosupport.constant import \ - RecordConst, InstanceConst, ClassConst + BaseConstantGenerator, RecordConst, InstanceConst, ClassConst from pypy.translator.jvm.typesystem import \ - jPyPyConst, jObject + jPyPyConst, jObject, jVoid # ___________________________________________________________________________ # Constant Generator @@ -30,9 +30,10 @@ def _begin_gen_constants(self, gen, all_constants): gen.begin_class(jPyPyConst, jObject) + return gen def _declare_const(self, gen, const): - gen.add_field(c.fieldobj) + gen.add_field(const.fieldobj) def _declare_step(self, gen, stepnum): next_nm = "constant_init_%d" % stepnum @@ -46,7 +47,7 @@ # The static init code just needs to call constant_init_1..N gen.begin_function('', [], [], jVoid, True) for x in range(numsteps): - m = jvmgen.Method.s(jPyPyConst, "constant_init_%d" % x, [], jVoid) + m = Method.s(jPyPyConst, "constant_init_%d" % x, [], jVoid) gen.emit(m) gen.return_val(jVoid) gen.end_function() Modified: pypy/dist/pypy/translator/jvm/genjvm.py ============================================================================== --- pypy/dist/pypy/translator/jvm/genjvm.py (original) +++ pypy/dist/pypy/translator/jvm/genjvm.py Wed Nov 8 12:52:54 2006 @@ -15,6 +15,7 @@ from pypy.translator.jvm.log import log from pypy.translator.jvm.node import EntryPoint, Function from pypy.translator.jvm.opcodes import opcodes +from pypy.translator.jvm.constant import JVMConstantGenerator class JvmError(Exception): """ Indicates an error occurred in JVM backend """ @@ -173,9 +174,7 @@ opcodes = opcodes log = log - RecordConst = jvmconst.JVMRecordConst - InstanceConst = jvmconst.JVMInstanceConst - ClassConst = jvmconst.JVMClassConst + ConstantGenerator = JVMConstantGenerator def __init__(self, tmpdir, translator, entrypoint): """ Modified: pypy/dist/pypy/translator/jvm/node.py ============================================================================== --- pypy/dist/pypy/translator/jvm/node.py (original) +++ pypy/dist/pypy/translator/jvm/node.py Wed Nov 8 12:52:54 2006 @@ -27,6 +27,8 @@ class Node(object): def set_db(self, db): self.db = db + def dependencies(self): + pass class EntryPoint(Node): Modified: pypy/dist/pypy/translator/oosupport/constant.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/constant.py (original) +++ pypy/dist/pypy/translator/oosupport/constant.py Wed Nov 8 12:52:54 2006 @@ -426,9 +426,9 @@ for f_name, (FIELD_TYPE, f_default) in self.value._TYPE._fields.iteritems(): if FIELD_TYPE is not ootype.Void: gen.dup(SELFTYPE) + value = self.value._items[f_name] push_constant(self.db, FIELD_TYPE, value, gen) gen.set_field(SELFTYPE, f_name) - gen.pop(SELFTYPE) # ______________________________________________________________________ # Instances @@ -508,9 +508,6 @@ push_constant(self.db, FIELD_TYPE, value, gen) gen.set_field(INSTANCE, name) - # Pop selves from stack when done. - gen.pop(SELFTYPE) - # ______________________________________________________________________ # Class constants Modified: pypy/dist/pypy/translator/oosupport/function.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/function.py (original) +++ pypy/dist/pypy/translator/oosupport/function.py Wed Nov 8 12:52:54 2006 @@ -173,9 +173,6 @@ assert isinstance(instr_list, InstructionList) instr_list.render(self.generator, op) - def field_name(self, obj, field): - raise NotImplementedError - # ---------------------------------------------------------# # These methods are quite backend independent, but not # # used in all backends. Invoke them from your __init__ if # Modified: pypy/dist/pypy/translator/oosupport/genoo.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/genoo.py (original) +++ pypy/dist/pypy/translator/oosupport/genoo.py Wed Nov 8 12:52:54 2006 @@ -2,7 +2,7 @@ """ from pypy.config.config import Config from pypy.config.pypyoption import pypy_optiondescription - +from pypy.translator.oosupport import constant as ooconst class GenOO(object): TypeSystem = None @@ -15,14 +15,14 @@ # _create_complex_const: ConstantGenerator = None - InstanceConst = None - RecordConst = None - ClassConst = None - ListConst = None - StaticMethodConst = None - CustomDictConst = None - DictConst = None - WeakRefConst = None + InstanceConst = ooconst.InstanceConst + RecordConst = ooconst.RecordConst + ClassConst = ooconst.ClassConst + ListConst = ooconst.ListConst + StaticMethodConst = ooconst.StaticMethodConst + CustomDictConst = ooconst.CustomDictConst + DictConst = ooconst.DictConst + WeakRefConst = ooconst.WeakRefConst def __init__(self, tmpdir, translator, entrypoint, config=None): self.tmpdir = tmpdir From mwh at codespeak.net Wed Nov 8 13:47:53 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 8 Nov 2006 13:47:53 +0100 (CET) Subject: [pypy-svn] r34364 - in pypy/dist/pypy/jit/codegen/ppc: . test Message-ID: <20061108124753.6BE791006E@code0.codespeak.net> Author: mwh Date: Wed Nov 8 13:47:51 2006 New Revision: 34364 Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/regalloc.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Log: change the registers we allocate from for the restricted test-the-allocator tests. changing the gprs uncovered a bug, changing the crfs required a little code for spilling non-gprs. Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Wed Nov 8 13:47:51 2006 @@ -12,6 +12,8 @@ is_register = False def __init__(self, offset): self.offset = offset + def __repr__(self): + return "stack@%s"%(self.offset,) _stack_slot_cache = {} def stack_slot(offset): Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Wed Nov 8 13:47:51 2006 @@ -44,6 +44,12 @@ if freeregs: reg = freeregs.pop() + if newarg in self.var2loc: + spill = self.var2loc[newarg] + assert not spill.is_register + self.insns.append(Unspill(newarg, reg, spill)) + del self.loc2var[spill] # not stored there anymore, reuse?? + #print "allocate_reg: Unspilled %r from %r." % (newarg, spill) self.loc2var[reg] = newarg self.var2loc[newarg] = reg #print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) @@ -65,7 +71,12 @@ spill = stack_slot(self.spill()) self.var2loc[argtospill] = spill self.loc2var[spill] = argtospill - self.insns.append(Spill(argtospill, reg, spill)) + if regclass != GP_REGISTER: + self.insns.append(reg.move_to_gpr(self, 0)) + _reg = gprs[0] + else: + _reg = reg + self.insns.append(Spill(argtospill, _reg, spill)) #print "allocate_reg: Spilled %r to %r." % (argtospill, spill) # If the value is currently on the stack, load it up into the Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Wed Nov 8 13:47:51 2006 @@ -53,6 +53,7 @@ def load_now(self, asm, loc): if loc.is_register: + assert isinstance(loc, insn.GPR) asm.load_word(loc.number, self.value) else: asm.load_word(rSCRATCH, self.value) @@ -316,7 +317,7 @@ if not loc.is_register: min_stack_offset = min(min_stack_offset, loc.offset) else: - usedregs[loc] = None # XXX use this + usedregs[loc] = None unusedregs = [loc for loc in self.rgenop.freeregs[insn.GP_REGISTER] if loc not in usedregs] arg_locations = [] Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Wed Nov 8 13:47:51 2006 @@ -7,9 +7,9 @@ class FewRegisters(RPPCGenOp): freeregs = { - insn.GP_REGISTER:insn.gprs[29:], + insn.GP_REGISTER:insn.gprs[3:6], insn.FP_REGISTER:insn.fprs, - insn.CR_FIELD:insn.crfs, + insn.CR_FIELD:insn.crfs[:1], insn.CT_REGISTER:[insn.ctr]} class TestRPPCGenop(AbstractRGenOpTests): @@ -25,7 +25,7 @@ args_gv = [gv_x, gv_y] builder.enter_next_block([signed_kind, signed_kind], args_gv) [gv_x, gv_y] = args_gv - + gv_gt = builder.genop2("int_gt", gv_x, gv_y) gv_lt = builder.genop2("int_lt", gv_x, gv_y) gv_ge = builder.genop2("int_ge", gv_x, gv_y) From cfbolz at codespeak.net Wed Nov 8 14:34:57 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 8 Nov 2006 14:34:57 +0100 (CET) Subject: [pypy-svn] r34365 - pypy/dist/pypy/doc Message-ID: <20061108133457.B629610069@code0.codespeak.net> Author: cfbolz Date: Wed Nov 8 14:34:55 2006 New Revision: 34365 Modified: pypy/dist/pypy/doc/summer-of-pypy.txt Log: add leonardo to summer of pypy list of accepted proposals Modified: pypy/dist/pypy/doc/summer-of-pypy.txt ============================================================================== --- pypy/dist/pypy/doc/summer-of-pypy.txt (original) +++ pypy/dist/pypy/doc/summer-of-pypy.txt Wed Nov 8 14:34:55 2006 @@ -84,6 +84,8 @@ - `Complete gencli, the PyPy CLI backend`_ by Antonio Cuni, mentored by Armin Rigo +- `JavaScript interpreter`_ by Leonardo Santagada, mentored by various people + Note that Maciej, Lawrence and Antonio also have their proposal registered with the Google's Summer of Code under the PSF_. @@ -96,3 +98,4 @@ .. _`Complete gencli, the PyPy CLI backend`: http://code.google.com/soc/psf/appinfo.html?csaid=CB4EC4BA30BDDBCD +.. _`JavaScript interpreter`: http://codespeak.net/svn/user/santagada/javascript_interpreter_sop.txt From arigo at codespeak.net Wed Nov 8 14:37:51 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 14:37:51 +0100 (CET) Subject: [pypy-svn] r34366 - in pypy/dist/pypy/rpython: . test Message-ID: <20061108133751.5FB331006E@code0.codespeak.net> Author: arigo Date: Wed Nov 8 14:37:50 2006 New Revision: 34366 Modified: pypy/dist/pypy/rpython/rmodel.py pypy/dist/pypy/rpython/test/test_rstr.py Log: A test that passes anyway, and a fix for some other problem that is quite hard to test explicitly :-( Modified: pypy/dist/pypy/rpython/rmodel.py ============================================================================== --- pypy/dist/pypy/rpython/rmodel.py (original) +++ pypy/dist/pypy/rpython/rmodel.py Wed Nov 8 14:37:50 2006 @@ -198,7 +198,8 @@ raise TyperError("getattr() with a non-constant attribute name") def rtype_str(self, hop): - return hop.gendirectcall(self.ll_str, hop.args_v[0]) + [v_self] = hop.inputargs(self) + return hop.gendirectcall(self.ll_str, v_self) def rtype_nonzero(self, hop): return self.rtype_is_true(hop) # can call a subclass' rtype_is_true() Modified: pypy/dist/pypy/rpython/test/test_rstr.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rstr.py (original) +++ pypy/dist/pypy/rpython/test/test_rstr.py Wed Nov 8 14:37:50 2006 @@ -573,6 +573,13 @@ res = self.interpret(fn, [1]) assert typeOf(res) == Signed + def test_call_str_on_string(self): + def fn(i): + s = "x" * i + return str(s) + res = self.interpret(fn, [3]) + assert self.ll_to_string(res) == 'xxx' + def FIXME_test_str_to_pystringobj(): def f(n): From arigo at codespeak.net Wed Nov 8 14:52:28 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 14:52:28 +0100 (CET) Subject: [pypy-svn] r34367 - pypy/dist/pypy/annotation Message-ID: <20061108135228.743E410071@code0.codespeak.net> Author: arigo Date: Wed Nov 8 14:52:26 2006 New Revision: 34367 Modified: pypy/dist/pypy/annotation/annrpython.py Log: Fix the crash in ondegenerated() that sometimes hides the real error message. Modified: pypy/dist/pypy/annotation/annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/annrpython.py (original) +++ pypy/dist/pypy/annotation/annrpython.py Wed Nov 8 14:52:26 2006 @@ -312,8 +312,8 @@ graph = position_key[0] msgstr = format_someobject_error(self, position_key, what, s_value, - called_from_graph, self.bindings[what]) - + called_from_graph, + self.bindings.get(what, "(none)")) raise AnnotatorError(msgstr) From arigo at codespeak.net Wed Nov 8 14:54:36 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 14:54:36 +0100 (CET) Subject: [pypy-svn] r34368 - in pypy/dist/pypy: interpreter objspace/flow translator/c/test Message-ID: <20061108135436.E13CE10072@code0.codespeak.net> Author: arigo Date: Wed Nov 8 14:54:35 2006 New Revision: 34368 Modified: pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/objspace/flow/specialcase.py pypy/dist/pypy/translator/c/test/test_standalone.py Log: Support for "print" in RPython. * doesn't support "print >> f". * uses str() on each item, so inherits str()'s limitations. * the output is done with os.write(1,...) but it is line-buffered. Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Wed Nov 8 14:54:35 2006 @@ -305,22 +305,22 @@ def PRINT_ITEM_TO(f): w_stream = f.valuestack.pop() w_item = f.valuestack.pop() - if w_stream == f.space.w_None: + if f.space.is_w(w_stream, f.space.w_None): w_stream = sys_stdout(f.space) # grumble grumble special cases print_item_to(f.space, w_item, w_stream) def PRINT_ITEM(f): w_item = f.valuestack.pop() - print_item_to(f.space, w_item, sys_stdout(f.space)) + print_item(f.space, w_item) def PRINT_NEWLINE_TO(f): w_stream = f.valuestack.pop() - if w_stream == f.space.w_None: + if f.space.is_w(w_stream, f.space.w_None): w_stream = sys_stdout(f.space) # grumble grumble special cases print_newline_to(f.space, w_stream) def PRINT_NEWLINE(f): - print_newline_to(f.space, sys_stdout(f.space)) + print_newline(f.space) def BREAK_LOOP(f): raise pyframe.SBreakLoop @@ -909,10 +909,18 @@ file_softspace(stream, True) print_item_to._annspecialcase_ = "specialize:argtype(0)" + def print_item(x): + print_item_to(x, sys_stdout()) + print_item._annspecialcase_ = "flowspace:print_item" + def print_newline_to(stream): stream.write("\n") file_softspace(stream, False) + def print_newline(): + print_newline_to(sys_stdout()) + print_newline._annspecialcase_ = "flowspace:print_newline" + def file_softspace(file, newflag): try: softspace = file.softspace @@ -927,7 +935,9 @@ sys_stdout = app.interphook('sys_stdout') print_expr = app.interphook('print_expr') +print_item = app.interphook('print_item') print_item_to = app.interphook('print_item_to') +print_newline = app.interphook('print_newline') print_newline_to= app.interphook('print_newline_to') file_softspace = app.interphook('file_softspace') Modified: pypy/dist/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/dist/pypy/objspace/flow/specialcase.py (original) +++ pypy/dist/pypy/objspace/flow/specialcase.py Wed Nov 8 14:54:35 2006 @@ -66,6 +66,28 @@ return dic _build = staticmethod(_build) +# _________________________________________________________________________ +# a simplified version of the basic printing routines, for RPython programs +class StdOutBuffer: + linebuf = [] +stdoutbuffer = StdOutBuffer() +def rpython_print_item(s): + buf = stdoutbuffer.linebuf + for c in s: + buf.append(c) + buf.append(' ') +def rpython_print_newline(): + buf = stdoutbuffer.linebuf + if buf: + buf[-1] = '\n' + s = ''.join(buf) + del buf[:] + else: + s = '\n' + import os + os.write(1, s) +# _________________________________________________________________________ + compiled_funcs = FunctionCache() def sc_applevel(space, app, name, args_w): @@ -73,6 +95,18 @@ if not dic: return None # signal that this is not RPython func = dic[name] + if getattr(func, '_annspecialcase_', '').startswith('flowspace:'): + # a hack to replace specific app-level helpers with simplified + # RPython versions + name = func._annspecialcase_[len('flowspace:'):] + if name == 'print_item': # more special cases... + w_s = space.do_operation('str', *args_w) + args_w = (w_s,) + func = globals()['rpython_' + name] + else: + # otherwise, just call the app-level helper and hope that it + # is RPython enough + pass return space.do_operation('simple_call', Constant(func), *args_w) def setup(space): Modified: pypy/dist/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_standalone.py (original) +++ pypy/dist/pypy/translator/c/test/test_standalone.py Wed Nov 8 14:54:35 2006 @@ -22,3 +22,28 @@ cbuilder.compile() data = cbuilder.cmdexec('hi there') assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''') + +def test_print(): + def entry_point(argv): + print "hello simpler world" + argv = argv[1:] + print "argument count:", len(argv) + print "arguments:", argv + print "argument lengths:", + print [len(s) for s in argv] + return 0 + + t = TranslationContext() + t.buildannotator().build_types(entry_point, [s_list_of_strings]) + t.buildrtyper().specialize() + + cbuilder = CStandaloneBuilder(t, entry_point) + cbuilder.generate_source() + cbuilder.compile() + data = cbuilder.cmdexec('hi there') + assert data.startswith('''hello simpler world\n''' + '''argument count: 2\n''' + '''arguments: [hi, there]\n''' + '''argument lengths: [2, 5]\n''') + # NB. RPython has only str, not repr, so str() on a list of strings + # gives the strings unquoted in the list From cfbolz at codespeak.net Wed Nov 8 15:03:41 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 8 Nov 2006 15:03:41 +0100 (CET) Subject: [pypy-svn] r34369 - pypy/dist/pypy/config Message-ID: <20061108140341.E48FB10072@code0.codespeak.net> Author: cfbolz Date: Wed Nov 8 15:03:39 2006 New Revision: 34369 Modified: pypy/dist/pypy/config/pypyoption.py Log: add vanilla option that tries to make pypy more portable. samuele to implement the actual functionality. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Wed Nov 8 15:03:39 2006 @@ -135,7 +135,6 @@ "boehm", requires={ "stacklessgc": [("translation.stackless", True)]}, cmdline="--gc"), - BoolOption("thread", "enable use of threading primitives", default=False, cmdline="--thread"), BoolOption("verbose", "Print extra information", default=False), @@ -153,6 +152,16 @@ BoolOption("debug_transform", "Perform the debug transformation", default=False, cmdline="--debug-transform", negation=False), + # portability options + BoolOption("vanilla", + "Try to be as portable as possible, which is not much", + default=False, + cmdline="--vanilla", + requires=[("translation.no__thread", True)]), + BoolOption("no__thread", + "don't use __thread for implementing TLS", + default=False, cmdline="--no__thread", negation=False), + # Flags of the TranslationContext: BoolOption("simplifying", "Simplify flow graphs", default=True), BoolOption("do_imports_immediately", "XXX", default=True, @@ -163,7 +172,7 @@ cmdline=None), ChoiceOption("fork_before", "(UNIX) Create restartable checkpoint before step", - ["annotate", "rtype", "backendopt", "database", "source"], + ["annotate", "rtype", "backendopt", "database", "source"], default=None, cmdline="--fork-before"), OptionDescription("backendopt", "Backend Optimization Options", [ From mwh at codespeak.net Wed Nov 8 15:07:06 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 8 Nov 2006 15:07:06 +0100 (CET) Subject: [pypy-svn] r34371 - pypy/dist/pypy/doc Message-ID: <20061108140706.625C910078@code0.codespeak.net> Author: mwh Date: Wed Nov 8 15:07:05 2006 New Revision: 34371 Modified: pypy/dist/pypy/doc/project-ideas.txt Log: language review + substantial rewriting of the "wp6ish" item. Modified: pypy/dist/pypy/doc/project-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/project-ideas.txt (original) +++ pypy/dist/pypy/doc/project-ideas.txt Wed Nov 8 15:07:05 2006 @@ -1,9 +1,12 @@ -Independent project ideas in PyPy -================================= +Independent project ideas relating to PyPy +========================================== PyPy allows experimentation in many directions -- indeed facilitating -experimentation in language implementation was one of the main motivations for -the project. This page is meant to collect some ideas of things to try. +experimentation in language implementation was one of the main +motivations for the project. This page is meant to collect some ideas +of experiments that the core developers have not had time to perform +yet and also do not require too much in depth knowledge to get started +with. If you are a student, maybe you will be inspired to make a proposal for our `Summer of PyPy`_ campaign: you will have an experienced PyPy developer as a @@ -20,15 +23,16 @@ Experiment with optimizations ----------------------------- -A research project: experiment with optimizations in PyPy, e.g. by trying -various **data structures** for dicts or other built-in objects, by switching -between data structures at run-time, comparing results for different -applications, etc. This should produce experimental results (mostly timings, -memory usage trade-offs) as much as code. (The point of PyPy is that we can -do this without making the interpreted applications aware of the optimization -at all.) +Although PyPy's Python interpreter is very compatible with CPython, it is not +yet as fast. There are several approaches to making it faster, including the +on-going Just-In-Time compilation efforts and improving the compilation tool +chain, but probably the most suited to being divided into reasonably sized +chunks is to play with alternate implementations of key data structures or +algorithms used by the interpreter. PyPy's structure is designed to make this +straightforward, so it is easy to provide a different implementation of, say, +dictionaries or lists without disturbing any other code. -For example, we've got working implementations of things like: +As examples, we've got working implementations of things like: * lazy string slices (slicing a string gives an object that references a part of the original string). @@ -38,52 +42,68 @@ * dictionaries specialized for string-only keys. -Other interesting ideas might be: +* dictionaries which use a different strategy when very small. + +Things we've thought about but not yet implemented include: * lists which are specialised for int-only values (for saving memory). +* some form of caching the lookups of builtin or even global names (mostly + likely by special forms of dictionaries that can invalidate the caches when + they are written to). + +Experiments of this kind are really experiments in the sense that we do not know +whether they will work well or not and the only way to find out is to try. A +project of this nature should provide benchmark results (both timing and memory +usage) as much as code. + Start or improve a back-end --------------------------- -PyPy has complete, or nearly so, back-ends for C, LLVM and CLI/.NET and -partial backends for JavaScript, Common Lisp, Squeak and the JVM. It would -be an interesting project to improve either of these partial backends, -or start one for another platform (objective C comes to mind). +PyPy has complete, or nearly so, back-ends for C, LLVM and CLI/.NET and partial +backends for JavaScript, Common Lisp, Squeak and the JVM. It would be an +interesting project to improve either of these partial backends, or start one +for another platform (Objective C comes to mind as one that should not be too +terribly hard). Improve JavaScript backend -------------------------- -A JavaScript backend is somehow different from other pypy's backends -because it does not try to support all pypy (where it might be run than?), -but rather to compile RPython programs into browser-stuff. -Some documents are in a `JavaScript whatis`_ file and a `JavaScript using`_ -file. Some project ideas might be: +The JavaScript backend is somehow different from other pypy's backends because +it does not try to support all of PyPy (where it might be run then?), but rather +to compile RPython programs into code that runs in a browser. Some documents +are in `what is PyPy.js`_ file and `using the JavaScript backend`_. Some project +ideas might be: -* Write some examples to show different possibilities of using them +* Write some examples to show different possibilities of using the backend. -* Improve facilities of testing RPython code on top of CPython, mostly - by improving existing DOM interface. +* Improve the facilities for testing RPython intended to be translated to + JavaScript on top of CPython, mostly by improving existing DOM interface. Improve one of the JIT back-ends -------------------------------- PyPy's Just-In-Time compiler relies on two assembler backends for actual code -generation: One for PowerPC and one for i386. Those two backends so far are -mostly working, but nearly no effort was made to make them produce good -assembler. This is an area where quite some improvements could be made. -Another idea in a similar vein would be to use LLVM to re-compile functions -that are particularly often used (LLVM cannot be used for *all* code +generation, one for PowerPC and the other for i386. Those two backends so far +are mostly working, but nearly no effort has been made to make them produce +efficient code. This is an area where significant improvements could be made, +hopefully without having to understand the full intricacies of the JIT. + +Another idea in a similar vein would be to use LLVM to re-compile functions that +are executed particularly frequently (LLVM cannot be used for *all* code generation, since it can only work on function at a time). Write a new front end --------------------- Write an interpreter for **another dynamic language** in the PyPy framework. -For example, a Scheme interpreter would be suitable. Ruby too (though -the latter is probably more than two months of work), or Lua, or ... +For example, a Scheme interpreter would be suitable (and it would even be +interesting from a semi-academic point of view to see if ``call/cc`` can be +implemented on top of the primitives the stackless transform provides). Ruby +too (though the latter is probably more than two months of work), or Lua, or ... -We have a somewhat useable `Prolog interpreter`_ and the beginnings of a -`JavaScript interpreter`_ +We already have a somewhat usable `Prolog interpreter`_ and the beginnings of a +`JavaScript interpreter`_. Investigate restricted execution models --------------------------------------- @@ -96,7 +116,7 @@ about safely executing limited snippets of untrusted RPython code (see http://codespeak.net/pipermail/pypy-dev/2006q2/003131.html). More general approaches, to execute general but untrusted Python code on top of PyPy, -require more design. The object space model of PyPy would easily allow +require more design. The object space model of PyPy will easily allow objects to be tagged and tracked. The translation of PyPy would also be a good place to insert e.g. systematic checks around all system calls. @@ -174,9 +194,6 @@ ...or whatever else interests you! -Note: currently it is a bit difficult for us to identify nice independent -sub-tasks in the context of the JIT compiler of PyPy... - Feel free to mention your interest and discuss these ideas on the `pypy-dev mailing list`_. You can also have a look around our documentation_. @@ -197,4 +214,4 @@ .. _`ZODB's Persistent class`: http://www.zope.org/Documentation/Books/ZDG/current/Persistence.stx .. _`JavaScript whatis`: js/whatis.html .. _`JavaScript using`: js/using.html -.. _`transparent proxy`: proxy.html \ No newline at end of file +.. _`transparent proxy`: proxy.html From mwh at codespeak.net Wed Nov 8 15:16:15 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 8 Nov 2006 15:16:15 +0100 (CET) Subject: [pypy-svn] r34372 - pypy/dist/pypy/doc Message-ID: <20061108141615.BF8DD10071@code0.codespeak.net> Author: mwh Date: Wed Nov 8 15:16:14 2006 New Revision: 34372 Modified: pypy/dist/pypy/doc/project-ideas.txt Log: fix links Modified: pypy/dist/pypy/doc/project-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/project-ideas.txt (original) +++ pypy/dist/pypy/doc/project-ideas.txt Wed Nov 8 15:16:14 2006 @@ -212,6 +212,6 @@ .. _`pypy-dev mailing list`: http://codespeak.net/mailman/listinfo/pypy-dev .. _`Summer of PyPy`: summer-of-pypy.html .. _`ZODB's Persistent class`: http://www.zope.org/Documentation/Books/ZDG/current/Persistence.stx -.. _`JavaScript whatis`: js/whatis.html -.. _`JavaScript using`: js/using.html +.. _`what is pypy.js`: js/whatis.html +.. _`using the JavaScript backend`: js/using.html .. _`transparent proxy`: proxy.html From cfbolz at codespeak.net Wed Nov 8 15:34:24 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 8 Nov 2006 15:34:24 +0100 (CET) Subject: [pypy-svn] r34373 - pypy/dist/pypy/doc Message-ID: <20061108143424.89D3F10060@code0.codespeak.net> Author: cfbolz Date: Wed Nov 8 15:34:23 2006 New Revision: 34373 Modified: pypy/dist/pypy/doc/news.txt Log: update news page about end of duesseldorf sprint Modified: pypy/dist/pypy/doc/news.txt ============================================================================== --- pypy/dist/pypy/doc/news.txt (original) +++ pypy/dist/pypy/doc/news.txt Wed Nov 8 15:34:23 2006 @@ -16,6 +16,18 @@ .. _eventhistory: eventhistory.html +Duesseldorf sprint #2, 30th October - 5th November over +================================================================== + +The Duesseldorf sprint is over. It was a very productive sprint with work done +in various areas. Read the `sprint report`_ for a detailed description of what +was achieved and the `full announcement`_ for various details. + +.. _`full announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/ddorf2006b/announce.html +.. _`sprint report`: http://codespeak.net/pipermail/pypy-dev/2006q4/003396.html + + + Dynamic Languages Symposium (OOPSLA, 23rd October) ================================================================== @@ -34,18 +46,6 @@ .. _`PyPy's approach to virtual machine construction`: http://codespeak.net/svn/pypy/extradoc/talk/dls2006/pypy-vm-construction.pdf -Duesseldorf sprint #2, 30th October - 5th November -================================================================== - -The next PyPy sprint will be held in Duesseldorf in Germany, where we -already met in June. This is a "non-core-people" friendly sprint; we -will work on any topic of interest, be it from areas we are currently -focusing on (JIT, optimizations, py.test, build tools...) or from areas -that other people would like to consider (new back-ends, distribution, -security...). Read the `full announcement`_ for more details. - -.. _`full announcement`: http://codespeak.net/pypy/extradoc/sprintinfo/ddorf2006b/announce.html - Summer of PyPy: Calls for proposals open now! ================================================================== From ericvrp at codespeak.net Wed Nov 8 16:09:13 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 8 Nov 2006 16:09:13 +0100 (CET) Subject: [pypy-svn] r34375 - in pypy/dist/pypy/jit/codegen/llvm: . test Message-ID: <20061108150913.3AC4210074@code0.codespeak.net> Author: ericvrp Date: Wed Nov 8 16:09:12 2006 New Revision: 34375 Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: implemented to call across modules test, not fully working though Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Wed Nov 8 16:09:12 2006 @@ -21,7 +21,7 @@ #So we always need to recompile the library if its platform (output of file libllvmjit.so) #differs from the current (remote) platform. #note: we can't do this in global scope because that will only be executed on the master server. -os.system('rm -rf libllvmjit.so build') +#os.system('rm -rf libllvmjit.so build') #We might want to generate an up-to-date version of the library always so running (tests) #on a clean checkout will produce correct results. Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Wed Nov 8 16:09:12 2006 @@ -27,6 +27,36 @@ ret int %n2 }''' +llacross1 = '''declare int %across2(int %n2) + +int %across1(int %n) { +block0: + %n2 = mul int %n, 3 + ret int %n2 +} + +int %across1to2(int %n) { +block0: + %n2 = add int %n, 5 + %n3 = call int %across2(int %n2) + ret int %n3 +}''' + +llacross2 = '''declare int %across1(int %n2) + +int %across2(int %n) { +block0: + %n2 = mul int %n, 7 + ret int %n2 +} + +int %across2to1(int %n) { +block0: + %n2 = add int %n, 9 + %n3 = call int %across1(int %n2) + ret int %n3 +}''' + #helpers def execute(llsource, function_name, param): assert llvmjit.compile(llsource) @@ -80,8 +110,28 @@ assert square(i) == i * i assert mul2(i) == i * 2 -def DONTtest_execute_accross_module(): - pass +def DONTtest_execute_across_module(): + def my_across1(n): + return n * 3 + + def my_across1to2(n): + return my_across2(n + 5) + + def my_across2(n): + return n * 7 + + def my_across2to1(n): + return my_across1(n + 9) + + llvmjit.restart() + llvmjit.compile(llacross1) + llvmjit.compile(llacross2) + across1to2 = llvmjit.FindFunction('across1to2') + across2to1 = llvmjit.FindFunction('across2to1') + for i in range(5): + assert across1to2(i) == my_across1to2(i) + assert across2to1(i) == my_across2to1(i) + def DONTtest_modify_global_data(): pass From arigo at codespeak.net Wed Nov 8 16:41:05 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 16:41:05 +0100 (CET) Subject: [pypy-svn] r34376 - in pypy/dist/pypy: config translator/backendopt translator/backendopt/test Message-ID: <20061108154105.E4A0C10078@code0.codespeak.net> Author: arigo Date: Wed Nov 8 16:41:04 2006 New Revision: 34376 Added: pypy/dist/pypy/translator/backendopt/removeassert.py (contents, props changed) pypy/dist/pypy/translator/backendopt/test/test_removeassert.py (contents, props changed) Modified: pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/translator/backendopt/all.py Log: A backend optimization (disabled for now) which kills the checks that go into 'raise AssertionError' branches in ll graphs. This leaves some useless computations behind (the expression in the 'assert' statement) but the hope is that the C optimizer will remove them. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Wed Nov 8 16:41:04 2006 @@ -191,6 +191,9 @@ requires=[("translation.stackless", False)]), BoolOption("clever_malloc_removal", "Remove mallocs in a clever way", default=False), + BoolOption("remove_asserts", + "Kill 'raise AssertionError', which lets the C " + "optimizer remove the asserts", default=False), IntOption("inline_threshold", "Threshold when to inline functions", default=1, cmdline=None), ]), Modified: pypy/dist/pypy/translator/backendopt/all.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/all.py (original) +++ pypy/dist/pypy/translator/backendopt/all.py Wed Nov 8 16:41:04 2006 @@ -8,6 +8,7 @@ from pypy.translator import simplify from pypy.translator.backendopt.escape import malloc_to_stack from pypy.translator.backendopt.mallocprediction import clever_inlining_and_malloc_removal +from pypy.translator.backendopt.removeassert import remove_asserts from pypy.translator.backendopt.support import log from pypy.objspace.flow.model import checkgraph @@ -15,7 +16,7 @@ # sensible keywords are # raisingop2direct_call, inline_threshold, mallocs # merge_if_blocks, constfold, heap2stack - # clever_malloc_removal + # clever_malloc_removal, remove_asserts config = translator.config.translation.backendopt.copy() config.set(**kwds) @@ -83,6 +84,9 @@ for graph in graphs: constant_fold_graph(graph) + if config.remove_asserts: + remove_asserts(translator, graphs) + if config.heap2stack: assert graphs is translator.graphs # XXX for now malloc_to_stack(translator) Added: pypy/dist/pypy/translator/backendopt/removeassert.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/backendopt/removeassert.py Wed Nov 8 16:41:04 2006 @@ -0,0 +1,38 @@ +from pypy.objspace.flow.model import Constant +from pypy.translator.simplify import eliminate_empty_blocks, join_blocks +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rclass + + +def remove_asserts(translator, graphs): + rtyper = translator.rtyper + clsdef = translator.annotator.bookkeeper.getuniqueclassdef(AssertionError) + r_AssertionError = rclass.getclassrepr(rtyper, clsdef) + ll_AssertionError = r_AssertionError.convert_const(AssertionError) + + while graphs: + pending = [] + for graph in graphs: + eliminate_empty_blocks(graph) + join_blocks(graph) + for link in graph.iterlinks(): + if (link.target is graph.exceptblock + and isinstance(link.args[0], Constant) + and link.args[0].value == ll_AssertionError): + kill_assertion_link(graph, link) + pending.append(graph) + break + graphs = pending + + +def kill_assertion_link(graph, link): + block = link.prevblock + exits = list(block.exits) + if len(exits) > 1: + exits.remove(link) + if len(exits) == 1 and block.exitswitch.concretetype is lltype.Bool: + # condition no longer necessary + block.exitswitch = None + exits[0].exitcase = None + exits[0].llexitcase = None + block.recloseblock(*exits) Added: pypy/dist/pypy/translator/backendopt/test/test_removeassert.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/backendopt/test/test_removeassert.py Wed Nov 8 16:41:04 2006 @@ -0,0 +1,62 @@ +from pypy.objspace.flow.model import summary +from pypy.translator.backendopt.removeassert import remove_asserts +from pypy.translator.backendopt.constfold import constant_fold_graph +from pypy.translator.backendopt.test import test_constfold +from pypy.translator.backendopt.test.test_constfold import check_graph + + +def get_graph(fn, signature): + graph, t = test_constfold.get_graph(fn, signature) + constant_fold_graph(graph) + return graph, t + +def contains_raise(graph): + for link in graph.iterlinks(): + if link.target is graph.exceptblock: + return True + else: + return False + +def check(fn, args, expected_result): + signature = [int] * len(args) # for now + graph, t = get_graph(fn, signature) + remove_asserts(t, [graph]) + assert not contains_raise(graph) + check_graph(graph, args, expected_result, t) + + +def test_simple(): + def fn(n): + assert n >= 1 + return n-1 + check(fn, [125], 124) + +def test_and(): + def fn(n): + assert n >= 1 and n < 10 + return n-1 + check(fn, [1], 0) + +def test_or(): + def fn(n): + assert n >= 1 or n % 2 == 0 + return n-1 + check(fn, [-120], -121) + +def test_isinstance(): + class A: + pass + class B(A): + pass + def g(n): + if n > 10: + return A() + else: + b = B() + b.value = 321 + return b + def fn(n): + x = g(n) + assert isinstance(x, B) + return x.value + check(fn, [5], 321) From niko at codespeak.net Wed Nov 8 17:04:38 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Wed, 8 Nov 2006 17:04:38 +0100 (CET) Subject: [pypy-svn] r34377 - in pypy/dist/pypy/translator: cli oosupport Message-ID: <20061108160438.D44CF1007F@code0.codespeak.net> Author: niko Date: Wed Nov 8 17:04:37 2006 New Revision: 34377 Modified: pypy/dist/pypy/translator/cli/constant.py pypy/dist/pypy/translator/cli/ilgenerator.py pypy/dist/pypy/translator/oosupport/constant.py Log: merge the definition of oosupport List and CLI List, fixing a few bugs. also move isnan and isinf to ilgenerator, where they are actually used... Modified: pypy/dist/pypy/translator/cli/constant.py ============================================================================== --- pypy/dist/pypy/translator/cli/constant.py (original) +++ pypy/dist/pypy/translator/cli/constant.py Wed Nov 8 17:04:37 2006 @@ -49,12 +49,6 @@ MAX_CONST_PER_STEP = 100 SERIALIZE = False -def isnan(v): - return v != v*1.0 or (v == 1.0 and v == 2.0) - -def isinf(v): - return v!=0 and (v == v*2) - # ______________________________________________________________________ # Constant Generators # @@ -389,55 +383,20 @@ class CLIListConst(CLIBaseConstMixin, ListConst): # Eventually code should look more like this: - #def _do_not_initialize(self): - # # Check if it is a list of all zeroes: - # try: - # if self.value._list == [0] * len(self.value._list): - # return True - # except: - # pass - # return super(CLIListConst, self)._do_not_initialize(self) - # - #def create_pointer(self, gen): - # self.db.const_count.inc('List') - # self.db.const_count.inc('List', self.value._TYPE._ITEMTYPE) - # self.db.const_count.inc('List', len(self.value._list)) - # super(CLIListConst, self).create_pointer(gen) - + def _do_not_initialize(self): + # Check if it is a list of all zeroes: + try: + if self.value._list == [0] * len(self.value._list): + return True + except: + pass + return super(CLIListConst, self)._do_not_initialize() + def create_pointer(self, gen): - assert not self.is_null() - class_name = self.get_type(False) - push_constant(self.db, ootype.Signed, len(self.value._list), gen) - gen.ilasm.new('instance void class %s::.ctor(int32)' % class_name) self.db.const_count.inc('List') self.db.const_count.inc('List', self.value._TYPE._ITEMTYPE) self.db.const_count.inc('List', len(self.value._list)) - - def _list_of_zeroes(self): - try: - return self.value._list == [0] * len(self.value._list) - except: - return False - - def initialize_data(self, gen): - assert not self.is_null() - ITEMTYPE = self.value._TYPE._ITEMTYPE - itemtype = self.cts.lltype_to_cts(ITEMTYPE) - itemtype_T = self.cts.lltype_to_cts(self.value._TYPE.ITEMTYPE_T) - - # special case: List(Void); only resize it, don't care of the contents - # special case: list of zeroes, don't need to initialize every item - if ITEMTYPE is ootype.Void or self._list_of_zeroes(): - push_constant(self.db, ootype.Signed, len(self.value._list), gen) - meth = 'void class %s::_ll_resize(int32)' % self.get_type(False) #PYPY_LIST_OF_VOID - gen.ilasm.call_method(meth, False) - return True - - for item in self.value._list: - gen.ilasm.opcode('dup') - push_constant(self.db, ITEMTYPE, item, gen) - meth = 'void class [pypylib]pypy.runtime.List`1<%s>::Add(%s)' % (itemtype, itemtype_T) - gen.ilasm.call_method(meth, False) + super(CLIListConst, self).create_pointer(gen) class CLIDictConst(CLIDictMixin, DictConst): Modified: pypy/dist/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/dist/pypy/translator/cli/ilgenerator.py (original) +++ pypy/dist/pypy/translator/cli/ilgenerator.py Wed Nov 8 17:04:37 2006 @@ -7,6 +7,12 @@ from pypy.objspace.flow import model as flowmodel from pypy.translator.cli.support import string_literal +def isnan(v): + return v != v*1.0 or (v == 1.0 and v == 2.0) + +def isinf(v): + return v!=0 and (v == v*2) + class CodeGenerator(object): def __init__(self, out, indentstep = 4, startblock = '{', endblock = '}'): self._out = out Modified: pypy/dist/pypy/translator/oosupport/constant.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/constant.py (original) +++ pypy/dist/pypy/translator/oosupport/constant.py Wed Nov 8 17:04:37 2006 @@ -560,7 +560,7 @@ gen.new(SELFTYPE) # And then resize it to the correct size - gen.dup() + gen.dup(SELFTYPE) push_constant(self.db, ootype.Signed, len(self.value._list), gen) gen.call_method(SELFTYPE, '_ll_resize') @@ -589,7 +589,7 @@ gen.dup(SELFTYPE) push_constant(self.db, ootype.Signed, idx, gen) push_constant(self.db, ITEMTYPE, item, gen) - gen.call_method(SELFFTYPE, 'll_setitem_fast') + gen.call_method(SELFTYPE, 'll_setitem_fast') # ______________________________________________________________________ # Dictionary constants From arigo at codespeak.net Wed Nov 8 17:09:55 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 17:09:55 +0100 (CET) Subject: [pypy-svn] r34378 - pypy/dist/pypy/translator/backendopt Message-ID: <20061108160955.631BF10082@code0.codespeak.net> Author: arigo Date: Wed Nov 8 17:09:54 2006 New Revision: 34378 Modified: pypy/dist/pypy/translator/backendopt/removeassert.py Log: Oups! Infinite loop. Modified: pypy/dist/pypy/translator/backendopt/removeassert.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/removeassert.py (original) +++ pypy/dist/pypy/translator/backendopt/removeassert.py Wed Nov 8 17:09:54 2006 @@ -19,9 +19,9 @@ if (link.target is graph.exceptblock and isinstance(link.args[0], Constant) and link.args[0].value == ll_AssertionError): - kill_assertion_link(graph, link) - pending.append(graph) - break + if kill_assertion_link(graph, link): + pending.append(graph) + break graphs = pending @@ -36,3 +36,6 @@ exits[0].exitcase = None exits[0].llexitcase = None block.recloseblock(*exits) + return True + else: + return False From arigo at codespeak.net Wed Nov 8 17:28:45 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 17:28:45 +0100 (CET) Subject: [pypy-svn] r34380 - in pypy/dist/pypy/translator/backendopt: . test Message-ID: <20061108162845.15BB71007B@code0.codespeak.net> Author: arigo Date: Wed Nov 8 17:28:35 2006 New Revision: 34380 Modified: pypy/dist/pypy/translator/backendopt/removeassert.py pypy/dist/pypy/translator/backendopt/test/test_removeassert.py Log: Got reminded by cfbolz that we have a way to melt low-level operations away. Hum. Modified: pypy/dist/pypy/translator/backendopt/removeassert.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/removeassert.py (original) +++ pypy/dist/pypy/translator/backendopt/removeassert.py Wed Nov 8 17:28:35 2006 @@ -1,5 +1,6 @@ from pypy.objspace.flow.model import Constant from pypy.translator.simplify import eliminate_empty_blocks, join_blocks +from pypy.translator.simplify import transform_dead_op_vars from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem import rclass @@ -10,6 +11,7 @@ r_AssertionError = rclass.getclassrepr(rtyper, clsdef) ll_AssertionError = r_AssertionError.convert_const(AssertionError) + modified = {} while graphs: pending = [] for graph in graphs: @@ -20,9 +22,13 @@ and isinstance(link.args[0], Constant) and link.args[0].value == ll_AssertionError): if kill_assertion_link(graph, link): + modified[graph] = True pending.append(graph) break graphs = pending + # now melt away the (hopefully) dead operation that compute the condition + for graph in modified: + transform_dead_op_vars(graph, translator) def kill_assertion_link(graph, link): Modified: pypy/dist/pypy/translator/backendopt/test/test_removeassert.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_removeassert.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_removeassert.py Wed Nov 8 17:28:35 2006 @@ -31,6 +31,16 @@ return n-1 check(fn, [125], 124) +def test_simple_melting_away(): + def fn(n): + assert n >= 1 + return n-1 + graph, t = get_graph(fn, [int]) + assert summary(graph) == {'int_ge': 1, 'int_sub': 1} + remove_asserts(t, [graph]) + assert summary(graph) == {'int_sub': 1} + check_graph(graph, [1], 0, t) + def test_and(): def fn(n): assert n >= 1 and n < 10 From arigo at codespeak.net Wed Nov 8 17:47:43 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 17:47:43 +0100 (CET) Subject: [pypy-svn] r34381 - in pypy/dist/pypy/translator/backendopt: . test Message-ID: <20061108164743.E7DC31008A@code0.codespeak.net> Author: arigo Date: Wed Nov 8 17:47:42 2006 New Revision: 34381 Modified: pypy/dist/pypy/translator/backendopt/removeassert.py pypy/dist/pypy/translator/backendopt/test/test_removeassert.py Log: - Add logging. - A test and a fix for it. Modified: pypy/dist/pypy/translator/backendopt/removeassert.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/removeassert.py (original) +++ pypy/dist/pypy/translator/backendopt/removeassert.py Wed Nov 8 17:47:42 2006 @@ -1,8 +1,9 @@ -from pypy.objspace.flow.model import Constant +from pypy.objspace.flow.model import Constant, checkgraph, c_last_exception from pypy.translator.simplify import eliminate_empty_blocks, join_blocks from pypy.translator.simplify import transform_dead_op_vars from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem import rclass +from pypy.translator.backendopt.support import log def remove_asserts(translator, graphs): @@ -11,10 +12,11 @@ r_AssertionError = rclass.getclassrepr(rtyper, clsdef) ll_AssertionError = r_AssertionError.convert_const(AssertionError) - modified = {} - while graphs: - pending = [] - for graph in graphs: + for graph in graphs: + count = 0 + morework = True + while morework: + morework = False eliminate_empty_blocks(graph) join_blocks(graph) for link in graph.iterlinks(): @@ -22,26 +24,35 @@ and isinstance(link.args[0], Constant) and link.args[0].value == ll_AssertionError): if kill_assertion_link(graph, link): - modified[graph] = True - pending.append(graph) + count += 1 + morework = True break - graphs = pending - # now melt away the (hopefully) dead operation that compute the condition - for graph in modified: - transform_dead_op_vars(graph, translator) + if count: + # now melt away the (hopefully) dead operation that compute + # the condition + log.removeassert("removed %d asserts in %s" % (count, graph.name)) + checkgraph(graph) + transform_dead_op_vars(graph, translator) def kill_assertion_link(graph, link): block = link.prevblock exits = list(block.exits) - if len(exits) > 1: - exits.remove(link) - if len(exits) == 1 and block.exitswitch.concretetype is lltype.Bool: - # condition no longer necessary - block.exitswitch = None - exits[0].exitcase = None - exits[0].llexitcase = None - block.recloseblock(*exits) - return True - else: + if len(exits) <= 1: return False + remove_condition = len(exits) == 2 + if block.exitswitch == c_last_exception: + if link is exits[0]: + return False # cannot remove the non-exceptional path + else: + if block.exitswitch.concretetype is not lltype.Bool: # a switch + remove_condition = False + + exits.remove(link) + if remove_condition: + # condition no longer necessary + block.exitswitch = None + exits[0].exitcase = None + exits[0].llexitcase = None + block.recloseblock(*exits) + return True Modified: pypy/dist/pypy/translator/backendopt/test/test_removeassert.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/test/test_removeassert.py (original) +++ pypy/dist/pypy/translator/backendopt/test/test_removeassert.py Wed Nov 8 17:47:42 2006 @@ -17,11 +17,11 @@ else: return False -def check(fn, args, expected_result): +def check(fn, args, expected_result, remaining_raise=False): signature = [int] * len(args) # for now graph, t = get_graph(fn, signature) remove_asserts(t, [graph]) - assert not contains_raise(graph) + assert contains_raise(graph) == remaining_raise check_graph(graph, args, expected_result, t) @@ -70,3 +70,15 @@ assert isinstance(x, B) return x.value check(fn, [5], 321) + +def test_with_exception(): + def g(n): + if n < 0: + raise ValueError + def fn(n): + try: + g(n) + assert False + except ValueError: + return 42 + check(fn, [-8], 42, remaining_raise=True) From mwh at codespeak.net Wed Nov 8 17:50:26 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 8 Nov 2006 17:50:26 +0100 (CET) Subject: [pypy-svn] r34382 - pypy/dist/pypy/doc Message-ID: <20061108165026.9A03C1008F@code0.codespeak.net> Author: mwh Date: Wed Nov 8 17:50:25 2006 New Revision: 34382 Modified: pypy/dist/pypy/doc/stackless.txt Log: small wording improvements, couple of xxxs Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Wed Nov 8 17:50:25 2006 @@ -53,29 +53,29 @@ has shown, so supporting this would probably be reasonably easy. An interesting point is that the same ``stackless`` module can provide -three different concurrency paradigms at the same time. From a -theoretical point of view, none of these three paradigms considered -alone is new: two of them are from previous Python work, and the third -one is a quite classical coroutine variant. The new part is that the -PyPy implementation manages to provide all of them and let the user -implement more. Moreover - and this might be an important theoretical -contribution of this work - we manage to provide these concurrency -concepts in a "composable" way. In other words, it is possible to -naturally mix in a single application multiple concurrency paradigms, -and multiple unrelated usages of the same paradigm. This is detailed in -the Composability_ section below. +a number of different concurrency paradigms at the same time. From a +theoretical point of view, none of above-mentioned existing three +paradigms considered on its own is new: two of them are from previous +Python work, and the third one is a variant of the classical coroutine. +The new part is that the PyPy implementation manages to provide all of +them and let the user implement more. Moreover - and this might be an +important theoretical contribution of this work - we manage to provide +these concurrency concepts in a "composable" way. In other words, it +is possible to naturally mix in a single application multiple +concurrency paradigms, and multiple unrelated usages of the same +paradigm. This is discussed in the Composability_ section below. Coroutines ++++++++++ -A Coroutine is similar to a microthread, with no preemptive scheduling. -Within a family of coroutines, the execution can be explicitly -transferred from one to another by the user. When execution is -transferred to a coroutine, it starts executing some Python code. When -execution is transferred away from it, it is temporarily suspended. -When the execution comes back to it, it resumes its execution from the -point where it was suspend. Conceptually, only one coroutine is +A Coroutine is similar to a very small thread, with no preemptive scheduling. +Within a family of coroutines, the flow of execution is explicitly +transferred from one to another by the programmer. When execution is +transferred to a coroutine, it begins to execute some Python code. When +it transfers execution away from itself it is temporarily suspended, and +when execution returns to it it resumes its execution from the +point where it was suspended. Conceptually, only one coroutine is actively running at any given time (but see Composability_ below). The ``stackless.coroutine`` class is instantiated with no argument. @@ -119,7 +119,7 @@ The ``stackless`` module also provides an interface that is roughly compatible with the interface of the ``stackless`` module in `Stackless Python`_: it contains ``stackless.tasklet`` and ``stackless.channel`` -classes. Tasklets are similar to microthreads, but (like coroutines) +classes. Tasklets are also similar to microthreads, but (like coroutines) they don't actually run in parallel with other microthreads; instead, they synchronize and exchange data with each other over Channels, and these exchanges determine which Tasklet runs next. @@ -129,12 +129,12 @@ Note that Tasklets and Channels are implemented at application-level in `pypy/lib/stackless.py`_ on top of coroutines_. You can refer to this -module for more details and the actual documentation. +module for more details and API documentation. The stackless.py code tries to resemble the stackless C code as much as possible. This makes the code somewhat unpythonic. -Bird eyes view of tasklets and channels +Bird's eye view of tasklets and channels ---------------------------------------- Tasklets are a bit like threads: they encapsulate a function in such a way that @@ -147,16 +147,16 @@ Communication between tasklets is done via channels. There are three ways for a tasklet to give up control: -1. call ``schedule()`` +1. call ``stackless.schedule()`` 2. send something over a channel 3. receive something from a channel -A (living) tasklet can either be running, or wait to get scheduled, or be +A (live) tasklet can either be running, waiting to get scheduled, or be blocked by a channel. -Scheduling is done in strictly round-robin manner. A blocked tasklet is -removed from the scheduling queue and a blocked tasklet will be -reinserted into the queue when it becomes unblocked. +Scheduling is done in strictly round-robin manner. A blocked tasklet +is removed from the scheduling queue and will be reinserted when it +becomes unblocked. Greenlets @@ -222,6 +222,8 @@ interface that allows an RPython program to artifically rebuild a chain of calls in a reflective way, completely from scratch, and jump to it. +XXX examples, limitations? + Coroutine Cloning +++++++++++++++++ @@ -274,11 +276,12 @@ current pool cause the target objects to be recursively copied; pointers outside the current pool are simply shared. +XXX examples? might be hard... Composability +++++++++++++ -Although coroutines exist since a long time, they have not been +Although the concept of coroutines is far from new, they have not been generally integrated into mainstream languages, or only in limited form (like generators in Python and iterators C#). We can argue that a possible reason for that is that they do not scale well when a program's From niko at codespeak.net Wed Nov 8 17:50:37 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Wed, 8 Nov 2006 17:50:37 +0100 (CET) Subject: [pypy-svn] r34383 - pypy/dist/pypy/translator/jvm Message-ID: <20061108165037.AE7B610092@code0.codespeak.net> Author: niko Date: Wed Nov 8 17:50:35 2006 New Revision: 34383 Modified: pypy/dist/pypy/translator/jvm/database.py pypy/dist/pypy/translator/jvm/generator.py pypy/dist/pypy/translator/jvm/genjvm.py Log: fix a remarkable number of tests by removing code which walked the directory to find the set of jasmin files to compile and replacing it with code that tracks which .j files we create, and then just iterates over this list. this prevents one bad test from leaving an uncompilable .j file and thus breaking the following tests. Modified: pypy/dist/pypy/translator/jvm/database.py ============================================================================== --- pypy/dist/pypy/translator/jvm/database.py (original) +++ pypy/dist/pypy/translator/jvm/database.py Wed Nov 8 17:50:35 2006 @@ -26,6 +26,7 @@ OODatabase.__init__(self, genoo) # Private attributes: + self._jasmin_files = [] # list of strings --- .j files we made self._classes = {} # Maps ootype class objects to node.Class objects, # and JvmType objects as well self._functions = {} # graph -> jvmgen.Method @@ -59,6 +60,14 @@ assert isinstance(jtype, jvmtype.JvmClassType) return jtype.name + def add_jasmin_file(self, jfile): + """ Adds to the list of files we need to run jasmin on """ + self._jasmin_files.append(jfile) + + def jasmin_files(self): + """ Returns list of files we need to run jasmin on """ + return self._jasmin_files + # _________________________________________________________________ # Node Creation # Modified: pypy/dist/pypy/translator/jvm/generator.py ============================================================================== --- pypy/dist/pypy/translator/jvm/generator.py (original) +++ pypy/dist/pypy/translator/jvm/generator.py Wed Nov 8 17:50:35 2006 @@ -961,6 +961,7 @@ os.makedirs(jdir) except OSError: pass self.curclass.file = open(jfile, 'w') + self.db.add_jasmin_file(jfile) # Write the JasminXT header self.curclass.out(".class public %s\n" % iclassnm) Modified: pypy/dist/pypy/translator/jvm/genjvm.py ============================================================================== --- pypy/dist/pypy/translator/jvm/genjvm.py (original) +++ pypy/dist/pypy/translator/jvm/genjvm.py Wed Nov 8 17:50:35 2006 @@ -67,12 +67,14 @@ 'tmpdir' --- the base directory where the sources are located 'package' --- the package the sources are in; if package is pypy.jvm, then we expect to find the sources in $tmpdir/pypy/jvm + 'jfiles' --- list of files we need to run jasmin on """ self.tmpdir = tmpdir self.package = package self.compiled = False + self.jasmin_files = None - # Compute directory where .java files are + # Compute directory where .j files are self.javadir = self.tmpdir for subpkg in package.split('.'): self.javadir = self.javadir.join(subpkg) @@ -80,6 +82,9 @@ # Compute directory where .class files should go self.classdir = self.javadir + def set_jasmin_files(self, jfiles): + self.jasmin_files = jfiles + def _invoke(self, args, allow_stderr): subp = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -93,24 +98,22 @@ """ Compiles the .java sources into .class files, ready for execution. """ - javacmd = [getoption('jasmin'), '-d', str(self.javadir)] - pypydir = self.javadir.join("pypy") # HACK; should do recursive - javafiles = [str(f) for f in pypydir.listdir() - if str(f).endswith('.j')] - - for javafile in javafiles: - print "Invoking jasmin on %s" % javafile - self._invoke(javacmd+[javafile], False) + jascmd = [getoption('jasmin'), '-d', str(self.javadir)] + for jasfile in self.jasmin_files: + print "Invoking jasmin on %s" % jasfile + self._invoke(jascmd+[jasfile], False) # HACK: compile the Java helper class. Should eventually # use rte.py - sl = __file__.rindex('/') - javasrc = __file__[:sl]+"/src/PyPy.java" - self._invoke([getoption('javac'), - '-nowarn', - '-d', str(self.javadir), - javasrc], - True) + pypycls = self.classdir.join('PyPy.class') + if not os.path.exists(str(pypycls)): + sl = __file__.rindex('/') + javasrc = __file__[:sl]+"/src/PyPy.java" + self._invoke([getoption('javac'), + '-nowarn', + '-d', str(self.classdir), + javasrc], + True) self.compiled = True @@ -190,6 +193,7 @@ """ Creates the sources, and returns a JvmGeneratedSource object for manipulating them """ GenOO.generate_source(self) + self.jvmsrc.set_jasmin_files(self.db.jasmin_files()) return self.jvmsrc def create_assembler(self): From arigo at codespeak.net Wed Nov 8 18:02:31 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 18:02:31 +0100 (CET) Subject: [pypy-svn] r34384 - pypy/dist/pypy/translator/backendopt Message-ID: <20061108170231.2FA7510070@code0.codespeak.net> Author: arigo Date: Wed Nov 8 18:02:30 2006 New Revision: 34384 Modified: pypy/dist/pypy/translator/backendopt/removeassert.py Log: Improve log. Modified: pypy/dist/pypy/translator/backendopt/removeassert.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/removeassert.py (original) +++ pypy/dist/pypy/translator/backendopt/removeassert.py Wed Nov 8 18:02:30 2006 @@ -27,6 +27,8 @@ count += 1 morework = True break + else: + log.removeassert("cannot remove an assert from %s" % (graph.name,)) if count: # now melt away the (hopefully) dead operation that compute # the condition From arigo at codespeak.net Wed Nov 8 19:10:59 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 19:10:59 +0100 (CET) Subject: [pypy-svn] r34388 - pypy/dist/lib-python Message-ID: <20061108181059.5DD6D10071@code0.codespeak.net> Author: arigo Date: Wed Nov 8 19:10:58 2006 New Revision: 34388 Modified: pypy/dist/lib-python/conftest.py Log: Remove 'uselibfile' here too. Modified: pypy/dist/lib-python/conftest.py ============================================================================== --- pypy/dist/lib-python/conftest.py (original) +++ pypy/dist/lib-python/conftest.py Wed Nov 8 19:10:58 2006 @@ -286,17 +286,16 @@ class RegrTest: """ Regression Test Declaration.""" def __init__(self, basename, enabled=False, dumbtest=False, - oldstyle=False, core=False, uselibfile=False, + oldstyle=False, core=False, compiler=None, usemodules = ''): self.basename = basename self.enabled = enabled self.dumbtest = dumbtest - # we have to determine oldstyle and uselibfile values + # we have to determine the value of oldstyle # lazily because at RegrTest() call time the command # line options haven't been parsed! self._oldstyle = oldstyle - self._uselibfile = uselibfile self._usemodules = usemodules.split() self._compiler = compiler self.core = core @@ -305,10 +304,6 @@ return self._oldstyle or pypy_option.oldstyle oldstyle = property(oldstyle) - def uselibfile(self): - return self._uselibfile or pypy_option.uselibfile - uselibfile = property(uselibfile) - def usemodules(self): return self._usemodules + pypy_option.usemodules usemodules = property(usemodules) @@ -319,7 +314,7 @@ def getoptions(self): l = [] - for name in 'oldstyle', 'core', 'uselibfile': + for name in 'oldstyle', 'core': if getattr(self, name): l.append(name) for name in self.usemodules: @@ -361,13 +356,6 @@ assert fspath.check() if self.oldstyle: space.enable_old_style_classes_as_default_metaclass() - if self.uselibfile: - w_original_faked_file = space.appexec([], '''(): - from _file import file - prev = __builtins__.file - __builtins__.file = __builtins__.open = file - return prev - ''') try: modname = fspath.purebasename space.appexec([], '''(): @@ -378,10 +366,6 @@ ''' % locals()) finally: space.enable_new_style_classes_as_default_metaclass() - if self.uselibfile: - space.appexec([w_original_faked_file], '''(prev): - __builtins__.file = __builtins__.open = prev - ''') testmap = [ RegrTest('test___all__.py', enabled=True, core=True), @@ -493,7 +477,7 @@ RegrTest('test_exceptions.py', enabled=True, core=True), RegrTest('test_extcall.py', enabled=True, core=True), RegrTest('test_fcntl.py', enabled=False, dumbtest=1), - RegrTest('test_file.py', enabled=True, dumbtest=1, usemodules="posix", core=True, uselibfile=True), + RegrTest('test_file.py', enabled=True, dumbtest=1, usemodules="posix", core=True), RegrTest('test_filecmp.py', enabled=True, core=True), RegrTest('test_fileinput.py', enabled=True, dumbtest=1, core=True), RegrTest('test_fnmatch.py', enabled=True, core=True), @@ -546,7 +530,7 @@ RegrTest('test_inspect.py', enabled=True, dumbtest=1), RegrTest('test_ioctl.py', enabled=False), RegrTest('test_isinstance.py', enabled=True, core=True), - RegrTest('test_iter.py', enabled=True, core=True, uselibfile=True), + RegrTest('test_iter.py', enabled=True, core=True), #rev 10840: Uncaught interp-level exception: Same place as test_cfgparser RegrTest('test_iterlen.py', enabled=True, core=True), RegrTest('test_itertools.py', enabled=True, core=True), @@ -892,8 +876,6 @@ if option.use_compiled: py.test.skip("old-style classes not available in pypy-c") pypy_options.append('--oldstyle') - if regrtest.uselibfile: - pypy_options.append('--uselibfile') if regrtest.compiler: pypy_options.append('--compiler=%s' % regrtest.compiler) pypy_options.extend( From pedronis at codespeak.net Wed Nov 8 19:20:58 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 8 Nov 2006 19:20:58 +0100 (CET) Subject: [pypy-svn] r34389 - in pypy/dist/pypy/translator/c: . src Message-ID: <20061108182058.B600710071@code0.codespeak.net> Author: pedronis Date: Wed Nov 8 19:20:56 2006 New Revision: 34389 Modified: pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/c/src/thread.h Log: implement the behavior for --no__thread (implied by --vanilla) Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Wed Nov 8 19:20:56 2006 @@ -141,7 +141,8 @@ symboltable = self.symboltable) else: if CBuilder.have___thread: - defines['HAVE___THREAD'] = 1 + if not self.config.translation.no__thread: + defines['USE___THREAD'] = 1 cfile, extra = gen_source_standalone(db, modulename, targetdir, entrypointname = pfname, defines = defines) @@ -389,7 +390,7 @@ def gen_readable_parts_of_source(self, f): if py.std.sys.platform != "win32": - split_criteria_big = SPLIT_CRITERIA * 4 + split_criteria_big = SPLIT_CRITERIA * 4 else: split_criteria_big = SPLIT_CRITERIA if self.one_source_file: 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 Wed Nov 8 19:20:56 2006 @@ -18,7 +18,7 @@ #include "thread_nt.h" #endif -#ifdef HAVE___THREAD +#ifdef USE___THREAD #define RPyThreadStaticTLS __thread void * #define RPyThreadStaticTLS_Create(tls) NULL From arigo at codespeak.net Wed Nov 8 19:27:12 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 19:27:12 +0100 (CET) Subject: [pypy-svn] r34390 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20061108182712.C395510078@code0.codespeak.net> Author: arigo Date: Wed Nov 8 19:27:11 2006 New Revision: 34390 Modified: pypy/dist/pypy/objspace/std/longobject.py pypy/dist/pypy/objspace/std/test/test_longobject.py Log: An exception case that got lost during the rlong refactoring. Modified: pypy/dist/pypy/objspace/std/longobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/longobject.py (original) +++ pypy/dist/pypy/objspace/std/longobject.py Wed Nov 8 19:27:11 2006 @@ -139,6 +139,9 @@ except ZeroDivisionError: raise OperationError(space.w_ZeroDivisionError, space.wrap("long division or modulo by zero")) + except OverflowError: + raise OperationError(space.w_OverflowError, + space.wrap("long/long too large for a float")) def floordiv__Long_Long(space, w_long1, w_long2): try: Modified: pypy/dist/pypy/objspace/std/test/test_longobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_longobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_longobject.py Wed Nov 8 19:27:11 2006 @@ -123,4 +123,9 @@ assert long(n) == n assert str(long(n)) == str(n) - + def test_huge_longs(self): + import operator + huge = 1L << 40000L + raises(OverflowError, float, huge) + raises(OverflowError, operator.truediv, huge, 3) + raises(OverflowError, operator.truediv, huge, 3L) From ericvrp at codespeak.net Wed Nov 8 19:34:09 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 8 Nov 2006 19:34:09 +0100 (CET) Subject: [pypy-svn] r34391 - pypy/dist/pypy/translator/goal Message-ID: <20061108183409.826C41007B@code0.codespeak.net> Author: ericvrp Date: Wed Nov 8 19:34:08 2006 New Revision: 34391 Modified: pypy/dist/pypy/translator/goal/bench-cronjob.py Log: fix the thread build. Modified: pypy/dist/pypy/translator/goal/bench-cronjob.py ============================================================================== --- pypy/dist/pypy/translator/goal/bench-cronjob.py (original) +++ pypy/dist/pypy/translator/goal/bench-cronjob.py Wed Nov 8 19:34:08 2006 @@ -168,7 +168,7 @@ llvm--_objspace-std-withstrdict c c--gc=framework - c--_thread + c--thread--_objspace-std-withstrdict--profopt='-c "from richards import *;main(iterations=1)"' c--stackless c--stackless--_objspace-std-withstrdict--profopt='-c "from richards import *;main(iterations=1)"' c--profopt='-c "from richards import *;main(iterations=1)"' @@ -199,4 +199,4 @@ if args and args[0] == '--dry-run': del args[0] dry_run = True - main(*args) + main(args) From arigo at codespeak.net Wed Nov 8 19:58:28 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 19:58:28 +0100 (CET) Subject: [pypy-svn] r34392 - pypy/dist/pypy/interpreter/astcompiler/test Message-ID: <20061108185828.065741007B@code0.codespeak.net> Author: arigo Date: Wed Nov 8 19:58:27 2006 New Revision: 34392 Modified: pypy/dist/pypy/interpreter/astcompiler/test/test_ast.py Log: Remove unnecessary unpackiterable(). More friendly with py.test -A. Modified: pypy/dist/pypy/interpreter/astcompiler/test/test_ast.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/test/test_ast.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/test/test_ast.py Wed Nov 8 19:58:27 2006 @@ -59,7 +59,7 @@ class AppTestMutate: def setup_class(cls): - cls.w_BaseVisitor, = cls.space.unpackiterable(cls.space.appexec([], '''(): + cls.w_BaseVisitor = cls.space.appexec([], '''(): class BaseVisitor: def __getattr__(self, attr): if attr.startswith('visit'): @@ -68,7 +68,7 @@ raise AttributeError(attr) def default(self, node): return node - return BaseVisitor,''')) + return BaseVisitor''') def test_mutate_add(self): import parser From arigo at codespeak.net Wed Nov 8 20:04:17 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 20:04:17 +0100 (CET) Subject: [pypy-svn] r34394 - pypy/dist/pypy/interpreter/test Message-ID: <20061108190417.C42C41007C@code0.codespeak.net> Author: arigo Date: Wed Nov 8 20:04:16 2006 New Revision: 34394 Modified: pypy/dist/pypy/interpreter/test/test_pickle.py Log: Skip this file with -A. Modified: pypy/dist/pypy/interpreter/test/test_pickle.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_pickle.py (original) +++ pypy/dist/pypy/interpreter/test/test_pickle.py Wed Nov 8 20:04:16 2006 @@ -1,3 +1,6 @@ +import py +from pypy import conftest + def _attach_helpers(space): from pypy.interpreter import pytraceback def hide_top_frame(space, w_frame): @@ -46,6 +49,8 @@ class AppTestInterpObjectPickling: def setup_class(cls): + if conftest.option.runappdirect: + py.test.skip("not for py.test -A") _attach_helpers(cls.space) def teardown_class(cls): From mwh at codespeak.net Wed Nov 8 20:09:37 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 8 Nov 2006 20:09:37 +0100 (CET) Subject: [pypy-svn] r34395 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061108190937.9C4DC1007C@code0.codespeak.net> Author: mwh Date: Wed Nov 8 20:09:36 2006 New Revision: 34395 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: remove a pointless indirection Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Wed Nov 8 20:09:36 2006 @@ -433,7 +433,7 @@ return self._compare('ne', gv_x, gv_y) def _jump(self, gv_condition, if_true): - targetbuilder = self._fork() + targetbuilder = self.rgenop.openbuilder() targetaddr = targetbuilder.asm.mc.tell() @@ -452,9 +452,6 @@ def jump_if_true(self, gv_condition): return self._jump(gv_condition, True) - def _fork(self): - return self.rgenop.openbuilder() - class RPPCGenOp(AbstractRGenOp): From arigo at codespeak.net Wed Nov 8 21:16:27 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 21:16:27 +0100 (CET) Subject: [pypy-svn] r34397 - pypy/dist/pypy/interpreter/test Message-ID: <20061108201627.D8BCC1006F@code0.codespeak.net> Author: arigo Date: Wed Nov 8 21:16:27 2006 New Revision: 34397 Modified: pypy/dist/pypy/interpreter/test/test_compiler.py Log: argh, nested scopes in our Python compiler are a MESS Modified: pypy/dist/pypy/interpreter/test/test_compiler.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_compiler.py (original) +++ pypy/dist/pypy/interpreter/test/test_compiler.py Wed Nov 8 21:16:27 2006 @@ -465,6 +465,25 @@ space.raises_w(space.w_SyntaxError, self.compiler.compile, snippet, '', 'exec', 0) + def test_really_nested_stuff(self): + py.test.skip("argh, scopes are a MESS") + space = self.space + snippet = str(py.code.Source(r''' + def f(self): + def get_nested_class(): + self + class Test: + def _STOP_HERE_(self): + return _STOP_HERE_(self) + get_nested_class() + f(42) + ''')) + code = self.compiler.compile(snippet, '', 'exec', 0) + space = self.space + w_d = space.newdict() + space.exec_(code, w_d, w_d) + # assert did not crash + class TestECCompiler(BaseTestCompiler): def setup_method(self, method): self.compiler = self.space.getexecutioncontext().compiler From pedronis at codespeak.net Wed Nov 8 22:15:53 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 8 Nov 2006 22:15:53 +0100 (CET) Subject: [pypy-svn] r34398 - in pypy/dist/pypy/interpreter: astcompiler test Message-ID: <20061108211553.9A2FC10063@code0.codespeak.net> Author: pedronis Date: Wed Nov 8 22:15:51 2006 New Revision: 34398 Modified: pypy/dist/pypy/interpreter/astcompiler/symbols.py pypy/dist/pypy/interpreter/test/test_compiler.py Log: tentative fix Modified: pypy/dist/pypy/interpreter/astcompiler/symbols.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/symbols.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/symbols.py Wed Nov 8 22:15:51 2006 @@ -144,7 +144,7 @@ if name in self.frees: del self.frees[name] for child in self.children: - if child.check_name(name) == SC_FREE: + if child.check_name(name) == SC_FREE or isinstance(child, ClassScope): child.force_global(name) def add_frees(self, names): Modified: pypy/dist/pypy/interpreter/test/test_compiler.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_compiler.py (original) +++ pypy/dist/pypy/interpreter/test/test_compiler.py Wed Nov 8 22:15:51 2006 @@ -466,7 +466,6 @@ snippet, '', 'exec', 0) def test_really_nested_stuff(self): - py.test.skip("argh, scopes are a MESS") space = self.space snippet = str(py.code.Source(r''' def f(self): From arigo at codespeak.net Wed Nov 8 22:48:12 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 22:48:12 +0100 (CET) Subject: [pypy-svn] r34399 - pypy/dist/pypy/interpreter Message-ID: <20061108214812.740DC10068@code0.codespeak.net> Author: arigo Date: Wed Nov 8 22:48:10 2006 New Revision: 34399 Modified: pypy/dist/pypy/interpreter/opcodeorder.py (props changed) Log: Remove pointless property svn:executable on this file. From fijal at codespeak.net Wed Nov 8 22:54:06 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 8 Nov 2006 22:54:06 +0100 (CET) Subject: [pypy-svn] r34400 - pypy/dist/pypy/translator/js/examples Message-ID: <20061108215406.DC09710068@code0.codespeak.net> Author: fijal Date: Wed Nov 8 22:54:05 2006 New Revision: 34400 Modified: pypy/dist/pypy/translator/js/examples/console.py Log: Tag console explicitely to be not working. Modified: pypy/dist/pypy/translator/js/examples/console.py ============================================================================== --- pypy/dist/pypy/translator/js/examples/console.py (original) +++ pypy/dist/pypy/translator/js/examples/console.py Wed Nov 8 22:54:05 2006 @@ -63,7 +63,9 @@ #console.onload(data_field) get_document().onkeypress = onchange #get_document().onkeyup = onchangedown - + + print "It's not working" + raise SystemExit() fn = compile_function(some_fun, [], root = ConsoleRoot, run_browser = True) fn() From arigo at codespeak.net Wed Nov 8 23:06:30 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 8 Nov 2006 23:06:30 +0100 (CET) Subject: [pypy-svn] r34401 - in pypy/dist/pypy: module/posix module/signal/test rpython translator/c/src Message-ID: <20061108220630.4A6F41006F@code0.codespeak.net> Author: arigo Date: Wed Nov 8 23:06:27 2006 New Revision: 34401 Modified: pypy/dist/pypy/module/posix/__init__.py pypy/dist/pypy/module/signal/test/test_interp_signal.py pypy/dist/pypy/module/signal/test/test_signal.py pypy/dist/pypy/rpython/extfunctable.py pypy/dist/pypy/translator/c/src/ll_os.h Log: No os.kill() on Windows (thanks Lameiro). Modified: pypy/dist/pypy/module/posix/__init__.py ============================================================================== --- pypy/dist/pypy/module/posix/__init__.py (original) +++ pypy/dist/pypy/module/posix/__init__.py Wed Nov 8 23:06:27 2006 @@ -47,7 +47,6 @@ 'chmod' : 'interp_posix.chmod', 'rename' : 'interp_posix.rename', '_exit' : 'interp_posix._exit', - 'kill' : 'interp_posix.kill', #'getuid' : 'interp_posix.getuid', #'geteuid' : 'interp_posix.geteuid', } @@ -57,6 +56,8 @@ interpleveldefs['putenv'] = 'interp_posix.putenv' if hasattr(posix, 'unsetenv'): # note: emulated in os interpleveldefs['unsetenv'] = 'interp_posix.unsetenv' + if hasattr(os, 'kill'): + interpleveldefs['kill'] = 'interp_posix.kill' if hasattr(os, 'getpid'): interpleveldefs['getpid'] = 'interp_posix.getpid' if hasattr(os, 'link'): Modified: pypy/dist/pypy/module/signal/test/test_interp_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/test/test_interp_signal.py (original) +++ pypy/dist/pypy/module/signal/test/test_interp_signal.py Wed Nov 8 23:06:27 2006 @@ -1,7 +1,11 @@ -import os +import os, py from pypy.translator.c.test.test_genc import compile from pypy.module.signal import interp_signal +def setup_module(mod): + if not hasattr(os, 'kill') or not hasattr(os, 'getpid'): + py.test.skip("requires os.kill() and os.getpid()") + def check(expected): res = interp_signal.pypysig_poll() Modified: pypy/dist/pypy/module/signal/test/test_signal.py ============================================================================== --- pypy/dist/pypy/module/signal/test/test_signal.py (original) +++ pypy/dist/pypy/module/signal/test/test_signal.py Wed Nov 8 23:06:27 2006 @@ -1,8 +1,11 @@ +import os from pypy.conftest import gettestobjspace class AppTestSignal: def setup_class(cls): + if not hasattr(os, 'kill') or not hasattr(os, 'getpid'): + py.test.skip("requires os.kill() and os.getpid()") space = gettestobjspace(usemodules=['signal']) cls.space = space cls.w_signal = space.appexec([], "(): import signal; return signal") Modified: pypy/dist/pypy/rpython/extfunctable.py ============================================================================== --- pypy/dist/pypy/rpython/extfunctable.py (original) +++ pypy/dist/pypy/rpython/extfunctable.py Wed Nov 8 23:06:27 2006 @@ -217,7 +217,8 @@ declare(os.chmod , noneannotation, 'll_os/chmod') declare(os.rename , noneannotation, 'll_os/rename') declare(os._exit , noneannotation, 'll_os/_exit') -declare(os.kill , noneannotation, 'll_os/kill') +if hasattr(os, 'kill'): + declare(os.kill , noneannotation, 'll_os/kill') if hasattr(os, 'getpid'): declare(os.getpid , int, 'll_os/getpid') if hasattr(os, 'link'): Modified: pypy/dist/pypy/translator/c/src/ll_os.h ============================================================================== --- pypy/dist/pypy/translator/c/src/ll_os.h (original) +++ pypy/dist/pypy/translator/c/src/ll_os.h Wed Nov 8 23:06:27 2006 @@ -344,12 +344,14 @@ return getpid(); } +#ifdef HAVE_KILL void LL_os_kill(int pid, int sig) { int error = kill(pid, sig); if (error != 0) { RPYTHON_RAISE_OSERROR(errno); } } +#endif #ifdef HAVE_FILESYSTEM_WITH_LINKS From fijal at codespeak.net Wed Nov 8 23:13:14 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 8 Nov 2006 23:13:14 +0100 (CET) Subject: [pypy-svn] r34402 - pypy/dist/pypy/translator/js/demo/jsdemo Message-ID: <20061108221314.CE5EB1006F@code0.codespeak.net> Author: fijal Date: Wed Nov 8 23:13:13 2006 New Revision: 34402 Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Log: Fixed multiline appearance. Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Wed Nov 8 23:13:13 2006 @@ -16,6 +16,7 @@ from pypy.translator.js.main import rpython2javascript from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy +from pypy.translator.js.modules.mochikit import createLoggingPane, log commproxy.USE_MOCHIKIT = True @@ -70,6 +71,13 @@ data_elem = get_document().getElementById("data") data_elem.innerHTML += text +class Storage(object): + def __init__(self): + self.level = 0 + self.cmd = "" + +storage = Storage() + def keypressed(key): kc = key.keyCode if kc == ord("\r"): @@ -77,10 +85,18 @@ cmd = inp_elem.value add_text(">>> %s\n" % (cmd,)) inp_elem.value = '' - inp_elem.disabled = True - httpd.some_callback(cmd, callback) + storage.cmd += cmd + "\n" + if cmd.endswith(':'): + storage.level += 1 + elif storage.level == 0: + inp_elem.disabled = True + httpd.some_callback(storage.cmd, callback) + storage.cmd = "" + else: + storage.level -= 1 def setup_page(): + createLoggingPane(True) get_document().onkeypress = keypressed class Server(HTTPServer, BasicExternal): From fijal at codespeak.net Wed Nov 8 23:23:01 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 8 Nov 2006 23:23:01 +0100 (CET) Subject: [pypy-svn] r34403 - pypy/dist/pypy/translator/js/demo/jsdemo Message-ID: <20061108222301.07E2B10068@code0.codespeak.net> Author: fijal Date: Wed Nov 8 23:23:00 2006 New Revision: 34403 Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Log: Proper multiline support. Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Wed Nov 8 23:23:00 2006 @@ -16,7 +16,7 @@ from pypy.translator.js.main import rpython2javascript from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy -from pypy.translator.js.modules.mochikit import createLoggingPane, log +#from pypy.translator.js.modules.mochikit import createLoggingPane, log commproxy.USE_MOCHIKIT = True @@ -53,7 +53,7 @@

 
-    
+    
 
 
 
@@ -66,6 +66,7 @@
     inp_elem.disabled = False
     answer = data.get('answer', '')
     add_text(answer)
+    inp_elem.focus()
 
 def add_text(text):
     data_elem = get_document().getElementById("data")
@@ -83,21 +84,25 @@
     if kc == ord("\r"):
         inp_elem = get_document().getElementById("inp")
         cmd = inp_elem.value
-        add_text(">>> %s\n" % (cmd,))
+        if storage.level == 0:
+            add_text(">>> %s\n" % (cmd,))
+        else:
+            add_text("... %s\n" % (cmd,))
         inp_elem.value = ''
-        storage.cmd += cmd + "\n"
+        if cmd:
+            storage.cmd += cmd + "\n"
         if cmd.endswith(':'):
-            storage.level += 1
-        elif storage.level == 0:
-            inp_elem.disabled = True
-            httpd.some_callback(storage.cmd, callback)
-            storage.cmd = ""
-        else:
-            storage.level -= 1
+            storage.level = 1
+        elif storage.level == 0 or cmd == "":
+            if (not storage.level) or (not cmd):
+                inp_elem.disabled = True
+                httpd.some_callback(storage.cmd, callback)
+                storage.cmd = ""
+                storage.level = 0
 
 def setup_page():
-    createLoggingPane(True)
     get_document().onkeypress = keypressed
+    get_document().getElementById("inp").focus()
 
 class Server(HTTPServer, BasicExternal):
     # Methods and signatures how they are rendered for JS


From fijal at codespeak.net  Wed Nov  8 23:30:39 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Wed,  8 Nov 2006 23:30:39 +0100 (CET)
Subject: [pypy-svn] r34404 - in pypy/dist/pypy/translator/js: demo/jsdemo
	modules
Message-ID: <20061108223039.104431006F@code0.codespeak.net>

Author: fijal
Date: Wed Nov  8 23:30:38 2006
New Revision: 34404

Modified:
   pypy/dist/pypy/translator/js/demo/jsdemo/consserv.py
   pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py
   pypy/dist/pypy/translator/js/modules/mochikit.py
Log:
Added escapeHTML to exported functions and use this. We really need DOM tests now!!!!


Modified: pypy/dist/pypy/translator/js/demo/jsdemo/consserv.py
==============================================================================
--- pypy/dist/pypy/translator/js/demo/jsdemo/consserv.py	(original)
+++ pypy/dist/pypy/translator/js/demo/jsdemo/consserv.py	Wed Nov  8 23:30:38 2006
@@ -31,9 +31,9 @@
     def index(self):
         return dict(now=time.ctime(), onload=self.jsname, code=self.jssource)
 
+    @described(retval={'aa':'aa'}, args={'str_to_eval':"aa"})
     @turbogears.expose(format="json")
-    @described(retval={'aa':'aa'})
-    def run_command(self, str_to_eval = "aa"):
+    def run_command(self, str_to_eval):
         # we need what has changed
         # we try to run it...
         lines = str_to_eval.split("
") Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Wed Nov 8 23:30:38 2006 @@ -16,7 +16,8 @@ from pypy.translator.js.main import rpython2javascript from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy -#from pypy.translator.js.modules.mochikit import createLoggingPane, log +from pypy.translator.js.modules.mochikit import createLoggingPane, log,\ + escapeHTML commproxy.USE_MOCHIKIT = True @@ -70,7 +71,7 @@ def add_text(text): data_elem = get_document().getElementById("data") - data_elem.innerHTML += text + data_elem.innerHTML += escapeHTML(text) class Storage(object): def __init__(self): Modified: pypy/dist/pypy/translator/js/modules/mochikit.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/mochikit.py (original) +++ pypy/dist/pypy/translator/js/modules/mochikit.py Wed Nov 8 23:30:38 2006 @@ -31,3 +31,7 @@ pass logFatal.suggested_primitive = True logFatal._annspecialcase_ = "specialize:argtype(0)" + +def escapeHTML(data): + return data +escapeHTML.suggested_primitive = True From niko at codespeak.net Thu Nov 9 09:13:43 2006 From: niko at codespeak.net (niko at codespeak.net) Date: Thu, 9 Nov 2006 09:13:43 +0100 (CET) Subject: [pypy-svn] r34406 - in pypy/dist/pypy/translator: cli oosupport Message-ID: <20061109081343.2EF8D1006F@code0.codespeak.net> Author: niko Date: Thu Nov 9 09:13:40 2006 New Revision: 34406 Modified: pypy/dist/pypy/translator/cli/constant.py pypy/dist/pypy/translator/cli/ilgenerator.py pypy/dist/pypy/translator/oosupport/constant.py Log: the final (for now) iteration of the constant refactoring --- pull most of the CLI specific dictionary code into oosupport/constant.py Modified: pypy/dist/pypy/translator/cli/constant.py ============================================================================== --- pypy/dist/pypy/translator/cli/constant.py (original) +++ pypy/dist/pypy/translator/cli/constant.py Thu Nov 9 09:13:40 2006 @@ -3,15 +3,10 @@ CLI Constants This module extends the oosupport/constant.py to be specific to the -CLI. - -Currently, it is not terribly well integrated with the constant -framework. In particular, each kind of constant overloads the -create_pointer() and initialize_data() methods with some CLI-specific -stuff, rather than implementing the more general generator interface. -This allowed me to cut and paste from the old CLI code, but should -eventually be changed. I have included some commented routines -showing how the code should eventually look. +CLI. Most of the code in this file is in the constant generators, which +determine how constants are stored and loaded (static fields, lazy +initialization, etc), but some constant classes have been overloaded or +extended to allow for special handling. The CLI implementation is broken into three sections: @@ -282,64 +277,29 @@ gen.ilasm.opcode('ldnull') class CLIDictMixin(CLIBaseConstMixin): - # Eventually code should look more like this: - #def _check_for_void_dict(self, gen): - # KEYTYPE = self.value._TYPE._KEYTYPE - # keytype = self.cts.lltype_to_cts(KEYTYPE) - # keytype_T = self.cts.lltype_to_cts(self.value._TYPE.KEYTYPE_T) - # VALUETYPE = self.value._TYPE._VALUETYPE - # valuetype = self.cts.lltype_to_cts(VALUETYPE) - # valuetype_T = self.cts.lltype_to_cts(self.value._TYPE.VALUETYPE_T) - # if VALUETYPE is ootype.Void: - # class_name = PYPY_DICT_OF_VOID % keytype - # for key in self.value._dict: - # gen.ilasm.opcode('dup') - # push_constant(self.db, KEYTYPE, key, gen) - # meth = 'void class %s::ll_set(%s)' % (class_name, keytype_T) - # gen.ilasm.call_method(meth, False) - # gen.ilasm.opcode('pop') - # return True - # return False - # - #def initialize_data(self, gen): - # # special case: dict of void, ignore the values - # if _check_for_void_dict(self, gen): - # return - # return super(CLIDictMixin, self).record_dependencies() - - def initialize_data(self, gen): - assert not self.is_null() - class_name = self.get_type(False) + def _check_for_void_dict(self, gen): KEYTYPE = self.value._TYPE._KEYTYPE keytype = self.cts.lltype_to_cts(KEYTYPE) keytype_T = self.cts.lltype_to_cts(self.value._TYPE.KEYTYPE_T) - VALUETYPE = self.value._TYPE._VALUETYPE valuetype = self.cts.lltype_to_cts(VALUETYPE) valuetype_T = self.cts.lltype_to_cts(self.value._TYPE.VALUETYPE_T) - - if KEYTYPE is ootype.Void: - assert VALUETYPE is ootype.Void - return - - # special case: dict of void, ignore the values if VALUETYPE is ootype.Void: + gen.add_comment(' CLI Dictionary w/ void value') class_name = PYPY_DICT_OF_VOID % keytype for key in self.value._dict: gen.ilasm.opcode('dup') push_constant(self.db, KEYTYPE, key, gen) meth = 'void class %s::ll_set(%s)' % (class_name, keytype_T) gen.ilasm.call_method(meth, False) - return - - for key, value in self.value._dict.iteritems(): - gen.ilasm.opcode('dup') - push_constant(self.db, KEYTYPE, key, gen) - push_constant(self.db, VALUETYPE, value, gen) - meth = 'void class [pypylib]pypy.runtime.Dict`2<%s, %s>::ll_set(%s, %s)' %\ - (keytype, valuetype, keytype_T, valuetype_T) - gen.ilasm.call_method(meth, False) + return True + return False + def initialize_data(self, gen): + # special case: dict of void, ignore the values + if self._check_for_void_dict(gen): + return + return super(CLIDictMixin, self).initialize_data(gen) # ______________________________________________________________________ # Constant Classes @@ -361,7 +321,6 @@ super(CLIRecordConst, self).create_pointer(gen) class CLIInstanceConst(CLIBaseConstMixin, InstanceConst): - # Eventually code should look more like this: def create_pointer(self, gen): self.db.const_count.inc('Instance') self.db.const_count.inc('Instance', self.OOTYPE()) @@ -382,7 +341,6 @@ class CLIListConst(CLIBaseConstMixin, ListConst): - # Eventually code should look more like this: def _do_not_initialize(self): # Check if it is a list of all zeroes: try: @@ -399,19 +357,10 @@ super(CLIListConst, self).create_pointer(gen) class CLIDictConst(CLIDictMixin, DictConst): - - # Eventually code should look more like this: - #def create_pointer(self, gen): - # self.db.const_count.inc('Dict') - # self.db.const_count.inc('Dict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE) - # super(CLIDictConst, self).create_pointer(gen) - def create_pointer(self, gen): - assert not self.is_null() - class_name = self.get_type(False) - gen.ilasm.new('instance void class %s::.ctor()' % class_name) self.db.const_count.inc('Dict') self.db.const_count.inc('Dict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE) + super(CLIDictConst, self).create_pointer(gen) class CLICustomDictConst(CLIDictMixin, CustomDictConst): def record_dependencies(self): Modified: pypy/dist/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/dist/pypy/translator/cli/ilgenerator.py (original) +++ pypy/dist/pypy/translator/cli/ilgenerator.py Thu Nov 9 09:13:40 2006 @@ -273,7 +273,7 @@ self.ilasm.opcode('pop') def add_comment(self, text): - pass + self.ilasm.add_comment(text) def function_signature(self, graph, func_name=None): return self.cts.graph_to_signature(graph, False, func_name) Modified: pypy/dist/pypy/translator/oosupport/constant.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/constant.py (original) +++ pypy/dist/pypy/translator/oosupport/constant.py Thu Nov 9 09:13:40 2006 @@ -613,15 +613,18 @@ KEYTYPE = self.value._TYPE._KEYTYPE VALUETYPE = self.value._TYPE._VALUETYPE + gen.add_comment('Initializing dictionary constant') + if KEYTYPE is ootype.Void: assert VALUETYPE is ootype.Void return for key, value in self.value._dict.iteritems(): gen.dup(SELFTYPE) + gen.add_comment(' key=%r value=%r' % (key,value)) push_constant(self.db, KEYTYPE, key, gen) if VALUETYPE is ootype.Void: - # special case dict of Void + # special case dict of Void; for now store the key as value? gen.dup(KEYTYPE) else: push_constant(self.db, VALUETYPE, value, gen) From mwh at codespeak.net Thu Nov 9 11:04:45 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Nov 2006 11:04:45 +0100 (CET) Subject: [pypy-svn] r34407 - pypy/dist/pypy/doc Message-ID: <20061109100445.BFA3810072@code0.codespeak.net> Author: mwh Date: Thu Nov 9 11:04:44 2006 New Revision: 34407 Modified: pypy/dist/pypy/doc/project-ideas.txt Log: fix a typo, and another idea i had in the shower this morning. Modified: pypy/dist/pypy/doc/project-ideas.txt ============================================================================== --- pypy/dist/pypy/doc/project-ideas.txt (original) +++ pypy/dist/pypy/doc/project-ideas.txt Thu Nov 9 11:04:44 2006 @@ -48,10 +48,13 @@ * lists which are specialised for int-only values (for saving memory). -* some form of caching the lookups of builtin or even global names (mostly +* some form of caching the lookups of builtin or even global names (most likely by special forms of dictionaries that can invalidate the caches when they are written to). +* create multiple representations of Unicode string that store the character + data in narrower arrays when they can. + Experiments of this kind are really experiments in the sense that we do not know whether they will work well or not and the only way to find out is to try. A project of this nature should provide benchmark results (both timing and memory From arigo at codespeak.net Thu Nov 9 13:22:58 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 9 Nov 2006 13:22:58 +0100 (CET) Subject: [pypy-svn] r34408 - pypy/dist/pypy/jit/codegen/i386 Message-ID: <20061109122258.0EDEA10071@code0.codespeak.net> Author: arigo Date: Thu Nov 9 13:22:57 2006 New Revision: 34408 Modified: pypy/dist/pypy/jit/codegen/i386/rgenop.py Log: Trying to fix the stack alignment code for calls on the Mac/x86 machines. Modified: pypy/dist/pypy/jit/codegen/i386/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/i386/rgenop.py Thu Nov 9 13:22:57 2006 @@ -337,11 +337,15 @@ def genop_call(self, sigtoken, gv_fnptr, args_gv): MASK = CALL_ALIGN-1 - final_depth = self.stackdepth + len(args_gv) - delta = (final_depth+MASK)&~MASK-final_depth - if delta: - self.mc.SUB(esp, imm(delta*WORD)) - self.stackdepth += delta + if MASK: + final_depth = self.stackdepth + for gv_arg in args_gv: + if gv_arg is not None: + final_depth += 1 + delta = (final_depth+MASK)&~MASK-final_depth + if delta: + self.mc.SUB(esp, imm(delta*WORD)) + self.stackdepth += delta for i in range(len(args_gv)-1, -1, -1): gv_arg = args_gv[i] if gv_arg is not None: From mwh at codespeak.net Thu Nov 9 13:24:48 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Nov 2006 13:24:48 +0100 (CET) Subject: [pypy-svn] r34409 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061109122448.65F0610074@code0.codespeak.net> Author: mwh Date: Thu Nov 9 13:24:47 2006 New Revision: 34409 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: slightly less stupid stack alignment code for ppc Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Thu Nov 9 13:24:47 2006 @@ -209,7 +209,7 @@ that there are 'param' bytes of parameters for callee functions and 'lv' is the largest (wrt to abs() :) rFP-relative byte offset of any variable on the stack.""" - return ((24 + param - lv) & ~15)+16 + return ((24 + param - lv + 15) & ~15) def _close(self): self.rgenop.close_mc(self.asm.mc) From afayolle at codespeak.net Thu Nov 9 14:36:06 2006 From: afayolle at codespeak.net (afayolle at codespeak.net) Date: Thu, 9 Nov 2006 14:36:06 +0100 (CET) Subject: [pypy-svn] r34410 - pypy/dist/pypy/translator/goal Message-ID: <20061109133606.6CBA210036@code0.codespeak.net> Author: afayolle Date: Thu Nov 9 14:36:05 2006 New Revision: 34410 Modified: pypy/dist/pypy/translator/goal/targetpypystandalone.py Log: typo fix Modified: pypy/dist/pypy/translator/goal/targetpypystandalone.py ============================================================================== --- pypy/dist/pypy/translator/goal/targetpypystandalone.py (original) +++ pypy/dist/pypy/translator/goal/targetpypystandalone.py Thu Nov 9 14:36:05 2006 @@ -79,7 +79,7 @@ class PyPyTarget(object): - usage = "taget PyPy standalone" + usage = "target PyPy standalone" take_options = True From ac at codespeak.net Thu Nov 9 15:04:53 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 9 Nov 2006 15:04:53 +0100 (CET) Subject: [pypy-svn] r34411 - in pypy/dist: lib-python/modified-2.4.1/test pypy/rlib Message-ID: <20061109140453.CD9CC10075@code0.codespeak.net> Author: ac Date: Thu Nov 9 15:04:50 2006 New Revision: 34411 Added: pypy/dist/lib-python/modified-2.4.1/test/test_socket.py - copied, changed from r34251, pypy/dist/lib-python/2.4.1/test/test_socket.py Modified: pypy/dist/pypy/rlib/rsocket.py Log: Make rsocket pass test_socket.py Modified: pypy/dist/pypy/rlib/rsocket.py ============================================================================== --- pypy/dist/pypy/rlib/rsocket.py (original) +++ pypy/dist/pypy/rlib/rsocket.py Thu Nov 9 15:04:50 2006 @@ -690,7 +690,11 @@ byref(address.addr), byref(addrlen)) if read_bytes < 0: raise self.error_handler() - address.addrlen = addrlen.value + result_addrlen = addrlen.value + if result_addrlen: + address.addrlen = result_addrlen + else: + address = None return (buf[:read_bytes], address) def send(self, data, flags=0): From pedronis at codespeak.net Thu Nov 9 15:06:26 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 9 Nov 2006 15:06:26 +0100 (CET) Subject: [pypy-svn] r34412 - pypy/dist/pypy/jit/tl/test Message-ID: <20061109140626.7F1421007D@code0.codespeak.net> Author: pedronis Date: Thu Nov 9 15:06:24 2006 New Revision: 34412 Modified: pypy/dist/pypy/jit/tl/test/test_tl.py pypy/dist/pypy/jit/tl/test/test_tlr.py Log: fix distrubeted testing (execnet=threads) boehm interference Modified: pypy/dist/pypy/jit/tl/test/test_tl.py ============================================================================== --- pypy/dist/pypy/jit/tl/test/test_tl.py (original) +++ pypy/dist/pypy/jit/tl/test/test_tl.py Thu Nov 9 15:06:24 2006 @@ -3,29 +3,15 @@ from pypy.jit.tl.opcode import * from pypy.jit.conftest import Benchmark -from pypy.translator.translator import TranslationContext +from pypy.translator.c.test import test_boehm from pypy.annotation import policy -def translate(func, inputargs): - t = TranslationContext() - pol = policy.AnnotatorPolicy() - pol.allow_someobjects = False - t.buildannotator(policy=pol).build_types(func, inputargs) - t.buildrtyper().specialize() - - from pypy.translator.c import genc - builder = genc.CExtModuleBuilder(t, func) - builder.generate_source() - builder.compile() - builder.import_module() - return builder.get_entry_point() - def list2bytecode(insn): return ''.join([chr(i & 0xff) for i in insn]) # actual tests go here -class TestTL(object): +class TestTL(test_boehm.AbstractGCTestClass): from pypy.jit.tl.tl import interp interp = staticmethod(interp) @@ -52,7 +38,7 @@ def test_tl_translatable(self): code = list2bytecode([PUSH,42, PUSH,100, ADD]) - fn = translate(self.interp, [str, int, int]) + fn = self.getcompiled(self.interp, [str, int, int]) assert self.interp(code) == fn(code) def test_swap(self): @@ -249,11 +235,10 @@ break return res - fn = translate(driver, []) + fn = self.getcompiled(driver, []) res = fn() assert res == 0 # too many powers of 2 to be anything else - FACTORIAL_SOURCE = ''' PUSH 1 # accumulator PUSHARG Modified: pypy/dist/pypy/jit/tl/test/test_tlr.py ============================================================================== --- pypy/dist/pypy/jit/tl/test/test_tlr.py (original) +++ pypy/dist/pypy/jit/tl/test/test_tlr.py Thu Nov 9 15:06:24 2006 @@ -1,22 +1,25 @@ from pypy.jit.tl import tlr -from pypy.jit.tl.test.test_tl import translate from pypy.jit.conftest import Benchmark +from pypy.translator.c.test import test_boehm -def test_square(): - assert tlr.interpret(tlr.SQUARE, 1) == 1 - assert tlr.interpret(tlr.SQUARE, 7) == 49 - assert tlr.interpret(tlr.SQUARE, 9) == 81 - -def test_translate(): - def driver(): - bench = Benchmark() - while 1: - res = tlr.interpret(tlr.SQUARE, 1764) - if bench.stop(): - break - return res - - fn = translate(driver, []) - res = fn() - assert res == 1764 * 1764 + +class TestTLR(test_boehm.AbstractGCTestClass): + + def test_square(self): + assert tlr.interpret(tlr.SQUARE, 1) == 1 + assert tlr.interpret(tlr.SQUARE, 7) == 49 + assert tlr.interpret(tlr.SQUARE, 9) == 81 + + def test_translate(self): + def driver(): + bench = Benchmark() + while 1: + res = tlr.interpret(tlr.SQUARE, 1764) + if bench.stop(): + break + return res + + fn = self.getcompiled(driver, []) + res = fn() + assert res == 1764 * 1764 From afayolle at codespeak.net Thu Nov 9 16:11:49 2006 From: afayolle at codespeak.net (afayolle at codespeak.net) Date: Thu, 9 Nov 2006 16:11:49 +0100 (CET) Subject: [pypy-svn] r34417 - pypy/dist/pypy/translator/goal Message-ID: <20061109151149.9F51710089@code0.codespeak.net> Author: afayolle Date: Thu Nov 9 16:11:24 2006 New Revision: 34417 Modified: pypy/dist/pypy/translator/goal/translate.py Log: typo fix Modified: pypy/dist/pypy/translator/goal/translate.py ============================================================================== --- pypy/dist/pypy/translator/goal/translate.py (original) +++ pypy/dist/pypy/translator/goal/translate.py Thu Nov 9 16:11:24 2006 @@ -46,7 +46,7 @@ cmdline="--profile"), BoolOption("batch", "Don't run interactive helpers", default=False, cmdline="--batch", negation=False), - IntOption("huge", "Threshold in the number of functions after which" + IntOption("huge", "Threshold in the number of functions after which " "a local call graph and not a full one is displayed", default=100, cmdline="--huge"), BoolOption("text", "Don't start the pygame viewer", default=False, From ac at codespeak.net Thu Nov 9 16:44:47 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 9 Nov 2006 16:44:47 +0100 (CET) Subject: [pypy-svn] r34419 - pypy/dist/pypy/module/rsocket Message-ID: <20061109154447.F3F2810092@code0.codespeak.net> Author: ac Date: Thu Nov 9 16:44:47 2006 New Revision: 34419 Modified: pypy/dist/pypy/module/rsocket/interp_socket.py Log: Oops, forgotten change. Modified: pypy/dist/pypy/module/rsocket/interp_socket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_socket.py (original) +++ pypy/dist/pypy/module/rsocket/interp_socket.py Thu Nov 9 16:44:47 2006 @@ -217,8 +217,11 @@ data, addr = self.recvfrom(buffersize, flags) finally: if GIL is not None: GIL.acquire(True) - return space.newtuple([space.wrap(data), - addr.as_object(space)]) + if addr: + w_addr = addr.as_object(space) + else: + w_addr = space.w_None + return space.newtuple([space.wrap(data), w_addr]) except SocketError, e: raise converted_error(space, e) recvfrom_w.unwrap_spec = ['self', ObjSpace, int, int] From afayolle at codespeak.net Thu Nov 9 17:22:10 2006 From: afayolle at codespeak.net (afayolle at codespeak.net) Date: Thu, 9 Nov 2006 17:22:10 +0100 (CET) Subject: [pypy-svn] r34422 - pypy/dist/pypy/config Message-ID: <20061109162210.12E401007F@code0.codespeak.net> Author: afayolle Date: Thu Nov 9 17:22:09 2006 New Revision: 34422 Modified: pypy/dist/pypy/config/pypyoption.py Log: First shot at module dependencies. Testing in progress to check the interdependencies, in order to fill the module_dependencies dictionary. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Thu Nov 9 17:22:09 2006 @@ -12,6 +12,10 @@ "_codecs", "gc", "_weakref", "array", "marshal", "errno", "math", "_sre", "_pickle_support", "sys", "exceptions", "__builtins__", "recparser", "symbol", "_random", "_file"]) + +module_dependencies = { 'rctime': [("objspace.usemodules.select", True),], + } + pypy_optiondescription = OptionDescription("pypy", "All PyPy Options", [ OptionDescription("objspace", "Object Space Option", [ @@ -42,7 +46,8 @@ OptionDescription("usemodules", "Which Modules should be used", [ BoolOption(modname, "use module %s" % (modname, ), default=modname in default_modules, - cmdline="--withmod-%s" % (modname, )) + cmdline="--withmod-%s" % (modname, ), + requires= module_dependencies.get(modname, [])) for modname in all_modules]), BoolOption("geninterp", "specify whether geninterp should be used", From pedronis at codespeak.net Thu Nov 9 17:41:16 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 9 Nov 2006 17:41:16 +0100 (CET) Subject: [pypy-svn] r34425 - pypy/dist/pypy/annotation Message-ID: <20061109164116.A438410097@code0.codespeak.net> Author: pedronis Date: Thu Nov 9 17:41:14 2006 New Revision: 34425 Modified: pypy/dist/pypy/annotation/classdef.py Log: ignore bound methods for the warning. Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Thu Nov 9 17:41:14 2006 @@ -115,8 +115,11 @@ if not s_newvalue.isNone() and s_newvalue.getKind() == description.MethodDesc: if homedef.classdesc.read_attribute(attr, None) is None: # is method if not homedef.check_missing_attribute_update(attr): - self.bookkeeper.warning("demoting method %s to base class %s" % - (self.name, homedef)) + for desc in s_newvalue.descriptions: + if desc.selfclassdef is None: + self.bookkeeper.warning("demoting method %s to base class %s" % + (self.name, homedef)) + break # check for attributes forbidden by slots if homedef.classdesc.allslots is not None: From mwh at codespeak.net Thu Nov 9 17:56:23 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Nov 2006 17:56:23 +0100 (CET) Subject: [pypy-svn] r34426 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061109165623.672C710097@code0.codespeak.net> Author: mwh Date: Thu Nov 9 17:56:21 2006 New Revision: 34426 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: add a comment describing how we layout the stack (currently...) also a trivial fix Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Thu Nov 9 17:56:21 2006 @@ -145,6 +145,37 @@ ## def add_case(self, gv_case): ## def add_default(self): + + +# our approach to stack layout: + +# on function entry, the stack looks like this: + +# .... +# | parameter area | +# | linkage area | <- rSP points to the last word of the linkage area +# +----------------+ + +# we set things up like so: + +# | parameter area | +# | linkage area | <- rFP points to where the rSP was +# | saved registers | +# | local variables | +# +-----------------+ <- rSP points here, and moves around between basic blocks + +# points of note (as of 2006-11-09 anyway :-): +# 1. we currently never spill to the parameter area (should fix?) +# 2. we always save all callee-save registers +# 3. as each basic block can move the SP around as it sees fit, we index +# into the local variables area from the FP (frame pointer; it is not +# usual on the PPC to have a frame pointer, but there's no reason we +# can't have one :-) +# 4. we don't support calls, so we never allocate a parameter or +# linkage area for functions we call. this shouldn't be too hard +# to support, it's just not done yet... + + class Builder(GenBuilder): def __init__(self, rgenop, mc): @@ -233,7 +264,7 @@ def finish_and_return(self, sigtoken, gv_returnvar): self.insns.append(insn.Return(gv_returnvar)) - allocator = self.allocate_and_emit() + self.allocate_and_emit() # standard epilogue: From pedronis at codespeak.net Thu Nov 9 17:58:37 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 9 Nov 2006 17:58:37 +0100 (CET) Subject: [pypy-svn] r34427 - pypy/dist/pypy/interpreter Message-ID: <20061109165837.16BEA1009F@code0.codespeak.net> Author: pedronis Date: Thu Nov 9 17:58:34 2006 New Revision: 34427 Modified: pypy/dist/pypy/interpreter/typedef.py Log: fix some spurious annotator warnings this way Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Thu Nov 9 17:58:34 2006 @@ -157,7 +157,7 @@ supercls = _get_unique_interplevel_subclass(cls, hasdict, False, False, False) class Proto(object): - slots_w = None + slots_w = [] def user_setup_slots(self, nslots): if nslots > 0: self.slots_w = [None] * nslots From ac at codespeak.net Thu Nov 9 18:02:41 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 9 Nov 2006 18:02:41 +0100 (CET) Subject: [pypy-svn] r34429 - in pypy/dist: lib-python/modified-2.4.1 lib-python/modified-2.4.1/test pypy/module/rsocket Message-ID: <20061109170241.26B021009F@code0.codespeak.net> Author: ac Date: Thu Nov 9 18:02:40 2006 New Revision: 34429 Added: pypy/dist/lib-python/modified-2.4.1/socket.py - copied, changed from r34409, pypy/dist/lib-python/2.4.1/socket.py Modified: pypy/dist/lib-python/modified-2.4.1/test/test_socket.py pypy/dist/pypy/module/rsocket/interp_socket.py Log: Implement explicit refcounting for sockets Modified: pypy/dist/lib-python/modified-2.4.1/test/test_socket.py ============================================================================== --- pypy/dist/lib-python/modified-2.4.1/test/test_socket.py (original) +++ pypy/dist/lib-python/modified-2.4.1/test/test_socket.py Thu Nov 9 18:02:40 2006 @@ -26,7 +26,6 @@ def tearDown(self): self.serv.close() self.serv = None - gc.collect() class SocketUDPTest(unittest.TestCase): @@ -38,7 +37,6 @@ def tearDown(self): self.serv.close() self.serv = None - gc.collect() class ThreadableTest: """Threadable Test class @@ -136,7 +134,6 @@ def clientTearDown(self): self.done.set() - gc.collect() thread.exit() class ThreadedTCPSocketTest(SocketTCPTest, ThreadableTest): @@ -224,6 +221,7 @@ s.close() s = None gc.collect() + gc.collect() try: p.fileno() except ReferenceError: Modified: pypy/dist/pypy/module/rsocket/interp_socket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_socket.py (original) +++ pypy/dist/pypy/module/rsocket/interp_socket.py Thu Nov 9 18:02:40 2006 @@ -354,6 +354,31 @@ raise converted_error(space, e) shutdown_w.unwrap_spec = ['self', ObjSpace, int] + #------------------------------------------------------------ + # Support functions for socket._socketobject + usecount = 1 + def _reuse_w(self): + """_resue() + + Increase the usecount of the socketobject. + Intended only to be used by socket._socketobject + """ + self.usecount += 1 + _reuse_w.unwrap_spec = ['self'] + + def _drop_w(self, space): + """_drop() + + Decrease the usecount of the socketobject. If the + usecount reaches 0 close the socket. + Intended only to be used by socket._socketobject + """ + self.usecount -= 1 + if self.usecount > 0: + return + self.close_w(space) + _drop_w.unwrap_spec = ['self', ObjSpace] + app_makefile = gateway.applevel(r''' def makefile(self, mode="r", buffersize=-1): """makefile([mode[, buffersize]]) -> file object @@ -399,7 +424,7 @@ accept bind close connect connect_ex dup fileno getpeername getsockname getsockopt gettimeout listen makefile recv recvfrom send sendall sendto setblocking -setsockopt settimeout shutdown +setsockopt settimeout shutdown _reuse _drop """.split() socketmethods = {} for methodname in socketmethodnames: From mwh at codespeak.net Thu Nov 9 18:05:21 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Nov 2006 18:05:21 +0100 (CET) Subject: [pypy-svn] r34430 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061109170521.7B76D100A0@code0.codespeak.net> Author: mwh Date: Thu Nov 9 18:05:19 2006 New Revision: 34430 Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/regalloc.py Log: refactoring and comment clean up in the register allocator. this went through an amusing phase of making a proper bidirectional mapping between variables and locations and then realizing that all the uses of the location -> variable mapping were entirely trivial and removing the whole thing again. Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Thu Nov 9 18:05:19 2006 @@ -94,9 +94,9 @@ self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - self.arg_reg1 = allocator.var2loc[self.reg_args[0]] - self.arg_reg2 = allocator.var2loc[self.reg_args[1]] + self.result_reg = allocator.loc_of(self.result) + self.arg_reg1 = allocator.loc_of(self.reg_args[0]) + self.arg_reg2 = allocator.loc_of(self.reg_args[1]) def emit(self, asm): self.methptr(asm, @@ -115,8 +115,8 @@ self.reg_args = [args[0]] self.reg_arg_regclasses = [GP_REGISTER] def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - self.arg_reg = allocator.var2loc[self.reg_args[0]] + self.result_reg = allocator.loc_of(self.result) + self.arg_reg = allocator.loc_of(self.reg_args[0]) def emit(self, asm): self.methptr(asm, self.result_reg.number, @@ -134,7 +134,7 @@ self.reg_args = [] self.reg_arg_regclasses = [] def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] + self.result_reg = allocator.loc_of(self.result) def emit(self, asm): self.methptr(asm, self.result_reg.number, @@ -156,9 +156,9 @@ self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - self.arg_reg1 = allocator.var2loc[self.reg_args[0]] - self.arg_reg2 = allocator.var2loc[self.reg_args[1]] + self.result_reg = allocator.loc_of(self.result) + self.arg_reg1 = allocator.loc_of(self.reg_args[0]) + self.arg_reg2 = allocator.loc_of(self.reg_args[1]) def emit(self, asm): asm.cmpw(self.result_reg.number, self.arg_reg1.number, self.arg_reg2.number) @@ -176,8 +176,8 @@ self.reg_arg_regclasses = [GP_REGISTER] def allocate(self, allocator): - self.result_reg = allocator.var2loc[self.result] - self.arg_reg = allocator.var2loc[self.reg_args[0]] + self.result_reg = allocator.loc_of(self.result) + self.arg_reg = allocator.loc_of(self.reg_args[0]) def emit(self, asm): asm.cmpwi(self.result_reg.number, self.arg_reg.number, self.imm.value) @@ -192,7 +192,7 @@ ## self.reg_arg_regclasses = [GP_REGISTER] ## def allocate(self, allocator): -## self.arg_reg = allocator.var2loc[self.reg_args[0]] +## self.arg_reg = allocator.loc_of(self.reg_args[0]) ## def emit(self, asm): ## asm.mtctr(self.arg_reg.number) @@ -209,8 +209,8 @@ self.reg_args = [gv_cond, gv_target] self.reg_arg_regclasses = [CR_FIELD, CT_REGISTER] def allocate(self, allocator): - assert allocator.var2loc[self.reg_args[1]] is ctr - self.crf = allocator.var2loc[self.reg_args[0]] + assert allocator.loc_of(self.reg_args[1]) is ctr + self.crf = allocator.loc_of(self.reg_args[0]) self.bit, self.negated = allocator.crfinfo[self.crf.number] def emit(self, asm): if self.negated ^ self.jump_if_true: @@ -293,7 +293,7 @@ self.result_regclass = NO_REGISTER self.reg = None def allocate(self, allocator): - self.reg = allocator.var2loc[self.var] + self.reg = allocator.loc_of(self.var) def emit(self, asm): if self.reg.number != 3: asm.mr(r3, self.reg.number) Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Thu Nov 9 18:05:19 2006 @@ -9,33 +9,51 @@ #print #print "RegisterAllocation __init__", initial_mapping - self.insns = [] # Output list of instructions - # Registers with dead values + self.insns = [] # output list of instructions + + # registers with dead values self.freeregs = {} for regcls in freeregs: self.freeregs[regcls] = freeregs[regcls][:] - self.var2loc = {} # Maps a Var to an AllocationSlot - self.loc2var = {} # Maps an AllocationSlot to a Var - self.lru = [] # Least-recently-used list of vars; first is oldest. - # Contains all vars in registers, and no vars on stack - self.spill_offset = initial_spill_offset # Where to put next spilled + + self.var2loc = {} # maps Vars to AllocationSlots + self.lru = [] # least-recently-used list of vars; first is oldest. + # contains all vars in registers, and no vars on stack + + self.spill_offset = initial_spill_offset # where to put next spilled # value, relative to rFP, # measured in bytes + self.free_stack_slots = [] # a free list for stack slots - # Go through the initial mapping and initialize the data structures + # go through the initial mapping and initialize the data structures for var, loc in initial_mapping.iteritems(): - self.loc2var[loc] = var - self.var2loc[var] = loc + self.set(var, loc) if loc.is_register and loc in self.freeregs[loc.regclass]: self.freeregs[loc.regclass].remove(loc) self.lru.append(var) + + # crfinfo is a bit of a hack used to transmit which bit a compare + # instruction set to the branch instruction self.crfinfo = [(0, 0)] * 8 - def spill(self): - """ Returns an offset onto the stack for an unused spill location """ - # TODO --- reuse spill slots when contained values go dead? - self.spill_offset -= 4 - return self.spill_offset + def set(self, var, loc): + assert var not in self.var2loc + self.var2loc[var] = loc + + def forget(self, var, loc): + assert self.var2loc[var] is loc + del self.var2loc[var] + + def loc_of(self, var): + return self.var2loc[var] + + def spill_slot(self): + """ Returns an unused stack location. """ + if self.free_stack_slots: + return self.free_stack_slots.pop() + else: + self.spill_offset -= 4 + return stack_slot(self.spill_offset) def _allocate_reg(self, regclass, newarg): @@ -44,21 +62,14 @@ if freeregs: reg = freeregs.pop() - if newarg in self.var2loc: - spill = self.var2loc[newarg] - assert not spill.is_register - self.insns.append(Unspill(newarg, reg, spill)) - del self.loc2var[spill] # not stored there anymore, reuse?? - #print "allocate_reg: Unspilled %r from %r." % (newarg, spill) - self.loc2var[reg] = newarg - self.var2loc[newarg] = reg + self.set(newarg, reg) #print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) return reg # if not, find something to spill for i in range(len(self.lru)): argtospill = self.lru[i] - reg = self.var2loc[argtospill] + reg = self.loc_of(argtospill) assert reg.is_register if reg.regclass == regclass: del self.lru[i] @@ -68,29 +79,21 @@ # Move the value we are spilling onto the stack, both in the # data structures and in the instructions: - spill = stack_slot(self.spill()) - self.var2loc[argtospill] = spill - self.loc2var[spill] = argtospill + + self.forget(argtospill, reg) + spill = self.spill_slot() if regclass != GP_REGISTER: self.insns.append(reg.move_to_gpr(self, 0)) - _reg = gprs[0] + spillfrom_reg = gprs[0] else: - _reg = reg - self.insns.append(Spill(argtospill, _reg, spill)) + spillfrom_reg = reg + self.insns.append(Spill(argtospill, spillfrom_reg, spill)) + self.set(argtospill, spill) + #print "allocate_reg: Spilled %r to %r." % (argtospill, spill) - # If the value is currently on the stack, load it up into the - # register we are putting it into - if newarg in self.var2loc: - spill = self.var2loc[newarg] - assert not spill.is_register - self.insns.append(Unspill(newarg, reg, spill)) - del self.loc2var[spill] # not stored there anymore, reuse?? - #print "allocate_reg: Unspilled %r from %r." % (newarg, spill) - - # Update data structures to put newarg into the register - self.var2loc[newarg] = reg - self.loc2var[reg] = newarg + # update data structures to put newarg into the register + self.set(newarg, reg) #print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) return reg @@ -100,48 +103,57 @@ self.lru.append(arg) def allocate_for_insns(self, insns): - from pypy.jit.codegen.ppc.rgenop import IntConst, Var + from pypy.jit.codegen.ppc.rgenop import Var insns2 = [] + # make a pass through the instructions, loading constants into + # Vars where needed. for insn in insns: - for i in range(len(insn.reg_args)): - arg = insn.reg_args[i] + newargs = [] + for arg in insn.reg_args: if not isinstance(arg, Var): - v = Var() - arg.load(insns2, v) - insn.reg_args[i] = v + newarg = Var() + arg.load(insns2, newarg) + newargs.append(newarg) + else: + newargs.append(arg) + insn.reg_args[0:len(newargs)] = newargs insns2.append(insn) # Walk through instructions in forward order for insn in insns2: - #print "Processing instruction %r with args %r and result %r:" % (insn, insn.reg_args, insn.result) + #print "Processing instruction", insn, + #print "with args", insn.reg_args, "and result", insn.result, ":" - #print "LRU list was: %r" % (self.lru,) + #print "LRU list was:", self.lru # put things into the lru - for i in range(len(insn.reg_args)): - arg = insn.reg_args[i] + for arg in insn.reg_args: self._promote(arg) if insn.result: self._promote(insn.result) - #print "LRU list is now: %r" % (self.lru,) + #print "LRU list is now:", self.lru # We need to allocate a register for each used # argument that is not already in one for i in range(len(insn.reg_args)): arg = insn.reg_args[i] argcls = insn.reg_arg_regclasses[i] - #print "Allocating register for %r..." % (arg,) - argloc = self.var2loc[arg] + #print "Allocating register for", arg, "..." + argloc = self.loc_of(arg) if not argloc.is_register: # It has no register now because it has been spilled - self._allocate_reg(argcls, arg) + self.forget(arg, argloc) + newargloc = self._allocate_reg(argcls, arg) + self.insns.append(Unspill(arg, newargloc, argloc)) + self.free_stack_slots.append(argloc) elif argloc.regclass != argcls: - del self.var2loc[arg] - del self.loc2var[argloc] + # it's in the wrong kind of register + # (this code is excessively confusing) + self.forget(arg, argloc) if argloc.regclass != GP_REGISTER: if argcls == GP_REGISTER: gpr = self._allocate_reg(GP_REGISTER, arg).number @@ -156,23 +168,16 @@ self.insns.append( newargloc.move_from_gpr(self, gpr)) else: - #print "it was in ", self.var2loc[arg] + #print "it was in ", argloc pass # Need to allocate a register for the destination assert not insn.result or insn.result not in self.var2loc if insn.result_regclass != NO_REGISTER: #print "Allocating register for result %r..." % (insn.result,) - cand = self._allocate_reg(insn.result_regclass, insn.result) + resultreg = self._allocate_reg(insn.result_regclass, insn.result) if isinstance(insn, CMPInsn): - self.crfinfo[cand.number] = insn.info - else: - cand = None - if cand is not None and cand not in self.loc2var: - self.var2loc[insn.result] = cand - self.loc2var[cand] = insn.result - else: - assert cand is None or self.loc2var[cand] is insn.result + self.crfinfo[resultreg.number] = insn.info insn.allocate(self) self.insns.append(insn) return self.insns From pedronis at codespeak.net Thu Nov 9 18:29:04 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 9 Nov 2006 18:29:04 +0100 (CET) Subject: [pypy-svn] r34434 - pypy/dist/pypy/translator Message-ID: <20061109172904.88B40100A4@code0.codespeak.net> Author: pedronis Date: Thu Nov 9 18:28:59 2006 New Revision: 34434 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: don't use the generic __args__ signature and argument unpacking when possible in geninterp generated code, avoid also the extra arg parsing function in those cases. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Thu Nov 9 18:28:59 2006 @@ -45,6 +45,7 @@ from __future__ import generators import autopath, os, sys, types +import inspect import cPickle as pickle, __builtin__ from copy_reg import _HEAPTYPE from pypy.objspace.flow.model import Variable, Constant, SpaceOperation @@ -71,7 +72,7 @@ log = py.log.Producer("geninterp") py.log.setconsumer("geninterp", ansi_log) -GI_VERSION = '1.1.18' # bump this for substantial changes +GI_VERSION = '1.1.19' # bump this for substantial changes # ____________________________________________________________ try: @@ -605,9 +606,18 @@ return self.skipped_function(func) name = self.uniquename('gfunc_' + self.trans_funcname( namehint + func.__name__)) - f_name = 'f_' + name[6:] + + positional, varargs, varkwds, defs = inspect.getargspec(func) + if varargs is varkwds is defs is None: + unwrap = ', '.join(['gateway.W_Root']*len(positional)) + interp_name = 'fastf_' + name[6:] + else: + unwrap = 'gateway.Arguments' + interp_name = 'f_' + name[6:] + self.initcode.append1('from pypy.interpreter import gateway') - self.initcode.append1('%s = space.wrap(gateway.interp2app(%s, unwrap_spec=[gateway.ObjSpace, gateway.Arguments]))' % (name, f_name)) + self.initcode.append1('%s = space.wrap(gateway.interp2app(%s, unwrap_spec=[gateway.ObjSpace, %s]))' % + (name, interp_name, unwrap)) self.pendingfunctions.append(func) return name @@ -1203,6 +1213,8 @@ fast_set = dict(zip(fast_args, fast_args)) + simple = (varargname is varkwname is None) and not name_of_defaults + # create function declaration name = self.trans_funcname(func.__name__) # for argstr = ", ".join(['space'] + fast_args) @@ -1219,10 +1231,6 @@ #else: # self.initcode.append1('del m.%s' % (name,)) - print >> f, ' def %s(space, __args__):' % (name,) - if docstr is not None: - print >> f, docstr - print >> f def tupstr(seq): if len(seq) == 1: fmt = '%s,' @@ -1235,23 +1243,29 @@ else: return tupstr(seq) + " = " - print >> f, ' funcname = "%s"' % func.__name__ - - kwlist = list(func.func_code.co_varnames[:func.func_code.co_argcount]) - signature = ' signature = %r' % kwlist - signature = ", ".join([signature, repr(varargname), repr(varkwname)]) - print >> f, signature + if not simple: + print >> f, ' def %s(space, __args__):' % (name,) + if docstr is not None: + print >> f, docstr + print >> f + + print >> f, ' funcname = "%s"' % func.__name__ + kwlist = list(func.func_code.co_varnames[:func.func_code.co_argcount]) + signature = ' signature = %r' % kwlist + signature = ", ".join([signature, repr(varargname), repr(varkwname)]) + print >> f, signature + + print >> f, ' defaults_w = [%s]' % ", ".join(name_of_defaults) + + print >> f, ' %s__args__.parse(funcname, signature, defaults_w)' % ( + tupassstr(fast_args),) + print >> f, ' return %s(%s)' % (fast_name, ', '.join(["space"]+fast_args)) - print >> f, ' defaults_w = [%s]' % ", ".join(name_of_defaults) - - print >> f, ' %s__args__.parse(funcname, signature, defaults_w)' % ( - tupassstr(fast_args),) - print >> f, ' return %s(%s)' % (fast_name, ', '.join(["space"]+fast_args)) - - for line in install_func(f_name, name): - print >> f, line + for line in install_func(f_name, name): + print >> f, line - print >> f + print >> f + print >> f, fast_function_header if docstr is not None: print >> f, docstr From mwh at codespeak.net Thu Nov 9 18:39:35 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Nov 2006 18:39:35 +0100 (CET) Subject: [pypy-svn] r34436 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061109173935.7F301100A6@code0.codespeak.net> Author: mwh Date: Thu Nov 9 18:39:34 2006 New Revision: 34436 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: more brainless code motion in rgenop, the better to contrast with arigo's compiler mind-bendery Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Thu Nov 9 18:39:34 2006 @@ -110,43 +110,6 @@ self.arg_locations = arg_locations self.min_stack_offset = min_stack_offset -## class FlexSwitch(CodeGenSwitch): - -## def __init__(self, rgenop): -## self.rgenop = rgenop -## self.default_case_addr = 0 - -## def initialize(self, builder, gv_exitswitch): -## self.switch_reg = gv_exitswitch.load(builder) -## self.saved_state = builder._save_state() -## self._reserve(mc) - -## def _reserve(self, mc): -## RESERVED = 11 # enough for 5 cases and a default -## pos = mc.tell() -## for i in range(RESERVED): -## mc.write(0) -## self.nextfreepos = pos -## self.endfreepos = pos + RESERVED * 4 - -## def _reserve_more(self): -## XXX -## start = self.nextfreepos -## end = self.endfreepos -## newmc = self.rgenop.open_mc() -## self._reserve(newmc) -## self.rgenop.close_mc(newmc) -## fullmc = InMemoryCodeBuilder(start, end) -## a = RPPCAssembler() -## a.mc = newmc -## fullmc.ba(rel32(self.nextfreepos)) -## fullmc.done() - -## def add_case(self, gv_case): -## def add_default(self): - - - # our approach to stack layout: # on function entry, the stack looks like this: @@ -188,6 +151,120 @@ self.initial_var2loc = None self.fresh_from_jump = False + # ---------------------------------------------------------------- + # the public Builder interface: + +## @specialize.arg(1) +## def genop1(self, opname, gv_arg): + + @specialize.arg(1) + def genop2(self, opname, gv_arg1, gv_arg2): + genmethod = getattr(self, 'op_' + opname) + return genmethod(gv_arg1, gv_arg2) + +## def genop_getfield(self, fieldtoken, gv_ptr): +## def genop_setfield(self, fieldtoken, gv_ptr, gv_value): +## def genop_getsubstruct(self, fieldtoken, gv_ptr): +## def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index): +## def genop_getarraysize(self, arraytoken, gv_ptr): +## def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): +## def genop_malloc_fixedsize(self, alloctoken): +## def genop_malloc_varsize(self, varsizealloctoken, gv_size): +## def genop_call(self, sigtoken, gv_fnptr, args_gv): +## def genop_same_as(self, kindtoken, gv_x): +## def genop_debug_pdb(self): # may take an args_gv later + + def enter_next_block(self, kinds, args_gv): + if self.fresh_from_jump: + var2loc = self.initial_var2loc + self.fresh_from_jump = False + else: + var2loc = self.allocate_and_emit().var2loc + + #print "enter_next_block:", args_gv, var2loc + + min_stack_offset = self._var_offset(0) + usedregs = {} + livevar2loc = {} + for gv in args_gv: + if isinstance(gv, Var): + assert gv in var2loc + loc = var2loc[gv] + livevar2loc[gv] = loc + if not loc.is_register: + min_stack_offset = min(min_stack_offset, loc.offset) + else: + usedregs[loc] = None + + unusedregs = [loc for loc in self.rgenop.freeregs[insn.GP_REGISTER] if loc not in usedregs] + arg_locations = [] + + for i in range(len(args_gv)): + gv = args_gv[i] + if isinstance(gv, Var): + arg_locations.append(livevar2loc[gv]) + else: + if unusedregs: + loc = unusedregs.pop() + else: + loc = insn.stack_slot(min_stack_offset) + min_stack_offset -= 4 + gv.load_now(self.asm, loc) + args_gv[i] = gv = Var() + livevar2loc[gv] = loc + arg_locations.append(loc) + + #print livevar2loc + + self.insns = [] + self.initial_var2loc = livevar2loc + self.initial_spill_offset = min_stack_offset + target_addr = self.asm.mc.tell() + self.emit_stack_adjustment() + return Label(target_addr, arg_locations, min_stack_offset) + + def jump_if_false(self, gv_condition): + return self._jump(gv_condition, False) + + def jump_if_true(self, gv_condition): + return self._jump(gv_condition, True) + + def finish_and_return(self, sigtoken, gv_returnvar): + self.insns.append(insn.Return(gv_returnvar)) + self.allocate_and_emit() + + # standard epilogue: + + # restore old SP + self.asm.lwz(rSP, rSP, 0) + # restore all callee-save GPRs + self.asm.lmw(gprs[32-NSAVEDREGISTERS].number, rSP, -4*(NSAVEDREGISTERS+1)) + # restore Condition Register + self.asm.lwz(rSCRATCH, rSP, 4) + self.asm.mtcr(rSCRATCH) + # restore Link Register and jump to it + self.asm.lwz(rSCRATCH, rSP, 8) + self.asm.mtlr(rSCRATCH) + self.asm.blr() + + self._close() + + def finish_and_goto(self, outputargs_gv, target): + allocator = self.allocate_and_emit() + min_offset = min(allocator.spill_offset, target.min_stack_offset) + min_offset = prepare_for_jump( + self.asm, min_offset, outputargs_gv, allocator.var2loc, target) + self.patch_stack_adjustment(self._stack_size(0, min_offset)) + self.asm.load_word(rSCRATCH, target.startaddr) + self.asm.mtctr(rSCRATCH) + self.asm.bctr() + self._close() + +## def flexswitch(self, gv_exitswitch): + + # ---------------------------------------------------------------- + # ppc-specific interface: + def make_fresh_from_jump(self, initial_var2loc): self.fresh_from_jump = True self.initial_var2loc = initial_var2loc @@ -246,11 +323,6 @@ self.rgenop.close_mc(self.asm.mc) self.asm.mc = None - @specialize.arg(1) - def genop2(self, opname, gv_arg1, gv_arg2): - genmethod = getattr(self, 'op_' + opname) - return genmethod(gv_arg1, gv_arg2) - def allocate_and_emit(self): assert self.initial_var2loc is not None allocator = RegisterAllocation( @@ -262,37 +334,6 @@ insn.emit(self.asm) return allocator - def finish_and_return(self, sigtoken, gv_returnvar): - self.insns.append(insn.Return(gv_returnvar)) - self.allocate_and_emit() - - # standard epilogue: - - # restore old SP - self.asm.lwz(rSP, rSP, 0) - # restore all callee-save GPRs - self.asm.lmw(gprs[32-NSAVEDREGISTERS].number, rSP, -4*(NSAVEDREGISTERS+1)) - # restore Condition Register - self.asm.lwz(rSCRATCH, rSP, 4) - self.asm.mtcr(rSCRATCH) - # restore Link Register and jump to it - self.asm.lwz(rSCRATCH, rSP, 8) - self.asm.mtlr(rSCRATCH) - self.asm.blr() - - self._close() - - def finish_and_goto(self, outputargs_gv, target): - allocator = self.allocate_and_emit() - min_offset = min(allocator.spill_offset, target.min_stack_offset) - min_offset = prepare_for_jump( - self.asm, min_offset, outputargs_gv, allocator.var2loc, target) - self.patch_stack_adjustment(self._stack_size(0, min_offset)) - self.asm.load_word(rSCRATCH, target.startaddr) - self.asm.mtctr(rSCRATCH) - self.asm.bctr() - self._close() - def emit_stack_adjustment(self): # the ABI requires that at all times that r1 is valid, in the # sense that it must point to the bottom of the stack and that @@ -328,55 +369,6 @@ p_instruction = cast(c_void_p(self.stack_adj_addr), POINTER(c_int*1)) p_instruction.contents[0] = opcode | rD | rA | SIMM - def enter_next_block(self, kinds, args_gv): - if self.fresh_from_jump: - var2loc = self.initial_var2loc - self.fresh_from_jump = False - else: - var2loc = self.allocate_and_emit().var2loc - - #print "enter_next_block:", args_gv, var2loc - - min_stack_offset = self._var_offset(0) - usedregs = {} - livevar2loc = {} - for gv in args_gv: - if isinstance(gv, Var): - assert gv in var2loc - loc = var2loc[gv] - livevar2loc[gv] = loc - if not loc.is_register: - min_stack_offset = min(min_stack_offset, loc.offset) - else: - usedregs[loc] = None - - unusedregs = [loc for loc in self.rgenop.freeregs[insn.GP_REGISTER] if loc not in usedregs] - arg_locations = [] - - for i in range(len(args_gv)): - gv = args_gv[i] - if isinstance(gv, Var): - arg_locations.append(livevar2loc[gv]) - else: - if unusedregs: - loc = unusedregs.pop() - else: - loc = insn.stack_slot(min_stack_offset) - min_stack_offset -= 4 - gv.load_now(self.asm, loc) - args_gv[i] = gv = Var() - livevar2loc[gv] = loc - arg_locations.append(loc) - - #print livevar2loc - - self.insns = [] - self.initial_var2loc = livevar2loc - self.initial_spill_offset = min_stack_offset - target_addr = self.asm.mc.tell() - self.emit_stack_adjustment() - return Label(target_addr, arg_locations, min_stack_offset) - def op_int_mul(self, gv_x, gv_y): gv_result = Var() self.insns.append( @@ -477,12 +469,6 @@ return targetbuilder - def jump_if_false(self, gv_condition): - return self._jump(gv_condition, False) - - def jump_if_true(self, gv_condition): - return self._jump(gv_condition, True) - class RPPCGenOp(AbstractRGenOp): @@ -497,27 +483,8 @@ def __init__(self): self.mcs = [] # machine code blocks where no-one is currently writing - def open_mc(self): - if self.mcs: - return self.mcs.pop() - else: - return codebuf.MachineCodeBlock(65536) # XXX supposed infinite for now - - def close_mc(self, mc): - self.mcs.append(mc) - - @staticmethod - @specialize.memo() - def sigToken(FUNCTYPE): - return len(FUNCTYPE.ARGS) # for now - - @staticmethod - @specialize.memo() - def kindToken(T): - return None # for now - - def openbuilder(self): - return Builder(self, self.open_mc()) + # ---------------------------------------------------------------- + # the public RGenOp interface def newgraph(self, sigtoken): numargs = sigtoken # for now @@ -526,7 +493,6 @@ inputargs_gv = builder._write_prologue(sigtoken) return builder, entrypoint, inputargs_gv - @staticmethod @specialize.genconst(0) def genconst(llvalue): @@ -540,5 +506,90 @@ else: assert 0, "XXX not implemented" +## @staticmethod +## @specialize.genconst(0) +## def constPrebuiltGlobal(llvalue): + def gencallableconst(self, sigtoken, name, entrypointaddr): return IntConst(entrypointaddr) + +## def replay(self, label, kinds): + +## @staticmethod +## def erasedType(T): + +## @staticmethod +## @specialize.memo() +## def fieldToken(T, name): + +## @staticmethod +## @specialize.memo() +## def allocToken(T): + +## @staticmethod +## @specialize.memo() +## def varsizeAllocToken(T): + +## @staticmethod +## @specialize.memo() +## def arrayToken(A): + + @staticmethod + @specialize.memo() + def kindToken(T): + return None # for now + + @staticmethod + @specialize.memo() + def sigToken(FUNCTYPE): + return len(FUNCTYPE.ARGS) # for now + + # ---------------------------------------------------------------- + # ppc-specific interface: + + def open_mc(self): + if self.mcs: + return self.mcs.pop() + else: + return codebuf.MachineCodeBlock(65536) # XXX supposed infinite for now + + def close_mc(self, mc): + self.mcs.append(mc) + + def openbuilder(self): + return Builder(self, self.open_mc()) + +## class FlexSwitch(CodeGenSwitch): + +## def __init__(self, rgenop): +## self.rgenop = rgenop +## self.default_case_addr = 0 + +## def initialize(self, builder, gv_exitswitch): +## self.switch_reg = gv_exitswitch.load(builder) +## self.saved_state = builder._save_state() +## self._reserve(mc) + +## def _reserve(self, mc): +## RESERVED = 11 # enough for 5 cases and a default +## pos = mc.tell() +## for i in range(RESERVED): +## mc.write(0) +## self.nextfreepos = pos +## self.endfreepos = pos + RESERVED * 4 + +## def _reserve_more(self): +## XXX +## start = self.nextfreepos +## end = self.endfreepos +## newmc = self.rgenop.open_mc() +## self._reserve(newmc) +## self.rgenop.close_mc(newmc) +## fullmc = InMemoryCodeBuilder(start, end) +## a = RPPCAssembler() +## a.mc = newmc +## fullmc.ba(rel32(self.nextfreepos)) +## fullmc.done() + +## def add_case(self, gv_case): +## def add_default(self): From ac at codespeak.net Thu Nov 9 18:42:27 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 9 Nov 2006 18:42:27 +0100 (CET) Subject: [pypy-svn] r34437 - in pypy/dist: lib-python/modified-2.4.1 pypy/module/rsocket Message-ID: <20061109174227.38ACD100A8@code0.codespeak.net> Author: ac Date: Thu Nov 9 18:42:26 2006 New Revision: 34437 Modified: pypy/dist/lib-python/modified-2.4.1/socket.py pypy/dist/pypy/module/rsocket/interp_socket.py Log: Only simulate dup() and makefile() if _socket.socket doesn't have them Modified: pypy/dist/lib-python/modified-2.4.1/socket.py ============================================================================== --- pypy/dist/lib-python/modified-2.4.1/socket.py (original) +++ pypy/dist/lib-python/modified-2.4.1/socket.py Thu Nov 9 18:42:26 2006 @@ -195,8 +195,8 @@ for _m in _socketmethods: exec _s % (_m, _m, _m, _m) del _m, _s - -socket = SocketType = _socketobject +if not hasattr(socket, 'dup'): # Simulate dup() and makefile() + socket = SocketType = _socketobject class _fileobject(object): """Faux file object attached to a socket object.""" Modified: pypy/dist/pypy/module/rsocket/interp_socket.py ============================================================================== --- pypy/dist/pypy/module/rsocket/interp_socket.py (original) +++ pypy/dist/pypy/module/rsocket/interp_socket.py Thu Nov 9 18:42:26 2006 @@ -1,5 +1,5 @@ from pypy.interpreter.baseobjspace import Wrappable -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped from pypy.interpreter.gateway import interp2app from pypy.rlib.rsocket import RSocket, AF_INET, SOCK_STREAM @@ -472,5 +472,6 @@ [*] not available on all platforms!""", __new__ = descr_socket_new, + __weakref__ = make_weakref_descr(W_RSocket), ** socketmethods ) From ac at codespeak.net Thu Nov 9 19:53:12 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 9 Nov 2006 19:53:12 +0100 (CET) Subject: [pypy-svn] r34439 - pypy/dist/lib-python/modified-2.4.1 Message-ID: <20061109185312.76C30100AA@code0.codespeak.net> Author: ac Date: Thu Nov 9 19:53:11 2006 New Revision: 34439 Modified: pypy/dist/lib-python/modified-2.4.1/socket.py Log: Go back to allways simulating dup() and makefile() as a translated pypy does not pass all tests in test_socket.py Modified: pypy/dist/lib-python/modified-2.4.1/socket.py ============================================================================== --- pypy/dist/lib-python/modified-2.4.1/socket.py (original) +++ pypy/dist/lib-python/modified-2.4.1/socket.py Thu Nov 9 19:53:11 2006 @@ -195,8 +195,7 @@ for _m in _socketmethods: exec _s % (_m, _m, _m, _m) del _m, _s -if not hasattr(socket, 'dup'): # Simulate dup() and makefile() - socket = SocketType = _socketobject +socket = SocketType = _socketobject class _fileobject(object): """Faux file object attached to a socket object.""" From arigo at codespeak.net Thu Nov 9 20:47:36 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 9 Nov 2006 20:47:36 +0100 (CET) Subject: [pypy-svn] r34441 - in pypy/dist/pypy/interpreter: astcompiler pyparser/test test Message-ID: <20061109194736.D6184100A2@code0.codespeak.net> Author: arigo Date: Thu Nov 9 20:47:32 2006 New Revision: 34441 Modified: pypy/dist/pypy/interpreter/astcompiler/misc.py pypy/dist/pypy/interpreter/astcompiler/pyassem.py pypy/dist/pypy/interpreter/astcompiler/pycodegen.py pypy/dist/pypy/interpreter/astcompiler/symbols.py pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py pypy/dist/pypy/interpreter/test/test_compiler.py pypy/dist/pypy/interpreter/test/test_generator.py pypy/dist/pypy/interpreter/test/test_syntax.py Log: issue266 testing A rewrite of the compiler's scoping logic. Trying to be more explicit about the rules this time... The diff certainly contains a lot of *removed* lines, in favor of a more centralized logic. This version also solves a few bugs that we had (see new tests), and solves a couple of problems in CPython with class vs. scope interaction. The main new incompatibilities with CPython are: 1. some code involving classes and import * / exec now raise a SyntaxError instead of producing broken bytecode, which I think is not a bad thing (there are pending SourceForge bug reports for CPython) 2. in class scopes, variables that just go "through" (because they are free in a method and come from an enclosing function) now have their name mangled, if you try to inspect them with locals(). This avoids confusion between a class-level name and the variable going "through". It fixes another CPython bug (also reported on SF I think) which allows strange code to modify bindings in parent scopes. This fully passes CPython's test_scope, and all our previous tests with the exception of the cases now rejected by 1. above. Modified: pypy/dist/pypy/interpreter/astcompiler/misc.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/misc.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/misc.py Thu Nov 9 20:47:32 2006 @@ -39,7 +39,7 @@ if tlen > MANGLE_LEN: end = len(klass) + MANGLE_LEN-tlen if end < 0: - klass = '' # annotator hint + klass = '' # slices of negative length are invalid in RPython else: klass = klass[:end] Modified: pypy/dist/pypy/interpreter/astcompiler/pyassem.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pyassem.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pyassem.py Thu Nov 9 20:47:32 2006 @@ -431,15 +431,15 @@ class PyFlowGraph(FlowGraph): - def __init__(self, space, name, filename, args=None, mangler=None, + def __init__(self, space, name, filename, argnames=None, optimized=0, klass=0, newlocals=0): FlowGraph.__init__(self, space) - if args is None: - args = [] + if argnames is None: + argnames = [] self.name = name self.filename = filename self.docstring = space.w_None - self.argcount = len(args) + self.argcount = len(argnames) self.klass = klass self.flags = 0 if optimized: @@ -458,13 +458,7 @@ # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both # kinds of variables. self.closure = [] - self.varnames = [] - for i in range(len(args)): - var = args[i] - if isinstance(var, ast.AssName): - self.varnames.append(mangler.mangle(var.name)) - elif isinstance(var, ast.AssTuple): - self.varnames.append('.%d' % (2 * i)) + self.varnames = list(argnames) self.stage = RAW self.orderedblocks = [] Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Thu Nov 9 20:47:32 2006 @@ -66,8 +66,6 @@ self.source = source self.filename = filename self.code = None - # XXX: this attribute looks like unused anyway ??? - self.mode = "" # defined by subclass def _get_tree(self): tree = parse(self.source, self.mode) @@ -82,19 +80,15 @@ return self.code class Expression(AbstractCompileMode): - def __init__(self, source, filename): - AbstractCompileMode.__init__(self, source, filename ) - self.mode = "eval" - + mode = "eval" + def compile(self): tree = self._get_tree() gen = ExpressionCodeGenerator(tree) self.code = gen.getCode() class Interactive(AbstractCompileMode): - def __init__(self, source, filename): - AbstractCompileMode.__init__(self, source, filename ) - self.mode = "single" + mode = "single" def compile(self): tree = self._get_tree() @@ -102,9 +96,7 @@ self.code = gen.getCode() class Module(AbstractCompileMode): - def __init__(self, source, filename): - AbstractCompileMode.__init__(self, source, filename ) - self.mode = "exec" + mode = "exec" def compile(self, display=0): tree = self._get_tree() @@ -145,9 +137,6 @@ """Defines basic code generator for Python bytecode """ - scopeambiguity = False - class_name = "" - def __init__(self, space, graph): self.space = space self.setups = [] @@ -208,10 +197,7 @@ return self.graph.getCode() def mangle(self, name): - if self.class_name: - return misc.mangle(name, self.class_name) - else: - return name + return self.scope.mangle(name) def parseSymbols(self, tree): s = symbols.SymbolVisitor(self.space) @@ -227,12 +213,6 @@ self._nameOp('STORE', name) def loadName(self, name, lineno): - if (self.scope.nested and self.scopeambiguity and - name in self.scope.hasbeenfree): - raise SyntaxError("cannot reference variable '%s' because " - "of ambiguity between " - "scopes" % name, lineno) - self._nameOp('LOAD', name) def delName(self, name, lineno): @@ -240,7 +220,7 @@ raise SyntaxError('deleting %s is not allowed' % name, lineno) scope = self.scope.check_name(self.mangle(name)) if scope == SC_CELL: - raise SyntaxError("can not delete variable '%s' " + raise SyntaxError("cannot delete variable '%s' " "referenced in nested scope" % name, lineno) self._nameOp('DELETE', name) @@ -262,8 +242,8 @@ else: self.emitop(prefix + '_NAME', name) else: - raise RuntimeError, "unsupported scope for var %s: %d" % \ - (name, scope) + raise RuntimeError, "unsupported scope for var %s in %s: %d" % \ + (name, self.scope.name, scope) def _implicitNameOp(self, prefix, name): """Emit name ops for names generated implicitly by for loops @@ -352,17 +332,14 @@ ndecorators = 0 gen = FunctionCodeGenerator(self.space, node, isLambda, - self.class_name, self.get_module(), - self.scopeambiguity) + self.get_module()) node.code.accept( gen ) gen.finish() self.set_lineno(node) for default in node.defaults: default.accept( self ) - frees = gen.scope.get_free_vars() + frees = gen.scope.get_free_vars_in_parent() if frees: - # We contain a func with free vars. - # Any unqualified exec or import * is a SyntaxError for name in frees: self.emitop('LOAD_CLOSURE', name) self.emitop_code('LOAD_CONST', gen) @@ -376,8 +353,7 @@ def visitClass(self, node): gen = ClassCodeGenerator(self.space, node, - self.get_module(), - self.scopeambiguity) + self.get_module()) node.code.accept( gen ) gen.finish() self.set_lineno(node) @@ -385,10 +361,8 @@ for base in node.bases: base.accept( self ) self.emitop_int('BUILD_TUPLE', len(node.bases)) - frees = gen.scope.get_free_vars() + frees = gen.scope.get_free_vars_in_parent() if frees: - # We contain a func with free vars. - # Any unqualified exec or import * is a SyntaxError for name in frees: self.emitop('LOAD_CLOSURE', name) self.emitop_code('LOAD_CONST', gen) @@ -689,17 +663,14 @@ self.emit('POP_TOP') def visitGenExpr(self, node): - gen = GenExprCodeGenerator(self.space, node, self.class_name, - self.get_module(), self.scopeambiguity) + gen = GenExprCodeGenerator(self.space, node, self.get_module()) inner = node.code assert isinstance(inner, ast.GenExprInner) inner.accept( gen ) gen.finish() self.set_lineno(node) - frees = gen.scope.get_free_vars() + frees = gen.scope.get_free_vars_in_parent() if frees: - # We contain a func with free vars. - # Any unqualified exec or import * is a SyntaxError for name in frees: self.emitop('LOAD_CLOSURE', name) self.emitop_code('LOAD_CONST', gen) @@ -1090,6 +1061,8 @@ if node.value is None: self.emitop_obj('LOAD_CONST', self.space.w_None) else: + if self.scope.generator: + raise SyntaxError("'return' with argument inside generator") node.value.accept( self ) self.emit('RETURN_VALUE') @@ -1305,8 +1278,7 @@ self.emit('PRINT_EXPR') class AbstractFunctionCode(CodeGenerator): - def __init__(self, space, func, isLambda, class_name, mod): - self.class_name = class_name + def __init__(self, space, func, isLambda, mod): self.module = mod if isLambda: name = "" @@ -1330,8 +1302,15 @@ if 'None' in argnames: raise SyntaxError('assignment to None is not allowed', func.lineno) - graph = pyassem.PyFlowGraph(space, name, func.filename, func.argnames, - mangler=self, + argnames = [] + for i in range(len(func.argnames)): + var = func.argnames[i] + if isinstance(var, ast.AssName): + argnames.append(self.mangle(var.name)) + elif isinstance(var, ast.AssTuple): + argnames.append('.%d' % (2 * i)) + # (2 * i) just because CPython does that too + graph = pyassem.PyFlowGraph(space, name, func.filename, argnames, optimized=self.localsfullyknown, newlocals=1) self.isLambda = isLambda @@ -1383,28 +1362,25 @@ class FunctionCodeGenerator(AbstractFunctionCode): - def __init__(self, space, func, isLambda, class_name, mod, parentscopeambiguity): + def __init__(self, space, func, isLambda, mod): assert func.scope is not None self.scope = func.scope - self.localsfullyknown = self.scope.localsfullyknown - self.scopeambiguity = (not self.localsfullyknown or parentscopeambiguity) - AbstractFunctionCode.__init__(self, space, func, isLambda, class_name, mod) + self.localsfullyknown = self.scope.locals_fully_known() + AbstractFunctionCode.__init__(self, space, func, isLambda, mod) - self.graph.setFreeVars(self.scope.get_free_vars()) + self.graph.setFreeVars(self.scope.get_free_vars_in_scope()) self.graph.setCellVars(self.scope.get_cell_vars()) if self.scope.generator: self.graph.setFlag(CO_GENERATOR) class GenExprCodeGenerator(AbstractFunctionCode): - def __init__(self, space, gexp, class_name, mod, parentscopeambiguity): + def __init__(self, space, gexp, mod): assert gexp.scope is not None self.scope = gexp.scope - self.localsfullyknown = self.scope.localsfullyknown - self.scopeambiguity = (not self.localsfullyknown or parentscopeambiguity) - - AbstractFunctionCode.__init__(self, space, gexp, 1, class_name, mod) - self.graph.setFreeVars(self.scope.get_free_vars()) + self.localsfullyknown = self.scope.locals_fully_known() + AbstractFunctionCode.__init__(self, space, gexp, 1, mod) + self.graph.setFreeVars(self.scope.get_free_vars_in_scope()) self.graph.setCellVars(self.scope.get_cell_vars()) self.graph.setFlag(CO_GENERATOR) @@ -1416,7 +1392,6 @@ optimized=0, klass=1) CodeGenerator.__init__(self, space, graph) - self.class_name = klass.name self.graph.setFlag(CO_NEWLOCALS) if not space.is_w(klass.w_doc, space.w_None): self.setDocstring(klass.w_doc) @@ -1431,12 +1406,11 @@ class ClassCodeGenerator(AbstractClassCode): - def __init__(self, space, klass, module, parentscopeambiguity): + def __init__(self, space, klass, module): assert klass.scope is not None self.scope = klass.scope - self.scopeambiguity = parentscopeambiguity AbstractClassCode.__init__(self, space, klass, module) - self.graph.setFreeVars(self.scope.get_free_vars()) + self.graph.setFreeVars(self.scope.get_free_vars_in_scope()) self.graph.setCellVars(self.scope.get_cell_vars()) self.set_lineno(klass) self.emitop("LOAD_GLOBAL", "__name__") Modified: pypy/dist/pypy/interpreter/astcompiler/symbols.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/symbols.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/symbols.py Thu Nov 9 20:47:32 2006 @@ -7,210 +7,293 @@ from pypy.interpreter.pyparser.error import SyntaxError from pypy.interpreter import gateway - import sys -MANGLE_LEN = 256 + +# the 'role' of variables records how the variable is +# syntactically used in a given scope. +ROLE_NONE = ' ' +ROLE_USED = 'U' # used only +ROLE_DEFINED = 'D' # defined (i.e. assigned to) in the current scope +ROLE_GLOBAL = 'G' # marked with the 'global' keyword in the current scope +ROLE_PARAM = 'P' # function parameter + class Scope: - localsfullyknown = True - # XXX how much information do I need about each name? - def __init__(self, name, module, klass=None): - self.name = name - self.module = module - self.defs = {} - self.uses = {} - self.globals = {} - self.params = {} - self.frees = {} - self.hasbeenfree = {} - self.cells = {} - self.children = [] - # nested is true if the class could contain free variables, - # i.e. if it is nested within another function. - self.nested = 0 - self.generator = False - self.firstReturnWithArgument = None - self.klass = None - if klass is not None: - for i in range(len(klass)): - if klass[i] != '_': - self.klass = klass[i:] - break + bare_exec = False + import_star = False - def __repr__(self): - return "<%s: %s>" % (self.__class__.__name__, self.name) + def __init__(self, name, parent): + self.name = name + self.varroles = {} # {variable: role} + self.children = [] # children scopes + self.varscopes = None # initialized by build_var_scopes() + self.freevars = {} # vars to show up in the code object's + # co_freevars. Note that some vars may + # be only in this dict and not in + # varscopes; see need_passthrough_name() + self.parent = parent + if parent is not None: + parent.children.append(self) def mangle(self, name): - if self.klass is None: + if self.parent is None: return name - return mangle(name, self.klass) + else: + return self.parent.mangle(name) - def add_def(self, name): - self.defs[self.mangle(name)] = 1 + def locals_fully_known(self): + return not self.bare_exec and not self.import_star - def add_use(self, name): - self.uses[self.mangle(name)] = 1 + def __repr__(self): + return "<%s: %s>" % (self.__class__.__name__, self.name) - def add_global(self, name): + def add_use(self, name): name = self.mangle(name) - if name in self.uses or name in self.defs: - pass # XXX warn about global following def/use - if name in self.params: - msg = "%s in %s is global and parameter" % (name, self.name) - raise SyntaxError( msg ) - self.globals[name] = 1 - self.module.add_def(name) + if name not in self.varroles: + self.varroles[name] = ROLE_USED - def add_param(self, name): + def add_def(self, name): name = self.mangle(name) - self.defs[name] = 1 - self.params[name] = 1 + if self.varroles.get(name, ROLE_USED) == ROLE_USED: + self.varroles[name] = ROLE_DEFINED - def get_names(self): - d = {} - d.update(self.defs) - d.update(self.uses) - d.update(self.globals) - return d.keys() + def add_global(self, name): + name = self.mangle(name) + prevrole = self.varroles.get(name, ROLE_NONE) + self.varroles[name] = ROLE_GLOBAL + return prevrole - def add_child(self, child): - self.children.append(child) + def add_return(self): + raise SyntaxError("'return' outside function") - def get_children(self): - return self.children + def add_yield(self): + raise SyntaxError("'yield' outside function") def DEBUG(self): - print >> sys.stderr, self.name, self.nested and "nested" or "" - print >> sys.stderr, "\tglobals: ", self.globals - print >> sys.stderr, "\tcells: ", self.cells - print >> sys.stderr, "\tdefs: ", self.defs - print >> sys.stderr, "\tuses: ", self.uses - print >> sys.stderr, "\tfrees:", self.frees + print >> sys.stderr, self + print >> sys.stderr, "\troles: ", self.varroles + print >> sys.stderr, "\tscopes: ", self.varscopes + + def build_var_scopes(self, names_from_enclosing_funcs): + """Build the varscopes dictionary of this scope and all children. + + The names_from_enclosing_funcs are the names that come from + enclosing scopes. It is a dictionary {name: source_function_scope}, + where the source_function_scope might be None to mean 'from the + global scope'. The whole names_from_enclosing_funcs can also be + None, to mean that we don't know anything statically because of a + bare exec or import *. + + A call to build_var_scopes() that uses a variable from an enclosing + scope must patch the varscopes of that enclosing scope, to make the + variable SC_CELL instead of SC_LOCAL, as well as the intermediate + scopes, to make the variable SC_FREE in them. + """ + newnames = {} # new names that this scope potentially exports + # to its children (if it is a FunctionScope) + self.varscopes = {} + for name, role in self.varroles.items(): + if role == ROLE_USED: + # where does this variable come from? + if names_from_enclosing_funcs is None: + msg = self.parent.get_ambiguous_name_msg( + "it contains a nested function using the " + "variable '%s'" % (name,)) + raise SyntaxError(msg) + if name in names_from_enclosing_funcs: + enclosingscope = names_from_enclosing_funcs[name] + if enclosingscope is None: + # it is a global var + scope = SC_GLOBAL + else: + if not self.locals_fully_known(): + msg = self.get_ambiguous_name_msg( + "it is a nested function, so the origin of " + "the variable '%s' is ambiguous" % (name,)) + raise SyntaxError(msg) + enclosingscope.varscopes[name] = SC_CELL + parent = self.parent + while parent is not enclosingscope: + parent.need_passthrough_name(name) + parent = parent.parent + self.freevars[name] = True + scope = SC_FREE + else: + scope = SC_DEFAULT + self._use_var() + elif role == ROLE_GLOBAL: + # a global var + newnames[name] = None + scope = SC_GLOBAL + else: + # a ROLE_DEFINED or ROLE_PARAM local var + newnames[name] = self + scope = SC_LOCAL + self.varscopes[name] = scope + # call build_var_scopes() on all the children + names_enclosing_children = self.export_names_to_children( + names_from_enclosing_funcs, + newnames) + for subscope in self.children: + subscope.build_var_scopes(names_enclosing_children) + + def export_names_to_children(self, names_from_enclosing_funcs, newnames): + # by default, scopes don't export names to their children + # (only FunctionScopes do) + return names_from_enclosing_funcs + + def need_passthrough_name(self, name): + # make the 'name' pass through the 'self' scope, without showing + # up in the normal way in the scope. This case occurs when a + # free variable is needed in some inner sub-scope, and comes from + # some outer super-scope. Hiding the name is needed for e.g. class + # scopes, otherwise the name sometimes end up in the class __dict__. + # Note that FunctionScope override this to *not* hide the name, + # because users might expect it to show up in the function's locals + # then... + self.freevars[name] = True + + def _use_var(self): + pass + + def get_ambiguous_name_msg(self, reason): + if self.bare_exec: + cause = "unqualified exec" + elif self.import_star: + cause = "import *" + else: + assert self.parent + return self.parent.get_ambiguous_name_msg(reason) + return "%s is not allowed in '%s' because %s" % (cause, self.name, + reason) def check_name(self, name): """Return scope of name. - - The scope of a name could be LOCAL, GLOBAL, FREE, or CELL. """ - if name in self.globals: - return SC_GLOBAL - if name in self.cells: - return SC_CELL - if name in self.defs: - return SC_LOCAL - if self.nested and (name in self.frees or - name in self.uses): - return SC_FREE - if self.nested: - return SC_UNKNOWN - else: - return SC_DEFAULT - - def get_free_vars(self): - if not self.nested: - return [] - free = {} - free.update(self.frees) - for name in self.uses.keys(): - if not (name in self.defs or - name in self.globals): - free[name] = 1 - self.hasbeenfree.update(free) - return free.keys() - - def handle_children(self): - for child in self.children: - frees = child.get_free_vars() - globals = self.add_frees(frees) - for name in globals: - child.force_global(name) - - def force_global(self, name): - """Force name to be global in scope. - - Some child of the current node had a free reference to name. - When the child was processed, it was labelled a free - variable. Now that all its enclosing scope have been - processed, the name is known to be a global or builtin. So - walk back down the child chain and set the name to be global - rather than free. + return self.varscopes.get(name, SC_UNKNOWN) - Be careful to stop if a child does not think the name is - free. - """ - if name not in self.defs: - self.globals[name] = 1 - if name in self.frees: - del self.frees[name] - for child in self.children: - if child.check_name(name) == SC_FREE or isinstance(child, ClassScope): - child.force_global(name) - - def add_frees(self, names): - """Process list of free vars from nested scope. - - Returns a list of names that are either 1) declared global in the - parent or 2) undefined in a top-level parent. In either case, - the nested scope should treat them as globals. - """ - child_globals = [] - for name in names: - name = self.mangle(name) - sc = self.check_name(name) - if self.nested: - if sc == SC_UNKNOWN or sc == SC_FREE \ - or isinstance(self, ClassScope): - self.frees[name] = 1 - elif sc == SC_DEFAULT or sc == SC_GLOBAL: - child_globals.append(name) - elif isinstance(self, FunctionScope) and sc == SC_LOCAL: - self.cells[name] = 1 - elif sc != SC_CELL: - child_globals.append(name) - else: - if sc == SC_LOCAL: - self.cells[name] = 1 - elif sc != SC_CELL: - child_globals.append(name) - return child_globals + def get_free_vars_in_scope(self): + # list the names of the free variables, giving them the name they + # should have inside this scope + result = [] + for name in self.freevars: + if self.check_name(name) != SC_FREE: + # it's not considered as a free variable within this scope, + # but only a need_passthrough_name(). We need to hide the + # name to avoid confusion with another potential use of the + # name in the 'self' scope. + name = hiddenname(name) + result.append(name) + return result + + def get_free_vars_in_parent(self): + # list the names of the free variables, giving them the name they + # should have in the parent scope + result = [] + for name in self.freevars: + if self.parent.check_name(name) not in (SC_FREE, SC_CELL): + # it's not considered as a free variable in the parent scope, + # but only a need_passthrough_name(). We need to hide the + # name to avoid confusion with another potential use of the + # name in the parent scope. + name = hiddenname(name) + result.append(name) + return result def get_cell_vars(self): - return self.cells.keys() + return [name for name, scope in self.varscopes.items() + if scope == SC_CELL] + class ModuleScope(Scope): def __init__(self): - Scope.__init__(self, "global", self) + Scope.__init__(self, "global", None) + + def finished(self): + self.build_var_scopes({}) + class FunctionScope(Scope): - pass + generator = False + + def add_param(self, name): + name = self.mangle(name) + if name in self.varroles: + msg = "duplicate argument '%s' in function definition" % (name,) + raise SyntaxError(msg) + self.varroles[name] = ROLE_PARAM + + def add_return(self): + pass + + def add_yield(self): + self.generator = True + + def export_names_to_children(self, names_from_enclosing_funcs, newnames): + if names_from_enclosing_funcs is None: + return None + if not self.locals_fully_known(): + return None + d = names_from_enclosing_funcs.copy() + d.update(newnames) + return d + + def need_passthrough_name(self, name): + # overrides Scope.need_passthrough_name(), see comments there + if name not in self.varscopes: + self.varscopes[name] = SC_FREE + self.freevars[name] = True + + def _use_var(self): + # some extra checks just for CPython compatibility -- the logic + # of build_var_scopes() in symbols.py should be able to detect + # all the cases that would really produce broken code, but CPython + # insists on raising SyntaxError in some more cases + if self._is_nested_function(): + if self.bare_exec: + raise SyntaxError("for CPython compatibility, an unqualified " + "exec is not allowed here") + if self.import_star: + raise SyntaxError("for CPython compatibility, import * " + "is not allowed here") + + def _is_nested_function(self): + scope = self.parent + while scope is not None: + if isinstance(scope, FunctionScope): + return True + scope = scope.parent + return False -GenExprScopeCounter = Counter(1) class GenExprScope(FunctionScope): + _counter = Counter(1) - def __init__(self, module, klass=None): - i = GenExprScopeCounter.next() - Scope.__init__(self, "generator expression<%d>"%i, module, klass) + def __init__(self, parent): + i = GenExprScope._counter.next() + FunctionScope.__init__(self, "generator expression<%d>" % i, parent) self.add_param('[outmost-iterable]') - def get_names(self): - keys = Scope.get_names() - return keys - -LambdaScopeCounter = Counter(1) class LambdaScope(FunctionScope): + _counter = Counter(1) + + def __init__(self, parent): + i = LambdaScope._counter.next() + FunctionScope.__init__(self, "lambda.%d" % i, parent) - def __init__(self, module, klass=None): - i = LambdaScopeCounter.next() - Scope.__init__(self, "lambda.%d" % i, module, klass) class ClassScope(Scope): - def __init__(self, name, module): - Scope.__init__(self, name, module, name) + def mangle(self, name): + return mangle(name, self.name) + + +def hiddenname(name): + return '.(%s)' % (name,) + app = gateway.applevel(r''' def issue_warning(msg, filename, lineno): @@ -230,7 +313,6 @@ class SymbolVisitor(ast.ASTVisitor): def __init__(self, space): self.space = space - self.klass = None self.scope_stack = [] self.assign_stack = [ False ] @@ -256,15 +338,19 @@ def visitModule(self, node): scope = self.module = node.scope = ModuleScope() + if node.w_doc is not None: + scope.add_def('__doc__') self.push_scope(scope) node.node.accept(self) self.pop_scope() + scope.finished() def visitExpression(self, node): scope = self.module = node.scope = ModuleScope() self.push_scope(scope) node.node.accept(self) self.pop_scope() + scope.finished() def visitFunction(self, node): parent = self.cur_scope() @@ -273,33 +359,26 @@ parent.add_def(node.name) for n in node.defaults: n.accept( self ) - scope = FunctionScope(node.name, self.module, self.klass) - if parent.nested or isinstance(parent, FunctionScope): - scope.nested = 1 + scope = FunctionScope(node.name, parent) node.scope = scope self._do_args(scope, node.argnames) self.push_scope( scope ) node.code.accept(self ) self.pop_scope() - self.handle_free_vars(scope, parent) def visitExec(self, node): if not (node.globals or node.locals): parent = self.cur_scope() - parent.localsfullyknown = False # bare exec statement + parent.bare_exec = True ast.ASTVisitor.visitExec(self, node) def visitGenExpr(self, node ): parent = self.cur_scope() - scope = GenExprScope(self.module, self.klass); - if parent.nested or isinstance(parent, FunctionScope): - scope.nested = 1 - + scope = GenExprScope(parent) node.scope = scope self.push_scope(scope) node.code.accept(self) self.pop_scope() - self.handle_free_vars(scope, parent) def visitGenExprInner(self, node ): for genfor in node.quals: @@ -311,7 +390,13 @@ self.push_assignment( True ) node.assign.accept(self) self.pop_assignment() - node.iter.accept(self ) + if node.is_outmost: + curscope = self.cur_scope() + self.pop_scope() + node.iter.accept(self) # in the parent scope + self.push_scope(curscope) + else: + node.iter.accept(self ) for if_ in node.ifs: if_.accept( self ) @@ -326,15 +411,12 @@ parent = self.cur_scope() for n in node.defaults: n.accept( self ) - scope = LambdaScope(self.module, self.klass) - if parent.nested or isinstance(parent, FunctionScope): - scope.nested = 1 + scope = LambdaScope(parent) node.scope = scope self._do_args(scope, node.argnames) self.push_scope(scope) node.code.accept(self) self.pop_scope() - self.handle_free_vars(scope, parent) def _do_args(self, scope, args): for arg in args: @@ -347,29 +429,19 @@ msg = "Argument list contains ASTNodes other than AssName or AssTuple" raise TypeError( msg ) - def handle_free_vars(self, scope, parent): - parent.add_child(scope) - scope.handle_children() - def visitClass(self, node): parent = self.cur_scope() parent.add_def(node.name) for n in node.bases: n.accept(self) - scope = ClassScope(node.name, self.module) - if parent.nested or isinstance(parent, FunctionScope): - scope.nested = 1 + scope = ClassScope(node.name, parent) if node.w_doc is not None: scope.add_def('__doc__') scope.add_def('__module__') node.scope = scope - prev = self.klass - self.klass = node.name self.push_scope( scope ) node.code.accept(self) self.pop_scope() - self.klass = prev - self.handle_free_vars(scope, parent) # name can be a def or a use @@ -399,7 +471,7 @@ scope = self.cur_scope() for name, asname in node.names: if name == "*": - scope.localsfullyknown = False + scope.import_star = True continue scope.add_def(asname or name) @@ -414,17 +486,18 @@ def visitGlobal(self, node ): scope = self.cur_scope() for name in node.names: - name = scope.mangle(name) - namescope = scope.check_name(name) - if namescope == SC_LOCAL: - issue_warning(self.space, "name '%s' is assigned to before " - "global declaration" %(name,), + prevrole = scope.add_global(name) + if prevrole == ROLE_PARAM: + msg = "name '%s' is a function parameter and declared global" + raise SyntaxError(msg % (name,)) + elif prevrole == ROLE_DEFINED: + msg = "name '%s' is assigned to before global declaration" + issue_warning(self.space, msg % (name,), node.filename, node.lineno) - elif namescope != SC_GLOBAL and name in scope.uses: - issue_warning(self.space, "name '%s' is used prior " - "to global declaration" %(name,), + elif prevrole == ROLE_USED: + msg = "name '%s' is used prior to global declaration" + issue_warning(self.space, msg % (name,), node.filename, node.lineno) - scope.add_global(name) def visitAssign(self, node ): """Propagate assignment flag down to child nodes. @@ -485,21 +558,13 @@ def visitYield(self, node ): scope = self.cur_scope() - scope.generator = True - if scope.firstReturnWithArgument is not None: - raise SyntaxError("'return' with argument inside generator", - scope.firstReturnWithArgument.lineno) - + scope.add_yield() node.value.accept( self ) def visitReturn(self, node): scope = self.cur_scope() + scope.add_return() if node.value is not None: - if scope.generator: - raise SyntaxError("'return' with argument inside generator", - node.lineno) - if scope.firstReturnWithArgument is None: - scope.firstReturnWithArgument = node node.value.accept(self) def visitCondExpr(self, node): 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 Thu Nov 9 20:47:32 2006 @@ -477,14 +477,15 @@ except ValueError, err: pass """, - """try: - a -except NameError, err: - a = 1 - b = 2 -except ValueError, err: - a = 2 - return a + """def f(): + try: + a + except NameError, err: + a = 1 + b = 2 + except ValueError, err: + a = 2 + return a """ """try: a @@ -500,11 +501,12 @@ finally: b """, - """try: - return a -finally: - a = 3 - return 1 + """def f(): + try: + return a + finally: + a = 3 + return 1 """, ] @@ -556,7 +558,7 @@ 'def f(): return a.b', 'def f(): return a', 'def f(): return a,b,c,d', - 'return (a,b,c,d)', + #'return (a,b,c,d)', --- this one makes no sense, as far as I can tell ] augassigns = [ Modified: pypy/dist/pypy/interpreter/test/test_compiler.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_compiler.py (original) +++ pypy/dist/pypy/interpreter/test/test_compiler.py Thu Nov 9 20:47:32 2006 @@ -88,12 +88,16 @@ assert ex.match(self.space, self.space.w_SyntaxError) def test_scope_unoptimized_clash1_b(self): + # as far as I can tell, this case can be handled correctly + # by the interpreter so a SyntaxError is not required, but + # let's give one anyway for "compatibility"... + # mostly taken from test_scope.py e = py.test.raises(OperationError, self.compiler.compile, """if 1: def unoptimized_clash1(strip): def f(): from string import * - return s # ambiguity: free or local + return s # ambiguity: free or local (? no, global or local) return f""", '', 'exec', 0) ex = e.value assert ex.match(self.space, self.space.w_SyntaxError) @@ -483,6 +487,62 @@ space.exec_(code, w_d, w_d) # assert did not crash + def test_free_vars_across_class(self): + space = self.space + snippet = str(py.code.Source(r''' + def f(x): + class Test: + def meth(self): + return x + 1 + return Test() + res = f(42).meth() + ''')) + code = self.compiler.compile(snippet, '', 'exec', 0) + space = self.space + w_d = space.newdict() + space.exec_(code, w_d, w_d) + assert space.int_w(space.getitem(w_d, space.wrap('res'))) == 43 + + def test_pick_global_names(self): + space = self.space + snippet = str(py.code.Source(r''' + def f(x): + def g(): + global x + def h(): + return x + return h() + return g() + x = "global value" + res = f("local value") + ''')) + code = self.compiler.compile(snippet, '', 'exec', 0) + space = self.space + w_d = space.newdict() + space.exec_(code, w_d, w_d) + w_res = space.getitem(w_d, space.wrap('res')) + assert space.str_w(w_res) == "global value" + + def test_method_and_var(self): + space = self.space + snippet = str(py.code.Source(r''' + def f(): + method_and_var = "var" + class Test: + def method_and_var(self): + return "method" + def test(self): + return method_and_var + return Test().test() + res = f() + ''')) + code = self.compiler.compile(snippet, '', 'exec', 0) + space = self.space + w_d = space.newdict() + space.exec_(code, w_d, w_d) + w_res = space.getitem(w_d, space.wrap('res')) + assert space.eq_w(w_res, space.wrap("var")) + class TestECCompiler(BaseTestCompiler): def setup_method(self, method): self.compiler = self.space.getexecutioncontext().compiler Modified: pypy/dist/pypy/interpreter/test/test_generator.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_generator.py (original) +++ pypy/dist/pypy/interpreter/test/test_generator.py Thu Nov 9 20:47:32 2006 @@ -54,3 +54,17 @@ skip("generator expressions only work on Python >= 2.4") exec "res = sum(i*i for i in range(5))" assert res == 30 + + def test_generator_expression_2(self): + import sys + if sys.version_info < (2, 4): + skip("generator expressions only work on Python >= 2.4") + d = {} + exec """ +def f(): + total = sum(i for i in [x for x in z]) + return total, x +z = [1, 2, 7] +res = f() +""" in d + assert d['res'] == (10, 7) 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 Nov 9 20:47:32 2006 @@ -101,23 +101,23 @@ exec "hi" x - def f(x): - class g: - exec "hi" - x - def f(): class g: from a import * x - def f(x): - class g: - from a import * - x - """) +## --- the following ones are valid in CPython, but not sensibly so: +## --- if x is rebound, then it is even rebound in the parent scope! +## def f(x): +## class g: +## from a import * +## x +## def f(x): +## class g: +## exec "x=41" +## x INVALID = splitcases(""" @@ -125,6 +125,7 @@ def g(): exec "hi" x + # NB. the above one is invalid in CPython, but there is no real reason def f(x): def g(): @@ -135,6 +136,7 @@ def g(): from a import * x + # NB. the above one is invalid in CPython, but there is no real reason def f(x): def g(): @@ -206,6 +208,12 @@ def f(): (i for i in x) = 10 + def f(x): + def g(): + from a import * + def k(): + return x + """) From mwh at codespeak.net Thu Nov 9 21:40:09 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 9 Nov 2006 21:40:09 +0100 (CET) Subject: [pypy-svn] r34443 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061109204009.49BDA100AC@code0.codespeak.net> Author: mwh Date: Thu Nov 9 21:40:06 2006 New Revision: 34443 Modified: pypy/dist/pypy/jit/codegen/ppc/codebuf.py pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: first implementation of flexswitch for ppc. i made some very silly mistakes doing this :-) Modified: pypy/dist/pypy/jit/codegen/ppc/codebuf.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/codebuf.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/codebuf.py Thu Nov 9 21:40:06 2006 @@ -49,12 +49,10 @@ class MachineCodeBlock: - def __init__(self, map_size): - assert map_size % 4 == 0 - res = alloc(map_size) - self._data = cast(res, POINTER(c_int * (map_size / 4))) - self._size = map_size/4 - self._pos = 0 + def __init__(self, _data, _size, _pos): + self._data = _data + self._size = _size + self._pos = _pos def write(self, data): p = self._pos @@ -63,9 +61,30 @@ self._data.contents[p] = data self._pos = p + 1 + def getpos(self): + return self._pos + + def setpos(self, _pos): + self._pos = _pos + def tell(self): baseaddr = cast(self._data, c_void_p).value return baseaddr + self._pos * 4 + def reserve(self, _size): + r = MachineCodeBlock(self._data, self._pos + _size, self._pos) + for i in range(_size): + self.write(0) + return r + +class OwningMachineCodeBlock(MachineCodeBlock): def __del__(self): free(cast(self._data, PTR), self._size * 4) + +def new_block(size_in_bytes): + assert size_in_bytes % 4 == 0 + res = alloc(size_in_bytes) + return OwningMachineCodeBlock( + cast(res, POINTER(c_int * (size_in_bytes / 4))), + size_in_bytes/4, + 0) Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Thu Nov 9 21:40:06 2006 @@ -297,3 +297,18 @@ def emit(self, asm): if self.reg.number != 3: asm.mr(r3, self.reg.number) + +class FakeUse(Insn): + """ A fake use of a var to get it into a register. And reserving + a condition register field.""" + def __init__(self, rvar, var): + Insn.__init__(self) + self.var = var + self.reg_args = [self.var] + self.reg_arg_regclasses = [GP_REGISTER] + self.result = rvar + self.result_regclass = CR_FIELD + def allocate(self, allocator): + pass + def emit(self, asm): + pass Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Thu Nov 9 21:40:06 2006 @@ -260,7 +260,17 @@ self.asm.bctr() self._close() -## def flexswitch(self, gv_exitswitch): + def flexswitch(self, gv_exitswitch): + # make sure the exitswitch ends the block in a register: + crresult = Var() + self.insns.append(insn.FakeUse(crresult, gv_exitswitch)) + allocator = self.allocate_and_emit() + switch_mc = self.asm.mc.reserve(7 * 5 + 4) + self._close() + return FlexSwitch(self.rgenop, switch_mc, + allocator.loc_of(gv_exitswitch), + allocator.loc_of(crresult), + allocator.var2loc) # ---------------------------------------------------------------- # ppc-specific interface: @@ -551,45 +561,68 @@ if self.mcs: return self.mcs.pop() else: - return codebuf.MachineCodeBlock(65536) # XXX supposed infinite for now + return codebuf.new_block(65536) # XXX supposed infinite for now def close_mc(self, mc): +## from pypy.translator.asm.ppcgen.asmfunc import get_ppcgen +## print '!!!!', cast(mc._data, c_void_p).value +## print '!!!!', mc._data.contents[0] +## get_ppcgen().flush2(cast(mc._data, c_void_p).value, +## mc._size*4) self.mcs.append(mc) def openbuilder(self): return Builder(self, self.open_mc()) -## class FlexSwitch(CodeGenSwitch): +# a switch can take 7 instructions: -## def __init__(self, rgenop): -## self.rgenop = rgenop -## self.default_case_addr = 0 - -## def initialize(self, builder, gv_exitswitch): -## self.switch_reg = gv_exitswitch.load(builder) -## self.saved_state = builder._save_state() -## self._reserve(mc) - -## def _reserve(self, mc): -## RESERVED = 11 # enough for 5 cases and a default -## pos = mc.tell() -## for i in range(RESERVED): -## mc.write(0) -## self.nextfreepos = pos -## self.endfreepos = pos + RESERVED * 4 +# load_word rSCRATCH, gv_case.value (really two instructions) +# cmpw crf, rSWITCH, rSCRATCH +# load_word rSCRATCH, targetaddr (again two instructions) +# mtctr rSCRATCH +# beqctr crf + +# yay RISC :/ + +class FlexSwitch(CodeGenSwitch): + + def __init__(self, rgenop, mc, switch_reg, crf, var2loc): + self.rgenop = rgenop + self.crf = crf + self.switch_reg = switch_reg + self.var2loc = var2loc + self.asm = RPPCAssembler() + self.asm.mc = mc + self.default_target_addr = 0 ## def _reserve_more(self): ## XXX -## start = self.nextfreepos -## end = self.endfreepos -## newmc = self.rgenop.open_mc() -## self._reserve(newmc) -## self.rgenop.close_mc(newmc) -## fullmc = InMemoryCodeBuilder(start, end) -## a = RPPCAssembler() -## a.mc = newmc -## fullmc.ba(rel32(self.nextfreepos)) -## fullmc.done() -## def add_case(self, gv_case): -## def add_default(self): + def add_case(self, gv_case): + targetbuilder = self.rgenop.openbuilder() + targetbuilder.make_fresh_from_jump(self.var2loc) + target_addr = targetbuilder.asm.mc.tell() + asm = self.asm + assert isinstance(gv_case, IntConst) + asm.load_word(rSCRATCH, gv_case.value) + asm.cmpw(self.crf.number, rSCRATCH, self.switch_reg.number) + asm.load_word(rSCRATCH, target_addr) + asm.mtctr(rSCRATCH) + asm.bcctr(12, self.crf.number*4 + 2) + if self.default_target_addr: + self._write_default() + return targetbuilder + + def add_default(self): + targetbuilder = self.rgenop.openbuilder() + targetbuilder.make_fresh_from_jump(self.var2loc) + self.default_target_addr = targetbuilder.asm.mc.tell() + self._write_default() + return targetbuilder + + def _write_default(self): + pos = self.asm.mc.getpos() + self.asm.load_word(rSCRATCH, self.default_target_addr) + self.asm.mtctr(rSCRATCH) + self.asm.bctr() + self.asm.mc.setpos(pos) From cfbolz at codespeak.net Thu Nov 9 22:23:02 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Nov 2006 22:23:02 +0100 (CET) Subject: [pypy-svn] r34444 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem rpython/ootypesystem rpython/test translator/cli/src Message-ID: <20061109212302.9D1F4100BC@code0.codespeak.net> Author: cfbolz Date: Thu Nov 9 22:22:58 2006 New Revision: 34444 Modified: pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/rpython/lltypesystem/rstr.py pypy/dist/pypy/rpython/ootypesystem/ootype.py pypy/dist/pypy/rpython/rstr.py pypy/dist/pypy/rpython/test/test_rstr.py pypy/dist/pypy/translator/cli/src/pypylib.cs Log: implement str.count Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Thu Nov 9 22:22:58 2006 @@ -416,6 +416,9 @@ def method_rfind(str, frag, start=None, end=None): return SomeInteger() + def method_count(str, frag, start=None, end=None): + return SomeInteger(nonneg=True) + def method_strip(str, chr): return SomeString() Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rstr.py Thu Nov 9 22:22:58 2006 @@ -126,6 +126,27 @@ # get flowed and annotated, mostly with SomePtr. # +def ll_construct_restart_positions(s, l): + # Construct the array of possible restarting positions + # T = Array_of_ints [-1..len2] + # T[-1] = -1 s2.chars[-1] is supposed to be unequal to everything else + T = malloc( SIGNED_ARRAY, l) + T[0] = 0 + i = 1 + j = 0 + while i0: + j = T[j-1] + else: + T[i] = 0 + i += 1 + j = 0 + return T + class LLHelpers(AbstractLLHelpers): def ll_char_mul(ch, times): @@ -355,6 +376,15 @@ return i return -1 + def ll_count_char(s, ch, start, end): + count = 0 + i = start + while i < end: + if s.chars[i] == ch: + count += 1 + i += 1 + return count + def ll_find(cls, s1, s2, start, end): """Knuth Morris Prath algorithm for substring match""" len1 = len(s1.chars) @@ -367,24 +397,8 @@ if (end-start) < 0: return -1 return start - # Construct the array of possible restarting positions - # T = Array_of_ints [-1..len2] - # T[-1] = -1 s2.chars[-1] is supposed to be unequal to everything else - T = malloc( SIGNED_ARRAY, len2 ) - T[0] = 0 - i = 1 - j = 0 - while i0: - j = T[j-1] - else: - T[i] = 0 - i += 1 - j = 0 + + T = ll_construct_restart_positions(s2, len2) # Now the find algorithm i = 0 @@ -451,6 +465,42 @@ return -1 ll_rfind = classmethod(ll_rfind) + def ll_count(cls, s1, s2, start, end): + """Knuth Morris Prath algorithm for substring match""" + # XXX more code should be shared with ll_find + len1 = len(s1.chars) + if end > len1: + end = len1 + len2 = len(s2.chars) + if len2 == 1: + return cls.ll_count_char(s1, s2.chars[0], start, end) + if len2 == 0: + if (end-start) < 0: + return 0 + return end - start + 1 + T = ll_construct_restart_positions(s2, len2) + + # Now the find algorithm + i = 0 + m = start + result = 0 + while m+i 2: + v_start = hop.inputarg(Signed, arg=2) + if not hop.args_s[2].nonneg: + raise TyperError("str.count() start must be proven non-negative") + else: + v_start = hop.inputconst(Signed, 0) + if hop.nb_args > 3: + v_end = hop.inputarg(Signed, arg=3) + if not hop.args_s[2].nonneg: + raise TyperError("str.count() end must be proven non-negative") + else: + v_end = hop.gendirectcall(self.ll.ll_strlen, v_str) + hop.exception_cannot_occur() + return hop.gendirectcall(llfn, v_str, v_value, v_start, v_end) + def rtype_method_strip(self, hop, left=True, right=True): rstr = hop.rtyper.type_system.rstr v_str = hop.inputarg(rstr.string_repr, arg=0) Modified: pypy/dist/pypy/rpython/test/test_rstr.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rstr.py (original) +++ pypy/dist/pypy/rpython/test/test_rstr.py Thu Nov 9 22:22:58 2006 @@ -580,6 +580,21 @@ res = self.interpret(fn, [3]) assert self.ll_to_string(res) == 'xxx' + def test_count_char(self): + def fn(i): + s = "".join(["abcasd"] * i) + return s.count("a") + s.count("a", 2) + s.count("b", 1, 6) + res = self.interpret(fn, [4]) + assert res == 8 + 7 + 1 + + def test_count(self): + def fn(i): + s = "".join(["abcabsd"] * i) + one = i / i # confuse the annotator + return (s.count("abc") + "abcde".count("") + + "abcda".count("a" * one)) + res = self.interpret(fn, [4]) + assert res == 4 + 6 + 2 def FIXME_test_str_to_pystringobj(): def f(n): Modified: pypy/dist/pypy/translator/cli/src/pypylib.cs ============================================================================== --- pypy/dist/pypy/translator/cli/src/pypylib.cs (original) +++ pypy/dist/pypy/translator/cli/src/pypylib.cs Thu Nov 9 22:22:58 2006 @@ -213,6 +213,44 @@ return s1.IndexOf(s2, start, count); } + public static int ll_count(string s1, string s2, int start, int stop) + { + if (stop > s1.Length) + stop = s1.Length; + if (s2.Length == 0) + { + if ((stop-start) < 0) + { + return 0; + } + return stop - start + 1; + } + int result = 0; + int i = start; + while (true) + { + int pos = ll_find(s1, s2, i, stop); + Console.Error.WriteLine("pos " + pos + "\n"); + if (pos < 0) + return result; + result += 1; + i = pos + s2.Length; + } + } + + public static int ll_count_char(string s1, char c, int start, int stop) + { + if (stop > s1.Length) + stop = s1.Length; + int result = 0; + for (int i=start; i < stop; i++) { + if (s1[i] == c) + result += 1; + } + return result; + } + + public static int ll_rfind(string s1, string s2, int start, int stop) { if (stop > s1.Length) From cfbolz at codespeak.net Thu Nov 9 22:25:39 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 9 Nov 2006 22:25:39 +0100 (CET) Subject: [pypy-svn] r34445 - pypy/dist/pypy/translator/cli/src Message-ID: <20061109212539.0813B100B4@code0.codespeak.net> Author: cfbolz Date: Thu Nov 9 22:25:36 2006 New Revision: 34445 Modified: pypy/dist/pypy/translator/cli/src/pypylib.cs Log: remove debug print Modified: pypy/dist/pypy/translator/cli/src/pypylib.cs ============================================================================== --- pypy/dist/pypy/translator/cli/src/pypylib.cs (original) +++ pypy/dist/pypy/translator/cli/src/pypylib.cs Thu Nov 9 22:25:36 2006 @@ -230,7 +230,6 @@ while (true) { int pos = ll_find(s1, s2, i, stop); - Console.Error.WriteLine("pos " + pos + "\n"); if (pos < 0) return result; result += 1; From guido at codespeak.net Fri Nov 10 10:56:44 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 10 Nov 2006 10:56:44 +0100 (CET) Subject: [pypy-svn] r34449 - in pypy/dist/pypy/translator/js/modules: . test Message-ID: <20061110095644.84ED4100B8@code0.codespeak.net> Author: guido Date: Fri Nov 10 10:56:38 2006 New Revision: 34449 Removed: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Removing unused module, going to replace with an improvement version soon. From guido at codespeak.net Fri Nov 10 11:17:19 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 10 Nov 2006 11:17:19 +0100 (CET) Subject: [pypy-svn] r34450 - in pypy/dist/pypy/translator/js: . demo/jsdemo demo/jsdemo/djangoping examples modules modules/test test Message-ID: <20061110101719.B271F100BA@code0.codespeak.net> Author: guido Date: Fri Nov 10 11:17:13 2006 New Revision: 34450 Added: pypy/dist/pypy/translator/js/modules/dom.py - copied, changed from r34449, pypy/dist/pypy/translator/js/modules/_dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Removed: pypy/dist/pypy/translator/js/modules/_dom.py Modified: pypy/dist/pypy/translator/js/database.py pypy/dist/pypy/translator/js/demo/jsdemo/consserv.py pypy/dist/pypy/translator/js/demo/jsdemo/djangoping/client.py pypy/dist/pypy/translator/js/demo/jsdemo/example.py pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py pypy/dist/pypy/translator/js/examples/console.py pypy/dist/pypy/translator/js/examples/start_bnb.py pypy/dist/pypy/translator/js/helper.py pypy/dist/pypy/translator/js/test/test_bltn.py Log: Replacing the old (unused) dom.py library with a new (although not shiny: some code was already available, previously known as _dom.py) implementation. The library provides a mock browser API for testing code that is supposed to be translated to JS and run in a browser on CPython. Some functionality is already available (e.g. xml.dom.minidom is wrapped a bit to provide a DOM level 2 implementation). Modified: pypy/dist/pypy/translator/js/database.py ============================================================================== --- pypy/dist/pypy/translator/js/database.py (original) +++ pypy/dist/pypy/translator/js/database.py Fri Nov 10 11:17:13 2006 @@ -17,7 +17,7 @@ from pypy.rpython.ootypesystem import bltregistry from pypy.objspace.flow.model import Variable, Constant -from pypy.translator.js.modules import _dom +from pypy.translator.js.modules import dom from pypy.translator.js.commproxy import XmlHttp try: Modified: pypy/dist/pypy/translator/js/demo/jsdemo/consserv.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/consserv.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/consserv.py Fri Nov 10 11:17:13 2006 @@ -13,7 +13,8 @@ from pypy.translator.js.test.runtest import compile_function -from pypy.translator.js.modules._dom import Node, get_document, setTimeout, alert +from pypy.translator.js.modules.dom import Node, get_document, setTimeout,\ + alert #from pypy.translator.js.modules.xmlhttp import XMLHttpRequest from pypy.translator.js.modules.mochikit import logDebug, createLoggingPane, log from pypy.translator.js.modules.bltns import date Modified: pypy/dist/pypy/translator/js/demo/jsdemo/djangoping/client.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/djangoping/client.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/djangoping/client.py Fri Nov 10 11:17:13 2006 @@ -3,7 +3,7 @@ from pypy.rpython.ootypesystem.bltregistry import BasicExternal, MethodDesc, described from pypy.translator.js.modules import mochikit -from pypy.translator.js.modules import _dom as dom +from pypy.translator.js.modules import dom class PingHandler(BasicExternal): """Server side code which handles javascript calls""" Modified: pypy/dist/pypy/translator/js/demo/jsdemo/example.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/example.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/example.py Fri Nov 10 11:17:13 2006 @@ -5,7 +5,7 @@ import autopath from pypy.translator.js.test.runtest import compile_function -from pypy.translator.js.modules._dom import setTimeout, get_document +from pypy.translator.js.modules.dom import setTimeout, get_document from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Fri Nov 10 11:17:13 2006 @@ -12,7 +12,7 @@ import new, sys, os, cStringIO from cgi import parse_qs -from pypy.translator.js.modules._dom import setTimeout, get_document +from pypy.translator.js.modules.dom import setTimeout, get_document from pypy.translator.js.main import rpython2javascript from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy Modified: pypy/dist/pypy/translator/js/examples/console.py ============================================================================== --- pypy/dist/pypy/translator/js/examples/console.py (original) +++ pypy/dist/pypy/translator/js/examples/console.py Fri Nov 10 11:17:13 2006 @@ -12,7 +12,8 @@ conftest.option.browser = "default" from pypy.translator.js.test.runtest import compile_function -from pypy.translator.js.modules._dom import Node, get_document, setTimeout, alert +from pypy.translator.js.modules.dom import Node, get_document, setTimeout, \ + alert #from pypy.translator.js.modules.xmlhttp import XMLHttpRequest from pypy.translator.js.modules.mochikit import logDebug, createLoggingPane, log from pypy.translator.js.modules.bltns import date Modified: pypy/dist/pypy/translator/js/examples/start_bnb.py ============================================================================== --- pypy/dist/pypy/translator/js/examples/start_bnb.py (original) +++ pypy/dist/pypy/translator/js/examples/start_bnb.py Fri Nov 10 11:17:13 2006 @@ -12,7 +12,7 @@ conftest.option.browser = "default" from pypy.translator.js.test.runtest import compile_function -from pypy.translator.js.modules._dom import get_document +from pypy.translator.js.modules.dom import get_document from pypy.translator.js.modules.xmlhttp import XMLHttpRequest from pypy.translator.js.modules.mochikit import log, logWarning, createLoggingPane, logDebug from pypy.translator.js.modules.bltns import date Modified: pypy/dist/pypy/translator/js/helper.py ============================================================================== --- pypy/dist/pypy/translator/js/helper.py (original) +++ pypy/dist/pypy/translator/js/helper.py Fri Nov 10 11:17:13 2006 @@ -2,7 +2,7 @@ """ Some helpers """ -from pypy.translator.js.modules._dom import get_document +from pypy.translator.js.modules.dom import get_document def escape(s): #return s.replace("&", "&").replace("<", "<").replace(">", ">"). \ Added: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Fri Nov 10 11:17:13 2006 @@ -0,0 +1,31 @@ +from pypy.translator.js.modules import dom + +def test_init(): + window = dom.Window('foo') + nodeType = window.document.nodeType + assert nodeType == 9 + docel = window.document.documentElement.nodeName + assert docel == 'HTML' + # XXX gotta love the DOM API ;) + assert window.document.getElementsByTagName('body')[0]\ + .childNodes[0].nodeValue == 'foo' + +def test_wrap(): + window = dom.Window() + document = window.document + div = document.createElement('div') + assert div.nodeType == 1 + document.documentElement.appendChild(div) + assert document.documentElement.childNodes[-1] == div + +def test_get_element_by_id(): + window = dom.Window('
') + div = window.document.getElementById('foo') + assert div.nodeName == 'DIV' + +def test_html_api(): + window = dom.Window() + document = window.document + div = document.createElement('div') + assert div.style + assert not div.style.backgroundColor Modified: pypy/dist/pypy/translator/js/test/test_bltn.py ============================================================================== --- pypy/dist/pypy/translator/js/test/test_bltn.py (original) +++ pypy/dist/pypy/translator/js/test/test_bltn.py Fri Nov 10 11:17:13 2006 @@ -10,9 +10,9 @@ def setup_function(fun): rebuild_basic_external() -# check rendering _dom.get_document() +# check rendering dom.get_document() def test_simple_builtin(): - from pypy.translator.js.modules._dom import get_document + from pypy.translator.js.modules.dom import get_document def test_document_call(): return get_document().getElementById("some_id") @@ -56,7 +56,7 @@ assert check_source_contains(fn, "\.some_callback = callback") def test_get_elements(): - from pypy.translator.js.modules import _dom as dom + from pypy.translator.js.modules import dom def getaa(tname): return dom.get_document().getElementsByTagName(tname)[0].nodeValue From arigo at codespeak.net Fri Nov 10 12:04:23 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 10 Nov 2006 12:04:23 +0100 (CET) Subject: [pypy-svn] r34452 - pypy/dist/pypy/config Message-ID: <20061110110423.8DEC3100C1@code0.codespeak.net> Author: arigo Date: Fri Nov 10 12:04:22 2006 New Revision: 34452 Modified: pypy/dist/pypy/config/pypyoption.py Log: The rctime->select dependency is only for posix platforms. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Fri Nov 10 12:04:22 2006 @@ -1,5 +1,5 @@ import autopath -import py +import py, os from pypy.config.config import OptionDescription, BoolOption, IntOption from pypy.config.config import ChoiceOption, StrOption, to_optparse, Config @@ -13,8 +13,9 @@ "math", "_sre", "_pickle_support", "sys", "exceptions", "__builtins__", "recparser", "symbol", "_random", "_file"]) -module_dependencies = { 'rctime': [("objspace.usemodules.select", True),], - } +module_dependencies = { } +if os.name == "posix": + module_dependencies['rctime'] = [("objspace.usemodules.select", True),] pypy_optiondescription = OptionDescription("pypy", "All PyPy Options", [ From cfbolz at codespeak.net Fri Nov 10 12:06:37 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 10 Nov 2006 12:06:37 +0100 (CET) Subject: [pypy-svn] r34453 - pypy/dist/pypy/objspace/std Message-ID: <20061110110637.B2E04100C4@code0.codespeak.net> Author: cfbolz Date: Fri Nov 10 12:06:36 2006 New Revision: 34453 Modified: pypy/dist/pypy/objspace/std/stringobject.py Log: count is now RPython Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Fri Nov 10 12:06:36 2006 @@ -629,20 +629,7 @@ u_end = space.int_w(w_end) assert u_start >= 0 assert u_end >= 0 - - if len(u_arg) == 0: - count = len(u_self) + 1 - else: - count = 0 - while 1: - pos = u_self.find(u_arg, u_start, u_end) - if pos < 0: - break - count += 1 - u_start = pos + len(u_arg) - - return wrapint(space, count) - + return wrapint(space, u_self.count(u_arg, u_start, u_end)) def str_endswith__String_String_ANY_ANY(space, w_self, w_suffix, w_start, w_end): (u_self, suffix, start, end) = _convert_idx_params(space, w_self, From ac at codespeak.net Fri Nov 10 12:27:22 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Fri, 10 Nov 2006 12:27:22 +0100 (CET) Subject: [pypy-svn] r34455 - in pypy/dist/pypy/module: rctime select Message-ID: <20061110112722.6DB31100CB@code0.codespeak.net> Author: ac Date: Fri Nov 10 12:27:21 2006 New Revision: 34455 Modified: pypy/dist/pypy/module/rctime/app_time.py pypy/dist/pypy/module/select/app_select.py Log: Do some typechecking on the arguments to time.sleep and select.select. Modified: pypy/dist/pypy/module/rctime/app_time.py ============================================================================== --- pypy/dist/pypy/module/rctime/app_time.py (original) +++ pypy/dist/pypy/module/rctime/app_time.py Fri Nov 10 12:27:21 2006 @@ -46,6 +46,8 @@ Delay execution for a given number of seconds. The argument may be a floating point number for subsecond precision.""" + if secs is None: + raise TypeError('a float is required') select([], [], [], secs) Modified: pypy/dist/pypy/module/select/app_select.py ============================================================================== --- pypy/dist/pypy/module/select/app_select.py (original) +++ pypy/dist/pypy/module/select/app_select.py Fri Nov 10 12:27:21 2006 @@ -56,7 +56,10 @@ for fd, mask in polldict.iteritems(): p.register(fd, mask) if timeout is not None: - ret = dict(p.poll(int(timeout * 1000))) + if (not hasattr(timeout, '__int__') and + not hasattr(timeout, '__float__')): + raise TypeError('timeout must be a float or None') + ret = dict(p.poll(int(float(timeout) * 1000))) else: ret = dict(p.poll()) From arigo at codespeak.net Fri Nov 10 12:49:06 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 10 Nov 2006 12:49:06 +0100 (CET) Subject: [pypy-svn] r34456 - in pypy/dist/pypy/interpreter/pyparser: . test Message-ID: <20061110114906.90F0410072@code0.codespeak.net> Author: arigo Date: Fri Nov 10 12:49:05 2006 New Revision: 34456 Modified: pypy/dist/pypy/interpreter/pyparser/astbuilder.py pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py Log: Test and fix for issue 259: def f((x)). Modified: pypy/dist/pypy/interpreter/pyparser/astbuilder.py ============================================================================== --- pypy/dist/pypy/interpreter/pyparser/astbuilder.py (original) +++ pypy/dist/pypy/interpreter/pyparser/astbuilder.py Fri Nov 10 12:49:05 2006 @@ -116,7 +116,7 @@ return arguments, stararg_token, dstararg_token -def parse_fpdef(tokens): +def parse_fpdef(tokens, index): """fpdef: fpdef: NAME | '(' fplist ')' fplist: fpdef (',' fpdef)* [','] @@ -124,29 +124,34 @@ but it can't work with the default compiler. We switched to use astcompiler module now """ - if tokens: - lineno = tokens[0].lineno - else: - lineno = -1 - top = ast.AssTuple([], lineno) - stack = [ top ] - tokens_read = 0 - while stack: - token = tokens[tokens_read] - tokens_read += 1 - if isinstance(token, TokenObject) and token.name == tok.COMMA: - continue - elif isinstance(token, TokenObject) and token.name == tok.LPAR: - new_tuple = ast.AssTuple([], lineno) - stack[-1].nodes.append( new_tuple ) - stack.append(new_tuple) - elif isinstance(token, TokenObject) and token.name == tok.RPAR: - stack.pop() - else: - assert isinstance(token, TokenObject) + nodes = [] + comma = False + while True: + token = tokens[index] + index += 1 + assert isinstance(token, TokenObject) + if token.name == tok.LPAR: # nested item + index, node = parse_fpdef(tokens, index) + elif token.name == tok.RPAR: # end of current nesting + break + else: # name val = token.get_value() - stack[-1].nodes.append(ast.AssName(val,consts.OP_ASSIGN, token.lineno)) - return tokens_read, top + node = ast.AssName(val, consts.OP_ASSIGN, token.lineno) + nodes.append(node) + + token = tokens[index] + index += 1 + assert isinstance(token, TokenObject) + if token.name == tok.COMMA: + comma = True + else: + assert token.name == tok.RPAR + break + if len(nodes) == 1 and not comma: + node = nodes[0] + else: + node = ast.AssTuple(nodes, token.lineno) + return index, node def parse_arglist(tokens): """returns names, defaults, flags""" @@ -169,9 +174,8 @@ # but we might do some experiment on the grammar at some point continue elif cur_token.name == tok.LPAR: - tokens_read, name_tuple = parse_fpdef(tokens[index:]) - index += tokens_read - names.append(name_tuple) + index, node = parse_fpdef(tokens, index) + names.append(node) elif cur_token.name == tok.STAR or cur_token.name == tok.DOUBLESTAR: if cur_token.name == tok.STAR: cur_token = tokens[index] @@ -1091,10 +1095,8 @@ # index += 1 while index < len(atoms): atom = atoms[index] - if isinstance(atom, TokenObject): - assert isinstance(atom, TokenObject) # rtyper info - if atom.get_value() == 'def': - break + if isinstance(atom, TokenObject) and atom.get_value() == 'def': + break decorators.append(atoms[index]) index += 1 if decorators: 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 Fri Nov 10 12:49:05 2006 @@ -525,6 +525,7 @@ "def f(a, b, (c, d), e): pass", "def f(a, b, (c, (d, e), f, (g, h))): pass", "def f(a, b, (c, (d, e), f, (g, h)), i): pass", + "def f((a)): pass", ] one_stmt_classdefs = [ From fijal at codespeak.net Fri Nov 10 14:26:42 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 10 Nov 2006 14:26:42 +0100 (CET) Subject: [pypy-svn] r34459 - in pypy/dist/pypy/rlib: . test Message-ID: <20061110132642.A3658100D3@code0.codespeak.net> Author: fijal Date: Fri Nov 10 14:26:40 2006 New Revision: 34459 Modified: pypy/dist/pypy/rlib/nonconst.py pypy/dist/pypy/rlib/test/test_nonconst.py Log: Fixed rlib to make sure that NonConst does not raise an exception. Modified: pypy/dist/pypy/rlib/nonconst.py ============================================================================== --- pypy/dist/pypy/rlib/nonconst.py (original) +++ pypy/dist/pypy/rlib/nonconst.py Fri Nov 10 14:26:40 2006 @@ -23,7 +23,7 @@ def specialize_call(self, hop): #v = Variable() #v.concretetype = hop.r_result.lowleveltype - hop.exception_is_here() + hop.exception_cannot_occur() retval = Constant(hop.r_result.convert_const(hop.args_v[0].value)) retval.concretetype = hop.r_result.lowleveltype return retval Modified: pypy/dist/pypy/rlib/test/test_nonconst.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_nonconst.py (original) +++ pypy/dist/pypy/rlib/test/test_nonconst.py Fri Nov 10 14:26:40 2006 @@ -6,6 +6,8 @@ from pypy.objspace.flow import FlowObjSpace from pypy.annotation.annrpython import RPythonAnnotator +from pypy.conftest import option +from pypy.annotation.model import SomeInstance def test_nonconst(): def nonconst_f(): @@ -16,6 +18,9 @@ s = a.build_types(nonconst_f, []) assert s.knowntype is int assert not hasattr(s, 'const') + #rtyper = a.translator.buildrtyper(type_system="ootype") + #rtyper.specialize() + def test_nonconst_list(): def nonconst_l(): @@ -26,3 +31,19 @@ s = a.build_types(nonconst_l, []) assert s.knowntype is int assert not hasattr(s, 'const') + +def test_nonconst_instance(): + class A: + pass + a = A() + + def nonconst_i(): + return NonConstant(a) + + a = RPythonAnnotator() + s = a.build_types(nonconst_i, []) + rtyper = a.translator.buildrtyper(type_system="ootype") + rtyper.specialize() + if option.view: + a.translator.view() + assert isinstance(s, SomeInstance) From fijal at codespeak.net Fri Nov 10 14:27:46 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 10 Nov 2006 14:27:46 +0100 (CET) Subject: [pypy-svn] r34460 - pypy/dist/pypy/translator/js/modules Message-ID: <20061110132746.B264D100D7@code0.codespeak.net> Author: fijal Date: Fri Nov 10 14:27:45 2006 New Revision: 34460 Modified: pypy/dist/pypy/translator/js/modules/dom.py Log: Make Style NonConstant. Probably everything else should be non-constant too, or we just need to kill constantness at some point on bltregistry. Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Fri Nov 10 14:27:45 2006 @@ -14,6 +14,7 @@ import time from pypy.rpython.ootypesystem.bltregistry import BasicExternal, MethodDesc +from pypy.rlib.nonconst import NonConstant from pypy.translator.stackless.test.test_transform import one from xml.dom import minidom @@ -298,7 +299,7 @@ 'scrollLeft' : 12, 'scrollTop' : 12, 'scrollWidth' : 12, - 'style' : Style(), + 'style' : NonConstant(Style()), 'tabIndex' : 12, 'tagName' : "aa", 'textContent' : "aa", @@ -483,18 +484,16 @@ # set the global 'window' instance to an empty HTML document, override using # dom.window = Window(html) (this will also set dom.document) window = Window() + def get_document(): - return document + return NonConstant(document) def get_window(): - return window + return NonConstant(window) get_window.suggested_primitive = True get_document.suggested_primitive = True -def some_fun(): - pass - def setTimeout(func, delay): # scheduler call, but we don't want to mess with threads right now if one(): From guido at codespeak.net Fri Nov 10 14:40:32 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 10 Nov 2006 14:40:32 +0100 (CET) Subject: [pypy-svn] r34461 - in pypy/dist/pypy/translator/js/modules: . test Message-ID: <20061110134032.2277C100CF@code0.codespeak.net> Author: guido Date: Fri Nov 10 14:40:31 2006 New Revision: 34461 Modified: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Improved inheritance tree, moved stuff around, overriding getElementsByTagName so it is case insensitive, added references to windows (self, parent, top, etc.), added innerHTML support. Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Fri Nov 10 14:40:31 2006 @@ -28,29 +28,92 @@ """base class of all node types""" def __init__(self, node=None): - if node is not None: - self._original = node + self._original = node def __getattr__(self, name): """attribute access gets proxied to the contained minidom node all returned minidom nodes are wrapped as Nodes """ + if (name not in self._fields and + (not hasattr(self, '_methods') or name not in self._methods)): + raise NameError, name value = getattr(self._original, name) return _wrap(value) + def __eq__(self, other): + original = getattr(other, '_original', other) + return original is self._original + +def _quote_html(text): + for char, e in [('&', 'amp'), ('<', 'lt'), ('>', 'gt'), ('"', 'quot'), + ("'", 'apos')]: + text = text.replace(char, '&%s;' % (e,)) + return text + +_singletons = ['link', 'meta'] +def _serialize_html(node): + ret = [] + if node.nodeType == 1: + nodeName = getattr(node, '_original', node).nodeName + ret += ['<', nodeName] + if len(node.attributes): + for aname in node.attributes.keys(): + attr = node.attributes[aname] + ret.append(' %s="%s"' % (attr.nodeName, attr.nodeValue)) + if len(node.childNodes) or nodeName not in _singletons: + ret.append('>') + for child in node.childNodes: + if child.nodeType == 1: + ret.append(_serialize_html(child)) + else: + ret.append(_quote_html(child.nodeValue)) + ret += [''] + else: + ret.append(' />') + return ''.join(ret) + +class HTMLNode(Node): + def getElementsByTagName(self, name): + name = name.lower() + return self.__getattr__('getElementsByTagName')(name) + + def _get_innerHTML(self): + ret = [] + for child in self.childNodes: + ret.append(_serialize_html(child)) + return ''.join(ret) + + def _set_innerHTML(self, html): + dom = minidom.parseString('%s' % (html,)) + while self.childNodes: + self.removeChild(self.lastChild) + for child in dom.documentElement.childNodes: + child = self.ownerDocument.importNode(child, True) + self.appendChild(child) + del dom + + innerHTML = property(_get_innerHTML, _set_innerHTML) + class Element(Node): - """element type""" nodeType = 1 + +class HTMLElement(HTMLNode, Element): id = '' - nodeName = '' + style = None def __init__(self, node=None): super(Element, self).__init__(node) if node is not None: - self.id = node.getAttribute('id') - self.nodeName = node.nodeName.upper() - self.style = Style() + self._init(node) + + def _init(self, node): + self.id = node.getAttribute('id') + self.style = Style() + + def _nodeName(self): + return self._original.nodeName.upper() + nodeName = property(_nodeName) class Attribute(Node): nodeType = 2 @@ -58,13 +121,11 @@ class Text(Node): nodeType = 3 -class Form(Element): - pass - -class Document(Element): +class Document(HTMLNode): nodeType = 9 def __init__(self, docnode=None): + super(Document, self).__init__(docnode) self._original = docnode def getElementById(self, id): @@ -75,27 +136,49 @@ class Window(BasicExternal): def __init__(self, html=('Untitled document' - '')): + ''), parent=None): global document - self.html = html - document = Document(minidom.parseString(html)) + self._html = html + self.document = document = Document(minidom.parseString(html)) + + # references to windows + self.content = self + self.self = self + self.window = self + self.parent = parent or self + self.top = self.parent + while 1: + if self.top.parent is self.top: + break + self.top = self.top.parent + + # other properties + self.closed = True def __getattr__(self, name): return globals()[name] -# now some functionality to wrap minidom nodes with Node classes, and to make -# sure all methods on the nodes return wrapped nodes rather than minidom ones +# the following code wraps minidom nodes with Node classes, and makes +# sure all methods on the nodes return wrapped nodes + class _FunctionWrapper(object): """makes sure function return values are wrapped if appropriate""" def __init__(self, callable): self._original = callable def __call__(self, *args, **kwargs): + args = list(args) + for i, arg in enumerate(args): + if isinstance(arg, Node): + args[i] = arg._original + for name, arg in kwargs.iteritems(): + if isinstance(arg, Node): + kwargs[arg] = arg._original value = self._original(*args, **kwargs) return _wrap(value) _typetoclass = { - 1: Element, + 1: HTMLElement, 2: Attribute, 3: Text, 9: Document, @@ -114,244 +197,148 @@ # more DOM API, the stuff that doesn't directly deal with XML # note that we're mimicking the standard (Mozilla) APIs, so things tested -# against this code may not work on Internet Explorer +# against this code may not work in Internet Explorer + class Event(BasicExternal): pass class KeyEvent(Event): - _fields = { - 'keyCode' : 12, - 'charCode' : 12, - } + pass class MouseEvent(Event): pass class Style(BasicExternal): - _fields = { - 'azimuth' : 'aa', - 'background' : 'aa', - 'backgroundAttachment' : 'aa', - 'backgroundColor' : 'aa', - 'backgroundImage' : 'aa', - 'backgroundPosition' : 'aa', - 'backgroundRepeat' : 'aa', - 'border' : 'aa', - 'borderBottom' : 'aa', - 'borderBottomColor' : 'aa', - 'borderBottomStyle' : 'aa', - 'borderBottomWidth' : 'aa', - 'borderCollapse' : 'aa', - 'borderColor' : 'aa', - 'borderLeft' : 'aa', - 'borderLeftColor' : 'aa', - 'borderLeftStyle' : 'aa', - 'borderLeftWidth' : 'aa', - 'borderRight' : 'aa', - 'borderRightColor' : 'aa', - 'borderRightStyle' : 'aa', - 'borderRightWidth' : 'aa', - 'borderSpacing' : 'aa', - 'borderStyle' : 'aa', - 'borderTop' : 'aa', - 'borderTopColor' : 'aa', - 'borderTopStyle' : 'aa', - 'borderTopWidth' : 'aa', - 'borderWidth' : 'aa', - 'bottom' : 'aa', - 'captionSide' : 'aa', - 'clear' : 'aa', - 'clip' : 'aa', - 'color' : 'aa', - 'content' : 'aa', - 'counterIncrement' : 'aa', - 'counterReset' : 'aa', - 'cssFloat' : 'aa', - 'cssText' : 'aa', - 'cue' : 'aa', - 'cueAfter' : 'aa', - 'onBefore' : 'aa', - 'cursor' : 'aa', - 'direction' : 'aa', - 'displays' : 'aa', - 'elevation' : 'aa', - 'emptyCells' : 'aa', - 'font' : 'aa', - 'fontFamily' : 'aa', - 'fontSize' : 'aa', - 'fontSizeAdjust' : 'aa', - 'fontStretch' : 'aa', - 'fontStyle' : 'aa', - 'fontVariant' : 'aa', - 'fontWeight' : 'aa', - 'height' : 'aa', - 'left' : 'aa', - 'length' : 'aa', - 'letterSpacing' : 'aa', - 'lineHeight' : 'aa', - 'listStyle' : 'aa', - 'listStyleImage' : 'aa', - 'listStylePosition' : 'aa', - 'listStyleType' : 'aa', - 'margin' : 'aa', - 'marginBottom' : 'aa', - 'marginLeft' : 'aa', - 'marginRight' : 'aa', - 'marginTop' : 'aa', - 'markerOffset' : 'aa', - 'marks' : 'aa', - 'maxHeight' : 'aa', - 'maxWidth' : 'aa', - 'minHeight' : 'aa', - 'minWidth' : 'aa', - 'MozBinding' : 'aa', - 'MozOpacity' : 'aa', - 'orphans' : 'aa', - 'outline' : 'aa', - 'outlineColor' : 'aa', - 'outlineStyle' : 'aa', - 'outlineWidth' : 'aa', - 'overflow' : 'aa', - 'padding' : 'aa', - 'paddingBottom' : 'aa', - 'paddingLeft' : 'aa', - 'paddingRight' : 'aa', - 'paddingTop' : 'aa', - 'page' : 'aa', - 'pageBreakAfter' : 'aa', - 'pageBreakBefore' : 'aa', - 'pageBreakInside' : 'aa', - 'parentRule' : 'aa', - 'pause' : 'aa', - 'pauseAfter' : 'aa', - 'pauseBefore' : 'aa', - 'pitch' : 'aa', - 'pitchRange' : 'aa', - 'playDuring' : 'aa', - 'position' : 'aa', - 'quotes' : 'aa', - 'richness' : 'aa', - 'right' : 'aa', - 'size' : 'aa', - 'speak' : 'aa', - 'speakHeader' : 'aa', - 'speakNumeral' : 'aa', - 'speakPunctuation' : 'aa', - 'speechRate' : 'aa', - 'stress' : 'aa', - 'tableLayout' : 'aa', - 'textAlign' : 'aa', - 'textDecoration' : 'aa', - 'textIndent' : 'aa', - 'textShadow' : 'aa', - 'textTransform' : 'aa', - 'top' : 'aa', - 'unicodeBidi' : 'aa', - 'verticalAlign' : 'aa', - 'visibility' : 'aa', - 'voiceFamily' : 'aa', - 'volume' : 'aa', - 'whiteSpace' : 'aa', - 'widows' : 'aa', - 'width' : 'aa', - 'wordSpacing' : 'aa', - 'zIndex' : 'aa', - } - def __getattr__(self, name): - pass + if name not in self._fields: + raise AttributeError, name + return None + +# non-DOM ('DOM level 0') stuff + +def setTimeout(func, delay): + # scheduler call, but we don't want to mess with threads right now + if one(): + setTimeout(some_fun, delay) + else: + func() + #pass + +def alert(msg): + pass + +# some helper functions (XXX imo these can go, but the code seem to use them +# a lot... isn't it possible to just use dom.window and dom.document instead?) + +def get_document(): + return NonConstant(document) + +def get_window(): + return NonConstant(window) + +# rtyper stuff + +# the Node base class contains just about all XML-related properties +Node._fields = { + 'attributes' : [Attribute()], + 'childNodes' : [Element()], + 'firstChild' : Element(), + 'lastChild' : Element(), + 'localName' : "aa", + 'name' : "aa", + 'namespaceURI' : "aa", + 'nextSibling' : Element(), + 'nodeName' : "aa", + 'nodeType' : 1, + 'nodeValue' : "aa", + 'ownerDocument' : Document(), + 'parentNode' : Element(), + 'prefix' : "aa", + 'previousSibling' : Element(), + 'tagName' : "aa", + 'textContent' : "aa", + 'value' : "aa", +} + +Element._fields = Node._fields.copy() + +HTMLElement._fields = Element._fields.copy() +HTMLElement._fields.update({ + 'className' : "aa", + 'clientHeight' : 12, + 'clientWidth' : 12, + 'clientLeft' : 12, + 'clientTop' : 12, + 'dir' : "aa", + 'innerHTML' : "asd", + 'lang' : "asd", + 'id' : "aa", + 'offsetHeight' : 12, + 'offsetLeft' : 12, + 'offsetParent' : 12, + 'offsetTop' : 12, + 'offsetWidth' : 12, + 'scrollHeight' : 12, + 'scrollLeft' : 12, + 'scrollTop' : 12, + 'scrollWidth' : 12, + 'style' : NonConstant(Style()), + 'tabIndex' : 12, + 'onblur' : MethodDesc([Event()]), + 'onclick' : MethodDesc([MouseEvent()]), + 'ondblclick' : MethodDesc([MouseEvent()]), + 'onfocus' : MethodDesc([Event()]), + 'onkeydown' : MethodDesc([KeyEvent()]), + 'onkeypress' : MethodDesc([KeyEvent()]), + 'onkeyup' : MethodDesc([KeyEvent()]), + 'onmousedown' : MethodDesc([MouseEvent()]), + 'onmousemove' : MethodDesc([MouseEvent()]), + 'onmouseup' : MethodDesc([MouseEvent()]), + 'onmouseover' : MethodDesc([MouseEvent()]), + 'onmouseup' : MethodDesc([MouseEvent()]), + 'onresize' : MethodDesc([Event()]), +}) - def __setattr__(self, name): - pass +Node._methods = { + 'appendChild' : MethodDesc([Element()]), + 'cloneNode' : MethodDesc([12], Element()), + 'hasChildNodes' : MethodDesc([], True), + 'insertBefore' : MethodDesc([Element(), Element()], Element()), + 'removeChild' : MethodDesc([Element()], Element()), + 'replaceChild' : MethodDesc([Element(), Element()], Element()), +} -Element._fields = { - 'attributes' : [Attribute()], - 'childNodes' : [Element()], - 'className' : "aa", - 'clientHeight' : 12, - 'clientWidth' : 12, - 'clientLeft' : 12, - 'clientTop' : 12, - 'dir' : "aa", - 'firstChild' : Element(), - 'innerHTML' : "asd", - 'lang' : "asd", - 'id' : "aa", - 'lastChild' : Element(), - 'length' : 12, - 'localName' : "aa", - 'name' : "aa", - 'namespaceURI' : "aa", - 'nextSibling' : Element(), - 'nodeName' : "aa", - 'nodeType' : 1, - 'nodeValue' : "aa", - 'offsetHeight' : 12, - 'offsetLeft' : 12, - 'offsetParent' : 12, - 'offsetTop' : 12, - 'offsetWidth' : 12, - 'ownerDocument' : Document(), - 'parentNode' : Element(), - 'prefix' : "aa", - 'previousSibling' : Element(), - 'scrollHeight' : 12, - 'scrollLeft' : 12, - 'scrollTop' : 12, - 'scrollWidth' : 12, - 'style' : NonConstant(Style()), - 'tabIndex' : 12, - 'tagName' : "aa", - 'textContent' : "aa", - 'value' : "aa", - 'onblur' : MethodDesc([Event()]), - 'onclick' : MethodDesc([MouseEvent()]), - 'ondblclick' : MethodDesc([MouseEvent()]), - 'onfocus' : MethodDesc([Event()]), - 'onkeydown' : MethodDesc([KeyEvent()]), - 'onkeypress' : MethodDesc([KeyEvent()]), - 'onkeyup' : MethodDesc([KeyEvent()]), - 'onmousedown' : MethodDesc([MouseEvent()]), - 'onmousemove' : MethodDesc([MouseEvent()]), - 'onmouseup' : MethodDesc([MouseEvent()]), - 'onmouseover' : MethodDesc([MouseEvent()]), - 'onmouseup' : MethodDesc([MouseEvent()]), - 'onresize' : MethodDesc([Event()]), - } - -Element._methods = { - 'addEventListener' : MethodDesc(["aa", lambda : None, True]), - 'appendChild' : MethodDesc([Element()]), - 'blur' : MethodDesc([]), - 'click' : MethodDesc([]), - 'cloneNode' : MethodDesc([12], Element()), - 'dispatchEvent' : MethodDesc(["aa"], True), - 'focus' : MethodDesc([]), - 'getAttribute' : MethodDesc(["aa"], "aa"), - 'getAttributeNS' : MethodDesc(["aa", "aa"], "aa"), - 'getAttributeNode' : MethodDesc(["aa"], Element()), - 'getAttributeNodeNS' : MethodDesc(["aa", "aa"], Element()), - 'getElementsByTagName' : MethodDesc(["aa"], [Element(), Element()]), - 'hasAttribute' : MethodDesc(["aa"], True), - 'hasAttributeNS' : MethodDesc(["aa", "aa"], True), - 'hasAttributes' : MethodDesc([], True), - 'hasChildNodes' : MethodDesc([], True), - 'insertBefore' : MethodDesc([Element(), Element()], Element()), - 'item' : MethodDesc([3], Element()), - 'normalize' : MethodDesc([]), - 'removeAttribute' : MethodDesc(['aa']), - 'removeAttributeNS' : MethodDesc(["aa", "aa"]), - 'removeAttributeNode' : MethodDesc([Element()], "aa"), - 'removeChild' : MethodDesc([Element()], Element()), - 'removeEventListener' : MethodDesc(["aa", lambda : None, True]), - 'replaceChild' : MethodDesc([Element(), Element()], Element()), - 'scrollIntoView' : MethodDesc([12]), - 'setAttribute' : MethodDesc(["aa", "aa"]), - 'setAttributeNS' : MethodDesc(["aa", "aa", "aa"]), - 'setAttributeNode' : MethodDesc([Element()], Element()), - 'setAttributeNodeNS' : MethodDesc(["ns", Element()], Element()), - 'supports' : MethodDesc(["aa", 1.0]), - } +Element._methods = Node._methods.copy() +Element._methods.update({ + 'addEventListener' : MethodDesc(["aa", lambda : None, True]), + 'getAttribute' : MethodDesc(["aa"], "aa"), + 'getAttributeNS' : MethodDesc(["aa", "aa"], "aa"), + 'getAttributeNode' : MethodDesc(["aa"], Element()), + 'getAttributeNodeNS' : MethodDesc(["aa", "aa"], Element()), + 'getElementsByTagName' : MethodDesc(["aa"], [Element(), Element()]), + 'hasAttribute' : MethodDesc(["aa"], True), + 'hasAttributeNS' : MethodDesc(["aa", "aa"], True), + 'hasAttributes' : MethodDesc([], True), + 'removeAttribute' : MethodDesc(['aa']), + 'removeAttributeNS' : MethodDesc(["aa", "aa"]), + 'removeAttributeNode' : MethodDesc([Element()], "aa"), + 'removeEventListener' : MethodDesc(["aa", lambda : None, True]), + 'setAttribute' : MethodDesc(["aa", "aa"]), + 'setAttributeNS' : MethodDesc(["aa", "aa", "aa"]), + 'setAttributeNode' : MethodDesc([Element()], Element()), + 'setAttributeNodeNS' : MethodDesc(["ns", Element()], Element()), +}) + +HTMLElement._methods = Element._methods.copy() +HTMLElement._methods.update({ + 'blur' : MethodDesc([]), + 'click' : MethodDesc([]), + 'dispatchEvent' : MethodDesc(["aa"], True), + 'focus' : MethodDesc([]), + 'normalize' : MethodDesc([]), + 'scrollIntoView' : MethodDesc([12]), + 'supports' : MethodDesc(["aa", 1.0]), +}) Document._methods = Element._methods.copy() Document._methods.update({ @@ -366,7 +353,6 @@ #'createRange' : MethodDesc(["aa"], Range()) - don't know what to do here 'getElementById' : MethodDesc(["aa"], Element()), 'getElementsByName' : MethodDesc(["aa"], [Element(), Element()]), - 'getElementsByTagName' : MethodDesc(["aa"], [Element(), Element()]), 'importNode' : MethodDesc([Element(), True], Element()), 'open' : MethodDesc([]), 'write' : MethodDesc(["aa"]), @@ -388,14 +374,13 @@ 'embeds' : [Element(), Element()], 'fgColor' : "aa", 'firstChild' : Element(), - 'forms' : [Form(), Form()], + 'forms' : [Element(), Element()], 'height' : 123, 'images' : [Element(), Element()], 'lastModified' : "aa", 'linkColor' : "aa", 'links' : [Element(), Element()], 'location' : "aa", - 'namespaceURI' : "aa", 'referrer' : "aa", 'styleSheets' : [Style(), Style()], 'title' : "aa", @@ -404,8 +389,7 @@ 'width' : 123, }) -Window._fields = Element._fields.copy() -Window._fields.update({ +Window._fields = { 'content' : Window(), 'closed' : True, #'crypto' : Crypto() - not implemented in Gecko, leave alone @@ -438,7 +422,7 @@ 'status' : "asd", 'top' : Window(), 'window' : Window(), -}) +} Window._methods = Element._methods.copy() Window._methods.update({ @@ -481,30 +465,150 @@ 'onunload' : MethodDesc([Event()]), }) -# set the global 'window' instance to an empty HTML document, override using -# dom.window = Window(html) (this will also set dom.document) -window = Window() - -def get_document(): - return NonConstant(document) +Style._fields = { + 'azimuth' : 'aa', + 'background' : 'aa', + 'backgroundAttachment' : 'aa', + 'backgroundColor' : 'aa', + 'backgroundImage' : 'aa', + 'backgroundPosition' : 'aa', + 'backgroundRepeat' : 'aa', + 'border' : 'aa', + 'borderBottom' : 'aa', + 'borderBottomColor' : 'aa', + 'borderBottomStyle' : 'aa', + 'borderBottomWidth' : 'aa', + 'borderCollapse' : 'aa', + 'borderColor' : 'aa', + 'borderLeft' : 'aa', + 'borderLeftColor' : 'aa', + 'borderLeftStyle' : 'aa', + 'borderLeftWidth' : 'aa', + 'borderRight' : 'aa', + 'borderRightColor' : 'aa', + 'borderRightStyle' : 'aa', + 'borderRightWidth' : 'aa', + 'borderSpacing' : 'aa', + 'borderStyle' : 'aa', + 'borderTop' : 'aa', + 'borderTopColor' : 'aa', + 'borderTopStyle' : 'aa', + 'borderTopWidth' : 'aa', + 'borderWidth' : 'aa', + 'bottom' : 'aa', + 'captionSide' : 'aa', + 'clear' : 'aa', + 'clip' : 'aa', + 'color' : 'aa', + 'content' : 'aa', + 'counterIncrement' : 'aa', + 'counterReset' : 'aa', + 'cssFloat' : 'aa', + 'cssText' : 'aa', + 'cue' : 'aa', + 'cueAfter' : 'aa', + 'onBefore' : 'aa', + 'cursor' : 'aa', + 'direction' : 'aa', + 'displays' : 'aa', + 'elevation' : 'aa', + 'emptyCells' : 'aa', + 'font' : 'aa', + 'fontFamily' : 'aa', + 'fontSize' : 'aa', + 'fontSizeAdjust' : 'aa', + 'fontStretch' : 'aa', + 'fontStyle' : 'aa', + 'fontVariant' : 'aa', + 'fontWeight' : 'aa', + 'height' : 'aa', + 'left' : 'aa', + 'length' : 'aa', + 'letterSpacing' : 'aa', + 'lineHeight' : 'aa', + 'listStyle' : 'aa', + 'listStyleImage' : 'aa', + 'listStylePosition' : 'aa', + 'listStyleType' : 'aa', + 'margin' : 'aa', + 'marginBottom' : 'aa', + 'marginLeft' : 'aa', + 'marginRight' : 'aa', + 'marginTop' : 'aa', + 'markerOffset' : 'aa', + 'marks' : 'aa', + 'maxHeight' : 'aa', + 'maxWidth' : 'aa', + 'minHeight' : 'aa', + 'minWidth' : 'aa', + 'MozBinding' : 'aa', + 'MozOpacity' : 'aa', + 'orphans' : 'aa', + 'outline' : 'aa', + 'outlineColor' : 'aa', + 'outlineStyle' : 'aa', + 'outlineWidth' : 'aa', + 'overflow' : 'aa', + 'padding' : 'aa', + 'paddingBottom' : 'aa', + 'paddingLeft' : 'aa', + 'paddingRight' : 'aa', + 'paddingTop' : 'aa', + 'page' : 'aa', + 'pageBreakAfter' : 'aa', + 'pageBreakBefore' : 'aa', + 'pageBreakInside' : 'aa', + 'parentRule' : 'aa', + 'pause' : 'aa', + 'pauseAfter' : 'aa', + 'pauseBefore' : 'aa', + 'pitch' : 'aa', + 'pitchRange' : 'aa', + 'playDuring' : 'aa', + 'position' : 'aa', + 'quotes' : 'aa', + 'richness' : 'aa', + 'right' : 'aa', + 'size' : 'aa', + 'speak' : 'aa', + 'speakHeader' : 'aa', + 'speakNumeral' : 'aa', + 'speakPunctuation' : 'aa', + 'speechRate' : 'aa', + 'stress' : 'aa', + 'tableLayout' : 'aa', + 'textAlign' : 'aa', + 'textDecoration' : 'aa', + 'textIndent' : 'aa', + 'textShadow' : 'aa', + 'textTransform' : 'aa', + 'top' : 'aa', + 'unicodeBidi' : 'aa', + 'verticalAlign' : 'aa', + 'visibility' : 'aa', + 'voiceFamily' : 'aa', + 'volume' : 'aa', + 'whiteSpace' : 'aa', + 'widows' : 'aa', + 'width' : 'aa', + 'wordSpacing' : 'aa', + 'zIndex' : 'aa', +} -def get_window(): - return NonConstant(window) +KeyEvent_fields = { + 'keyCode' : 12, + 'charCode' : 12, +} get_window.suggested_primitive = True get_document.suggested_primitive = True - -def setTimeout(func, delay): - # scheduler call, but we don't want to mess with threads right now - if one(): - setTimeout(some_fun, delay) - else: - func() - #pass - setTimeout.suggested_primitive = True +alert.suggested_primitive = True -def alert(msg): - pass +# initialization + +# set the global 'window' instance to an empty HTML document, override using +# dom.window = Window(html) (this will also set dom.document) +window = Window() +this = window -alert.suggested_primitive = True Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Fri Nov 10 14:40:31 2006 @@ -1,3 +1,4 @@ +import py from pypy.translator.js.modules import dom def test_init(): @@ -7,25 +8,80 @@ docel = window.document.documentElement.nodeName assert docel == 'HTML' # XXX gotta love the DOM API ;) - assert window.document.getElementsByTagName('body')[0]\ - .childNodes[0].nodeValue == 'foo' + somediv = window.document.getElementsByTagName('body')[0].childNodes[0] + print somediv + assert somediv.nodeValue == 'foo' def test_wrap(): window = dom.Window() document = window.document div = document.createElement('div') + assert isinstance(div, dom.Element) # wrapped node assert div.nodeType == 1 + print document.documentElement document.documentElement.appendChild(div) - assert document.documentElement.childNodes[-1] == div + assert document.documentElement.childNodes[-1]._original is div._original def test_get_element_by_id(): window = dom.Window('
') div = window.document.getElementById('foo') assert div.nodeName == 'DIV' -def test_html_api(): +def test_element_style(): window = dom.Window() document = window.document div = document.createElement('div') assert div.style assert not div.style.backgroundColor + div.style.backgroundColor = 'green' + assert div.style.backgroundColor == 'green' + py.test.raises(AttributeError, 'div.style.nonExistent') + +def test_get_elements_by_tag_name(): + window = dom.Window('
foo
' + '
bar
') + document = window.document + divs = document.getElementsByTagName('div') + assert len(divs) == 2 + divs = document.getElementsByTagName('DIV') + assert len(divs) == 2 + +def test_window_references(): + window = dom.Window() + assert window is window.window + assert window is window.self + assert window is window.parent + assert window is window.top + + window2 = dom.Window(parent=window) + assert window2.parent is window + assert window2.top is window + + window3 = dom.Window(parent=window2) + assert window3.parent is window2 + assert window3.top is window + +def test_read_innerHTML(): + window = dom.Window('

some document

' + '

some content

') + document = window.document + nodeName = window.document.documentElement.nodeName + assert nodeName == 'HTML' + html = window.document.documentElement.innerHTML + assert html == ('

some document

' + '

some content

') + +def test_read_innerHTML_singletons(): + window = dom.Window('' + '') + metahtml = window.document.getElementsByTagName('head')[0].innerHTML + assert py.std.re.match('^$', + '') + +def test_set_innerHTML(): + window = dom.Window('initial content') + body = window.document.getElementsByTagName('body')[0] + assert body.innerHTML == '' + body.innerHTML = '
some content
' + assert body.innerHTML == '
some content
' + From pedronis at codespeak.net Fri Nov 10 14:41:56 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 10 Nov 2006 14:41:56 +0100 (CET) Subject: [pypy-svn] r34462 - pypy/dist/pypy/interpreter Message-ID: <20061110134156.4E82F100DA@code0.codespeak.net> Author: pedronis Date: Fri Nov 10 14:41:54 2006 New Revision: 34462 Modified: pypy/dist/pypy/interpreter/typedef.py Log: (arre, pedronis) fix annotation warnings and get rid of spurious duplicate User* classes. Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Fri Nov 10 14:41:54 2006 @@ -100,6 +100,13 @@ get_unique_interplevel_subclass._annspecialcase_ = "specialize:memo" def _get_unique_interplevel_subclass(cls, hasdict, wants_slots, needsdel, weakrefable): + "NOT_RPYTHON: initialization-time only" + typedef = cls.typedef + if hasdict and typedef.hasdict: + hasdict = False + if weakrefable and typedef.weakrefable: + weakrefable = False + key = cls, hasdict, wants_slots, needsdel, weakrefable try: return _subclass_cache[key] @@ -111,13 +118,6 @@ def _buildusercls(cls, hasdict, wants_slots, wants_del, weakrefable): "NOT_RPYTHON: initialization-time only" - typedef = cls.typedef - - if hasdict and typedef.hasdict: - hasdict = False - if weakrefable and typedef.weakrefable: - weakrefable = False - name = ['User'] if not hasdict: name.append('NoDict') From pedronis at codespeak.net Fri Nov 10 15:38:26 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 10 Nov 2006 15:38:26 +0100 (CET) Subject: [pypy-svn] r34465 - in pypy/dist/pypy/jit: timeshifter/test tl Message-ID: <20061110143826.72B5E100E1@code0.codespeak.net> Author: pedronis Date: Fri Nov 10 15:38:22 2006 New Revision: 34465 Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/jit/timeshifter/test/test_tlr.py pypy/dist/pypy/jit/tl/tlr.py Log: (arre, pedronis) port the tlr test to the portal style. Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Fri Nov 10 15:38:22 2006 @@ -9,7 +9,7 @@ import py.test -class TestPortal(object): +class PortalTest(object): from pypy.jit.codegen.llgraph.rgenop import RGenOp def setup_class(cls): @@ -28,7 +28,7 @@ backendoptimize=False): # decode the 'values' if they are specified as strings if hasattr(main, 'convert_arguments'): - assert len(main.convert_arguments) == len(values) + assert len(main.convert_arguments) == len(main_args) main_args = [decoder(value) for decoder, value in zip( main.convert_arguments, main_args)] @@ -40,7 +40,7 @@ else: self.__dict__.update(cache) assert argtypes == getargtypes(self.rtyper.annotator, main_args) - return + return main_args hs, ha, self.rtyper = hannotate(main, main_args, portal=portal, policy=policy, inline=inline, @@ -69,14 +69,15 @@ cache = self.__dict__.copy() self._cache[key] = cache, getargtypes(self.rtyper.annotator, main_args) self._cache_order.append(key) + return main_args def timeshift_from_portal(self, main, portal, main_args, inline=None, policy=None, backendoptimize=False): - self._timeshift_from_portal(main, portal, main_args, - inline=inline, policy=policy, - backendoptimize=backendoptimize) + main_args = self._timeshift_from_portal(main, portal, main_args, + inline=inline, policy=policy, + backendoptimize=backendoptimize) self.main_args = main_args llinterp = LLInterpreter(self.rtyper) res = llinterp.eval_graph(self.maingraph, main_args) @@ -92,6 +93,8 @@ assert self.insns == expected for opname, count in counts.items(): assert self.insns.get(opname, 0) == count + +class TestPortal(PortalTest): def test_simple(self): Modified: pypy/dist/pypy/jit/timeshifter/test/test_tlr.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_tlr.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_tlr.py Fri Nov 10 15:38:22 2006 @@ -1,12 +1,12 @@ from pypy.rpython.module.support import LLSupport -from pypy.jit.timeshifter.test.test_timeshift import TimeshiftingTests +from pypy.jit.timeshifter.test.test_portal import PortalTest from pypy.jit.timeshifter.test.test_vlist import P_OOPSPEC from pypy.tool.sourcetools import func_with_new_name from pypy.jit.tl import tlr -class TestTLR(TimeshiftingTests): +class TestTLR(PortalTest): def test_tlr(self): bytecode = ','.join([str(ord(c)) for c in tlr.SQUARE]) @@ -17,10 +17,10 @@ return LLSupport.to_rstr(result) tlr_interpret.convert_arguments = [build_bytecode, int] - res = self.timeshift(tlr_interpret, [bytecode, 1764], [0], + res = self.timeshift_from_portal(tlr_interpret, tlr_interpret, [bytecode, 1764], policy=P_OOPSPEC) assert res == 3111696 - res = self.timeshift(tlr_interpret, [bytecode, 9], [0, 1], + res = self.timeshift_from_portal(tlr_interpret, tlr_interpret, [bytecode, 9], policy=P_OOPSPEC) assert res == 81 Modified: pypy/dist/pypy/jit/tl/tlr.py ============================================================================== --- pypy/dist/pypy/jit/tl/tlr.py (original) +++ pypy/dist/pypy/jit/tl/tlr.py Fri Nov 10 15:38:22 2006 @@ -16,6 +16,7 @@ regs = [] pc = 0 while True: + hint(None, global_merge_point=True) opcode = hint(ord(bytecode[pc]), concrete=True) pc += 1 if opcode == MOV_A_R: From fijal at codespeak.net Fri Nov 10 15:55:27 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 10 Nov 2006 15:55:27 +0100 (CET) Subject: [pypy-svn] r34466 - pypy/dist/pypy/doc Message-ID: <20061110145527.0340D100E2@code0.codespeak.net> Author: fijal Date: Fri Nov 10 15:55:25 2006 New Revision: 34466 Modified: pypy/dist/pypy/doc/index.txt Log: Added link to automated pypy-c tests. Modified: pypy/dist/pypy/doc/index.txt ============================================================================== --- pypy/dist/pypy/doc/index.txt (original) +++ pypy/dist/pypy/doc/index.txt Fri Nov 10 15:55:25 2006 @@ -107,7 +107,8 @@ Status ====================================== -PyPy's own tests, daily updated, `on Linux`_ and `on Windows`_. +PyPy's own tests, daily updated, `on Linux`_ and `on Windows`_ and +on `build pypy-c`_ (various variants). `Nightly builds and benchmarks`_ of PyPy to C and LLVM. @@ -144,6 +145,7 @@ .. _`on Windows`: http://scottdial.com/pypytest/summary.html .. _`ideas for PyPy related projects`: project-ideas.html .. _`Nightly builds and benchmarks`: http://snake.cs.uni-duesseldorf.de/pypytest/benchmark.html +.. _`build pypy-c`: http://snake.cs.uni-duesseldorf.de/pypy-c-tests/ .. _`directory reference`: PyPy directory cross-reference @@ -244,7 +246,7 @@ .. _`translation`: translation.html .. _`GenC backend`: translation.html#genc .. _`LLVM backend`: translation.html#llvm -.. _`revision report`: http://codespeak.net/pypy/rev/current +.. _`revision report`: http://codespeak.net/pypy/rev/current .. _`garbage collector`: garbage_collection.html .. _`extension compiler`: extcompiler.html From fijal at codespeak.net Fri Nov 10 16:21:44 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 10 Nov 2006 16:21:44 +0100 (CET) Subject: [pypy-svn] r34467 - pypy/dist/pypy/translator/js/modules/test Message-ID: <20061110152144.AEB68100E7@code0.codespeak.net> Author: fijal Date: Fri Nov 10 16:21:42 2006 New Revision: 34467 Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Added (not working yet) concept of testing builds. Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Fri Nov 10 16:21:42 2006 @@ -1,5 +1,7 @@ import py from pypy.translator.js.modules import dom +from pypy.translator.js.main import rpython2javascript +import sys def test_init(): window = dom.Window('foo') @@ -9,7 +11,6 @@ assert docel == 'HTML' # XXX gotta love the DOM API ;) somediv = window.document.getElementsByTagName('body')[0].childNodes[0] - print somediv assert somediv.nodeValue == 'foo' def test_wrap(): @@ -18,7 +19,6 @@ div = document.createElement('div') assert isinstance(div, dom.Element) # wrapped node assert div.nodeType == 1 - print document.documentElement document.documentElement.appendChild(div) assert document.documentElement.childNodes[-1]._original is div._original @@ -39,7 +39,7 @@ def test_get_elements_by_tag_name(): window = dom.Window('
foo
' - '
bar
') + '
bar
') document = window.document divs = document.getElementsByTagName('div') assert len(divs) == 2 @@ -69,7 +69,7 @@ assert nodeName == 'HTML' html = window.document.documentElement.innerHTML assert html == ('

some document

' - '

some content

') + '

some content

') def test_read_innerHTML_singletons(): window = dom.Window('' @@ -85,3 +85,9 @@ body.innerHTML = '
some content
' assert body.innerHTML == '
some content
' +def test_build(): + py.test.skip("Not implemented yet") + for var in globals(): + if var.startswith('test_') and var != 'test_build': + # just build it + rpython2javascript(sys.modules[__name__], [var]) From fijal at codespeak.net Fri Nov 10 16:23:32 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 10 Nov 2006 16:23:32 +0100 (CET) Subject: [pypy-svn] r34468 - pypy/dist/pypy/translator/js/modules Message-ID: <20061110152332.E8955100E9@code0.codespeak.net> Author: fijal Date: Fri Nov 10 16:23:30 2006 New Revision: 34468 Modified: pypy/dist/pypy/translator/js/modules/dom.py Log: Reverted some changes. We cannot rely on those methods in that way. We need to provide interface ALL THE TIME, because we need to know what we return. Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Fri Nov 10 16:23:30 2006 @@ -262,8 +262,7 @@ Element._fields = Node._fields.copy() -HTMLElement._fields = Element._fields.copy() -HTMLElement._fields.update({ +Element._fields.update({ 'className' : "aa", 'clientHeight' : 12, 'clientWidth' : 12, @@ -282,7 +281,7 @@ 'scrollLeft' : 12, 'scrollTop' : 12, 'scrollWidth' : 12, - 'style' : NonConstant(Style()), + 'style' : Style(), 'tabIndex' : 12, 'onblur' : MethodDesc([Event()]), 'onclick' : MethodDesc([MouseEvent()]), @@ -299,13 +298,14 @@ 'onresize' : MethodDesc([Event()]), }) +HTMLElement._fields = Element._fields.copy() Node._methods = { - 'appendChild' : MethodDesc([Element()]), - 'cloneNode' : MethodDesc([12], Element()), + 'appendChild' : MethodDesc([HTMLElement()]), + 'cloneNode' : MethodDesc([12], HTMLElement()), 'hasChildNodes' : MethodDesc([], True), - 'insertBefore' : MethodDesc([Element(), Element()], Element()), - 'removeChild' : MethodDesc([Element()], Element()), - 'replaceChild' : MethodDesc([Element(), Element()], Element()), + 'insertBefore' : MethodDesc([HTMLElement(), HTMLElement()], HTMLElement()), + 'removeChild' : MethodDesc([HTMLElement()], HTMLElement()), + 'replaceChild' : MethodDesc([HTMLElement(), HTMLElement()], HTMLElement()), } Element._methods = Node._methods.copy() @@ -327,10 +327,6 @@ 'setAttributeNS' : MethodDesc(["aa", "aa", "aa"]), 'setAttributeNode' : MethodDesc([Element()], Element()), 'setAttributeNodeNS' : MethodDesc(["ns", Element()], Element()), -}) - -HTMLElement._methods = Element._methods.copy() -HTMLElement._methods.update({ 'blur' : MethodDesc([]), 'click' : MethodDesc([]), 'dispatchEvent' : MethodDesc(["aa"], True), @@ -340,6 +336,8 @@ 'supports' : MethodDesc(["aa", 1.0]), }) +HTMLElement._methods = Element._methods.copy() + Document._methods = Element._methods.copy() Document._methods.update({ 'clear' : MethodDesc([]), From pedronis at codespeak.net Fri Nov 10 16:40:01 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 10 Nov 2006 16:40:01 +0100 (CET) Subject: [pypy-svn] r34469 - in pypy/dist/pypy/jit: timeshifter/test tl Message-ID: <20061110154001.D96BD100E2@code0.codespeak.net> Author: pedronis Date: Fri Nov 10 16:39:58 2006 New Revision: 34469 Modified: pypy/dist/pypy/jit/timeshifter/test/test_tlc.py pypy/dist/pypy/jit/tl/tlc.py Log: (arre, pedronis) start porting this test to the portal style. We will need to add more tests and try out inserting promotions in the tlc itself. Modified: pypy/dist/pypy/jit/timeshifter/test/test_tlc.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_tlc.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_tlc.py Fri Nov 10 16:39:58 2006 @@ -1,6 +1,6 @@ import py from pypy.rpython.module.support import LLSupport -from pypy.jit.timeshifter.test.test_timeshift import TimeshiftingTests +from pypy.jit.timeshifter.test.test_portal import PortalTest from pypy.jit.timeshifter.test.test_vlist import P_OOPSPEC from pypy.tool.sourcetools import func_with_new_name from pypy.jit.conftest import Benchmark @@ -11,6 +11,8 @@ tlc_interp_without_call = func_with_new_name( tlc.interp_without_call, "tlc_interp_without_call") +tlc_interp_eval_without_call = tlc.interp_eval_without_call + # to stick attributes on the new function object, not on tlc.interp_wi* def build_bytecode(s): result = ''.join([chr(int(t)) for t in s.split(',')]) @@ -18,19 +20,19 @@ tlc_interp_without_call.convert_arguments = [build_bytecode, int, int] -class TestTLC(TimeshiftingTests): +class TestTLC(PortalTest): def test_factorial(self): code = tlc.compile(FACTORIAL_SOURCE) bytecode = ','.join([str(ord(c)) for c in code]) - if Benchmark.ENABLED: - n = 2500 - expected = 0 # far too many powers of 2 to be anything else - else: - n = 5 - expected = 120 - res = self.timeshift(tlc_interp_without_call, [bytecode, 0, n], - [0, 1], policy=P_OOPSPEC)#, backendoptimize=True) + + n = 5 + expected = 120 + + res = self.timeshift_from_portal(tlc_interp_without_call, + tlc_interp_eval_without_call, + [bytecode, 0, n], + policy=P_OOPSPEC)#, backendoptimize=True) assert res == expected def test_nth_item(self): Modified: pypy/dist/pypy/jit/tl/tlc.py ============================================================================== --- pypy/dist/pypy/jit/tl/tlc.py (original) +++ pypy/dist/pypy/jit/tl/tlc.py Fri Nov 10 16:39:58 2006 @@ -45,6 +45,8 @@ def lt(self, other): return self.value < other.int_o() +zero = IntObj(0) + class LispObj(Obj): def div(self, n): @@ -108,14 +110,19 @@ return t def make_interp(supports_call): + def interp(code='', pc=0, inputarg=0): if not isinstance(code,str): raise TypeError("code '%s' should be a string" % str(code)) - + + return interp_eval(code, pc, IntObj(inputarg)).int_o() + + def interp_eval(code, pc, inputarg): code_len = len(code) stack = [] while pc < code_len: + hint(None, global_merge_point=True) opcode = ord(code[pc]) opcode = hint(opcode, concrete=True) pc += 1 @@ -224,22 +231,22 @@ elif supports_call and opcode == CALL: offset = char2int(code[pc]) pc += 1 - res = interp(code, pc + offset) - stack.append( IntObj(res) ) + res = interp_eval(code, pc + offset, zero) + stack.append( res ) elif opcode == RETURN: break elif opcode == PUSHARG: - stack.append(IntObj(inputarg)) + stack.append(inputarg) else: raise RuntimeError("unknown opcode: " + str(opcode)) - return stack[-1].int_o() + return stack[-1] - return interp + return interp, interp_eval -interp = make_interp(supports_call = True) -interp_without_call = make_interp(supports_call = False) +interp , interp_eval = make_interp(supports_call = True) +interp_without_call, interp_eval_without_call = make_interp(supports_call = False) From pedronis at codespeak.net Fri Nov 10 17:29:14 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 10 Nov 2006 17:29:14 +0100 (CET) Subject: [pypy-svn] r34470 - in pypy/dist/pypy: jit/hintannotator jit/timeshifter objspace/flow translator/tool Message-ID: <20061110162914.2E99E100E6@code0.codespeak.net> Author: pedronis Date: Fri Nov 10 17:29:10 2006 New Revision: 34470 Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/objspace/flow/model.py pypy/dist/pypy/translator/tool/make_dot.py Log: (arre, pedronis) use different colors for the graphs headers, depending whether the graph is normal, timeshifted or a portal-entry. Given the variable header color, use different distinct colors for the return and except blocks. All these colors are defined based on tag strings in make_dot.py. Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/bookkeeper.py (original) +++ pypy/dist/pypy/jit/hintannotator/bookkeeper.py Fri Nov 10 17:29:10 2006 @@ -34,6 +34,7 @@ except KeyError: bk = self.bookkeeper graph = copygraph(self.origgraph) + graph.tag = 'timeshifted' try: etrafo = bk.annotator.exceptiontransformer except AttributeError: Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Fri Nov 10 17:29:10 2006 @@ -274,6 +274,7 @@ s_result = annmodel.lltype_to_annotation( origportalgraph.getreturnvar().concretetype) portalentrygraph = annhelper.getgraph(portalentry, args_s, s_result) + portalentrygraph.tag = "portal_entry" self.readportalgraph = annhelper.getgraph(readportal, args_s, annmodel.SomePtr(lltype.Ptr(FUNC))) Modified: pypy/dist/pypy/objspace/flow/model.py ============================================================================== --- pypy/dist/pypy/objspace/flow/model.py (original) +++ pypy/dist/pypy/objspace/flow/model.py Fri Nov 10 17:29:10 2006 @@ -57,6 +57,7 @@ Variable('evalue')]) # exception value self.exceptblock.operations = () self.exceptblock.exits = () + self.tag = None def getargs(self): return self.startblock.inputargs Modified: pypy/dist/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/dist/pypy/translator/tool/make_dot.py (original) +++ pypy/dist/pypy/translator/tool/make_dot.py Fri Nov 10 17:29:10 2006 @@ -74,6 +74,14 @@ self.emit('%s [%s];' % (safename(name), ", ".join(attrs))) +TAG_TO_COLORS = { + "timeshifted": "#cfa5f0", + "portal_entry": "#f084c2" +} +DEFAULT_TAG_COLOR = "#a5e6f0" +RETURN_COLOR = "green" +EXCEPT_COLOR = "#ffa000" + class FlowGraphDotGen(DotGen): VERBOSE = False @@ -86,9 +94,10 @@ self.func = None self.prefix = name self.enter_subgraph(name) - self.visit_FunctionGraph(node) + tagcolor = TAG_TO_COLORS.get(node.tag, DEFAULT_TAG_COLOR) + self.visit_FunctionGraph(node, tagcolor) for block in safe_iterblocks(node): - self.visit_Block(block) + self.visit_Block(block, tagcolor) self.leave_subgraph() def blockname(self, block): @@ -99,7 +108,7 @@ self.blocks[i] = name = "%s_%d" % (self.prefix, len(self.blocks)) return name - def visit_FunctionGraph(self, funcgraph): + def visit_FunctionGraph(self, funcgraph, tagcolor): name = self.prefix # +'_'+funcgraph.name data = funcgraph.name if getattr(funcgraph, 'source', None) is not None: @@ -111,14 +120,11 @@ data += "\\l".join(source.split('\n')) if hasattr(funcgraph, 'func'): self.func = funcgraph.func - - self.emit_node(name, label=data, shape="box", fillcolor="green", style="filled") - #('%(name)s [fillcolor="green", shape=box, label="%(data)s"];' % locals()) + self.emit_node(name, label=data, shape="box", fillcolor=tagcolor, style="filled") if hasattr(funcgraph, 'startblock'): self.emit_edge(name, self.blockname(funcgraph.startblock), 'startblock') - #self.emit_edge(name, self.blockname(funcgraph.returnblock), 'returnblock', style="dashed") - def visit_Block(self, block): + def visit_Block(self, block, tagcolor): # do the block itself name = self.blockname(block) if not isinstance(block, Block): @@ -135,11 +141,12 @@ fillcolor = getattr(block, "blockcolor", "white") if not numblocks: shape = "box" - fillcolor="green" if len(block.inputargs) == 1: lines[-1] += 'return %s' % tuple(block.inputargs) + fillcolor= RETURN_COLOR elif len(block.inputargs) == 2: lines[-1] += 'raise %s, %s' % tuple(block.inputargs) + fillcolor= EXCEPT_COLOR elif numblocks == 1: shape = "box" else: From cfbolz at codespeak.net Fri Nov 10 17:55:03 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 10 Nov 2006 17:55:03 +0100 (CET) Subject: [pypy-svn] r34471 - in pypy/dist/pypy/rpython: lltypesystem test Message-ID: <20061110165503.9C32F100E7@code0.codespeak.net> Author: cfbolz Date: Fri Nov 10 17:55:01 2006 New Revision: 34471 Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py pypy/dist/pypy/rpython/test/test_rstr.py Log: oops. count was counting overlapping occurences of the substring. Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rstr.py Fri Nov 10 17:55:01 2006 @@ -489,8 +489,9 @@ i += 1 if i==len2: result += 1 - else: - continue + i = 0 + m += len2 + continue # mismatch, go back to the last possible starting pos if i==0: m += 1 Modified: pypy/dist/pypy/rpython/test/test_rstr.py ============================================================================== --- pypy/dist/pypy/rpython/test/test_rstr.py (original) +++ pypy/dist/pypy/rpython/test/test_rstr.py Fri Nov 10 17:55:01 2006 @@ -596,6 +596,12 @@ res = self.interpret(fn, [4]) assert res == 4 + 6 + 2 + def test_count_overlapping_occurences(self): + def fn(): + return 'ababa'.count('aba') + res = self.interpret(fn, []) + assert res == 1 + def FIXME_test_str_to_pystringobj(): def f(n): if n >= 0: From cfbolz at codespeak.net Fri Nov 10 18:02:34 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 10 Nov 2006 18:02:34 +0100 (CET) Subject: [pypy-svn] r34472 - pypy/dist/pypy/module/_weakref/test Message-ID: <20061110170234.9E40A100E9@code0.codespeak.net> Author: cfbolz Date: Fri Nov 10 18:02:32 2006 New Revision: 34472 Modified: pypy/dist/pypy/module/_weakref/test/test_weakref.py Log: adding the necessary amount of gc.collect to the weakref tests Modified: pypy/dist/pypy/module/_weakref/test/test_weakref.py ============================================================================== --- pypy/dist/pypy/module/_weakref/test/test_weakref.py (original) +++ pypy/dist/pypy/module/_weakref/test/test_weakref.py Fri Nov 10 18:02:32 2006 @@ -6,7 +6,7 @@ cls.space = space def test_simple(self): - import _weakref + import _weakref, gc class A: pass a = A() @@ -16,10 +16,11 @@ assert a.__weakref__ is ref assert _weakref.getweakrefcount(a) == 1 del a + gc.collect() assert ref() is None def test_callback(self): - import _weakref + import _weakref, gc class A: pass a1 = A() @@ -30,11 +31,12 @@ ref2 = _weakref.ref(a1) assert _weakref.getweakrefcount(a1) == 2 del a1 + gc.collect() assert ref1() is None assert a2.ref is None def test_callback_order(self): - import _weakref + import _weakref, gc class A: pass a1 = A() @@ -46,10 +48,11 @@ ref1 = _weakref.ref(a1, callback1) ref2 = _weakref.ref(a1, callback2) del a1 + gc.collect() assert a2.x == 42 def test_dont_callback_if_weakref_dead(self): - import _weakref + import _weakref, gc class A: pass a1 = A() @@ -61,12 +64,14 @@ ref = _weakref.ref(a2, callback) assert _weakref.getweakrefcount(a2) == 1 ref = None + gc.collect() assert _weakref.getweakrefcount(a2) == 0 a2 = None + gc.collect() assert a1.x == 40 def test_callback_cannot_ressurect(self): - import _weakref + import _weakref, gc class A: pass a = A() @@ -77,10 +82,11 @@ ref1 = _weakref.ref(a, callback) ref2 = _weakref.ref(a, callback) del a + gc.collect() assert alive.a is None def test_weakref_reusing(self): - import _weakref + import _weakref, gc class A: pass a = A() @@ -93,7 +99,7 @@ assert isinstance(wref1, wref) def test_correct_weakrefcount_after_death(self): - import _weakref + import _weakref, gc class A: pass a = A() @@ -101,12 +107,14 @@ ref2 = _weakref.ref(a) assert _weakref.getweakrefcount(a) == 1 del ref1 + gc.collect() assert _weakref.getweakrefcount(a) == 1 del ref2 + gc.collect() assert _weakref.getweakrefcount(a) == 0 def test_weakref_equality(self): - import _weakref + import _weakref, gc class A: def __eq__(self, other): return True @@ -116,14 +124,16 @@ ref2 = _weakref.ref(a2) assert ref1 == ref2 del a1 + gc.collect() assert not ref1 == ref2 assert ref1 != ref2 del a2 + gc.collect() assert not ref1 == ref2 assert ref1 != ref2 def test_getweakrefs(self): - import _weakref + import _weakref, gc class A: pass a = A() @@ -133,7 +143,7 @@ assert _weakref.getweakrefs(a) == [ref1] def test_hashing(self): - import _weakref + import _weakref, gc class A(object): def __hash__(self): return 42 @@ -141,12 +151,14 @@ w = _weakref.ref(a) assert hash(a) == hash(w) del a + gc.collect() assert hash(w) == 42 w = _weakref.ref(A()) + gc.collect() raises(TypeError, hash, w) def test_weakref_subclassing(self): - import _weakref + import _weakref, gc class A(object): pass class Ref(_weakref.ref): @@ -163,22 +175,24 @@ w2 = _weakref.ref(a, callable) assert a.__weakref__ is w1 del a + gc.collect() assert w1() is None assert w() is None assert w2() is None assert b.a == 42 def test_function_weakrefable(self): - import _weakref + import _weakref, gc def f(x): return 42 wf = _weakref.ref(f) assert wf()(63) == 42 del f + gc.collect() assert wf() is None def test_method_weakrefable(self): - import _weakref + import _weakref, gc class A(object): def f(self): return 42 @@ -190,20 +204,22 @@ w_bound = _weakref.ref(meth) assert w_bound()() == 42 del meth + gc.collect() assert w_unbound() is None assert w_bound() is None def test_set_weakrefable(self): skip("missing: weakrefs to interp-level sets") - import _weakref + import _weakref, gc s = set([1, 2, 3, 4]) w = _weakref.ref(s) assert w() is s del s + gc.collect() assert w() is None def test_generator_weakrefable(self): - import _weakref + import _weakref, gc def f(x): for i in range(x): yield i @@ -214,10 +230,11 @@ r = g.next() assert r == 1 del g + gc.collect() assert w() is None def test_weakref_subclass_with_del(self): - import _weakref + import _weakref, gc class Ref(_weakref.ref): def __del__(self): b.a = 42 @@ -228,6 +245,7 @@ b.a = 1 w = Ref(a) del w + gc.collect() assert b.a == 42 if _weakref.getweakrefcount(a) > 0: # the following can crash if the presence of the applevel __del__ @@ -241,7 +259,7 @@ cls.space = space def test_simple(self): - import _weakref + import _weakref, gc class A(object): def __init__(self, x): self.x = x @@ -252,13 +270,13 @@ raises(TypeError, p) def test_caching(self): - import _weakref + import _weakref, gc class A(object): pass a = A() assert _weakref.proxy(a) is _weakref.proxy(a) def test_callable_proxy(self): - import _weakref + import _weakref, gc class A(object): def __call__(self): global_a.x = 1 @@ -272,7 +290,7 @@ assert global_a.x == 1 def test_callable_proxy_type(self): - import _weakref + import _weakref, gc class Callable: def __call__(self, x): pass @@ -281,12 +299,12 @@ assert type(ref1) is _weakref.CallableProxyType def test_dont_create_directly(self): - import _weakref + import _weakref, gc raises(TypeError, _weakref.ProxyType, []) raises(TypeError, _weakref.CallableProxyType, []) def test_dont_hash(self): - import _weakref + import _weakref, gc class A(object): pass a = A() @@ -294,7 +312,7 @@ raises(TypeError, hash, p) def test_subclassing_not_allowed(self): - import _weakref + import _weakref, gc def tryit(): class A(_weakref.ProxyType): pass From cfbolz at codespeak.net Fri Nov 10 18:05:44 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 10 Nov 2006 18:05:44 +0100 (CET) Subject: [pypy-svn] r34473 - pypy/dist/pypy/objspace/std/test Message-ID: <20061110170544.CED0C1007B@code0.codespeak.net> Author: cfbolz Date: Fri Nov 10 18:05:43 2006 New Revision: 34473 Modified: pypy/dist/pypy/objspace/std/test/test_userobject.py Log: adding gc.collects here as well Modified: pypy/dist/pypy/objspace/std/test/test_userobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_userobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_userobject.py Fri Nov 10 18:05:43 2006 @@ -143,15 +143,17 @@ assert not hasattr(a, 'x') def test_del(self): + import gc lst = [] class A(object): def __del__(self): lst.append(42) A() + gc.collect() assert lst == [42] def test_del_exception(self): - import sys, StringIO + import sys, StringIO, gc class A(object): def __del__(self): yaddadlaouti @@ -159,8 +161,10 @@ try: sys.stderr = StringIO.StringIO() A() + gc.collect() res = sys.stderr.getvalue() A() + gc.collect() res2 = sys.stderr.getvalue() finally: sys.stderr = prev From cfbolz at codespeak.net Fri Nov 10 22:16:09 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 10 Nov 2006 22:16:09 +0100 (CET) Subject: [pypy-svn] r34475 - pypy/dist/pypy Message-ID: <20061110211609.48EF8100F5@code0.codespeak.net> Author: cfbolz Date: Fri Nov 10 22:16:06 2006 New Revision: 34475 Modified: pypy/dist/pypy/conftest.py Log: add trivial wrap method to make more app-tests that simply expose constants via setup_class runnable Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Fri Nov 10 22:16:06 2006 @@ -107,6 +107,9 @@ exec src.compile() in d return d['anonymous'](*args) + def wrap(self, obj): + return obj + class OpErrKeyboardInterrupt(KeyboardInterrupt): pass From cfbolz at codespeak.net Fri Nov 10 23:39:03 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Fri, 10 Nov 2006 23:39:03 +0100 (CET) Subject: [pypy-svn] r34477 - pypy/dist/pypy/translator/tool/pygame Message-ID: <20061110223903.22B6F100F0@code0.codespeak.net> Author: cfbolz Date: Fri Nov 10 23:39:01 2006 New Revision: 34477 Modified: pypy/dist/pypy/translator/tool/pygame/graphclient.py Log: try to check whether the graph is an undirected graph and use neato in that case. Modified: pypy/dist/pypy/translator/tool/pygame/graphclient.py ============================================================================== --- pypy/dist/pypy/translator/tool/pygame/graphclient.py (original) +++ pypy/dist/pypy/translator/tool/pygame/graphclient.py Fri Nov 10 23:39:01 2006 @@ -23,8 +23,12 @@ plainfile = py.path.local(plainfile) plainfile.write(py.path.local(dotfile).read()) elif not use_codespeak: - py.process.cmdexec('dot -Tplain %s>%s' % (dotfile, plainfile)) - elif 0: + # try to see whether it is a directed graph or not: + if "digraph" in py.path.local(dotfile).read(): + py.process.cmdexec('dot -Tplain %s>%s' % (dotfile, plainfile)) + else: + py.process.cmdexec('neato -Tplain %s>%s' % (dotfile, plainfile)) + elif 0: gw = py.execnet.SshGateway('codespeak.net') channel = gw.remote_exec(""" import py From mwh at codespeak.net Sat Nov 11 02:09:49 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sat, 11 Nov 2006 02:09:49 +0100 (CET) Subject: [pypy-svn] r34479 - in pypy/dist/pypy/jit/codegen: ppc test Message-ID: <20061111010949.6B27C10089@code0.codespeak.net> Author: mwh Date: Sat Nov 11 02:09:47 2006 New Revision: 34479 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Log: handle switch overflow, and actually check in the flexswitch test for ppc. Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Sat Nov 11 02:09:47 2006 @@ -14,11 +14,9 @@ from pypy.translator.asm.ppcgen.rassemblermaker import make_rassembler from pypy.translator.asm.ppcgen.ppc_assembler import MyPPCAssembler -RPPCAssembler = make_rassembler(MyPPCAssembler) - -def emit(self, value): - self.mc.write(value) -RPPCAssembler.emit = emit +class RPPCAssembler(make_rassembler(MyPPCAssembler)): + def emit(self, value): + self.mc.write(value) NSAVEDREGISTERS = 19 @@ -355,6 +353,8 @@ # register allocation for this block we don't know how much # stack will be required, so we patch it later (see # patch_stack_adjustment below). + # note that this stomps on both rSCRATCH (not a problem) and + # crf0 (a very small chance of being a problem) self.stack_adj_addr = self.asm.mc.tell() self.asm.addi(rSCRATCH, rFP, 0) # this is the immediate that later gets patched self.asm.subx(rSCRATCH, rSCRATCH, rSP) # rSCRATCH should now be <= 0 @@ -586,6 +586,9 @@ class FlexSwitch(CodeGenSwitch): + # a fair part of this code could likely be shared with the i386 + # backend. + def __init__(self, rgenop, mc, switch_reg, crf, var2loc): self.rgenop = rgenop self.crf = crf @@ -595,13 +598,31 @@ self.asm.mc = mc self.default_target_addr = 0 -## def _reserve_more(self): -## XXX - def add_case(self, gv_case): targetbuilder = self.rgenop.openbuilder() targetbuilder.make_fresh_from_jump(self.var2loc) target_addr = targetbuilder.asm.mc.tell() + p = self.asm.mc.getpos() + # that this works depends a bit on the fixed length of the + # instruction sequences we use to jump around. if the code is + # ever updated to use the branch-relative instructions (a good + # idea, btw) this will need to be thought about again + try: + self._add_case(gv_case, target_addr) + except codebuf.CodeBlockOverflow: + self.asm.mc.setpos(p) + mc = self.rgenop.open_mc() + newmc = mc.reserve(7 * 5 + 4) + self.rgenop.close_mc(mc) + new_addr = newmc.tell() + self.asm.load_word(rSCRATCH, new_addr) + self.asm.mtctr(rSCRATCH) + self.asm.bctr() + self.asm.mc = newmc + self._add_case(gv_case, target_addr) + return targetbuilder + + def _add_case(self, gv_case, target_addr): asm = self.asm assert isinstance(gv_case, IntConst) asm.load_word(rSCRATCH, gv_case.value) @@ -611,7 +632,6 @@ asm.bcctr(12, self.crf.number*4 + 2) if self.default_target_addr: self._write_default() - return targetbuilder def add_default(self): targetbuilder = self.rgenop.openbuilder() Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py ============================================================================== --- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py (original) +++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Sat Nov 11 02:09:47 2006 @@ -212,7 +212,7 @@ return res return if_runner -def build_switch(rgenop): +def make_switch(rgenop): """ def f(v0, v1): if v0 == 0: # switch @@ -222,9 +222,9 @@ else: return v1 """ - signed_tok = rgenop.kindToken(lltype.Signed) - f2_token = rgenop.sigToken(FUNC2) - builder, graph, (gv0, gv1) = rgenop.newgraph(f2_token) + signed_kind = rgenop.kindToken(lltype.Signed) + sigtoken = rgenop.sigToken(FUNC2) + builder, entrypoint, [gv0, gv1] = rgenop.newgraph(sigtoken) flexswitch = builder.flexswitch(gv0) const21 = rgenop.genconst(21) @@ -233,38 +233,98 @@ const0 = rgenop.genconst(0) case_builder = flexswitch.add_case(const0) case_args_gv = [gv1] - case_builder.enter_next_block([signed_tok], case_args_gv) + case_builder.enter_next_block([signed_kind], case_args_gv) [gv1_case0] = case_args_gv gv_res_case0 = case_builder.genop2('int_mul', const21, gv1_case0) - case_builder.finish_and_return(f2_token, gv_res_case0) + case_builder.finish_and_return(sigtoken, gv_res_case0) # default default_builder = flexswitch.add_default() default_args_gv = [gv1] - default_builder.enter_next_block([signed_tok], default_args_gv) + default_builder.enter_next_block([signed_kind], default_args_gv) [gv1_default] = default_args_gv - default_builder.finish_and_return(f2_token, gv1_default) + default_builder.finish_and_return(sigtoken, gv1_default) # case == 1 const1 = rgenop.genconst(1) case_builder = flexswitch.add_case(const1) case_args_gv = [gv1] - case_builder.enter_next_block([signed_tok], case_args_gv) + case_builder.enter_next_block([signed_kind], case_args_gv) [gv1_case1] = case_args_gv gv_res_case1 = case_builder.genop2('int_add', const21, gv1_case1) - case_builder.finish_and_return(f2_token, gv_res_case1) + case_builder.finish_and_return(sigtoken, gv_res_case1) - gv_switch = rgenop.gencallableconst(f2_token, "switch", graph) + gv_switch = rgenop.gencallableconst(sigtoken, "switch", entrypoint) return gv_switch def get_switch_runner(RGenOp): def switch_runner(x, y): rgenop = RGenOp() - gv_switchfn = build_switch(rgenop) + gv_switchfn = make_switch(rgenop) switchfn = gv_switchfn.revealconst(lltype.Ptr(FUNC2)) res = switchfn(x, y) keepalive_until_here(rgenop) # to keep the code blocks alive return res return switch_runner +def make_large_switch(rgenop): + """ + def f(v0, v1): + if v0 == 0: # switch + return 21*v1 + elif v0 == 1: + return 2+v1 + elif v0 == 2: + return 4+v1 + ... + elif v0 == 10: + return 2**10+v1 + else: + return v1 + """ + signed_tok = rgenop.kindToken(lltype.Signed) + f2_token = rgenop.sigToken(FUNC2) + builder, graph, (gv0, gv1) = rgenop.newgraph(f2_token) + + flexswitch = builder.flexswitch(gv0) + const21 = rgenop.genconst(21) + + # case == 0 + const0 = rgenop.genconst(0) + case_builder = flexswitch.add_case(const0) + case_args_gv = [gv1] + case_builder.enter_next_block([signed_tok], case_args_gv) + [gv1_case0] = case_args_gv + gv_res_case0 = case_builder.genop2('int_mul', const21, gv1_case0) + case_builder.finish_and_return(f2_token, gv_res_case0) + # default + default_builder = flexswitch.add_default() + default_args_gv = [gv1] + default_builder.enter_next_block([signed_tok], default_args_gv) + [gv1_default] = default_args_gv + default_builder.finish_and_return(f2_token, gv1_default) + # case == x + for x in range(1,11): + constx = rgenop.genconst(x) + case_builder = flexswitch.add_case(constx) + case_args_gv = [gv1] + case_builder.enter_next_block([signed_tok], case_args_gv) + [gv1_casex] = case_args_gv + const2px= rgenop.genconst(1< Author: arigo Date: Sat Nov 11 13:19:56 2006 New Revision: 34482 Modified: pypy/dist/pypy/translator/tool/pygame/graphdisplay.py Log: Mac OS/X workaround. After closing and re-opening the Pygame viewer, it was resized to a height of 32 pixels. This is due to a pair of bogus VideoResize events that we receive, no clue why (probably the X11 window manager being confused by windows of height 1). Modified: pypy/dist/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/dist/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/dist/pypy/translator/tool/pygame/graphdisplay.py Sat Nov 11 13:19:56 2006 @@ -634,8 +634,12 @@ if self.peek(VIDEORESIZE): return # XXX sometimes some jerk are trying to minimise our window, - # discard such event - if event.size[1] == 5: + # discard such event (we see a height of 5 in this case). + # XXX very specific MacOS/X workaround: after resizing the window + # to a height of 1 and back, we get two bogus VideoResize events, + # for height 16 and 32. + # XXX summary: let's ignore all resize events with a height <= 32 + if event.size[1] <= 32: return self.resize(event.size) self.must_redraw = True From pedronis at codespeak.net Sat Nov 11 13:40:46 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 11 Nov 2006 13:40:46 +0100 (CET) Subject: [pypy-svn] r34483 - pypy/dist/pypy/jit/codegen/i386/test Message-ID: <20061111124046.D1BCE10105@code0.codespeak.net> Author: pedronis Date: Sat Nov 11 13:40:45 2006 New Revision: 34483 Removed: pypy/dist/pypy/jit/codegen/i386/test/test_interp_tlr.py Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_tlr.py Log: fix test_genc_tlr now that the tlr tests use the portal style. kill test_interp_tlr which doesn't make complete sense now. Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_tlr.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/test/test_genc_tlr.py (original) +++ pypy/dist/pypy/jit/codegen/i386/test/test_genc_tlr.py Sat Nov 11 13:40:45 2006 @@ -1,9 +1,9 @@ import py from pypy.jit.timeshifter.test import test_tlr -from pypy.jit.codegen.i386.test.test_genc_ts import I386TimeshiftingTestMixin +from pypy.jit.codegen.i386.test.test_genc_portal import I386PortalTestMixin -class TestTLR(I386TimeshiftingTestMixin, +class TestTLR(I386PortalTestMixin, test_tlr.TestTLR): # for the individual tests see From fijal at codespeak.net Sat Nov 11 14:16:52 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 11 Nov 2006 14:16:52 +0100 (CET) Subject: [pypy-svn] r34485 - pypy/dist/pypy/rlib Message-ID: <20061111131652.EDC56100A0@code0.codespeak.net> Author: fijal Date: Sat Nov 11 14:16:51 2006 New Revision: 34485 Modified: pypy/dist/pypy/rlib/nonconst.py Log: Added support for testing it on top of CPython. Modified: pypy/dist/pypy/rlib/nonconst.py ============================================================================== --- pypy/dist/pypy/rlib/nonconst.py (original) +++ pypy/dist/pypy/rlib/nonconst.py Sat Nov 11 14:16:51 2006 @@ -9,7 +9,13 @@ class NonConstant(object): def __init__(self, _constant): - self.constant = _constant + self.__dict__['constant'] = _constant + + def __getattr__(self, attr): + return getattr(self.__dict__['constant'], attr) + + def __setattr__(self, attr, value): + setattr(self.__dict__['constant'], attr, value) class EntryNonConstant(ExtRegistryEntry): _about_ = NonConstant From arigo at codespeak.net Sat Nov 11 14:21:28 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 14:21:28 +0100 (CET) Subject: [pypy-svn] r34486 - pypy/dist/pypy/lang/automata Message-ID: <20061111132128.1BF341010B@code0.codespeak.net> Author: arigo Date: Sat Nov 11 14:21:27 2006 New Revision: 34486 Modified: pypy/dist/pypy/lang/automata/dfa.py Log: Slight rewrite of the main loop of the 2nd dfa recognizer. Now the loops looks typical for the interpreter, and it can use the global_merge_point hint as intended. Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Sat Nov 11 14:21:27 2006 @@ -111,14 +111,12 @@ finals = hint(finals, deepfreeze=True) alltrans = hint(alltrans, deepfreeze=True) - indx = 0 state = 0 - while True: + indx = 0 + while indx < len(s): hint(None, global_merge_point=True) - if indx >= len(s): - break - char = s[indx] + indx += 1 char = hint(char, promote=True) statetrans = alltrans.get(state, None) @@ -127,7 +125,6 @@ hint(state, concrete=True) if state == -1: return False - indx += 1 res = state in finals res = hint(res, concrete=True) From arigo at codespeak.net Sat Nov 11 17:22:56 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 17:22:56 +0100 (CET) Subject: [pypy-svn] r34488 - in pypy/dist/pypy/rlib: . test Message-ID: <20061111162256.7D787100C0@code0.codespeak.net> Author: arigo Date: Sat Nov 11 17:22:55 2006 New Revision: 34488 Added: pypy/dist/pypy/rlib/rctypesobject.py (contents, props changed) pypy/dist/pypy/rlib/test/test_rctypesobject.py (contents, props changed) Log: Yet another attempt for implementing rctypes: a rlib.rctypesobject module that is a regular RPython library offering the same functionality as (r)ctypes, but with a different interface. The idea is then to translate RPython programs using the regular ctypes interface by remapping it to the rctypesobject interface. This is much saner than the current rctypes implementation: hard bits like keeping objects alive are now purely implemented in RPython, in rctypesobject. Added: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 17:22:55 2006 @@ -0,0 +1,201 @@ +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.interpreter.miscutils import InitializedClass +from pypy.tool.sourcetools import func_with_new_name + + +class RawMemBlock(object): + ofs_keepalives = 0 + def __init__(self, num_keepalives): + self.keepalives = [None] * num_keepalives # list of RawMemBlocks + def addoffset(self, ofs_keepalives): + if ofs_keepalives == 0: + return self + else: + return self._addoffset(ofs_keepalives) + def _addoffset(self, ofs_keepalives): + return RawMemSubBlock(self, ofs_keepalives) + def getkeepalive(self, index): + return self.keepalives[self.ofs_keepalives + index] + def setkeepalive(self, index, memblock): + self.keepalives[self.ofs_keepalives + index] = memblock + +class AllocatedRawMemBlock(RawMemBlock): + def __init__(self, num_keepalives, rawsize): + RawMemBlock.__init__(self, num_keepalives) + addr = llmemory.raw_malloc(rawsize) + self.addr = addr + llmemory.raw_memclear(addr, rawsize) + #print 'raw_malloc:', addr + def __del__(self): + #print 'raw_free: ', self.addr + llmemory.raw_free(self.addr) + +class RawMemSubBlock(object): + def __init__(self, baseblock, ofs_keepalives): + self.baseblock = baseblock + self.keepalives = baseblock.keepalives + self.ofs_keepalives = ofs_keepalives + def _addoffset(self, ofs_keepalives): + ofs_keepalives = self.ofs_keepalives + ofs_keepalives + return RawMemSubBlock(self.baseblock, ofs_keepalives) + + +class RCTypesObject(object): + __metaclass__ = InitializedClass + num_keepalives = 0 + __slots__ = ('addr', 'memblock') + + def __init__(self, addr, memblock): + self.addr = addr + self.memblock = memblock + + def __initclass__(cls): + if hasattr(cls, 'LLTYPE'): + cls.__name__ = 'RCTypes_%s' % (cls.LLTYPE,) + if not hasattr(cls, 'CDATATYPE'): + if isinstance(cls.LLTYPE, lltype.ContainerType): + cls.CDATATYPE = cls.LLTYPE + else: + cls.CDATATYPE = lltype.FixedSizeArray(cls.LLTYPE, 1) + if not hasattr(cls, 'rawsize'): + cls.rawsize = llmemory.sizeof(cls.CDATATYPE) + + def allocate1(): + return allocate_object(cls, cls.num_keepalives, cls.rawsize) + cls.allocate = staticmethod(allocate1) + + def copyfrom1(self, srcbox): + assert isinstance(srcbox, cls) + llmemory.raw_memcopy(srcbox.addr, self.addr, cls.rawsize) + self.copykeepalives(0, srcbox) + cls.copyfrom = copyfrom1 + + def sameaddr(self, otherbox): + return self.addr == otherbox.addr + + def keepalivememblock(self, index, memblock): + self.memblock.setkeepalive(index, memblock) + + def copykeepalives(self, startindex, srcbox): + for i in range(self.num_keepalives): + memblock = srcbox.memblock.getkeepalive(startindex + i) + self.memblock.setkeepalive(i, memblock) + + def getmemblock(self, index, target_num_keepalives): + targetmemblock = self.memblock.getkeepalive(index) + if targetmemblock is None: + targetmemblock = RawMemBlock(target_num_keepalives) + self.memblock.setkeepalive(index, targetmemblock) + return targetmemblock + + def ll_ref(self, CDATATYPE): + return llmemory.cast_adr_to_ptr(self.addr, lltype.Ptr(CDATATYPE)) + + +def allocate_object(cls, num_keepalives, rawsize): + memblock = AllocatedRawMemBlock(num_keepalives, rawsize) + return cls(memblock.addr, memblock) + + +_primitive_cache = {} +def makePrimitive(TYPE): + """Build a return a new RCTypesPrimitive class.""" + try: + return _primitive_cache[TYPE] + except KeyError: + class RCTypesPrimitive(RCTypesObject): + LLTYPE = TYPE + + def get_value(self): + ptr = self.ll_ref(RCTypesPrimitive.CDATATYPE) + return ptr[0] + + def set_value(self, llvalue): + ptr = self.ll_ref(RCTypesPrimitive.CDATATYPE) + ptr[0] = llvalue + + _primitive_cache[TYPE] = RCTypesPrimitive + return RCTypesPrimitive + +# a few prebuilt primitive types +rc_int = makePrimitive(lltype.Signed) +rc_char = makePrimitive(lltype.Char) + + +def makeRPointer(contentscls): + """Build and return a new RCTypesPointer class.""" + try: + return contentscls._ptrcls + except AttributeError: + assert issubclass(contentscls, RCTypesObject) + + class RCTypesPtr(RCTypesObject): + CONTENTS = contentscls.CDATATYPE + LLTYPE = lltype.Ptr(CONTENTS) + num_keepalives = 1 + + def get_contents(self): + ptr = self.ll_ref(RCTypesPtr.CDATATYPE) + targetaddr = llmemory.cast_ptr_to_adr(ptr[0]) + targetkeepalives = contentscls.num_keepalives + targetmemblock = self.getmemblock(0, targetkeepalives) + return contentscls(targetaddr, targetmemblock) + + def set_contents(self, newcontentsbox): + targetaddr = newcontentsbox.addr + targetmemblock = newcontentsbox.memblock + ptr = self.ll_ref(RCTypesPtr.CDATATYPE) + ptr[0] = llmemory.cast_adr_to_ptr(targetaddr, + RCTypesPtr.LLTYPE) + self.keepalivememblock(0, targetmemblock) + + contentscls._ptrcls = RCTypesPtr + return RCTypesPtr +makeRPointer._annspecialcase_ = 'specialize:memo' + +def pointer(x): + PTR = makeRPointer(x.__class__) + p = PTR.allocate() + p.set_contents(x) + return p +pointer._annspecialcase_ = 'specialize:argtype(0)' + + +def makeRStruct(c_name, fields, c_external=False): + """Build and return a new RCTypesStruct class.""" + + def cmangle(name): + # obscure: names starting with '_' are not allowed in + # lltype.Struct, so we prefix all nam4es with 'c_' + return 'c_' + name + + fieldclasses = {} + llfields = [] + num_keepalives = 0 + for name, fieldboxcls in fields: + llname = cmangle(name) + fieldclasses[name] = llname, fieldboxcls, num_keepalives + llfields.append((llname, fieldboxcls.LLTYPE)) + num_keepalives += fieldboxcls.num_keepalives + + extras = {'hints': {'c_name': c_name, 'external': c_external}} + STRUCT = lltype.Struct(c_name, *llfields, **extras) + + class RCTypesStruct(RCTypesObject): + LLTYPE = STRUCT + RCTypesStruct.num_keepalives = num_keepalives + + def make_accessors(fieldname): + llname, fieldboxcls, ofs_keepalives = fieldclasses[fieldname] + FIELD = fieldboxcls.LLTYPE + FIELDOFS = llmemory.offsetof(STRUCT, llname) + + def refgetter(self): + subaddr = self.addr + FIELDOFS + subblock = self.memblock.addoffset(ofs_keepalives) + return fieldboxcls(subaddr, subblock) + setattr(RCTypesStruct, 'ref_' + fieldname, refgetter) + + for name in fieldclasses: + make_accessors(name) + return RCTypesStruct Added: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 17:22:55 2006 @@ -0,0 +1,45 @@ +from pypy.rlib.rctypesobject import * + +def test_primitive(): + x = rc_int.allocate() + assert x.get_value() == 0 + x.set_value(17) + assert x.get_value() == 17 + +def test_ptr(): + x = rc_int.allocate() + p1 = pointer(x) + p2 = pointer(x) + x.set_value(17) + assert p1.get_contents().get_value() == 17 + p2.get_contents().set_value(18) + assert x.get_value() == 18 + del x + assert p1.get_contents().get_value() == 18 + +def test_struct(): + x = rc_int.allocate() + x.set_value(42) + S = makeRStruct('S', [('x', rc_int), + ('y', makeRPointer(rc_int))]) + s = S.allocate() + s.ref_x().set_value(12) + s.ref_y().set_contents(x) + assert s.ref_x().get_value() == 12 + assert s.ref_y().get_contents().get_value() == 42 + +def test_copyfrom(): + x1 = rc_int.allocate() + x1.set_value(101) + p1 = pointer(x1) + x2 = rc_int.allocate() + x2.set_value(202) + p2 = pointer(x2) + del x1, x2 + p1.copyfrom(p2) + assert p1.get_contents().sameaddr(p2.get_contents()) + p1.get_contents().set_value(303) + assert p2.get_contents().get_value() == 303 + del p2 + import gc; gc.collect() + assert p1.get_contents().get_value() == 303 From arigo at codespeak.net Sat Nov 11 17:44:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 17:44:29 +0100 (CET) Subject: [pypy-svn] r34489 - in pypy/dist/pypy: annotation rpython Message-ID: <20061111164429.6AE8E1010F@code0.codespeak.net> Author: arigo Date: Sat Nov 11 17:44:28 2006 New Revision: 34489 Modified: pypy/dist/pypy/annotation/builtin.py pypy/dist/pypy/rpython/rbuiltin.py Log: Eventually got around to supporting the raw_*() functions in RPython programs, without regard of whether they come from llmemory or lladdress. Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Sat Nov 11 17:44:28 2006 @@ -560,6 +560,7 @@ # memory address from pypy.rpython.memory import lladdress +from pypy.rpython.lltypesystem import llmemory def raw_malloc(s_size): assert isinstance(s_size, SomeInteger) #XXX add noneg...? @@ -591,6 +592,12 @@ BUILTIN_ANALYZERS[lladdress.raw_memclear] = raw_memclear BUILTIN_ANALYZERS[lladdress.raw_memcopy] = raw_memcopy +BUILTIN_ANALYZERS[llmemory.raw_malloc] = raw_malloc +BUILTIN_ANALYZERS[llmemory.raw_malloc_usage] = raw_malloc_usage +BUILTIN_ANALYZERS[llmemory.raw_free] = raw_free +BUILTIN_ANALYZERS[llmemory.raw_memclear] = raw_memclear +BUILTIN_ANALYZERS[llmemory.raw_memcopy] = raw_memcopy + #_________________________________ # offsetof/sizeof Modified: pypy/dist/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/dist/pypy/rpython/rbuiltin.py (original) +++ pypy/dist/pypy/rpython/rbuiltin.py Sat Nov 11 17:44:28 2006 @@ -578,6 +578,12 @@ BUILTIN_TYPER[lladdress.raw_memclear] = rtype_raw_memclear BUILTIN_TYPER[lladdress.raw_memcopy] = rtype_raw_memcopy +BUILTIN_TYPER[llmemory.raw_malloc] = rtype_raw_malloc +BUILTIN_TYPER[llmemory.raw_malloc_usage] = rtype_raw_malloc_usage +BUILTIN_TYPER[llmemory.raw_free] = rtype_raw_free +BUILTIN_TYPER[llmemory.raw_memclear] = rtype_raw_memclear +BUILTIN_TYPER[llmemory.raw_memcopy] = rtype_raw_memcopy + def rtype_offsetof(hop): TYPE, field = hop.inputargs(lltype.Void, lltype.Void) return hop.inputconst(lltype.Signed, From arigo at codespeak.net Sat Nov 11 17:45:12 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 17:45:12 +0100 (CET) Subject: [pypy-svn] r34490 - in pypy/dist/pypy: rlib rlib/test rpython/lltypesystem rpython/lltypesystem/test Message-ID: <20061111164512.9418E10112@code0.codespeak.net> Author: arigo Date: Sat Nov 11 17:45:11 2006 New Revision: 34490 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py pypy/dist/pypy/rpython/lltypesystem/lltype.py pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py Log: Make rctypesobject really RPython (translatable). Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 17:45:11 2006 @@ -61,7 +61,9 @@ cls.rawsize = llmemory.sizeof(cls.CDATATYPE) def allocate1(): - return allocate_object(cls, cls.num_keepalives, cls.rawsize) + memblock = AllocatedRawMemBlock(cls.num_keepalives, + cls.rawsize) + return cls(memblock.addr, memblock) cls.allocate = staticmethod(allocate1) def copyfrom1(self, srcbox): @@ -90,11 +92,7 @@ def ll_ref(self, CDATATYPE): return llmemory.cast_adr_to_ptr(self.addr, lltype.Ptr(CDATATYPE)) - - -def allocate_object(cls, num_keepalives, rawsize): - memblock = AllocatedRawMemBlock(num_keepalives, rawsize) - return cls(memblock.addr, memblock) + ll_ref._annspecialcase_ = 'specialize:arg(1)' _primitive_cache = {} @@ -103,6 +101,8 @@ try: return _primitive_cache[TYPE] except KeyError: + assert not isinstance(TYPE, lltype.ContainerType) + class RCTypesPrimitive(RCTypesObject): LLTYPE = TYPE @@ -128,6 +128,10 @@ return contentscls._ptrcls except AttributeError: assert issubclass(contentscls, RCTypesObject) + if contentscls is RCTypesObject: + raise Exception("cannot call makeRPointer(RCTypesObject) or " + "pointer(x) if x degenerated to the base " + "RCTypesObject class") class RCTypesPtr(RCTypesObject): CONTENTS = contentscls.CDATATYPE Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 17:45:11 2006 @@ -1,45 +1,69 @@ from pypy.rlib.rctypesobject import * +from pypy.rpython.test.test_llinterp import interpret -def test_primitive(): - x = rc_int.allocate() - assert x.get_value() == 0 - x.set_value(17) - assert x.get_value() == 17 - -def test_ptr(): - x = rc_int.allocate() - p1 = pointer(x) - p2 = pointer(x) - x.set_value(17) - assert p1.get_contents().get_value() == 17 - p2.get_contents().set_value(18) - assert x.get_value() == 18 - del x - assert p1.get_contents().get_value() == 18 - -def test_struct(): - x = rc_int.allocate() - x.set_value(42) - S = makeRStruct('S', [('x', rc_int), - ('y', makeRPointer(rc_int))]) - s = S.allocate() - s.ref_x().set_value(12) - s.ref_y().set_contents(x) - assert s.ref_x().get_value() == 12 - assert s.ref_y().get_contents().get_value() == 42 - -def test_copyfrom(): - x1 = rc_int.allocate() - x1.set_value(101) - p1 = pointer(x1) - x2 = rc_int.allocate() - x2.set_value(202) - p2 = pointer(x2) - del x1, x2 - p1.copyfrom(p2) - assert p1.get_contents().sameaddr(p2.get_contents()) - p1.get_contents().set_value(303) - assert p2.get_contents().get_value() == 303 - del p2 - import gc; gc.collect() - assert p1.get_contents().get_value() == 303 + +class TestBasic: + + def do(self, func): + return func() + + def test_primitive(self): + def func(): + x = rc_int.allocate() + assert x.get_value() == 0 + x.set_value(17) + return x.get_value() + res = self.do(func) + assert res == 17 + + def test_ptr(self): + def func(): + x = rc_int.allocate() + p1 = pointer(x) + p2 = pointer(x) + x.set_value(17) + assert p1.get_contents().get_value() == 17 + p2.get_contents().set_value(18) + assert x.get_value() == 18 + del x + return p1.get_contents().get_value() + res = self.do(func) + assert res == 18 + + def test_struct(self): + S1 = makeRStruct('S1', [('x', rc_int), + ('y', makeRPointer(rc_int))]) + def func(): + x = rc_int.allocate() + x.set_value(42) + s = S1.allocate() + s.ref_x().set_value(12) + s.ref_y().set_contents(x) + assert s.ref_x().get_value() == 12 + return s.ref_y().get_contents().get_value() + res = self.do(func) + assert res == 42 + + def test_copyfrom(self): + def func(): + x1 = rc_int.allocate() + x1.set_value(101) + p1 = pointer(x1) + x2 = rc_int.allocate() + x2.set_value(202) + p2 = pointer(x2) + del x1, x2 + p1.copyfrom(p2) + assert p1.get_contents().sameaddr(p2.get_contents()) + p1.get_contents().set_value(303) + assert p2.get_contents().get_value() == 303 + del p2 + return p1.get_contents().get_value() + res = self.do(func) + assert res == 303 + + +class TestLLInterpreted(TestBasic): + + def do(self, func): + return interpret(func, []) Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Sat Nov 11 17:45:11 2006 @@ -1439,14 +1439,15 @@ start, stop = self._parentstructure().getbounds() return start - baseoffset, stop - baseoffset - def getitem(self, index): + def getitem(self, index, uninitialized_ok=False): baseoffset = self._parent_index if isinstance(baseoffset, str): assert index == 0 fieldname = baseoffset # structfield case return getattr(self._parentstructure(), fieldname) else: - return self._parentstructure().getitem(baseoffset + index) + return self._parentstructure().getitem(baseoffset + index, + uninitialized_ok=uninitialized_ok) def setitem(self, index, value): baseoffset = self._parent_index 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 Sat Nov 11 17:45:11 2006 @@ -482,6 +482,26 @@ raw_memcopy(at1, at2, sizeof(T)) assert t2.x == 1 +def test_raw_memcopy_nonrec(): + T = lltype.GcStruct('T', ('x', lltype.Signed)) + A = lltype.FixedSizeArray(lltype.Ptr(T), 1) + t1 = lltype.malloc(T) + t2 = lltype.malloc(T) + t1.x = 1 + t2.x = 2 + + at1 = raw_malloc(sizeof(A)) + at2 = raw_malloc(sizeof(A)) + p1 = cast_adr_to_ptr(at1, lltype.Ptr(A)) + p2 = cast_adr_to_ptr(at2, lltype.Ptr(A)) + p1[0] = t1 + p2[0] = t2 + raw_memcopy(at1, at2, sizeof(A)) + assert p1[0] == t1 + assert p2[0] == t1 + assert t1.x == 1 # not + assert t2.x == 2 # modified + def test_inlined_substruct(): T = lltype.Struct('T', ('x', lltype.Signed)) S1 = lltype.GcStruct('S1', ('t1', T), ('t2', T)) From arigo at codespeak.net Sat Nov 11 17:48:56 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 17:48:56 +0100 (CET) Subject: [pypy-svn] r34491 - pypy/dist/pypy/translator/c/src Message-ID: <20061111164856.A3AEF10117@code0.codespeak.net> Author: arigo Date: Sat Nov 11 17:48:55 2006 New Revision: 34491 Removed: pypy/dist/pypy/translator/c/src/ll__socket.h Modified: pypy/dist/pypy/translator/c/src/g_include.h Log: Kill ll__socket.h (thanks amaury). Modified: pypy/dist/pypy/translator/c/src/g_include.h ============================================================================== --- pypy/dist/pypy/translator/c/src/g_include.h (original) +++ pypy/dist/pypy/translator/c/src/g_include.h Sat Nov 11 17:48:55 2006 @@ -45,7 +45,6 @@ # ifdef RPyExc_thread_error # include "src/ll_thread.h" # endif -# include "src/ll__socket.h" #endif #include "src/stack.h" From arigo at codespeak.net Sat Nov 11 17:49:33 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 17:49:33 +0100 (CET) Subject: [pypy-svn] r34492 - pypy/dist/pypy/rlib Message-ID: <20061111164933.A22EB1011A@code0.codespeak.net> Author: arigo Date: Sat Nov 11 17:49:32 2006 New Revision: 34492 Modified: pypy/dist/pypy/rlib/rctypesobject.py Log: Add '_' in front of the internal method names. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 17:49:32 2006 @@ -69,21 +69,21 @@ def copyfrom1(self, srcbox): assert isinstance(srcbox, cls) llmemory.raw_memcopy(srcbox.addr, self.addr, cls.rawsize) - self.copykeepalives(0, srcbox) + self._copykeepalives(0, srcbox) cls.copyfrom = copyfrom1 def sameaddr(self, otherbox): return self.addr == otherbox.addr - def keepalivememblock(self, index, memblock): + def _keepalivememblock(self, index, memblock): self.memblock.setkeepalive(index, memblock) - def copykeepalives(self, startindex, srcbox): + def _copykeepalives(self, startindex, srcbox): for i in range(self.num_keepalives): memblock = srcbox.memblock.getkeepalive(startindex + i) self.memblock.setkeepalive(i, memblock) - def getmemblock(self, index, target_num_keepalives): + def _getmemblock(self, index, target_num_keepalives): targetmemblock = self.memblock.getkeepalive(index) if targetmemblock is None: targetmemblock = RawMemBlock(target_num_keepalives) @@ -142,7 +142,7 @@ ptr = self.ll_ref(RCTypesPtr.CDATATYPE) targetaddr = llmemory.cast_ptr_to_adr(ptr[0]) targetkeepalives = contentscls.num_keepalives - targetmemblock = self.getmemblock(0, targetkeepalives) + targetmemblock = self._getmemblock(0, targetkeepalives) return contentscls(targetaddr, targetmemblock) def set_contents(self, newcontentsbox): @@ -151,7 +151,7 @@ ptr = self.ll_ref(RCTypesPtr.CDATATYPE) ptr[0] = llmemory.cast_adr_to_ptr(targetaddr, RCTypesPtr.LLTYPE) - self.keepalivememblock(0, targetmemblock) + self._keepalivememblock(0, targetmemblock) contentscls._ptrcls = RCTypesPtr return RCTypesPtr From arigo at codespeak.net Sat Nov 11 18:08:27 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 18:08:27 +0100 (CET) Subject: [pypy-svn] r34493 - in pypy/dist/pypy/rlib: . test Message-ID: <20061111170827.1306E1011D@code0.codespeak.net> Author: arigo Date: Sat Nov 11 18:08:26 2006 New Revision: 34493 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py Log: - fixed-size arrays. - more annotation fixes. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 18:08:26 2006 @@ -30,7 +30,7 @@ #print 'raw_free: ', self.addr llmemory.raw_free(self.addr) -class RawMemSubBlock(object): +class RawMemSubBlock(RawMemBlock): def __init__(self, baseblock, ofs_keepalives): self.baseblock = baseblock self.keepalives = baseblock.keepalives @@ -203,3 +203,35 @@ for name in fieldclasses: make_accessors(name) return RCTypesStruct + + +def makeRArray(itemcls, fixedsize): + """Build and return a new RCTypesArray class.""" + + key = '_arraycls%d' % (fixedsize,) + try: + return getattr(itemcls, key) + except AttributeError: + assert issubclass(itemcls, RCTypesObject) + if itemcls is RCTypesObject: + raise Exception("cannot call makeRArray(RCTypesObject)") + + ARRAYTYPE = lltype.FixedSizeArray(itemcls.LLTYPE, fixedsize) + FIRSTITEMOFS = llmemory.ArrayItemsOffset(ARRAYTYPE) + ITEMOFS = llmemory.sizeof(itemcls.LLTYPE) + + class RCTypesArray(RCTypesObject): + LLTYPE = ARRAYTYPE + num_keepalives = itemcls.num_keepalives * fixedsize + + def ref(self, n): + subaddr = self.addr + FIRSTITEMOFS + ITEMOFS * n + subblock = self.memblock.addoffset(itemcls.num_keepalives * n) + return itemcls(subaddr, subblock) + + def length(self): + return fixedsize + + setattr(itemcls, key, RCTypesArray) + return RCTypesArray +makeRArray._annspecialcase_ = 'specialize:memo' Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 18:08:26 2006 @@ -1,5 +1,6 @@ from pypy.rlib.rctypesobject import * from pypy.rpython.test.test_llinterp import interpret +from pypy.annotation.policy import AnnotatorPolicy class TestBasic: @@ -62,8 +63,21 @@ res = self.do(func) assert res == 303 + def test_fixedsize_array(self): + def func(): + a = makeRArray(rc_int, 10).allocate() + for i in range(10): + a.ref(i).set_value(5 * i) + for i in range(10): + assert a.ref(i).get_value() == 5 * i + return a.length() + res = self.do(func) + assert res == 10 + class TestLLInterpreted(TestBasic): - + POLICY = AnnotatorPolicy() + POLICY.allow_someobjects = False + def do(self, func): - return interpret(func, []) + return interpret(func, [], policy=self.POLICY) From arigo at codespeak.net Sat Nov 11 19:04:26 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 19:04:26 +0100 (CET) Subject: [pypy-svn] r34494 - in pypy/dist/pypy/rlib: . test Message-ID: <20061111180426.6FFA010113@code0.codespeak.net> Author: arigo Date: Sat Nov 11 19:04:25 2006 New Revision: 34494 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py Log: - some support for var-sized arrays. - renamed makeRXxx() => RXxx(). Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 19:04:25 2006 @@ -96,7 +96,7 @@ _primitive_cache = {} -def makePrimitive(TYPE): +def Primitive(TYPE): """Build a return a new RCTypesPrimitive class.""" try: return _primitive_cache[TYPE] @@ -118,18 +118,18 @@ return RCTypesPrimitive # a few prebuilt primitive types -rc_int = makePrimitive(lltype.Signed) -rc_char = makePrimitive(lltype.Char) +rc_int = Primitive(lltype.Signed) +rc_char = Primitive(lltype.Char) -def makeRPointer(contentscls): +def RPointer(contentscls): """Build and return a new RCTypesPointer class.""" try: return contentscls._ptrcls except AttributeError: assert issubclass(contentscls, RCTypesObject) if contentscls is RCTypesObject: - raise Exception("cannot call makeRPointer(RCTypesObject) or " + raise Exception("cannot call RPointer(RCTypesObject) or " "pointer(x) if x degenerated to the base " "RCTypesObject class") @@ -155,17 +155,17 @@ contentscls._ptrcls = RCTypesPtr return RCTypesPtr -makeRPointer._annspecialcase_ = 'specialize:memo' +RPointer._annspecialcase_ = 'specialize:memo' def pointer(x): - PTR = makeRPointer(x.__class__) + PTR = RPointer(x.__class__) p = PTR.allocate() p.set_contents(x) return p pointer._annspecialcase_ = 'specialize:argtype(0)' -def makeRStruct(c_name, fields, c_external=False): +def RStruct(c_name, fields, c_external=False): """Build and return a new RCTypesStruct class.""" def cmangle(name): @@ -205,33 +205,88 @@ return RCTypesStruct -def makeRArray(itemcls, fixedsize): - """Build and return a new RCTypesArray class.""" +def RFixedArray(itemcls, fixedsize): + """Build and return a new RCTypesFixedArray class.""" - key = '_arraycls%d' % (fixedsize,) + key = '_fixedarraycls%d' % (fixedsize,) try: return getattr(itemcls, key) except AttributeError: assert issubclass(itemcls, RCTypesObject) if itemcls is RCTypesObject: - raise Exception("cannot call makeRArray(RCTypesObject)") + raise Exception("cannot call RFixedArray(RCTypesObject)") ARRAYTYPE = lltype.FixedSizeArray(itemcls.LLTYPE, fixedsize) FIRSTITEMOFS = llmemory.ArrayItemsOffset(ARRAYTYPE) ITEMOFS = llmemory.sizeof(itemcls.LLTYPE) - class RCTypesArray(RCTypesObject): + class RCTypesFixedArray(RCTypesObject): + ITEM = ARRAYTYPE.OF LLTYPE = ARRAYTYPE + length = fixedsize num_keepalives = itemcls.num_keepalives * fixedsize def ref(self, n): - subaddr = self.addr + FIRSTITEMOFS + ITEMOFS * n + subaddr = self.addr + (FIRSTITEMOFS + ITEMOFS * n) subblock = self.memblock.addoffset(itemcls.num_keepalives * n) return itemcls(subaddr, subblock) - def length(self): - return fixedsize + setattr(itemcls, key, RCTypesFixedArray) + return RCTypesFixedArray +RFixedArray._annspecialcase_ = 'specialize:memo' - setattr(itemcls, key, RCTypesArray) - return RCTypesArray -makeRArray._annspecialcase_ = 'specialize:memo' + +def RVarArray(itemcls): + """Build and return a new RCTypesVarArray class. + Note that this is *not* a subclass of RCTypesObject, so you cannot + take a pointer to it, use it as a field of a structure, etc. + """ + try: + return itemcls._vararraycls + except AttributeError: + assert issubclass(itemcls, RCTypesObject) + if itemcls is RCTypesObject: + raise Exception("cannot call RVarArray(RCTypesObject)") + + ARRAYTYPE = lltype.Array(itemcls.LLTYPE, hints={'nolength': True}) + FIRSTITEMOFS = llmemory.ArrayItemsOffset(ARRAYTYPE) + ITEMOFS = llmemory.sizeof(itemcls.LLTYPE) + + class RCTypesVarArray(object): + ITEM = ARRAYTYPE.OF + + def __init__(self, addr, memblock, length): + self.addr = addr + self.memblock = memblock + self.length = length + + def allocate(length): + rawsize = FIRSTITEMOFS + ITEMOFS * length + num_keepalives = itemcls.num_keepalives * length + memblock = AllocatedRawMemBlock(num_keepalives, rawsize) + addr = memblock.addr + FIRSTITEMOFS + return RCTypesVarArray(addr, memblock, length) + allocate = staticmethod(allocate) + + def fromitem(itembox, length): + """Return a VarArray from a reference to its first element. + Note that if you use the VarArray to store pointer-ish data, + you have to keep the VarArray alive as long as you want + this new data to stay alive. + """ + assert isinstance(itembox, itemcls) + num_keepalives = itemcls.num_keepalives * length + memblock = RawMemBlock(num_keepalives) + res = RCTypesVarArray(itembox.addr, memblock, length) + res._keepalive_memblock_fromitem = itembox.memblock + return res + fromitem = staticmethod(fromitem) + + def ref(self, n): + subaddr = self.addr + ITEMOFS * n + subblock = self.memblock.addoffset(itemcls.num_keepalives * n) + return itemcls(subaddr, subblock) + + itemcls._vararraycls = RCTypesVarArray + return RCTypesVarArray +RVarArray._annspecialcase_ = 'specialize:memo' Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 19:04:25 2006 @@ -32,8 +32,8 @@ assert res == 18 def test_struct(self): - S1 = makeRStruct('S1', [('x', rc_int), - ('y', makeRPointer(rc_int))]) + S1 = RStruct('S1', [('x', rc_int), + ('y', RPointer(rc_int))]) def func(): x = rc_int.allocate() x.set_value(42) @@ -63,17 +63,44 @@ res = self.do(func) assert res == 303 - def test_fixedsize_array(self): + def test_fixedarray(self): def func(): - a = makeRArray(rc_int, 10).allocate() + a = RFixedArray(rc_int, 10).allocate() for i in range(10): a.ref(i).set_value(5 * i) for i in range(10): assert a.ref(i).get_value() == 5 * i - return a.length() + return a.length res = self.do(func) assert res == 10 + def test_vararray(self): + def func(): + a = RVarArray(rc_int).allocate(10) + for i in range(10): + a.ref(i).set_value(5 * i) + for i in range(10): + assert a.ref(i).get_value() == 5 * i + return a.length + res = self.do(func) + assert res == 10 + + def test_vararray_cast(self): + def func(): + a = RVarArray(rc_int).allocate(10) + for i in range(10): + a.ref(i).set_value(100 + 5 * i) + p = pointer(a.ref(0)) + del a + assert p.get_contents().get_value() == 100 + a1 = RVarArray(rc_int).fromitem(p.get_contents(), 8) + del p + for i in range(8): + a1.ref(i).get_value() == 100 + 5 * i + return a1.length + res = self.do(func) + assert res == 8 + class TestLLInterpreted(TestBasic): POLICY = AnnotatorPolicy() From arigo at codespeak.net Sat Nov 11 19:24:41 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 19:24:41 +0100 (CET) Subject: [pypy-svn] r34495 - in pypy/dist/pypy/rlib: . test Message-ID: <20061111182441.929C81011B@code0.codespeak.net> Author: arigo Date: Sat Nov 11 19:24:40 2006 New Revision: 34495 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py Log: rc_char_p. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 19:24:40 2006 @@ -122,6 +122,51 @@ rc_char = Primitive(lltype.Char) +class _RCTypesStringData(object): + ARRAYTYPE = lltype.Array(lltype.Char, hints={'nolength': True}) + FIRSTITEMOFS = llmemory.ArrayItemsOffset(ARRAYTYPE) + ITEMOFS = llmemory.sizeof(lltype.Char) + + def __init__(self, string): + rawsize = self.FIRSTITEMOFS + self.ITEMOFS * (len(string) + 1) + self.addr = llmemory.raw_malloc(rawsize) + a = self.addr + self.FIRSTITEMOFS + for i in range(len(string)): + a.char[0] = string[i] + a += self.ITEMOFS + a.char[0] = '\x00' + def __del__(self): + llmemory.raw_free(self.addr) + +class RCTypesCharP(RCTypesObject): + LLTYPE = lltype.Ptr(_RCTypesStringData.ARRAYTYPE) + + def strlen(self): + ptr = self.ll_ref(RCTypesCharP.CDATATYPE) + a = ptr[0] + n = 0 + while a[n] != '\x00': + n += 1 + return n + + def get_value(self): + length = self.strlen() + ptr = self.ll_ref(RCTypesCharP.CDATATYPE) + a = ptr[0] + lst = ['\x00'] * length + for i in range(length): + lst[i] = a[i] + return ''.join(lst) + + def set_value(self, string): + data = _RCTypesStringData(string) + ptr = self.ll_ref(RCTypesCharP.CDATATYPE) + ptr[0] = llmemory.cast_adr_to_ptr(data.addr, RCTypesCharP.LLTYPE) + self._keepalive_stringdata = data + +rc_char_p = RCTypesCharP + + def RPointer(contentscls): """Build and return a new RCTypesPointer class.""" try: @@ -240,6 +285,8 @@ """Build and return a new RCTypesVarArray class. Note that this is *not* a subclass of RCTypesObject, so you cannot take a pointer to it, use it as a field of a structure, etc. + You can take a pointer to one of its elements (e.g. the first), + though, and that pointer will keep the whole array alive. """ try: return itemcls._vararraycls Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 19:24:40 2006 @@ -101,6 +101,21 @@ res = self.do(func) assert res == 8 + def test_char_p(self): + def func(): + p = rc_char_p.allocate() + s = '' + for i in range(65, 91): + s += chr(i) + p.set_value(s) + del s + s = p.get_value() + for i in range(26): + assert ord(s[i]) == 65 + i + return len(s) + res = self.do(func) + assert res == 26 + class TestLLInterpreted(TestBasic): POLICY = AnnotatorPolicy() From cfbolz at codespeak.net Sat Nov 11 19:36:36 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 11 Nov 2006 19:36:36 +0100 (CET) Subject: [pypy-svn] r34496 - in pypy/dist/pypy: config module/pypymagic module/pypymagic/test module/sys Message-ID: <20061111183636.C142F1011C@code0.codespeak.net> Author: cfbolz Date: Sat Nov 11 19:36:33 2006 New Revision: 34496 Added: pypy/dist/pypy/module/pypymagic/ (props changed) pypy/dist/pypy/module/pypymagic/__init__.py pypy/dist/pypy/module/pypymagic/interp_magic.py pypy/dist/pypy/module/pypymagic/test/ (props changed) pypy/dist/pypy/module/pypymagic/test/__init__.py Modified: pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/module/sys/__init__.py pypy/dist/pypy/module/sys/state.py Log: add module pypymagic that exposes special pypy specific magical functions Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Sat Nov 11 19:36:33 2006 @@ -11,7 +11,7 @@ [#"unicodedata", "_codecs", "gc", "_weakref", "array", "marshal", "errno", "math", "_sre", "_pickle_support", "sys", "exceptions", "__builtins__", - "recparser", "symbol", "_random", "_file"]) + "recparser", "symbol", "_random", "_file", "pypymagic"]) module_dependencies = { } if os.name == "posix": Added: pypy/dist/pypy/module/pypymagic/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/pypymagic/__init__.py Sat Nov 11 19:36:33 2006 @@ -0,0 +1,12 @@ + +# Package initialisation +from pypy.interpreter.mixedmodule import MixedModule + +class Module(MixedModule): + appleveldefs = { + } + + interpleveldefs = { + 'pypy_repr' : 'interp_magic.pypy_repr', + } + Added: pypy/dist/pypy/module/pypymagic/interp_magic.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/pypymagic/interp_magic.py Sat Nov 11 19:36:33 2006 @@ -0,0 +1,3 @@ + +def pypy_repr(space, w_object): + return space.wrap('%r' % (w_object,)) Added: pypy/dist/pypy/module/pypymagic/test/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/pypymagic/test/__init__.py Sat Nov 11 19:36:33 2006 @@ -0,0 +1 @@ +# Modified: pypy/dist/pypy/module/sys/__init__.py ============================================================================== --- pypy/dist/pypy/module/sys/__init__.py (original) +++ pypy/dist/pypy/module/sys/__init__.py Sat Nov 11 19:36:33 2006 @@ -34,7 +34,6 @@ 'warnoptions' : 'state.get(space).w_warnoptions', 'builtin_module_names' : 'state.w_None', 'pypy_getudir' : 'state.pypy_getudir', - 'pypy_repr' : 'state.pypy_repr', 'pypy_initial_path' : 'state.pypy_initial_path', '_getframe' : 'vm._getframe', Modified: pypy/dist/pypy/module/sys/state.py ============================================================================== --- pypy/dist/pypy/module/sys/state.py (original) +++ pypy/dist/pypy/module/sys/state.py Sat Nov 11 19:36:33 2006 @@ -112,6 +112,3 @@ def pypy_getudir(space): return _pypy_getudir(space) - -def pypy_repr(space, w_object): - return space.wrap('%r' % (w_object,)) From arigo at codespeak.net Sat Nov 11 19:47:57 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 19:47:57 +0100 (CET) Subject: [pypy-svn] r34499 - in pypy/dist/pypy/rlib: . test Message-ID: <20061111184757.9F59D10121@code0.codespeak.net> Author: arigo Date: Sat Nov 11 19:47:57 2006 New Revision: 34499 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py Log: Some extra getters and setters for arrays of char. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 19:47:57 2006 @@ -94,6 +94,7 @@ return llmemory.cast_adr_to_ptr(self.addr, lltype.Ptr(CDATATYPE)) ll_ref._annspecialcase_ = 'specialize:arg(1)' +# ____________________________________________________________ _primitive_cache = {} def Primitive(TYPE): @@ -121,16 +122,16 @@ rc_int = Primitive(lltype.Signed) rc_char = Primitive(lltype.Char) +# ____________________________________________________________ class _RCTypesStringData(object): - ARRAYTYPE = lltype.Array(lltype.Char, hints={'nolength': True}) - FIRSTITEMOFS = llmemory.ArrayItemsOffset(ARRAYTYPE) - ITEMOFS = llmemory.sizeof(lltype.Char) + ARRAYTYPE = lltype.FixedSizeArray(lltype.Char, 1) + ITEMOFS = llmemory.sizeof(lltype.Char) def __init__(self, string): - rawsize = self.FIRSTITEMOFS + self.ITEMOFS * (len(string) + 1) + rawsize = self.ITEMOFS * (len(string) + 1) self.addr = llmemory.raw_malloc(rawsize) - a = self.addr + self.FIRSTITEMOFS + a = self.addr for i in range(len(string)): a.char[0] = string[i] a += self.ITEMOFS @@ -138,25 +139,32 @@ def __del__(self): llmemory.raw_free(self.addr) +def strlen(p): + n = 0 + while p[n] != '\x00': + n += 1 + return n + +def strnlen(p, n_max): + n = 0 + while n < n_max and p[n] != '\x00': + n += 1 + return n + +def charp2string(p, length): + lst = ['\x00'] * length + for i in range(length): + lst[i] = p[i] + return ''.join(lst) + class RCTypesCharP(RCTypesObject): LLTYPE = lltype.Ptr(_RCTypesStringData.ARRAYTYPE) - def strlen(self): - ptr = self.ll_ref(RCTypesCharP.CDATATYPE) - a = ptr[0] - n = 0 - while a[n] != '\x00': - n += 1 - return n - def get_value(self): - length = self.strlen() ptr = self.ll_ref(RCTypesCharP.CDATATYPE) - a = ptr[0] - lst = ['\x00'] * length - for i in range(length): - lst[i] = a[i] - return ''.join(lst) + p = ptr[0] + length = strlen(p) + return charp2string(p, length) def set_value(self, string): data = _RCTypesStringData(string) @@ -166,6 +174,7 @@ rc_char_p = RCTypesCharP +# ____________________________________________________________ def RPointer(contentscls): """Build and return a new RCTypesPointer class.""" @@ -209,6 +218,7 @@ return p pointer._annspecialcase_ = 'specialize:argtype(0)' +# ____________________________________________________________ def RStruct(c_name, fields, c_external=False): """Build and return a new RCTypesStruct class.""" @@ -249,6 +259,7 @@ make_accessors(name) return RCTypesStruct +# ____________________________________________________________ def RFixedArray(itemcls, fixedsize): """Build and return a new RCTypesFixedArray class.""" @@ -276,6 +287,30 @@ subblock = self.memblock.addoffset(itemcls.num_keepalives * n) return itemcls(subaddr, subblock) + if itemcls is rc_char: + # special methods for arrays of chars + def _as_ll_charptr(self): + ptr = self.ll_ref(ARRAYTYPE) + return lltype.direct_arrayitems(ptr) + + def get_value(self): + p = self._as_ll_charptr() + n = strnlen(p, fixedsize) + return charp2string(p, n) + + def set_value(self, string): + p = self._as_ll_charptr() + for i in range(fixedsize): + if i < len(string): + p[i] = string[i] + else: + p[i] = '\x00' + break + + def get_raw(self): + p = self._as_ll_charptr() + return charp2string(p, fixedsize) + setattr(itemcls, key, RCTypesFixedArray) return RCTypesFixedArray RFixedArray._annspecialcase_ = 'specialize:memo' Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 19:47:57 2006 @@ -116,6 +116,24 @@ res = self.do(func) assert res == 26 + def test_char_array(self): + def func(): + a = RFixedArray(rc_char, 10).allocate() + for i in range(6): + a.ref(i).set_value("hello!"[i]) + assert a.get_value() == "hello!" + a.set_value("foo") + assert a.get_value() == "foo" + raw = ''.join([a.ref(i).get_value() for i in range(10)]) + assert raw == "foo\x00o!\x00\x00\x00\x00" + assert raw == a.get_raw() + a.set_value("0123456789") + assert a.get_raw() == "0123456789" + assert a.get_value() == "0123456789" + return 1 + res = self.do(func) + assert res == 1 + class TestLLInterpreted(TestBasic): POLICY = AnnotatorPolicy() From cfbolz at codespeak.net Sat Nov 11 19:58:00 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 11 Nov 2006 19:58:00 +0100 (CET) Subject: [pypy-svn] r34501 - in pypy/dist: demo pypy/config pypy/doc pypy/module/pypymagic pypy/objspace pypy/objspace/test Message-ID: <20061111185800.6CC6710125@code0.codespeak.net> Author: cfbolz Date: Sat Nov 11 19:57:56 2006 New Revision: 34501 Modified: pypy/dist/demo/fibonacci.py pypy/dist/demo/sharedref.py pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/doc/getting-started.txt pypy/dist/pypy/module/pypymagic/__init__.py pypy/dist/pypy/objspace/test/test_thunkobjspace.py pypy/dist/pypy/objspace/thunk.py Log: move thunk, is_thunk and become to pypymagic (if the thunk object space is used) Modified: pypy/dist/demo/fibonacci.py ============================================================================== --- pypy/dist/demo/fibonacci.py (original) +++ pypy/dist/demo/fibonacci.py Sat Nov 11 19:57:56 2006 @@ -9,8 +9,8 @@ """ try: - thunk # only available in 'py.py -o thunk' -except NameError: + from pypymagic import thunk # only available in 'py.py -o thunk' +except ImportError: print __doc__ raise SystemExit(2) Modified: pypy/dist/demo/sharedref.py ============================================================================== --- pypy/dist/demo/sharedref.py (original) +++ pypy/dist/demo/sharedref.py Sat Nov 11 19:57:56 2006 @@ -35,6 +35,7 @@ """ import sys, marshal +from pypymagic import thunk, become from socket import * from select import select Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Sat Nov 11 19:57:56 2006 @@ -24,7 +24,8 @@ ["std", "flow", "logic", "thunk", "cpy", "dump"], "std", requires = { "thunk": [("objspace.geninterp", False)], - "logic": [("objspace.geninterp", False)], + "logic": [("objspace.geninterp", False), + ("objspace.usemodules._stackless", True)], }, cmdline='--objspace -o'), Modified: pypy/dist/pypy/doc/getting-started.txt ============================================================================== --- pypy/dist/pypy/doc/getting-started.txt (original) +++ pypy/dist/pypy/doc/getting-started.txt Sat Nov 11 19:57:56 2006 @@ -246,6 +246,7 @@ cd pypy/bin python py.py -o thunk + >>>> from pypymagic import thunk >>>> def longcomputation(lst): .... print "computing..." .... return sum(lst) @@ -286,7 +287,7 @@ Try it out:: cd pypy/bin - python py.py -o logic --usemodules=_stackless + python py.py -o logic >>>> X = newvar() # a logic variable >>>> bind(X, 42) # give it a value Modified: pypy/dist/pypy/module/pypymagic/__init__.py ============================================================================== --- pypy/dist/pypy/module/pypymagic/__init__.py (original) +++ pypy/dist/pypy/module/pypymagic/__init__.py Sat Nov 11 19:57:56 2006 @@ -9,4 +9,3 @@ interpleveldefs = { 'pypy_repr' : 'interp_magic.pypy_repr', } - Modified: pypy/dist/pypy/objspace/test/test_thunkobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_thunkobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_thunkobjspace.py Sat Nov 11 19:57:56 2006 @@ -6,6 +6,7 @@ cls.space = gettestobjspace('thunk') def test_simple(self): + from pypymagic import thunk, become computed = [] def f(): computed.append(True) @@ -20,6 +21,7 @@ assert computed == [True] def test_setitem(self): + from pypymagic import thunk, become computed = [] def f(a): computed.append(True) @@ -37,6 +39,7 @@ assert d[7] == [43] def test_become(self): + from pypymagic import thunk, become x = [] y = [] assert x is not y @@ -44,6 +47,7 @@ assert x is y def test_id(self): + from pypymagic import thunk, become # these are the Smalltalk semantics of become(). x = []; idx = id(x) y = []; idy = id(y) @@ -52,6 +56,7 @@ assert id(x) == id(y) == idy def test_double_become(self): + from pypymagic import thunk, become x = [] y = [] z = [] @@ -60,18 +65,21 @@ assert x is y is z def test_thunk_forcing_while_forcing(self): + from pypymagic import thunk, become def f(): return x+1 x = thunk(f) raises(RuntimeError, 'x+1') def INPROGRESS_test_thunk_forcing_while_forcing_2(self): + from pypymagic import thunk, become def f(): return x x = thunk(f) raises(RuntimeError, 'x+1') def test_is_thunk(self): + from pypymagic import thunk, become, is_thunk def f(): pass assert is_thunk(thunk(f)) Modified: pypy/dist/pypy/objspace/thunk.py ============================================================================== --- pypy/dist/pypy/objspace/thunk.py (original) +++ pypy/dist/pypy/objspace/thunk.py Sat Nov 11 19:57:56 2006 @@ -1,6 +1,7 @@ """Example usage: $ py.py -o thunk + >>> from pypymagic import thunk, become >>> def f(): ... print 'computing...' ... return 6*7 @@ -152,10 +153,11 @@ from pypy.objspace import std space = std.Space(*args, **kwds) patch_space_in_place(space, 'thunk', proxymaker) - space.setitem(space.builtin.w_dict, space.wrap('thunk'), + w_pypymagic = space.getbuiltinmodule("pypymagic") + space.setattr(w_pypymagic, space.wrap('thunk'), space.wrap(app_thunk)) - space.setitem(space.builtin.w_dict, space.wrap('is_thunk'), + space.setattr(w_pypymagic, space.wrap('is_thunk'), space.wrap(app_is_thunk)) - space.setitem(space.builtin.w_dict, space.wrap('become'), + space.setattr(w_pypymagic, space.wrap('become'), space.wrap(app_become)) return space From fijal at codespeak.net Sat Nov 11 20:17:49 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 11 Nov 2006 20:17:49 +0100 (CET) Subject: [pypy-svn] r34502 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20061111191749.7E43B10122@code0.codespeak.net> Author: fijal Date: Sat Nov 11 20:17:47 2006 New Revision: 34502 Modified: pypy/dist/pypy/objspace/std/objspace.py pypy/dist/pypy/objspace/std/test/test_proxy.py pypy/dist/pypy/objspace/std/test/test_proxy_function.py pypy/dist/pypy/objspace/std/test/test_proxy_internals.py pypy/dist/pypy/objspace/std/test/test_proxy_object.py Log: Moved transparent_proxy to pypymagic. Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Sat Nov 11 20:17:47 2006 @@ -134,9 +134,10 @@ self.setup_builtin_modules() # Adding transparent proxy call if self.config.objspace.std.withtproxy: - from pypy.objspace.std.transparent import app_proxy + w_pypymagic = self.getbuiltinmodule("pypymagic") + from pypy.objspace.std.transparent import app_proxy - self.setitem(self.builtin.w_dict, self.wrap('proxy'), + self.setattr(w_pypymagic, self.wrap('transparent_proxy'), self.wrap(app_proxy)) def enable_old_style_classes_as_default_metaclass(self): Modified: pypy/dist/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/dist/pypy/objspace/std/test/test_proxy.py Sat Nov 11 20:17:47 2006 @@ -18,10 +18,14 @@ return getattr(self.obj, name)(*args, **kwargs) return Controller """) + self.w_proxy = self.space.appexec([], """(): + from pypymagic import transparent_proxy + return transparent_proxy + """) class AppTestListProxy(AppProxyBasic): def test_proxy(self): - lst = proxy(list, lambda : None) + lst = self.proxy(list, lambda : None) assert type(lst) is list def test_proxy_repr(self): @@ -30,19 +34,19 @@ if name == '__repr__': return repr(lst) - lst = proxy(list, controller) + lst = self.proxy(list, controller) assert repr(lst) == repr([1,2,3]) def test_proxy_append(self): c = self.Controller([]) - lst = proxy(list, c.perform) + lst = self.proxy(list, c.perform) lst.append(1) lst.append(2) assert repr(lst) == repr([1,2]) def test_gt_lt_list(self): c = self.Controller([]) - lst = proxy(list, c.perform) + lst = self.proxy(list, c.perform) lst.append(1) lst.append(2) assert lst < [1,2,3] @@ -56,7 +60,7 @@ def test_add_list(self): c = self.Controller([]) - lst = proxy(list, c.perform) + lst = self.proxy(list, c.perform) lst.append(1) assert lst + lst == [1,1] assert lst + [1] == [1,1] @@ -64,14 +68,14 @@ def test_list_getitem(self): c = self.Controller([1,2,3]) - lst = proxy(list, c.perform) + lst = self.proxy(list, c.perform) assert lst[2] == 3 lst[1] = 0 assert lst[0] + lst[1] == 1 def test_list_setitem(self): c = self.Controller([1,2,3]) - lst = proxy(list, c.perform) + lst = self.proxy(list, c.perform) try: lst[3] = "x" except IndexError: @@ -82,7 +86,7 @@ class AppTestDictProxy(AppProxyBasic): def test_dict(self): c = self.Controller({"xx":1}) - d = proxy(dict, c.perform) + d = self.proxy(dict, c.perform) assert d['xx'] == 1 assert 'yy' not in d d2 = {'yy':3} @@ -92,13 +96,13 @@ def test_dict_pop(self): c = self.Controller({'x':1}) - d = proxy(dict, c.perform) + d = self.proxy(dict, c.perform) assert d.pop('x') == 1 assert d.pop('x', None) is None def test_dict_iter(self): c = self.Controller({'a':1, 'b':2, 'c':3}) - d = proxy(dict, c.perform) + d = self.proxy(dict, c.perform) d['z'] = 4 assert sorted(list(d.iterkeys())) == ['a', 'b', 'c', 'z'] Modified: pypy/dist/pypy/objspace/std/test/test_proxy_function.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_proxy_function.py (original) +++ pypy/dist/pypy/objspace/std/test/test_proxy_function.py Sat Nov 11 20:17:47 2006 @@ -19,6 +19,7 @@ return getattr(self.obj, name)(*args, **kwargs) def get_proxy(f): import types + from pypymagic import transparent_proxy as proxy return proxy(types.FunctionType, Controller(f).perform) return get_proxy """) Modified: pypy/dist/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/dist/pypy/objspace/std/test/test_proxy_internals.py Sat Nov 11 20:17:47 2006 @@ -16,6 +16,7 @@ def perform(self, name, *args, **kwargs): return getattr(self.obj, name)(*args, **kwargs) def get_proxy(f): + from pypymagic import transparent_proxy as proxy return proxy(type(f), Controller(f).perform) return get_proxy """) @@ -58,6 +59,7 @@ import traceback def get_proxy(f): + from pypymagic import transparent_proxy as proxy return proxy(type(f), Controller(f).perform) class FakeTb(object): Modified: pypy/dist/pypy/objspace/std/test/test_proxy_object.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_proxy_object.py (original) +++ pypy/dist/pypy/objspace/std/test/test_proxy_object.py Sat Nov 11 20:17:47 2006 @@ -12,10 +12,14 @@ __slots__ = [] return A """) + self.w_proxy = self.space.appexec([], """(): + from pypymagic import transparent_proxy + return transparent_proxy + """) def test_write_dict(self): c = self.Controller(self.A()) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) raises(AttributeError, "obj.__dict__ = {}") class AppTestProxyObj(AppProxyBasic): @@ -32,14 +36,14 @@ pass c = self.Controller(self.A()) - obj = proxy(AT, c.perform) + obj = self.proxy(AT, c.perform) assert type(obj) is AT assert obj.__class__ is AT def test__class__override(self): c = self.Controller(self.A()) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) raises(TypeError, "obj.__class__ = self.A") @@ -47,19 +51,19 @@ a = self.A() a.x = 3 c = self.Controller(a) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) assert obj.x == 3 def test_nonexistant_attribuite_access(self): c = self.Controller(self.A()) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) raises(AttributeError, "obj.x") def test_setattr(self): a = self.A() c = self.Controller(a) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) obj.x = 1 assert obj.x == 1 assert a.x == 1 @@ -68,7 +72,7 @@ a = self.A() a.f = 3 c = self.Controller(a) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) del obj.f raises(AttributeError, "obj.f") @@ -76,13 +80,13 @@ a = self.A() a.x = 3 c = self.Controller(a) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) assert 'x' in obj.__dict__ def test_set__dict__(self): a = self.A() c = self.Controller(a) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) obj.__dict__ = {'x':3} assert obj.x == 3 assert obj.__dict__.keys() == ['x'] @@ -90,7 +94,7 @@ def test_repr(self): a = self.A() c = self.Controller(a) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) assert repr(obj)[:6] == repr(a)[:6] class AppTestProxyObjectList(AppTestProxyObj): @@ -101,10 +105,15 @@ pass return A """) + self.w_proxy = self.space.appexec([], """(): + from pypymagic import transparent_proxy + return transparent_proxy + """) + def test_list_append(self): a = self.A([1,2,3]) c = self.Controller(a) - obj = proxy(self.A, c.perform) + obj = self.proxy(self.A, c.perform) assert len(obj) == 3 assert obj[1] == 2 From fijal at codespeak.net Sat Nov 11 20:19:17 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 11 Nov 2006 20:19:17 +0100 (CET) Subject: [pypy-svn] r34503 - pypy/dist/pypy/doc Message-ID: <20061111191917.250DA10128@code0.codespeak.net> Author: fijal Date: Sat Nov 11 20:19:15 2006 New Revision: 34503 Modified: pypy/dist/pypy/doc/proxy.txt Log: Updated documents for name change. Modified: pypy/dist/pypy/doc/proxy.txt ============================================================================== --- pypy/dist/pypy/doc/proxy.txt (original) +++ pypy/dist/pypy/doc/proxy.txt Sat Nov 11 20:19:15 2006 @@ -20,6 +20,8 @@ Suppose we want to have list which stores all operations performed on it for later analysis. So we create a list an apropriate controller:: + from pypymagic import transparent_proxy + class Controller(object): def __init__(self, l): self.l = l @@ -29,10 +31,11 @@ return getattr(self.l, name)(*args, **kwargs) l = [] c = Controller(l) - lst = proxy(list, c.perform) + lst = transparent_proxy(list, c.perform) Here, we've created original list, some random class and called magic -``proxy`` function, which eats operation name and additional arguments. +``transparent_proxy`` function, which eats operation name and additional +arguments. Important bit is that we do not need some existing object to perform operations on, it can do whatever we like. And of course ``type(lst) is type(l)`` and ``lst is not l`` (well, the latter is not From arigo at codespeak.net Sat Nov 11 20:24:41 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 20:24:41 +0100 (CET) Subject: [pypy-svn] r34504 - in pypy/dist/pypy/rlib: . test Message-ID: <20061111192441.E170310126@code0.codespeak.net> Author: arigo Date: Sat Nov 11 20:24:39 2006 New Revision: 34504 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py Log: create_string_buffer(), implemented as a var-sized array of chars. Factored out the common extra methods of fixed- and var-sized arrays of chars. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 20:24:39 2006 @@ -127,15 +127,9 @@ class _RCTypesStringData(object): ARRAYTYPE = lltype.FixedSizeArray(lltype.Char, 1) ITEMOFS = llmemory.sizeof(lltype.Char) - - def __init__(self, string): - rawsize = self.ITEMOFS * (len(string) + 1) + def __init__(self, bufsize): + rawsize = self.ITEMOFS * bufsize self.addr = llmemory.raw_malloc(rawsize) - a = self.addr - for i in range(len(string)): - a.char[0] = string[i] - a += self.ITEMOFS - a.char[0] = '\x00' def __del__(self): llmemory.raw_free(self.addr) @@ -157,6 +151,14 @@ lst[i] = p[i] return ''.join(lst) +def string2charp(p, length, string): + for i in range(length): + if i < len(string): + p[i] = string[i] + else: + p[i] = '\x00' + break + class RCTypesCharP(RCTypesObject): LLTYPE = lltype.Ptr(_RCTypesStringData.ARRAYTYPE) @@ -167,7 +169,13 @@ return charp2string(p, length) def set_value(self, string): - data = _RCTypesStringData(string) + n = len(string) + data = _RCTypesStringData(n + 1) + a = data.addr + for i in range(n): + a.char[0] = string[i] + a += _RCTypesStringData.ITEMOFS + a.char[0] = '\x00' ptr = self.ll_ref(RCTypesCharP.CDATATYPE) ptr[0] = llmemory.cast_adr_to_ptr(data.addr, RCTypesCharP.LLTYPE) self._keepalive_stringdata = data @@ -287,29 +295,12 @@ subblock = self.memblock.addoffset(itemcls.num_keepalives * n) return itemcls(subaddr, subblock) - if itemcls is rc_char: - # special methods for arrays of chars - def _as_ll_charptr(self): - ptr = self.ll_ref(ARRAYTYPE) - return lltype.direct_arrayitems(ptr) - - def get_value(self): - p = self._as_ll_charptr() - n = strnlen(p, fixedsize) - return charp2string(p, n) - - def set_value(self, string): - p = self._as_ll_charptr() - for i in range(fixedsize): - if i < len(string): - p[i] = string[i] - else: - p[i] = '\x00' - break - - def get_raw(self): - p = self._as_ll_charptr() - return charp2string(p, fixedsize) + if itemcls is rc_char: + # attach special methods for arrays of chars + def as_ll_charptr(self): + ptr = self.ll_ref(ARRAYTYPE) + return lltype.direct_arrayitems(ptr) + _initialize_array_of_char(RCTypesFixedArray, as_ll_charptr) setattr(itemcls, key, RCTypesFixedArray) return RCTypesFixedArray @@ -369,6 +360,40 @@ subblock = self.memblock.addoffset(itemcls.num_keepalives * n) return itemcls(subaddr, subblock) + if itemcls is rc_char: + # attach special methods for arrays of chars + def as_ll_charptr(self): + return llmemory.cast_adr_to_ptr(self.addr, RCTypesCharP.LLTYPE) + _initialize_array_of_char(RCTypesVarArray, as_ll_charptr) + itemcls._vararraycls = RCTypesVarArray return RCTypesVarArray RVarArray._annspecialcase_ = 'specialize:memo' + +# ____________________________________________________________ + +def _initialize_array_of_char(RCClass, as_ll_charptr): + # Attach additional methods for fixed- or variable-sized arrays of char + + def get_value(self): + p = as_ll_charptr(self) + n = strnlen(p, self.length) + return charp2string(p, n) + + def set_value(self, string): + string2charp(as_ll_charptr(self), self.length, string) + + def get_raw(self): + return charp2string(as_ll_charptr(self), self.length) + + def get_substring(self, start, length): + p = lltype.direct_ptradd(as_ll_charptr(self), start) + return charp2string(p, length) + + RCClass.get_value = get_value + RCClass.set_value = set_value + RCClass.get_raw = get_raw + RCClass.get_substring = get_substring + + +create_string_buffer = RVarArray(rc_char).allocate Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 20:24:39 2006 @@ -130,6 +130,26 @@ a.set_value("0123456789") assert a.get_raw() == "0123456789" assert a.get_value() == "0123456789" + assert a.get_substring(2, 5) == "23456" + return 1 + res = self.do(func) + assert res == 1 + + def test_string_buffer(self): + def func(): + a = create_string_buffer(10) + for i in range(6): + a.ref(i).set_value("hello!"[i]) + assert a.get_value() == "hello!" + a.set_value("foo") + assert a.get_value() == "foo" + raw = ''.join([a.ref(i).get_value() for i in range(10)]) + assert raw == "foo\x00o!\x00\x00\x00\x00" + assert raw == a.get_raw() + a.set_value("0123456789") + assert a.get_raw() == "0123456789" + assert a.get_value() == "0123456789" + assert a.get_substring(2, 5) == "23456" return 1 res = self.do(func) assert res == 1 From fijal at codespeak.net Sat Nov 11 20:28:20 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 11 Nov 2006 20:28:20 +0100 (CET) Subject: [pypy-svn] r34505 - pypy/dist/pypy/translator/js/demo/jsdemo Message-ID: <20061111192820.05D3A1012C@code0.codespeak.net> Author: fijal Date: Sat Nov 11 20:28:19 2006 New Revision: 34505 Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Log: Remove unused import. Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Sat Nov 11 20:28:19 2006 @@ -16,8 +16,7 @@ from pypy.translator.js.main import rpython2javascript from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy -from pypy.translator.js.modules.mochikit import createLoggingPane, log,\ - escapeHTML +from pypy.translator.js.modules.mochikit import escapeHTML commproxy.USE_MOCHIKIT = True From fijal at codespeak.net Sat Nov 11 22:47:45 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 11 Nov 2006 22:47:45 +0100 (CET) Subject: [pypy-svn] r34512 - pypy/dist/pypy/objspace/std/test Message-ID: <20061111214745.F28E110127@code0.codespeak.net> Author: fijal Date: Sat Nov 11 22:47:44 2006 New Revision: 34512 Modified: pypy/dist/pypy/objspace/std/test/test_strjoinobject.py Log: s/sys.pypy_repr/pypymagic.pypy_repr/ Added failing test. Modified: pypy/dist/pypy/objspace/std/test/test_strjoinobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_strjoinobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_strjoinobject.py Sat Nov 11 22:47:44 2006 @@ -14,21 +14,37 @@ assert type(s) is str assert 'W_StringJoinObject' in sys.pypy_repr(s) + def test_function_with_strjoin(self): + py.test.skip("Failing") + def f(x, y): + if x[-1] != "/": + x += "/" + if y.startswith(x): + return y[len(x):] + + x = "a" + y = "a/b/c/d" + x += "" + y += "" + + assert f(x, y) + assert f(x, y) + def test_add(self): - import sys + import pypymagic all = "" for i in range(20): all += str(i) - assert 'W_StringJoinObject' in sys.pypy_repr(all) + assert 'W_StringJoinObject' in pypymagic.pypy_repr(all) def test_hash(self): - import sys + import pypymagic # check that we have the same hash as CPython for at least 31 bits # (but don't go checking CPython's special case -1) # disabled: assert hash('') == 0 --- different special case def join(s): return s[:len(s) // 2] + s[len(s) // 2:] s = join('a' * 101) - assert 'W_StringJoinObject' in sys.pypy_repr(s) + assert 'W_StringJoinObject' in pypymagic.pypy_repr(s) assert hash(s) & 0x7fffffff == 0x7e0bce58 def test_len(self): From arigo at codespeak.net Sat Nov 11 22:52:47 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 22:52:47 +0100 (CET) Subject: [pypy-svn] r34513 - in pypy/dist/pypy: rlib rlib/test rpython Message-ID: <20061111215247.4CD3D1012F@code0.codespeak.net> Author: arigo Date: Sat Nov 11 22:52:45 2006 New Revision: 34513 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py pypy/dist/pypy/rpython/annlowlevel.py Log: rctypesobject.RFuncType. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 22:52:45 2006 @@ -1,4 +1,5 @@ from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rpython import annlowlevel from pypy.interpreter.miscutils import InitializedClass from pypy.tool.sourcetools import func_with_new_name @@ -19,6 +20,8 @@ def setkeepalive(self, index, memblock): self.keepalives[self.ofs_keepalives + index] = memblock +EMPTY_RAW_MEM_BLOCK = RawMemBlock(0) + class AllocatedRawMemBlock(RawMemBlock): def __init__(self, num_keepalives, rawsize): RawMemBlock.__init__(self, num_keepalives) @@ -57,6 +60,9 @@ cls.CDATATYPE = cls.LLTYPE else: cls.CDATATYPE = lltype.FixedSizeArray(cls.LLTYPE, 1) + if not getattr(cls, 'can_allocate', True): + return + if not hasattr(cls, 'rawsize'): cls.rawsize = llmemory.sizeof(cls.CDATATYPE) @@ -397,3 +403,55 @@ create_string_buffer = RVarArray(rc_char).allocate + +# ____________________________________________________________ + +_functype_cache = {} +def RFuncType(args_cls, rescls): + """Build and return a new RCTypesFunc class. + Note that like lltype, but unlike ctypes, a 'function' type is not + automatically a pointer to a function. Conceptually, it represents + the area of memory where the function's machine code is stored.""" + args_cls = tuple(args_cls) + try: + return _functype_cache[args_cls, rescls] + except KeyError: + + ARGS = [cls.LLTYPE for cls in args_cls] + RES = rescls.LLTYPE + FUNCTYPE = lltype.FuncType(ARGS, RES) + PTRTYPE = lltype.Ptr(FUNCTYPE) + + class RCTypesFunc(RCTypesObject): + LLTYPE = FUNCTYPE + can_allocate = False + + def fromrpython(func): + """Return an RCTypes function that references the given + RPython function.""" + p = annlowlevel.llhelper(PTRTYPE, func) + addr = llmemory.cast_ptr_to_adr(p) + memblock = EMPTY_RAW_MEM_BLOCK + return RCTypesFunc(addr, memblock) + fromrpython._annspecialcase_ = 'specialize:arg(0)' + fromrpython = staticmethod(fromrpython) + + def call(self, *args): + assert len(args) == len(ARGS) + p = llmemory.cast_adr_to_ptr(self.addr, PTRTYPE) + return p(*args) + + _functype_cache[args_cls, rescls] = RCTypesFunc + return RCTypesFunc +RFuncType._annspecialcase_ = 'specialize:memo' + +##class RLibrary(object): + +## def __init__(self, c_libname=None, c_includes=None): +## self.c_libname = c_libname +## self.c_includes = c_includes + +## def link(self, cls, c_name): +## assert issubclass(cls, RCTypeObject) +## ... +## link._annspecialcase_ = 'specialize:arg(1)' Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 22:52:45 2006 @@ -154,6 +154,14 @@ res = self.do(func) assert res == 1 + def test_func(self): + def g(x, y): + return x - y + def func(): + a = RFuncType((rc_int, rc_int), rc_int).fromrpython(g) + return a.call(50, 8) + res = self.do(func) + assert res == 42 class TestLLInterpreted(TestBasic): POLICY = AnnotatorPolicy() Modified: pypy/dist/pypy/rpython/annlowlevel.py ============================================================================== --- pypy/dist/pypy/rpython/annlowlevel.py (original) +++ pypy/dist/pypy/rpython/annlowlevel.py Sat Nov 11 22:52:45 2006 @@ -331,7 +331,9 @@ def llhelper(F, f): - raise NotImplementedError("llhelper") + # implementation for the purpose of direct running only + # XXX need more cleverness to support translation of prebuilt llhelper ptr + return lltype.functionptr(F.TO, f.func_name, _callable=f) class LLHelperEntry(extregistry.ExtRegistryEntry): _about_ = llhelper From arigo at codespeak.net Sat Nov 11 23:10:36 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 11 Nov 2006 23:10:36 +0100 (CET) Subject: [pypy-svn] r34514 - in pypy/dist/pypy/rlib: . test Message-ID: <20061111221036.7A79510131@code0.codespeak.net> Author: arigo Date: Sat Nov 11 23:10:35 2006 New Revision: 34514 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py Log: Yay! Calls to external C functions. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sat Nov 11 23:10:35 2006 @@ -426,16 +426,35 @@ LLTYPE = FUNCTYPE can_allocate = False + def fromllptr(p): + addr = llmemory.cast_ptr_to_adr(p) + memblock = EMPTY_RAW_MEM_BLOCK + return RCTypesFunc(addr, memblock) + fromllptr = staticmethod(fromllptr) + def fromrpython(func): """Return an RCTypes function that references the given RPython function.""" p = annlowlevel.llhelper(PTRTYPE, func) - addr = llmemory.cast_ptr_to_adr(p) - memblock = EMPTY_RAW_MEM_BLOCK - return RCTypesFunc(addr, memblock) + return RCTypesFunc.fromllptr(p) fromrpython._annspecialcase_ = 'specialize:arg(0)' fromrpython = staticmethod(fromrpython) + def fromlib(rlib, c_funcname, llinterp_friendly_version=None): + flags = {'external': 'C'} + if rlib.pythonapi: + pass # no 'includes': hack to trigger + # in GenC a PyErr_Occurred() check + else: + flags['includes'] = rlib.c_includes + flags['libraries'] = rlib.c_libs + if llinterp_friendly_version: + flags['_callable'] = llinterp_friendly_version + p = lltype.functionptr(FUNCTYPE, c_funcname, **flags) + return RCTypesFunc.fromllptr(p) + fromlib._annspecialcase_ = 'specialize:memo' + fromlib = staticmethod(fromlib) + def call(self, *args): assert len(args) == len(ARGS) p = llmemory.cast_adr_to_ptr(self.addr, PTRTYPE) @@ -445,13 +464,22 @@ return RCTypesFunc RFuncType._annspecialcase_ = 'specialize:memo' -##class RLibrary(object): -## def __init__(self, c_libname=None, c_includes=None): -## self.c_libname = c_libname -## self.c_includes = c_includes - -## def link(self, cls, c_name): -## assert issubclass(cls, RCTypeObject) -## ... -## link._annspecialcase_ = 'specialize:arg(1)' +class RLibrary(object): + """A C library. Use to create references to external functions. + """ + # XXX for now, lltype only supports functions imported from external + # libraries, not variables + + pythonapi = False + + def __init__(self, c_libs=(), c_includes=()): + if isinstance(c_libs, str): c_libs = (c_libs,) + if isinstance(c_includes, str): c_includes = (c_includes,) + self.c_libs = c_libs + self.c_includes = c_includes + + def _freeze_(self): + return True + +LIBC = RLibrary() Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sat Nov 11 23:10:35 2006 @@ -1,5 +1,6 @@ from pypy.rlib.rctypesobject import * from pypy.rpython.test.test_llinterp import interpret +from pypy.translator.c.test.test_genc import compile from pypy.annotation.policy import AnnotatorPolicy @@ -163,9 +164,27 @@ res = self.do(func) assert res == 42 + def test_labs(self): + def ll_labs(n): + return abs(n) + labs = RFuncType((rc_int,), rc_int).fromlib(LIBC, 'labs', ll_labs) + def func(): + return labs.call(-7) + res = self.do(func) + assert res == 7 + + +POLICY = AnnotatorPolicy() +POLICY.allow_someobjects = False + class TestLLInterpreted(TestBasic): - POLICY = AnnotatorPolicy() - POLICY.allow_someobjects = False def do(self, func): - return interpret(func, [], policy=self.POLICY) + return interpret(func, [], policy=POLICY) + + +class TestCompiled(TestBasic): + + def do(self, func): + fn = compile(func, [], annotatorpolicy=POLICY) + return fn() From cfbolz at codespeak.net Sat Nov 11 23:15:46 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 11 Nov 2006 23:15:46 +0100 (CET) Subject: [pypy-svn] r34515 - in pypy/dist/pypy/objspace/std: benchmark test Message-ID: <20061111221546.D986A10134@code0.codespeak.net> Author: cfbolz Date: Sat Nov 11 23:15:44 2006 New Revision: 34515 Modified: pypy/dist/pypy/objspace/std/benchmark/bench_dict.py pypy/dist/pypy/objspace/std/test/test_rangeobject.py pypy/dist/pypy/objspace/std/test/test_strjoinobject.py pypy/dist/pypy/objspace/std/test/test_strsliceobject.py Log: pypy_repr moved to pypymagic Modified: pypy/dist/pypy/objspace/std/benchmark/bench_dict.py ============================================================================== --- pypy/dist/pypy/objspace/std/benchmark/bench_dict.py (original) +++ pypy/dist/pypy/objspace/std/benchmark/bench_dict.py Sat Nov 11 23:15:44 2006 @@ -47,6 +47,6 @@ if __name__ == '__main__': test_d = bench_simple_dict() - import sys - print sys.pypy_repr(test_d) - print sys.pypy_repr(test_d.iterkeys()) + import pypymagic + print pypymagic.pypy_repr(test_d) + print pypymagic.pypy_repr(test_d.iterkeys()) Modified: pypy/dist/pypy/objspace/std/test/test_rangeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_rangeobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_rangeobject.py Sat Nov 11 23:15:44 2006 @@ -7,10 +7,10 @@ def setup_class(cls): cls.space = gettestobjspace(**{"objspace.std.withrangelist": True}) cls.w_not_forced = cls.space.appexec([], """(): - import sys + import pypymagic def f(r): return (isinstance(r, list) and - "W_ListObject" not in sys.pypy_repr(r)) + "W_ListObject" not in pypymagic.pypy_repr(r)) return f """) Modified: pypy/dist/pypy/objspace/std/test/test_strjoinobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_strjoinobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_strjoinobject.py Sat Nov 11 23:15:44 2006 @@ -9,13 +9,13 @@ cls.space = gettestobjspace(**{"objspace.std.withstrjoin": True}) def test_basic(self): - import sys + import pypymagic s = "Hello, " + "World!" assert type(s) is str - assert 'W_StringJoinObject' in sys.pypy_repr(s) + assert 'W_StringJoinObject' in pypymagic.pypy_repr(s) def test_function_with_strjoin(self): - py.test.skip("Failing") + skip("Failing") def f(x, y): if x[-1] != "/": x += "/" @@ -48,7 +48,6 @@ assert hash(s) & 0x7fffffff == 0x7e0bce58 def test_len(self): - import sys s = "a" + "b" r = "c" + "d" t = s + r Modified: pypy/dist/pypy/objspace/std/test/test_strsliceobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_strsliceobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_strsliceobject.py Sat Nov 11 23:15:44 2006 @@ -9,22 +9,22 @@ cls.space = gettestobjspace(**{"objspace.std.withstrslice": True}) def test_basic(self): - import sys + import pypymagic def slice(s): return (s*3)[len(s):-len(s)] s = slice('0123456789' * 20) assert len(s) == 200 assert s[5] == '5' assert s[-2] == '8' assert s[3:7] == '3456' - assert 'W_StringSliceObject' in sys.pypy_repr(s) + assert 'W_StringSliceObject' in pypymagic.pypy_repr(s) # when the slice is too short, don't use the slice string object - assert 'W_StringObject' in sys.pypy_repr("abcdefgh"[3:7]) + assert 'W_StringObject' in pypymagic.pypy_repr("abcdefgh"[3:7]) def test_find(self): - import sys + import pypymagic def slice(s): return (s*3)[len(s):-len(s)] s = slice('abcdefghiabc' + "X" * 100) - assert 'W_StringSliceObject' in sys.pypy_repr(s) + assert 'W_StringSliceObject' in pypymagic.pypy_repr(s) assert slice('abcdefghiabc' + 'X' * 100) == 'abcdefghiabc' + 'X' * 100 res = s.find('abc') assert res == 0 @@ -32,11 +32,11 @@ assert s.find('def', 4) == -1 def test_index(self): - import sys + import pypymagic, sys m = sys.maxint def slice(s): return (s*3)[len(s):-len(s)] s = slice('abcdefghiabc' * 20) - assert 'W_StringSliceObject' in sys.pypy_repr(s) + assert 'W_StringSliceObject' in pypymagic.pypy_repr(s) assert s.index('') == 0 assert s.index('def') == 3 assert s.index('abc') == 0 @@ -50,21 +50,21 @@ raises(TypeError, slice('abcdefghijklmn' * 20).index, 'abc', -10.0, 30) def test_rfind(self): - import sys + import pypymagic def slice(s): return (s*3)[len(s):-len(s)] s = slice('abcdefghiabc' + "X" * 100) - assert 'W_StringSliceObject' in sys.pypy_repr(s) + assert 'W_StringSliceObject' in pypymagic.pypy_repr(s) assert s.rfind('abc') == 9 assert s.rfind('') == 112 assert s.rfind('abcd') == 0 assert s.rfind('abcz') == -1 def test_rindex(self): - import sys + import pypymagic from sys import maxint def slice(s): return (s*3)[len(s):-len(s)] s = slice("X" * 100 + 'abcdefghiabc') - assert 'W_StringSliceObject' in sys.pypy_repr(s) + assert 'W_StringSliceObject' in pypymagic.pypy_repr(s) assert s.rindex('') == 112 assert s.rindex('def') == 103 assert s.rindex('abc') == 109 @@ -81,10 +81,10 @@ 'abc', -10.0, 30) def test_contains(self): - import sys + import pypymagic def slice(s): return (s*3)[len(s):-len(s)] s = slice("abc" + "X" * 100) - assert 'W_StringSliceObject' in sys.pypy_repr(s) + assert 'W_StringSliceObject' in pypymagic.pypy_repr(s) assert '' in s assert 'a' in s assert 'ab' in s @@ -92,11 +92,11 @@ raises(TypeError, slice('a' * 100).__contains__, 1) def test_hash(self): - import sys + import pypymagic # check that we have the same hash as CPython for at least 31 bits # (but don't go checking CPython's special case -1) # disabled: assert hash('') == 0 --- different special case def slice(s): return (s*3)[len(s):-len(s)] s = slice('a' * 101) - assert 'W_StringSliceObject' in sys.pypy_repr(s) + assert 'W_StringSliceObject' in pypymagic.pypy_repr(s) assert hash(s) & 0x7fffffff == 0x7e0bce58 From cfbolz at codespeak.net Sun Nov 12 00:35:23 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 00:35:23 +0100 (CET) Subject: [pypy-svn] r34520 - pypy/dist/pypy/doc Message-ID: <20061111233523.64B7710134@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 00:35:21 2006 New Revision: 34520 Modified: pypy/dist/pypy/doc/coding-guide.txt Log: add a hint where to find the rarithmetic functions Modified: pypy/dist/pypy/doc/coding-guide.txt ============================================================================== --- pypy/dist/pypy/doc/coding-guide.txt (original) +++ pypy/dist/pypy/doc/coding-guide.txt Sun Nov 12 00:35:21 2006 @@ -338,7 +338,9 @@ We use normal integers for signed arithmetic. It means that before translation we get longs in case of overflow, and after translation we get a silent wrap-around. Whenever we need more control, we use the following -helpers: +helpers (which live the `pypy/rlib/rarithmetic.py`_): + +.. _`pypy/rlib/rarithmetic.py`: ../../pypy/rlib/rarithmetic.py **ovfcheck()** From cfbolz at codespeak.net Sun Nov 12 00:46:16 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 00:46:16 +0100 (CET) Subject: [pypy-svn] r34521 - pypy/dist/pypy/doc Message-ID: <20061111234616.22EA21013F@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 00:46:14 2006 New Revision: 34521 Added: pypy/dist/pypy/doc/rlib.txt Modified: pypy/dist/pypy/doc/index.txt Log: some documentations of the modules in rlib Modified: pypy/dist/pypy/doc/index.txt ============================================================================== --- pypy/dist/pypy/doc/index.txt (original) +++ pypy/dist/pypy/doc/index.txt Sun Nov 12 00:46:14 2006 @@ -14,7 +14,8 @@ `getting started`_ provides hands-on instructions including a two-liner to run PyPy on your system. -`coding guide`_ helps you to write code for PyPy. +`coding guide`_ helps you to write code for PyPy (especially also describes +coding in RPython a bit). `development methodology`_ describe our sprint-driven approach. @@ -76,6 +77,9 @@ to write modules in PyPy's style and compile them into regular CPython extension modules. +`rlib`_ describes some modules that can be used when implementing programs in +RPython. + `JavaScript backend`_ describes how to use JavaScript backend to create AJAX-based web pages. @@ -147,6 +151,7 @@ .. _`Nightly builds and benchmarks`: http://snake.cs.uni-duesseldorf.de/pypytest/benchmark.html .. _`build pypy-c`: http://snake.cs.uni-duesseldorf.de/pypy-c-tests/ .. _`directory reference`: +.. _`rlib`: rlib.html PyPy directory cross-reference ====================================================== Added: pypy/dist/pypy/doc/rlib.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/rlib.txt Sun Nov 12 00:46:14 2006 @@ -0,0 +1,229 @@ +================================================= +Generally Useful RPython Modules +================================================= + +.. _Python: http://www.python.org/dev/doc/maint24/ref/ref.html + +.. contents:: + + +This page lists some of the modules in `pypy/rlib`_ together with some hints +for what they can be used. The modules there are supposed to make up some sort +of library for RPython programs (since most of the standard library modules are +not RPython). Most of these modules are somewhat rough still and are likely to +be changed at one point. Usually it is useful to look at the tests in +`pypy/rlib/test`_ to get an impression how the modules should be used. + +.. _`pypy/rlib`: ../../pypy/rlib +.. _`pypy/rlib/test`: ../../pypy/rlib/test + +``listsort`` +============ + +The listsort_ module contains an implementation of the timsort sorting algorithm +(the sort method of lists is not RPython). To use it, subclass from the +``listsort.TimSort`` class and override the ``lt`` method to change the +comparison behaviour. The constructor of ``TimSort`` takes a list as an +argument, which will be sorted in place when the ``sort`` method of the +``TimSort`` instance is called. **Warning:** currently only one type of list can +be sorted using the ``listsort`` module in one program, otherwise the annotator +will be confused. + +.. _listsort: ../../pypy/rlib/listsort.py + +``nonconst`` +============ + +The nonconst_ module is useful mostly for tests. The `flow object space`_ and +the `annotator`_ do quite some constant folding, which is sometimes not desired +in a test. To prevent constant folding on a certain value, use the ``NonConst`` +class. The constructor of ``NonConst`` takes an arbitrary value. The instance of +``NonConst`` will behave during annotation like that value, but no constant +folding will happen. + +.. _nonconst: ../../pypy/rlib/nonconst.py +.. _`flow object space`: objspace.html#the-flow-object-space +.. _`annotator`: translation.html#the-annotation-pass + + +``objectmodel`` +=============== + +The objectmodel_ module is a mixed bag of various functionality. Some of the +more useful ones are: + +``ComputedIntSymbolic``: + Instances of ``ComputedIntSymbolic`` are treated like integers of unknown + value by the annotator. Their value is determined by a non-argument function + (which needs to be passed into the constructor of the class). When the + backend emits code, the function is called to determine the value. + +``CDefinedIntSymbolic``: + Instances of ``ComputedIntSymbolic`` are also treated like integers of + unknown value by the annotator. When C code is emitted they will be + represented by the attribute ``expr`` of the symbolic (which is also the + first argument of the constructor). + +``r_dict``: + An RPython dict-like object. The constructor of r_dict takes two functions: + ``key_eq`` and ``key_hash`` which are used for comparing and hashing the + entries in the dictionary. + +``instantiate(cls)``: + Instantiate class ``cls`` without calling ``__init__``. + +``we_are_translated()``: + This function returns ``False`` when run on top of CPython, but the + annotator thinks its return value is ``True``. Therefore it can be used to + do different things on top of CPython than after translation. This should be + used extremely sparingly (mostly for optimizations or debug code). + +``cast_object_to_weakaddress(obj)``: + Returns a sort of "weak reference" to obj, just without any convenience. The + weak address that it returns is not invalidated if the object dies, so you + need to take care yourself to know when the object dies. Use with extreme + care. + +``cast_weakadress_to_object(obj)``: + Inverse of the previous function. If the object died then a segfault will + ensue. + +``UnboxedValue``: + This is a class which should be used as a base class for a class which + carries exactly one integer field. The class should have ``__slots__`` + with exactly one entry defined. After translation, instances of this class + won't be allocated but represented by *tagged pointers**, that is pointers + who have the lowest bit set. + +.. _objectmodel: ../../pypy/rlib/objectmodel.py + + +``rarithmetic`` +=============== + +The rarithmetic_ module contains functionality to handle the small differences +in the behaviour of arithmetic code in regular Python and RPython code. Most of +them are already described in the `coding guide`_ + +.. _rarithmetic: ../../pypy/rlib/rarithmetic.py +.. _`coding guide`: coding-guide.html + + +``rlong`` +========= + +The rlong_ module contains a full RPython implementation of the Python ``long`` +type (which itself is not supported in RPython). The ``rlong`` class contains +that implementation. To construct ``rlong`` instances use the static methods +``fromint``, ``frombool``, ``fromfloat`` and ``fromdecimalstr``. To convert back +to other types use the methods ``toint``, ``tobool``, ``touint`` and +``tofloat``. Since RPython does not support operator overloading, all the +special methods of ``rlong`` that would normally start and end with "__" have +these underscores left out for better readability (so ``a.add(b)`` can be used +to add two rlongs). + +.. _rlong: ../../pypy/rlib/rlong.py + + +``rrandom`` +=========== + +The rrandom_ module contains an implementation of the mersenne twister random +number generator. It contains one class ``Random`` which most importantly has a +``random`` method which returns a pseudo-random floating point number between +0.0 and 1.0. + +.. _rrandom: ../../pypy/rlib/rrandom.py + +``rsocket`` +=========== + +The rsocket_ module contains an RPython implementation of the functionality of +the socket standard library with a slightly different interface. + +.. _rsocket: ../../pypy/rlib/rsocket.py + + +``rstack`` +========== + +The rstack_ module allows an RPython progam to control its own execution stack. +This is mostly only useful if the program is translated using stackless. An old +description of the exposed functions is below. + +We introduce an RPython type ``frame_stack_top`` and a built-in function +``yield_current_frame_to_caller()`` that work as follows (see example below): + +* The built-in function ``yield_current_frame_to_caller()`` causes the current + function's state to be captured in a new ``frame_stack_top`` object that is + returned to the parent. Only one frame, the current one, is captured this + way. The current frame is suspended and the caller continues to run. Note + that the caller is only resumed once: when + ``yield_current_frame_to_caller()`` is called. See below. + +* A ``frame_stack_top`` object can be jumped to by calling its ``switch()`` + method with no argument. + +* ``yield_current_frame_to_caller()`` and ``switch()`` themselves return a new + ``frame_stack_top`` object: the freshly captured state of the caller of the + source ``switch()`` that was just executed, or None in the case described + below. + +* the function that called ``yield_current_frame_to_caller()`` also has a + normal return statement, like all functions. This statement must return + another ``frame_stack_top`` object. The latter is *not* returned to the + original caller; there is no way to return several times to the caller. + Instead, it designates the place to which the execution must jump, as if by + a ``switch()``. The place to which we jump this way will see a None as the + source frame stack top. + +* every frame stack top must be resumed once and only once. Not resuming + it at all causes a leak. Resuming it several times causes a crash. + +* a function that called ``yield_current_frame_to_caller()`` should not raise. + It would have no implicit parent frame to propagate the exception to. That + would be a crashingly bad idea. + +The following example would print the numbers from 1 to 7 in order:: + + def g(): + print 2 + frametop_before_5 = yield_current_frame_to_caller() + print 4 + frametop_before_7 = frametop_before_5.switch() + print 6 + return frametop_before_7 + + def f(): + print 1 + frametop_before_4 = g() + print 3 + frametop_before_6 = frametop_before_4.switch() + print 5 + frametop_after_return = frametop_before_6.switch() + print 7 + assert frametop_after_return is None + + f() + +.. _rstack: ../../pypy/rlib/rstack.py + + +``streamio`` +============ + +The streamio_ contains an RPython stream I/O implementation (which was started +by Guido van Rossum as `sio.py`_ in the CPython sandbox as a prototype for the +upcoming new file implementation in Python 300). + +.. _streamio: ../../pypy/rlib/streamio.py +.. _`sio.py`: http://svn.python.org/view/sandbox/trunk/sio/sio.py + +``unroll`` +========== + +The unroll_ module most importantly contains the function ``unrolling_iterable`` +wich wraps an iterator. Looping over the iterator in RPython code will not +produce a loop in the resulting flow graph but will unroll the loop instead. + +.. _unroll: ../../pypy/rlib/unroll.py From cfbolz at codespeak.net Sun Nov 12 00:53:09 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 00:53:09 +0100 (CET) Subject: [pypy-svn] r34522 - pypy/dist/pypy/objspace/std/test Message-ID: <20061111235309.F3DB410144@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 00:53:08 2006 New Revision: 34522 Modified: pypy/dist/pypy/objspace/std/test/test_strjoinobject.py Log: minimize test case Modified: pypy/dist/pypy/objspace/std/test/test_strjoinobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_strjoinobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_strjoinobject.py Sun Nov 12 00:53:08 2006 @@ -14,21 +14,12 @@ assert type(s) is str assert 'W_StringJoinObject' in pypymagic.pypy_repr(s) - def test_function_with_strjoin(self): - skip("Failing") - def f(x, y): - if x[-1] != "/": - x += "/" - if y.startswith(x): - return y[len(x):] - - x = "a" - y = "a/b/c/d" - x += "" - y += "" - - assert f(x, y) - assert f(x, y) + def test_add_twice(self): + skip("minimal failing test") + x = "a" + "" + y = x + "b" + c = x + "b" + assert c == "ab" def test_add(self): import pypymagic From cfbolz at codespeak.net Sun Nov 12 01:17:00 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 01:17:00 +0100 (CET) Subject: [pypy-svn] r34523 - pypy/dist/pypy/objspace/std Message-ID: <20061112001700.5E2D210148@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 01:16:58 2006 New Revision: 34523 Modified: pypy/dist/pypy/objspace/std/strjoinobject.py Log: fix bug in strjoin object: we cannot append more strings to the stringjoin if another longer string is already sharing our joined_str list. Modified: pypy/dist/pypy/objspace/std/strjoinobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/strjoinobject.py (original) +++ pypy/dist/pypy/objspace/std/strjoinobject.py Sun Nov 12 01:16:58 2006 @@ -52,6 +52,8 @@ return W_StringJoinObject(w_self.joined_strs) def add__StringJoin_String(space, w_self, w_other): + if len(w_self.joined_strs) > w_self.until: + w_self.force() other = space.str_w(w_other) w_self.joined_strs.append(other) return W_StringJoinObject(w_self.joined_strs) From cfbolz at codespeak.net Sun Nov 12 01:19:22 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 01:19:22 +0100 (CET) Subject: [pypy-svn] r34524 - in pypy/dist/pypy/rlib/parsing: . test Message-ID: <20061112001922.59EBE1014A@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 01:19:14 2006 New Revision: 34524 Added: pypy/dist/pypy/rlib/parsing/ - copied from r34364, user/cfbolz/algorithm/automaton/ pypy/dist/pypy/rlib/parsing/deterministic.py - copied unchanged from r34478, user/cfbolz/algorithm/automaton/deterministic.py pypy/dist/pypy/rlib/parsing/ebnfparse.py (props changed) - copied unchanged from r34498, user/cfbolz/algorithm/automaton/ebnfparse.py pypy/dist/pypy/rlib/parsing/lexer.py (props changed) - copied unchanged from r34476, user/cfbolz/algorithm/automaton/lexer.py pypy/dist/pypy/rlib/parsing/parsing.py (props changed) - copied unchanged from r34481, user/cfbolz/algorithm/automaton/parsing.py pypy/dist/pypy/rlib/parsing/regex.py - copied unchanged from r34420, user/cfbolz/algorithm/automaton/regex.py pypy/dist/pypy/rlib/parsing/regexparse.py (props changed) - copied unchanged from r34438, user/cfbolz/algorithm/automaton/regexparse.py pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py (props changed) - copied unchanged from r34498, user/cfbolz/algorithm/automaton/test/test_ebnfparse.py pypy/dist/pypy/rlib/parsing/test/test_lexer.py (props changed) - copied unchanged from r34446, user/cfbolz/algorithm/automaton/test/test_lexer.py pypy/dist/pypy/rlib/parsing/test/test_parse.py (props changed) - copied unchanged from r34446, user/cfbolz/algorithm/automaton/test/test_parse.py pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py (props changed) - copied unchanged from r34516, user/cfbolz/algorithm/automaton/test/test_parseerrors.py pypy/dist/pypy/rlib/parsing/test/test_regex.py - copied unchanged from r34421, user/cfbolz/algorithm/automaton/test/test_regex.py pypy/dist/pypy/rlib/parsing/test/test_regexparse.py (props changed) - copied unchanged from r34516, user/cfbolz/algorithm/automaton/test/test_regexparse.py pypy/dist/pypy/rlib/parsing/test/test_translate.py (props changed) - copied unchanged from r34516, user/cfbolz/algorithm/automaton/test/test_translate.py pypy/dist/pypy/rlib/parsing/tree.py (props changed) - copied unchanged from r34498, user/cfbolz/algorithm/automaton/tree.py Log: move my parsing stuff here (to prepare the integration of the prolog interpreter into the pypy repository). From cfbolz at codespeak.net Sun Nov 12 01:26:06 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 01:26:06 +0100 (CET) Subject: [pypy-svn] r34525 - in pypy/dist/pypy/rlib/parsing: . test Message-ID: <20061112002606.B3B2C10145@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 01:26:02 2006 New Revision: 34525 Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py pypy/dist/pypy/rlib/parsing/lexer.py pypy/dist/pypy/rlib/parsing/parsing.py pypy/dist/pypy/rlib/parsing/regex.py pypy/dist/pypy/rlib/parsing/regexparse.py pypy/dist/pypy/rlib/parsing/test/test_deterministic.py pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py pypy/dist/pypy/rlib/parsing/test/test_lexer.py pypy/dist/pypy/rlib/parsing/test/test_parse.py pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py pypy/dist/pypy/rlib/parsing/test/test_regex.py pypy/dist/pypy/rlib/parsing/test/test_regexparse.py pypy/dist/pypy/rlib/parsing/test/test_translate.py Log: fix all imports Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/ebnfparse.py Sun Nov 12 01:26:02 2006 @@ -1,12 +1,12 @@ import py -from algorithm.automaton.parsing import PackratParser, Rule -from algorithm.automaton.tree import Nonterminal, Symbol, RPythonVisitor -from algorithm.automaton.regexparse import parse_regex +from pypy.rlib.parsing.parsing import PackratParser, Rule +from pypy.rlib.parsing.tree import Nonterminal, Symbol, RPythonVisitor +from pypy.rlib.parsing.regexparse import parse_regex import string -from algorithm.automaton.regex import * -from algorithm.automaton.deterministic import DFA +from pypy.rlib.parsing.regex import * +from pypy.rlib.parsing.deterministic import DFA from algorithm.tool.makeondemand import make_on_demand -from algorithm.automaton.lexer import Lexer, DummyLexer +from pypy.rlib.parsing.lexer import Lexer, DummyLexer def make_ebnf_parser(): NONTERMINALNAME = parse_regex("([a-z]|_)[a-z0-9_]*") @@ -54,7 +54,7 @@ return zip(visitor.names, visitor.regexs), visitor.rules, ToAstVisitor def make_parse_function(regexs, rules, eof=False): - from algorithm.automaton.lexer import Lexer + from pypy.rlib.parsing.lexer import Lexer names, regexs = zip(*regexs) if "IGNORE" in names: ignore = ["IGNORE"] Modified: pypy/dist/pypy/rlib/parsing/lexer.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/lexer.py (original) +++ pypy/dist/pypy/rlib/parsing/lexer.py Sun Nov 12 01:26:02 2006 @@ -1,6 +1,6 @@ import py from pypy.rlib.objectmodel import we_are_translated -from algorithm.automaton import deterministic, regex +from pypy.rlib.parsing import deterministic, regex class Lexer(object): def __init__(self, token_regexs, names, ignore=None): Modified: pypy/dist/pypy/rlib/parsing/parsing.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/parsing.py (original) +++ pypy/dist/pypy/rlib/parsing/parsing.py Sun Nov 12 01:26:02 2006 @@ -1,5 +1,5 @@ import py -from algorithm.automaton.tree import Node, Symbol, Nonterminal, Epsilon +from pypy.rlib.parsing.tree import Node, Symbol, Nonterminal, Epsilon class Rule(object): def __init__(self, nonterminal, expansions): Modified: pypy/dist/pypy/rlib/parsing/regex.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/regex.py (original) +++ pypy/dist/pypy/rlib/parsing/regex.py Sun Nov 12 01:26:02 2006 @@ -1,4 +1,4 @@ -from algorithm.automaton.deterministic import NFA +from pypy.rlib.parsing.deterministic import NFA class RegularExpression(object): def __init__(self): Modified: pypy/dist/pypy/rlib/parsing/regexparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/regexparse.py (original) +++ pypy/dist/pypy/rlib/parsing/regexparse.py Sun Nov 12 01:26:02 2006 @@ -1,8 +1,8 @@ import py -from algorithm.automaton.parsing import PackratParser, Rule -from algorithm.automaton.regex import StringExpression, RangeExpression -from algorithm.automaton.lexer import Lexer, DummyLexer -from algorithm.automaton.deterministic import compress_char_set, DFA +from pypy.rlib.parsing.parsing import PackratParser, Rule +from pypy.rlib.parsing.regex import StringExpression, RangeExpression +from pypy.rlib.parsing.lexer import Lexer, DummyLexer +from pypy.rlib.parsing.deterministic import compress_char_set, DFA import string ESCAPES = { @@ -17,7 +17,7 @@ } def make_regex_parser(): - from algorithm.automaton.ebnfparse import parse_ebnf, make_parse_function + from pypy.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function # construct regular expressions by hand, to not go completely insane # because of quoting special_chars = "*+()[]{}|.-?,^" Modified: pypy/dist/pypy/rlib/parsing/test/test_deterministic.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_deterministic.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_deterministic.py Sun Nov 12 01:26:02 2006 @@ -1,4 +1,4 @@ -from algorithm.automaton.deterministic import * +from pypy.rlib.parsing.deterministic import * def test_DFA_simple(): a = DFA() Modified: pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py Sun Nov 12 01:26:02 2006 @@ -1,8 +1,8 @@ import py -from algorithm.automaton.tree import Nonterminal, Symbol, RPythonVisitor -from algorithm.automaton.parsing import PackratParser, Symbol, ParseError, Rule -from algorithm.automaton.ebnfparse import parse_ebnf, make_parse_function -from algorithm.automaton.test.test_parse import EvaluateVisitor +from pypy.rlib.parsing.tree import Nonterminal, Symbol, RPythonVisitor +from pypy.rlib.parsing.parsing import PackratParser, Symbol, ParseError, Rule +from pypy.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function +from pypy.rlib.parsing.test.test_parse import EvaluateVisitor def test_simple(): Modified: pypy/dist/pypy/rlib/parsing/test/test_lexer.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_lexer.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_lexer.py Sun Nov 12 01:26:02 2006 @@ -1,7 +1,7 @@ import py -from algorithm.automaton.lexer import * -from algorithm.automaton.regex import * -from algorithm.automaton import deterministic +from pypy.rlib.parsing.lexer import * +from pypy.rlib.parsing.regex import * +from pypy.rlib.parsing import deterministic class TestDirectLexer(object): Modified: pypy/dist/pypy/rlib/parsing/test/test_parse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_parse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_parse.py Sun Nov 12 01:26:02 2006 @@ -1,4 +1,4 @@ -from algorithm.automaton.parsing import * +from pypy.rlib.parsing.parsing import * class EvaluateVisitor(object): def visit_additive(self, node): Modified: pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py Sun Nov 12 01:26:02 2006 @@ -1,9 +1,9 @@ import py -from algorithm.automaton.parsing import PackratParser, Rule, Nonterminal -from algorithm.automaton.parsing import Symbol, ParseError -from algorithm.automaton.ebnfparse import parse_ebnf, make_parse_function -from algorithm.automaton.deterministic import LexerError -from algorithm.automaton.tree import RPythonVisitor +from pypy.rlib.parsing.parsing import PackratParser, Rule, Nonterminal +from pypy.rlib.parsing.parsing import Symbol, ParseError +from pypy.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function +from pypy.rlib.parsing.deterministic import LexerError +from pypy.rlib.parsing.tree import RPythonVisitor class TestDictError(object): dictebnf = """ Modified: pypy/dist/pypy/rlib/parsing/test/test_regex.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_regex.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_regex.py Sun Nov 12 01:26:02 2006 @@ -1,4 +1,4 @@ -from algorithm.automaton.regex import * +from pypy.rlib.parsing.regex import * def compile_rex(rex, view=False): try: Modified: pypy/dist/pypy/rlib/parsing/test/test_regexparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_regexparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_regexparse.py Sun Nov 12 01:26:02 2006 @@ -1,5 +1,5 @@ def make_runner(regex, view=False): - from algorithm.automaton.regexparse import parse_regex + from pypy.rlib.parsing.regexparse import parse_regex r = parse_regex(regex) dfa = r.make_automaton().make_deterministic() if view: Modified: pypy/dist/pypy/rlib/parsing/test/test_translate.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_translate.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_translate.py Sun Nov 12 01:26:02 2006 @@ -1,9 +1,9 @@ import py from pypy.translator.interactive import Translation -from algorithm.automaton.lexer import * -from algorithm.automaton.regex import * -from algorithm.automaton.parsing import * -from algorithm.automaton import deterministic +from pypy.rlib.parsing.lexer import * +from pypy.rlib.parsing.regex import * +from pypy.rlib.parsing.parsing import * +from pypy.rlib.parsing import deterministic class TestTranslateLexer(object): @@ -93,12 +93,12 @@ assert res1 == res2 def make_transformer(transformer): - from algorithm.automaton.tree import RPythonVisitor + from pypy.rlib.parsing.tree import RPythonVisitor exec py.code.Source(transformer).compile() return ToAST def test_translate_ast_visitor(): - from algorithm.automaton.ebnfparse import parse_ebnf, make_parse_function + from pypy.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function regexs, rules, transformer = parse_ebnf(""" DECIMAL: "0|[1-9][0-9]*"; IGNORE: " "; From arigo at codespeak.net Sun Nov 12 12:21:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 12 Nov 2006 12:21:29 +0100 (CET) Subject: [pypy-svn] r34526 - pypy/branch/another-keepalive-experiment Message-ID: <20061112112129.14FDB10153@code0.codespeak.net> Author: arigo Date: Sun Nov 12 12:21:28 2006 New Revision: 34526 Added: pypy/branch/another-keepalive-experiment/ - copied from r34525, pypy/dist/ Log: A branch for another small experiment with keepalives. From arigo at codespeak.net Sun Nov 12 12:27:06 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 12 Nov 2006 12:27:06 +0100 (CET) Subject: [pypy-svn] r34527 - in pypy/branch/another-keepalive-experiment/pypy: jit/timeshifter rpython translator/backendopt translator/backendopt/test Message-ID: <20061112112706.CB2B410158@code0.codespeak.net> Author: arigo Date: Sun Nov 12 12:27:05 2006 New Revision: 34527 Modified: pypy/branch/another-keepalive-experiment/pypy/jit/timeshifter/hrtyper.py pypy/branch/another-keepalive-experiment/pypy/rpython/rtyper.py pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/inline.py pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/support.py pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/test/test_escape.py pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/test/test_support.py Log: Idea: early on - in the RTyper - we insert keepalives at the end of each block for each gc var of the block. Then all backend opts like inlining don't have to worry about inserting new keepalives any more: they are already there. I think. In a sense this makes explicit the assumption that a gc var should stay alive for the duration of a whole source basic block. Modified: pypy/branch/another-keepalive-experiment/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/branch/another-keepalive-experiment/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/branch/another-keepalive-experiment/pypy/jit/timeshifter/hrtyper.py Sun Nov 12 12:27:05 2006 @@ -330,6 +330,9 @@ def make_new_lloplist(self, block): return HintLowLevelOpList(self) + def finish_block(self, block, newops): + pass + def getgreenrepr(self, lowleveltype): try: return self.green_reprs[lowleveltype] Modified: pypy/branch/another-keepalive-experiment/pypy/rpython/rtyper.py ============================================================================== --- pypy/branch/another-keepalive-experiment/pypy/rpython/rtyper.py (original) +++ pypy/branch/another-keepalive-experiment/pypy/rpython/rtyper.py Sun Nov 12 12:27:05 2006 @@ -334,6 +334,7 @@ self.gottypererror(e, block, hop.spaceop, newops) return # cannot continue this block: no op.result.concretetype + self.finish_block(block, newops) block.operations[:] = newops block.renamevariables(varmapping) @@ -399,6 +400,13 @@ link.last_exc_value = inputconst( self.exceptiondata.r_exception_value, a.value) + def finish_block(self, block, newops): + allvars = block.inputargs + [op.result for op in newops] + for v in allvars: + T = v.concretetype + if isinstance(T, Ptr) and T._needsgc(): + newops.genop('keepalive', [v]) + def insert_link_conversions(self, block, skip=0): # insert the needed conversions on the links can_insert_here = block.exitswitch is None and len(block.exits) == 1 Modified: pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/inline.py (original) +++ pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/inline.py Sun Nov 12 12:27:05 2006 @@ -12,7 +12,7 @@ from pypy.rpython import rmodel from pypy.tool.algo import sparsemat from pypy.translator.backendopt.support import log, split_block_with_keepalive -from pypy.translator.backendopt.support import generate_keepalive, find_backedges, find_loop_blocks +from pypy.translator.backendopt.support import find_backedges, find_loop_blocks from pypy.translator.backendopt.canraise import RaiseAnalyzer BASE_INLINE_THRESHOLD = 32.4 # just enough to inline add__Int_Int() @@ -315,7 +315,7 @@ for exceptionlink in afterblock.exits[1:]: if exc_match(vtable, exceptionlink.llexitcase): passon_vars = self.passon_vars(link.prevblock) - copiedblock.operations += generate_keepalive(passon_vars) + #copiedblock.operations += generate_keepalive(passon_vars) copiedlink.target = exceptionlink.target linkargs = self.find_args_in_exceptional_case( exceptionlink, link.prevblock, var_etype, var_evalue, afterblock, passon_vars) @@ -363,7 +363,7 @@ del blocks[-1].exits[0].llexitcase linkargs = copiedexceptblock.inputargs copiedexceptblock.closeblock(Link(linkargs, blocks[0])) - copiedexceptblock.operations += generate_keepalive(linkargs) + #copiedexceptblock.operations += generate_keepalive(linkargs) def do_inline(self, block, index_operation): Modified: pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/support.py ============================================================================== --- pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/support.py (original) +++ pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/support.py Sun Nov 12 12:27:05 2006 @@ -55,54 +55,54 @@ else: return False -def generate_keepalive(vars, annotator=None): - keepalive_ops = [] - for v in vars: - if isinstance(v, Constant): - continue - if v.concretetype._is_atomic(): - continue - v_keepalive = Variable() - v_keepalive.concretetype = lltype.Void - if annotator is not None: - annotator.setbinding(v_keepalive, s_ImpossibleValue) - keepalive_ops.append(SpaceOperation('keepalive', [v], v_keepalive)) - return keepalive_ops +##def generate_keepalive(vars, annotator=None): +## keepalive_ops = [] +## for v in vars: +## if isinstance(v, Constant): +## continue +## if v.concretetype._is_atomic(): +## continue +## v_keepalive = Variable() +## v_keepalive.concretetype = lltype.Void +## if annotator is not None: +## annotator.setbinding(v_keepalive, s_ImpossibleValue) +## keepalive_ops.append(SpaceOperation('keepalive', [v], v_keepalive)) +## return keepalive_ops def split_block_with_keepalive(block, index_operation, keep_alive_op_args=True, annotator=None): splitlink = split_block(annotator, block, index_operation) - afterblock = splitlink.target - conservative_keepalives = needs_conservative_livevar_calculation(block) - if conservative_keepalives: - keep_alive_vars = [var for var in block.getvariables() - if var_needsgc(var)] - # XXX you could maybe remove more, if the variables are kept - # alive by something else. but this is sometimes hard to know - for i, var in enumerate(keep_alive_vars): - try: - index = splitlink.args.index(var) - newvar = afterblock.inputargs[index] - except ValueError: - splitlink.args.append(var) - newvar = copyvar(annotator, var) - afterblock.inputargs.append(newvar) - keep_alive_vars[i] = newvar - elif keep_alive_op_args and afterblock.operations: - keep_alive_vars = [var for var in afterblock.operations[0].args - if isinstance(var, Variable) and var_needsgc(var)] - if len(afterblock.operations) > 1 or afterblock.exitswitch != c_last_exception: - afterblock.operations[1:1] = generate_keepalive(keep_alive_vars, - annotator=annotator) - keep_alive_vars = [] - else: - keep_alive_vars = [] - pos = len(afterblock.operations) - if afterblock.exitswitch == c_last_exception: - pos -= 1 # insert the keepalives just before the last operation - # in case of exception-catching - afterblock.operations[pos:pos] = generate_keepalive(keep_alive_vars) +## afterblock = splitlink.target +## conservative_keepalives = needs_conservative_livevar_calculation(block) +## if conservative_keepalives: +## keep_alive_vars = [var for var in block.getvariables() +## if var_needsgc(var)] +## # XXX you could maybe remove more, if the variables are kept +## # alive by something else. but this is sometimes hard to know +## for i, var in enumerate(keep_alive_vars): +## try: +## index = splitlink.args.index(var) +## newvar = afterblock.inputargs[index] +## except ValueError: +## splitlink.args.append(var) +## newvar = copyvar(annotator, var) +## afterblock.inputargs.append(newvar) +## keep_alive_vars[i] = newvar +## elif keep_alive_op_args and afterblock.operations: +## keep_alive_vars = [var for var in afterblock.operations[0].args +## if isinstance(var, Variable) and var_needsgc(var)] +## if len(afterblock.operations) > 1 or afterblock.exitswitch != c_last_exception: +## afterblock.operations[1:1] = generate_keepalive(keep_alive_vars, +## annotator=annotator) +## keep_alive_vars = [] +## else: +## keep_alive_vars = [] +## pos = len(afterblock.operations) +## if afterblock.exitswitch == c_last_exception: +## pos -= 1 # insert the keepalives just before the last operation +## # in case of exception-catching +## afterblock.operations[pos:pos] = generate_keepalive(keep_alive_vars) return splitlink def calculate_call_graph(translator): Modified: pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/test/test_escape.py ============================================================================== --- pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/test/test_escape.py (original) +++ pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/test/test_escape.py Sun Nov 12 12:27:05 2006 @@ -1,8 +1,10 @@ from pypy.translator.translator import TranslationContext, graphof from pypy.translator.backendopt.escape import AbstractDataFlowInterpreter, malloc_to_stack from pypy.translator.backendopt.support import find_backedges, find_loop_blocks +from pypy.translator.simplify import join_blocks from pypy.rpython.llinterp import LLInterpreter from pypy.rlib.objectmodel import instantiate +from pypy import conftest def build_adi(function, types): t = TranslationContext() @@ -23,6 +25,9 @@ res = interp.eval_graph(graph, args) assert res == expected_result malloc_to_stack(t) + join_blocks(graph) + if conftest.option.view: + t.view() if must_remove: for block in graph.iterblocks(): for op in block.operations: @@ -456,7 +461,11 @@ return result t = check_malloc_removal(f, [int], [3], 3, must_remove=False) graph = graphof(t, f) - assert graph.startblock.exits[0].target.exits[0].target.operations[0].opname == "malloc" + ops = graph.startblock.exits[0].target.exits[0].target.operations + n = 0 + while ops[n].opname == "keepalive": + n += 1 + assert ops[n].opname == "malloc" def test_dont_remove_del_objects(): class A(object): Modified: pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/test/test_support.py ============================================================================== --- pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/test/test_support.py (original) +++ pypy/branch/another-keepalive-experiment/pypy/translator/backendopt/test/test_support.py Sun Nov 12 12:27:05 2006 @@ -1,4 +1,5 @@ from pypy.translator.unsimplify import varoftype +from pypy.translator.simplify import join_blocks from pypy.translator.translator import TranslationContext, graphof from pypy.translator.backendopt.support import \ needs_conservative_livevar_calculation, split_block_with_keepalive, \ @@ -54,40 +55,40 @@ block.closeblock(model.Link([v_res], None)) assert not needs_conservative_livevar_calculation(block) -def test_sbwk_should_insert_keepalives(): - # this is testing something like: - # v0 <- op_producing_non_gc - # v1 <- op_using_v0 <- split here - llops = LowLevelOpList() - ptr_a = varoftype(lltype.Ptr(GcA)) - v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)], - resulttype=lltype.Ptr(NonGcB)) - llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res], - resulttype=lltype.Void) - block = model.Block([ptr_a]) - block.operations.extend(llops) - block.closeblock(model.Link([], None)) - link = split_block_with_keepalive(block, 1) - assert 'keepalive' in [op.opname for op in link.target.operations] - -def test_sbwk_should_insert_keepalives_2(): - # this is testing something like: - # v0 <- op_producing_non_gc - # v1 <- op_not_using_v0 <- split here - # v2 <- op_using_v0 - llops = LowLevelOpList() - ptr_a = varoftype(lltype.Ptr(GcA)) - v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)], - resulttype=lltype.Ptr(NonGcB)) - llops.genop("direct_call", [model.Constant(None, lltype.Void)], - resulttype=lltype.Void) - llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res], - resulttype=lltype.Void) - block = model.Block([ptr_a]) - block.operations.extend(llops) - block.closeblock(model.Link([], None)) - link = split_block_with_keepalive(block, 1) - assert 'keepalive' in [op.opname for op in link.target.operations] +##def test_sbwk_should_insert_keepalives(): +## # this is testing something like: +## # v0 <- op_producing_non_gc +## # v1 <- op_using_v0 <- split here +## llops = LowLevelOpList() +## ptr_a = varoftype(lltype.Ptr(GcA)) +## v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)], +## resulttype=lltype.Ptr(NonGcB)) +## llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res], +## resulttype=lltype.Void) +## block = model.Block([ptr_a]) +## block.operations.extend(llops) +## block.closeblock(model.Link([], None)) +## link = split_block_with_keepalive(block, 1) +## assert 'keepalive' in [op.opname for op in link.target.operations] + +##def test_sbwk_should_insert_keepalives_2(): +## # this is testing something like: +## # v0 <- op_producing_non_gc +## # v1 <- op_not_using_v0 <- split here +## # v2 <- op_using_v0 +## llops = LowLevelOpList() +## ptr_a = varoftype(lltype.Ptr(GcA)) +## v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)], +## resulttype=lltype.Ptr(NonGcB)) +## llops.genop("direct_call", [model.Constant(None, lltype.Void)], +## resulttype=lltype.Void) +## llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res], +## resulttype=lltype.Void) +## block = model.Block([ptr_a]) +## block.operations.extend(llops) +## block.closeblock(model.Link([], None)) +## link = split_block_with_keepalive(block, 1) +## assert 'keepalive' in [op.opname for op in link.target.operations] #__________________________________________________________ # test compute_reachability @@ -140,6 +141,7 @@ t.buildannotator().build_types(f, [int]) t.buildrtyper().specialize() graph = graphof(t, f) + join_blocks(graph) loop_blocks = find_loop_blocks(graph) assert len(loop_blocks) == 4 From arigo at codespeak.net Sun Nov 12 12:29:53 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 12 Nov 2006 12:29:53 +0100 (CET) Subject: [pypy-svn] r34528 - in pypy/dist/pypy/translator/llvm/pyllvm: . test Message-ID: <20061112112953.0F9E510050@code0.codespeak.net> Author: arigo Date: Sun Nov 12 12:29:53 2006 New Revision: 34528 Modified: pypy/dist/pypy/translator/llvm/pyllvm/cc.py pypy/dist/pypy/translator/llvm/pyllvm/test/test_ee.py Log: Two avoid-to-hide-random-errors fixes. Modified: pypy/dist/pypy/translator/llvm/pyllvm/cc.py ============================================================================== --- pypy/dist/pypy/translator/llvm/pyllvm/cc.py (original) +++ pypy/dist/pypy/translator/llvm/pyllvm/cc.py Sun Nov 12 12:29:53 2006 @@ -13,8 +13,8 @@ else: cdll_load = cdll.LoadLibrary self.library = cdll_load(d + libname + ".so") - except: - raise Exception("llvmcapi not found: run 'python setup.py build_ext -i' in " + d) + except Exception, e: + raise Exception(str(e) + "\nrun 'python setup.py build_ext -i' in " + d) self.restype = restype self.argtypes = argtypes 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 Sun Nov 12 12:29:53 2006 @@ -6,7 +6,7 @@ try: from pypy.translator.llvm.pyllvm import pyllvm -except: +except ImportError: py.test.skip("Unable to import pyllvm") from pypy.translator.llvm.pyllvm.test import ll_snippet From arigo at codespeak.net Sun Nov 12 12:41:34 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 12 Nov 2006 12:41:34 +0100 (CET) Subject: [pypy-svn] r34530 - pypy/dist/pypy/jit/codegen/llvm Message-ID: <20061112114134.4A40910160@code0.codespeak.net> Author: arigo Date: Sun Nov 12 12:41:33 2006 New Revision: 34530 Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Log: More wacking at this hackish-looking file. Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Sun Nov 12 12:41:33 2006 @@ -29,6 +29,10 @@ os.chdir(curdir) +if not os.path.exists(path): + import py + py.test.skip("libllvmjit.so compilation failed (no llvm headers?)") + #load the actual library llvmjit = cdll.LoadLibrary(os.path.abspath(path)) class _FuncPtr(_CFuncPtr): From arigo at codespeak.net Sun Nov 12 14:27:34 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 12 Nov 2006 14:27:34 +0100 (CET) Subject: [pypy-svn] r34531 - in pypy/dist/pypy: rlib rlib/test rpython/test Message-ID: <20061112132734.DA4141015A@code0.codespeak.net> Author: arigo Date: Sun Nov 12 14:27:33 2006 New Revision: 34531 Modified: pypy/dist/pypy/rlib/rctypesobject.py pypy/dist/pypy/rlib/test/test_rctypesobject.py pypy/dist/pypy/rpython/test/test_llinterp.py Log: The keepalive logic for RCTypesCharP was wrong. Making it correct exposes a crash, which I think comes from malloc-removal forgetting to preserve some keepalives. To be investigated. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Sun Nov 12 14:27:33 2006 @@ -2,6 +2,7 @@ from pypy.rpython import annlowlevel from pypy.interpreter.miscutils import InitializedClass from pypy.tool.sourcetools import func_with_new_name +from pypy.rlib.objectmodel import keepalive_until_here class RawMemBlock(object): @@ -12,9 +13,10 @@ if ofs_keepalives == 0: return self else: - return self._addoffset(ofs_keepalives) - def _addoffset(self, ofs_keepalives): - return RawMemSubBlock(self, ofs_keepalives) + return RawMemSubBlock(self, ofs_keepalives) +## return self._addoffset(ofs_keepalives) +## def _addoffset(self, ofs_keepalives): +## return RawMemSubBlock(self, ofs_keepalives) def getkeepalive(self, index): return self.keepalives[self.ofs_keepalives + index] def setkeepalive(self, index, memblock): @@ -23,14 +25,15 @@ EMPTY_RAW_MEM_BLOCK = RawMemBlock(0) class AllocatedRawMemBlock(RawMemBlock): - def __init__(self, num_keepalives, rawsize): + def __init__(self, num_keepalives, rawsize, zero=True): RawMemBlock.__init__(self, num_keepalives) addr = llmemory.raw_malloc(rawsize) self.addr = addr - llmemory.raw_memclear(addr, rawsize) - #print 'raw_malloc:', addr + if zero: + llmemory.raw_memclear(addr, rawsize) + #print 'raw_malloc: %x' % llmemory.cast_adr_to_int(addr) def __del__(self): - #print 'raw_free: ', self.addr + #print 'raw_free: %x' % llmemory.cast_adr_to_int(self.addr) llmemory.raw_free(self.addr) class RawMemSubBlock(RawMemBlock): @@ -38,9 +41,9 @@ self.baseblock = baseblock self.keepalives = baseblock.keepalives self.ofs_keepalives = ofs_keepalives - def _addoffset(self, ofs_keepalives): - ofs_keepalives = self.ofs_keepalives + ofs_keepalives - return RawMemSubBlock(self.baseblock, ofs_keepalives) +## def _addoffset(self, ofs_keepalives): +## ofs_keepalives = self.ofs_keepalives + ofs_keepalives +## return RawMemSubBlock(self.baseblock, ofs_keepalives) class RCTypesObject(object): @@ -78,6 +81,20 @@ self._copykeepalives(0, srcbox) cls.copyfrom = copyfrom1 + if hasattr(cls, 'llvalue2value') and not hasattr(cls, 'get_value'): + def get_value(self): + ptr = self.ll_ref(cls.CDATATYPE) + res = cls.llvalue2value(ptr[0]) + keepalive_until_here(self) + return res + cls.get_value = get_value + + if hasattr(cls, 'value2llvalue') and not hasattr(cls, 'set_value'): + def set_value(self, value): + ptr = self.ll_ref(cls.CDATATYPE) + ptr[0] = cls.value2llvalue(value) + cls.set_value = set_value + def sameaddr(self, otherbox): return self.addr == otherbox.addr @@ -100,6 +117,8 @@ return llmemory.cast_adr_to_ptr(self.addr, lltype.Ptr(CDATATYPE)) ll_ref._annspecialcase_ = 'specialize:arg(1)' +_abstract_classes = [RCTypesObject] + # ____________________________________________________________ _primitive_cache = {} @@ -113,13 +132,13 @@ class RCTypesPrimitive(RCTypesObject): LLTYPE = TYPE - def get_value(self): - ptr = self.ll_ref(RCTypesPrimitive.CDATATYPE) - return ptr[0] - - def set_value(self, llvalue): - ptr = self.ll_ref(RCTypesPrimitive.CDATATYPE) - ptr[0] = llvalue + def _no_conversion_needed(x): + return x + llvalue2value = staticmethod(_no_conversion_needed) + value2llvalue = staticmethod(_no_conversion_needed) + + #def get_value(self): added by __initclass__() above + #def set_value(self, value): added by __initclass__() above _primitive_cache[TYPE] = RCTypesPrimitive return RCTypesPrimitive @@ -130,14 +149,14 @@ # ____________________________________________________________ -class _RCTypesStringData(object): - ARRAYTYPE = lltype.FixedSizeArray(lltype.Char, 1) - ITEMOFS = llmemory.sizeof(lltype.Char) - def __init__(self, bufsize): - rawsize = self.ITEMOFS * bufsize - self.addr = llmemory.raw_malloc(rawsize) - def __del__(self): - llmemory.raw_free(self.addr) +##class _RCTypesStringData(object): +## ARRAYTYPE = lltype.FixedSizeArray(lltype.Char, 1) +## ITEMOFS = llmemory.sizeof(lltype.Char) +## def __init__(self, bufsize): +## rawsize = self.ITEMOFS * bufsize +## self.addr = llmemory.raw_malloc(rawsize) +## def __del__(self): +## llmemory.raw_free(self.addr) def strlen(p): n = 0 @@ -166,25 +185,31 @@ break class RCTypesCharP(RCTypesObject): - LLTYPE = lltype.Ptr(_RCTypesStringData.ARRAYTYPE) + ARRAYTYPE = lltype.FixedSizeArray(lltype.Char, 1) + ITEMOFS = llmemory.sizeof(lltype.Char) + LLTYPE = lltype.Ptr(ARRAYTYPE) + num_keepalives = 1 - def get_value(self): - ptr = self.ll_ref(RCTypesCharP.CDATATYPE) - p = ptr[0] + def llvalue2value(p): length = strlen(p) return charp2string(p, length) + llvalue2value = staticmethod(llvalue2value) + + #def get_value(self): added by __initclass__() above def set_value(self, string): n = len(string) - data = _RCTypesStringData(n + 1) - a = data.addr + rawsize = RCTypesCharP.ITEMOFS * (n + 1) + targetmemblock = AllocatedRawMemBlock(0, rawsize, zero=False) + targetaddr = targetmemblock.addr + a = targetaddr for i in range(n): a.char[0] = string[i] - a += _RCTypesStringData.ITEMOFS + a += RCTypesCharP.ITEMOFS a.char[0] = '\x00' ptr = self.ll_ref(RCTypesCharP.CDATATYPE) - ptr[0] = llmemory.cast_adr_to_ptr(data.addr, RCTypesCharP.LLTYPE) - self._keepalive_stringdata = data + ptr[0] = llmemory.cast_adr_to_ptr(targetaddr, RCTypesCharP.LLTYPE) + self._keepalivememblock(0, targetmemblock) rc_char_p = RCTypesCharP @@ -196,10 +221,11 @@ return contentscls._ptrcls except AttributeError: assert issubclass(contentscls, RCTypesObject) - if contentscls is RCTypesObject: - raise Exception("cannot call RPointer(RCTypesObject) or " + if contentscls in _abstract_classes: + raise Exception("cannot call RPointer(%s) or " "pointer(x) if x degenerated to the base " - "RCTypesObject class") + "%s class" % (contentscls.__name__, + contentscls.__name__,)) class RCTypesPtr(RCTypesObject): CONTENTS = contentscls.CDATATYPE @@ -283,8 +309,9 @@ return getattr(itemcls, key) except AttributeError: assert issubclass(itemcls, RCTypesObject) - if itemcls is RCTypesObject: - raise Exception("cannot call RFixedArray(RCTypesObject)") + if itemcls in _abstract_classes: + raise Exception("cannot call RFixedArray(%s)" % ( + itemcls.__name__,)) ARRAYTYPE = lltype.FixedSizeArray(itemcls.LLTYPE, fixedsize) FIRSTITEMOFS = llmemory.ArrayItemsOffset(ARRAYTYPE) @@ -324,8 +351,9 @@ return itemcls._vararraycls except AttributeError: assert issubclass(itemcls, RCTypesObject) - if itemcls is RCTypesObject: - raise Exception("cannot call RVarArray(RCTypesObject)") + if itemcls in _abstract_classes: + raise Exception("cannot call RVarArray(%s)" % ( + itemcls.__name__,)) ARRAYTYPE = lltype.Array(itemcls.LLTYPE, hints={'nolength': True}) FIRSTITEMOFS = llmemory.ArrayItemsOffset(ARRAYTYPE) Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sun Nov 12 14:27:33 2006 @@ -1,3 +1,4 @@ +import py from pypy.rlib.rctypesobject import * from pypy.rpython.test.test_llinterp import interpret from pypy.translator.c.test.test_genc import compile @@ -117,6 +118,18 @@ res = self.do(func) assert res == 26 + def test_char_p_in_struct(self): + py.test.skip("keepalive problem in malloc removal?") + S2 = RStruct('S2', [('p', rc_char_p)]) + def func(): + s = S2.allocate() + for test in ["abc", "hello world"]: + s.ref_p().set_value(test) + assert s.ref_p().get_value() == "hello world" + return 1 + res = self.do(func) + assert res == 1 + def test_char_array(self): def func(): a = RFixedArray(rc_char, 10).allocate() @@ -180,7 +193,7 @@ class TestLLInterpreted(TestBasic): def do(self, func): - return interpret(func, [], policy=POLICY) + return interpret(func, [], policy=POLICY, backendopt=True) class TestCompiled(TestBasic): 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 Sun Nov 12 14:27:33 2006 @@ -32,7 +32,7 @@ return res def gengraph(func, argtypes=[], viewbefore='auto', policy=None, - type_system="lltype"): + type_system="lltype", backendopt=False): t = TranslationContext() a = t.buildannotator(policy=policy) timelog("annotating", a.build_types, func, argtypes) @@ -46,6 +46,10 @@ timelog("rtyper-specializing", typer.specialize) #t.view() timelog("checking graphs", t.checkgraphs) + if backendopt: + from pypy.translator.backendopt.all import backend_optimizations + backend_optimizations(t) + timelog("checking graphs", t.checkgraphs) desc = t.annotator.bookkeeper.getdesc(func) graph = desc.specialize(argtypes) return t, typer, graph @@ -57,8 +61,9 @@ _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,) + someobjects=False, type_system="lltype", backendopt=False): + key = (func,) + tuple([typeOf(x) for x in values])+ (someobjects, + backendopt) try: (t, interp, graph) = _tcache[key] except KeyError: @@ -72,7 +77,8 @@ return lltype_to_annotation(T) t, typer, graph = gengraph(func, [annotation(x) for x in values], - viewbefore, policy, type_system=type_system) + viewbefore, policy, type_system=type_system, + backendopt=backendopt) interp = LLInterpreter(typer) _tcache[key] = (t, interp, graph) # keep the cache small @@ -86,15 +92,18 @@ return interp, graph def interpret(func, values, view='auto', viewbefore='auto', policy=None, - someobjects=False, type_system="lltype"): + someobjects=False, type_system="lltype", backendopt=False): interp, graph = get_interpreter(func, values, view, viewbefore, policy, - someobjects, type_system=type_system) + someobjects, type_system=type_system, + backendopt=backendopt) return interp.eval_graph(graph, values) def interpret_raises(exc, func, values, view='auto', viewbefore='auto', - policy=None, someobjects=False, type_system="lltype"): + policy=None, someobjects=False, type_system="lltype", + backendopt=False): interp, graph = get_interpreter(func, values, view, viewbefore, policy, - someobjects, type_system=type_system) + someobjects, type_system=type_system, + backendopt=backendopt) info = py.test.raises(LLException, "interp.eval_graph(graph, values)") assert interp.find_exception(info.value) is exc, "wrong exception type" From cfbolz at codespeak.net Sun Nov 12 21:50:18 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 21:50:18 +0100 (CET) Subject: [pypy-svn] r34535 - pypy/dist/pypy/rlib/parsing Message-ID: <20061112205018.A63B410162@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 21:50:15 2006 New Revision: 34535 Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py pypy/dist/pypy/rlib/parsing/parsing.py pypy/dist/pypy/rlib/parsing/tree.py Log: make the visitor code more versatile Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/ebnfparse.py Sun Nov 12 21:50:15 2006 @@ -159,7 +159,7 @@ def make_transformer(rules, changes, star_rules): rulenames = dict.fromkeys([r.nonterminal for r in rules]) result = ["class ToAST(RPythonVisitor):"] - result.append(" def visit(self, node):") + result.append(" def general_visit(self, node):") result.append(" return node") for rule, change in zip(rules, changes): lenchanges = [len(c) for c in change] Modified: pypy/dist/pypy/rlib/parsing/parsing.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/parsing.py (original) +++ pypy/dist/pypy/rlib/parsing/parsing.py Sun Nov 12 21:50:15 2006 @@ -218,7 +218,8 @@ def __repr__(self): from pprint import pformat - return "PackratParser%s" % (pformat((self.rules, self.startsymbol)), ) + return "%s%s" % (self.__class__.__name__, + pformat((self.rules, self.startsymbol)), ) class ParserCompiler(object): def __init__(self, parser): Modified: pypy/dist/pypy/rlib/parsing/tree.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/tree.py (original) +++ pypy/dist/pypy/rlib/parsing/tree.py Sun Nov 12 21:50:15 2006 @@ -68,7 +68,43 @@ pass class VisitError(Exception): - pass + def __init__(self, node): + self.node = node + self.args = (node, ) + + def __str__(self): + return "could not visit %s" % (self.node, ) + +def make_dispatch_function(dispatch_table): + code = ["def dispatch(self, node):"] + code.append(" if isinstance(node, Nonterminal):") + code.append(" if node.symbol not in self.dispatch_table:") + if "__general_nonterminal_visit" in dispatch_table: + code.append( + " return self.dispatch_table['__general_nonterminal_visit'](self, node)") + elif "__general_visit" in dispatch_table: + code.append( + " return self.dispatch_table['__general_visit'](self, node)") + else: + code.append(" raise VisitError(node)") + code.append(" else:") + code.append(" return self.dispatch_table[node.symbol](self, node)") + code.append(" if isinstance(node, Symbol):") + code.append(" if node.symbol not in self.dispatch_table:") + if "__general_symbol_visit" in dispatch_table: + code.append( + " return self.dispatch_table['__general_symbol_visit'](self, node)") + elif "__general_visit" in dispatch_table: + code.append( + " return self.dispatch_table['__general_visit'](self, node)") + else: + code.append(" raise VisitError(node)") + code.append(" else:") + code.append(" return self.dispatch_table[node.symbol](self, node)") + code.append(" raise VisitError(node)") + print "\n".join(code) + exec py.code.Source("\n".join(code)).compile() + return dispatch class CreateDispatchDictionaryMetaclass(type): def __new__(cls, name, bases, dct): @@ -76,9 +112,13 @@ for name, value in dct.iteritems(): if name.startswith("visit_"): dispatch_table[name[len("visit_"):]] = value - if "visit" in dct: - dispatch_table["__general_symbol"] = dct["visit"] + for special in ["general_symbol_visit", + "general_nonterminal_visit", + "general_visit"]: + if special in dct: + dispatch_table["__" + special] = dct[special] dct["dispatch_table"] = dispatch_table + dct["dispatch"] = make_dispatch_function(dispatch_table) return type.__new__(cls, name, bases, dct) class RPythonVisitor(object): @@ -87,15 +127,16 @@ def dispatch(self, node): if isinstance(node, Nonterminal): if node.symbol not in self.dispatch_table: - raise VisitError + raise VisitError(node) else: return self.dispatch_table[node.symbol](self, node) elif isinstance(node, Symbol): if node.symbol not in self.dispatch_table: if "__general_symbol" in self.dispatch_table: return self.dispatch_table["__general_symbol"](self, node) - raise VisitError + raise VisitError(node) else: return self.dispatch_table[node.symbol](self, node) + else: - raise VisitError() + raise VisitError(node) From cfbolz at codespeak.net Sun Nov 12 22:16:21 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 22:16:21 +0100 (CET) Subject: [pypy-svn] r34536 - in pypy/dist/pypy/lang/prolog: . builtin builtin/test interpreter interpreter/test Message-ID: <20061112211621.A6C1A10164@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 22:16:10 2006 New Revision: 34536 Added: pypy/dist/pypy/lang/prolog/ (props changed) pypy/dist/pypy/lang/prolog/__init__.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/ (props changed) pypy/dist/pypy/lang/prolog/builtin/__init__.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/allsolution.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/arithmeticbuiltin.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/atomconstruction.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/control.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/database.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/exception.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/formatting.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/metacall.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/parseraccess.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/register.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/source.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/termconstruction.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/test/ (props changed) pypy/dist/pypy/lang/prolog/builtin/test/__init__.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/test/test_formatting.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/type.py (contents, props changed) pypy/dist/pypy/lang/prolog/builtin/unify.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/ (props changed) pypy/dist/pypy/lang/prolog/interpreter/__init__.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/arithmetic.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/choice.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/conftest.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/engine.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/error.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/helper.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/main.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/parsing.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/term.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/ (props changed) pypy/dist/pypy/lang/prolog/interpreter/test/__init__.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/dont_test_translate.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/test_arithmetic.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/test_builtin.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/test_engine.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/test_parsing.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/test_standard.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/test_unification.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/test/tool.py (contents, props changed) pypy/dist/pypy/lang/prolog/interpreter/translatedmain.py (contents, props changed) Log: import the prolog interpreter Added: pypy/dist/pypy/lang/prolog/__init__.py ============================================================================== Added: pypy/dist/pypy/lang/prolog/builtin/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/__init__.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,16 @@ +# all builtins +builtins = {} + +# imports to register builtins +import pypy.lang.prolog.builtin.allsolution +import pypy.lang.prolog.builtin.arithmeticbuiltin +import pypy.lang.prolog.builtin.atomconstruction +import pypy.lang.prolog.builtin.control +import pypy.lang.prolog.builtin.database +import pypy.lang.prolog.builtin.exception +import pypy.lang.prolog.builtin.formatting +import pypy.lang.prolog.builtin.metacall +import pypy.lang.prolog.builtin.parseraccess +import pypy.lang.prolog.builtin.source +import pypy.lang.prolog.builtin.termconstruction +import pypy.lang.prolog.builtin.unify Added: pypy/dist/pypy/lang/prolog/builtin/allsolution.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/allsolution.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,33 @@ +import py +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# finding all solutions to a goal + +class FindallContinuation(engine.Continuation): + def __init__(self, template): + self.found = [] + self.template = template + + def call(self, engine): + clone = self.template.getvalue(engine.frame) + self.found.append(clone) + raise error.UnificationFailed() + +def impl_findall(engine, template, goal, bag): + oldstate = engine.frame.branch() + collector = FindallContinuation(template) + try: + engine.call(goal, collector) + except error.UnificationFailed: + engine.frame.revert(oldstate) + result = term.Atom("[]") + for i in range(len(collector.found) - 1, -1, -1): + copy = collector.found[i] + d = {} + copy = copy.clone_compress_vars(d, engine.frame.maxvar()) + engine.frame.extend(len(d)) + result = term.Term(".", [copy, result]) + bag.unify(result, engine.frame) +expose_builtin(impl_findall, "findall", unwrap_spec=['raw', 'callable', 'raw']) Added: pypy/dist/pypy/lang/prolog/builtin/arithmeticbuiltin.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/arithmeticbuiltin.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,51 @@ +import py +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# arithmetic + + +def impl_between(engine, lower, upper, varorint, continuation): + if isinstance(varorint, term.Var): + for i in range(lower, upper): + oldstate = engine.frame.branch() + try: + varorint.unify(term.Number(i), engine.frame) + return continuation.call(engine) + except error.UnificationFailed: + engine.frame.revert(oldstate) + varorint.unify(term.Number(upper), engine.frame) + return continuation.call(engine) + else: + integer = helper.unwrap_int(varorint) + if not (lower <= integer <= upper): + raise error.UnificationFailed + return continuation.call(engine) +expose_builtin(impl_between, "between", unwrap_spec=["int", "int", "obj"], + handles_continuation=True) + +def impl_is(engine, var, num): + var.unify(num, engine.frame) +expose_builtin(impl_is, "is", unwrap_spec=["raw", "arithmetic"]) + +for ext, prolog, python in [("eq", "=:=", "=="), + ("ne", "=\\=", "!="), + ("lt", "<", "<"), + ("le", "=<", "<="), + ("gt", ">", ">"), + ("ge", ">=", ">=")]: + exec py.code.Source(""" +def impl_arith_%s(engine, num1, num2): + eq = False + if isinstance(num1, term.Number): + if isinstance(num2, term.Number): + eq = num1.num %s num2.num + elif isinstance(num1, term.Float): + if isinstance(num2, term.Float): + eq = num1.num %s num2.num + if not eq: + raise error.UnificationFailed()""" % (ext, python, python)).compile() + expose_builtin(globals()["impl_arith_%s" % (ext, )], prolog, + unwrap_spec=["arithmetic", "arithmetic"]) + Added: pypy/dist/pypy/lang/prolog/builtin/atomconstruction.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/atomconstruction.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,125 @@ +import py +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# analysing and construction atoms + +def impl_atom_concat(engine, a1, a2, result, continuation): + if isinstance(a1, term.Var): + if isinstance(a2, term.Var): + # nondeterministic splitting of result + r = helper.convert_to_str(result) + for i in range(len(r) + 1): + oldstate = engine.frame.branch() + try: + a1.unify(term.Atom(r[:i]), engine.frame) + a2.unify(term.Atom(r[i:]), engine.frame) + return continuation.call(engine) + except error.UnificationFailed: + engine.frame.revert(oldstate) + raise error.UnificationFailed() + else: + s2 = helper.convert_to_str(a2) + r = helper.convert_to_str(result) + if r.endswith(s2): + stop = len(r) - len(s2) + assert stop > 0 + a1.unify(term.Atom(r[:stop]), engine.frame) + else: + raise error.UnificationFailed() + else: + s1 = helper.convert_to_str(a1) + if isinstance(a2, term.Var): + r = helper.convert_to_str(result) + if r.startswith(s1): + a2.unify(term.Atom(r[len(s1):]), engine.frame) + else: + raise error.UnificationFailed() + else: + s2 = helper.convert_to_str(a2) + result.unify(term.Atom(s1 + s2), engine.frame) + return continuation.call(engine) +expose_builtin(impl_atom_concat, "atom_concat", + unwrap_spec=["obj", "obj", "obj"], + handles_continuation=True) + +def impl_atom_length(engine, s, length): + if not (isinstance(length, term.Var) or isinstance(length, term.Number)): + error.throw_type_error("integer", length) + term.Number(len(s)).unify(length, engine.frame) +expose_builtin(impl_atom_length, "atom_length", unwrap_spec = ["atom", "obj"]) + +def impl_sub_atom(engine, s, before, length, after, sub, continuation): + # XXX can possibly be optimized + if isinstance(length, term.Var): + startlength = 0 + stoplength = len(s) + 1 + else: + startlength = helper.unwrap_int(length) + stoplength = startlength + 1 + if startlength < 0: + startlength = 0 + stoplength = len(s) + 1 + if isinstance(before, term.Var): + startbefore = 0 + stopbefore = len(s) + 1 + else: + startbefore = helper.unwrap_int(before) + stopbefore = startbefore + 1 + if startbefore < 0: + startbefore = 0 + stopbefore = len(s) + 1 + if not isinstance(sub, term.Var): + s1 = helper.unwrap_atom(sub) + if len(s1) >= stoplength or len(s1) < startlength: + raise error.UnificationFailed() + i = s.find(s1) + if not startbefore <= i < stopbefore: + raise error.UnificationFailed() + if not startlength <= len(s1) < stoplength: + raise error.UnificationFailed() + if isinstance(after, term.Var): + for b in range(startbefore, stopbefore): + for l in range(startlength, stoplength): + if l + b > len(s): + continue + oldstate = engine.frame.branch() + try: + try: + before.unify(term.Number(b), engine.frame) + after.unify(term.Number(len(s) - l - b), engine.frame) + length.unify(term.Number(l), engine.frame) + sub.unify(term.Atom(s[b:b + l]), engine.frame) + return continuation.call(engine) + except: + engine.frame.revert(oldstate) + raise + except error.UnificationFailed: + pass + else: + a = helper.unwrap_int(after) + for l in range(startlength, stoplength): + b = len(s) - l - a + assert b >= 0 + if l + b > len(s): + continue + oldstate = engine.frame.branch() + try: + try: + before.unify(term.Number(b), engine.frame) + after.unify(term.Number(a), engine.frame) + length.unify(term.Number(l), engine.frame) + sub.unify(term.Atom(s[b:b + l]), engine.frame) + return continuation.call(engine) + return None + except: + engine.frame.revert(oldstate) + raise + except error.UnificationFailed: + pass + raise error.UnificationFailed() +expose_builtin(impl_sub_atom, "sub_atom", + unwrap_spec=["atom", "obj", "obj", "obj", "obj"], + handles_continuation=True) + Added: pypy/dist/pypy/lang/prolog/builtin/control.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/control.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,83 @@ +import py +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# control predicates + +def impl_fail(engine): + raise error.UnificationFailed() +expose_builtin(impl_fail, "fail", unwrap_spec=[]) + +def impl_true(engine): + pass +expose_builtin(impl_true, "true", unwrap_spec=[]) + +def impl_repeat(engine, continuation): + while 1: + try: + return continuation.call(engine) + except error.UnificationFailed: + pass +expose_builtin(impl_repeat, "repeat", unwrap_spec=[], handles_continuation=True) + +def impl_cut(engine, continuation): + raise error.CutException(continuation) +expose_builtin(impl_cut, "!", unwrap_spec=[], + handles_continuation=True) + +class AndContinuation(engine.Continuation): + def __init__(self, next_call, continuation): + self.next_call = next_call + self.continuation = continuation + + def call(self, engine): + next_call = self.next_call.dereference(engine.frame) + if isinstance(next_call, term.Var): + error.throw_instantiation_error() + if not isinstance(next_call, term.Callable): + error.throw_type_error('callable', next_call) + return engine.call(next_call, self.continuation) + +def impl_and(engine, call1, call2, continuation): + if not isinstance(call2, term.Var) and not isinstance(call2, term.Callable): + error.throw_type_error('callable', call2) + and_continuation = AndContinuation(call2, continuation) + return engine.call(call1, and_continuation) +expose_builtin(impl_and, ",", unwrap_spec=["callable", "raw"], + handles_continuation=True) + +def impl_or(engine, call1, call2, continuation): + oldstate = engine.frame.branch() + try: + return engine.call(call1, continuation) + except error.UnificationFailed: + engine.frame.revert(oldstate) + return engine.call(call2, continuation) + +expose_builtin(impl_or, ";", unwrap_spec=["callable", "callable"], + handles_continuation=True) + +def impl_not(engine, call): + try: + try: + engine.call(call) + except error.CutException, e: + engine.continue_after_cut(e.continuation) + except error.UnificationFailed: + return None + raise error.UnificationFailed() +expose_builtin(impl_not, ["not", "\\+"], unwrap_spec=["callable"]) + +def impl_if(engine, if_clause, then_clause, continuation): + oldstate = engine.frame.branch() + try: + engine.call(if_clause) + except error.UnificationFailed: + engine.frame.revert(oldstate) + raise + return engine.call(helper.ensure_callable(then_clause), continuation) +expose_builtin(impl_if, "->", unwrap_spec=["callable", "raw"], + handles_continuation=True) + Added: pypy/dist/pypy/lang/prolog/builtin/database.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/database.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,60 @@ +import py +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# database + +def impl_abolish(engine, predicate): + from pypy.lang.prolog.builtin import builtins + name, arity = helper.unwrap_predicate_indicator(predicate) + if arity < 0: + error.throw_domain_error("not_less_than_zero", term.Number(arity)) + signature = name + "/" + str(arity) + if signature in builtins: + error.throw_permission_error("modify", "static_procedure", + predicate) + if signature in engine.signature2rules: + del engine.signature2rules[signature] +expose_builtin(impl_abolish, "abolish", unwrap_spec=["obj"]) + +def impl_assert(engine, rule): + engine.add_rule(rule.getvalue(engine.frame)) +expose_builtin(impl_assert, ["assert", "assertz"], unwrap_spec=["callable"]) + +def impl_asserta(engine, rule): + engine.add_rule(rule.getvalue(engine.frame), end=False) +expose_builtin(impl_asserta, "asserta", unwrap_spec=["callable"]) + + +def impl_retract(engine, pattern): + from pypy.lang.prolog.builtin import builtins + if isinstance(pattern, term.Term) and pattern.name == ":-": + head = helper.ensure_callable(pattern.args[0]) + body = helper.ensure_callable(pattern.args[1]) + else: + head = pattern + body = None + if head.signature in builtins: + assert isinstance(head, term.Callable) + error.throw_permission_error("modify", "static_procedure", + head.get_prolog_signature()) + rules = engine.signature2rules.get(head.signature, []) + for i in range(len(rules)): + rule = rules[i] + oldstate = engine.frame.branch() + # standardizing apart + try: + deleted_body = rule.clone_and_unify_head(engine.frame, head) + if body is not None: + body.unify(deleted_body, engine.frame) + except error.UnificationFailed: + engine.frame.revert(oldstate) + else: + del rules[i] + break + else: + raise error.UnificationFailed() +expose_builtin(impl_retract, "retract", unwrap_spec=["callable"]) + + Added: pypy/dist/pypy/lang/prolog/builtin/exception.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/exception.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,47 @@ +import py +from pypy.lang.prolog.interpreter import engine as enginemod, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin +from pypy.lang.prolog.builtin.type import impl_ground + +# ___________________________________________________________________ +# exception handling + +def impl_catch(engine, goal, catcher, recover, continuation): + catching_continuation = enginemod.LimitedScopeContinuation(continuation) + old_state = engine.frame.branch() + try: + return engine.call(goal, catching_continuation) + except error.CatchableError, e: + if not catching_continuation.scope_active: + raise + exc_term = e.term.getvalue(engine.frame) + engine.frame.revert(old_state) + d = {} + exc_term = exc_term.clone_compress_vars(d, engine.frame.maxvar()) + engine.frame.extend(len(d)) + try: + impl_ground(engine, exc_term) + except error.UnificationFailed: + raise error.UncatchableError( + "not implemented: catching of non-ground terms") + try: + catcher.unify(exc_term, engine.frame) + except error.UnificationFailed: + if isinstance(e, error.UserError): + raise error.UserError(exc_term) + if isinstance(e, error.CatchableError): + raise error.CatchableError(exc_term) + return engine.call(recover, continuation) +expose_builtin(impl_catch, "catch", unwrap_spec=["callable", "obj", "callable"], + handles_continuation=True) + +def impl_throw(engine, exc): + try: + impl_ground(engine, exc) + except error.UnificationFailed: + raise error.UncatchableError( + "not implemented: raising of non-ground terms") + raise error.UserError(exc) +expose_builtin(impl_throw, "throw", unwrap_spec=["obj"]) + + Added: pypy/dist/pypy/lang/prolog/builtin/formatting.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/formatting.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,144 @@ +import os +import string + +from pypy.lang.prolog.interpreter.term import Term, Float, Number, Var, Atom +from pypy.lang.prolog.interpreter import error, helper, parsing +from pypy.lang.prolog.builtin.register import expose_builtin + +class TermFormatter(object): + def __init__(self, engine, quoted=False, max_depth=0, + ignore_ops=False): + self.engine = engine + self.quoted = quoted + self.max_depth = max_depth + self.ignore_ops = ignore_ops + self.curr_depth = 0 + self._make_reverse_op_mapping() + + def from_option_list(engine, options): + # XXX add numbervars support + quoted = False + max_depth = 0 + ignore_ops = False + number_vars = False + for option in options: + if (not isinstance(option, Term) or len(option.args) != 1): + error.throw_domain_error('write_option', option) + arg = option.args[0] + if option.name == "max_depth": + try: + max_depth = helper.unwrap_int(arg) + except error.CatchableError: + error.throw_domain_error('write_option', option) + elif (not isinstance(arg, Atom) or + (arg.name != "true" and arg.name != "false")): + error.throw_domain_error('write_option', option) + assert 0, "unreachable" + elif option.name == "quoted": + quoted = arg.name == "true" + elif option.name == "ignore_ops": + ignore_ops = arg.name == "true" + return TermFormatter(engine, quoted, max_depth, ignore_ops) + from_option_list = staticmethod(from_option_list) + + def format(self, term): + self.curr_depth += 1 + if self.max_depth > 0 and self.curr_depth > self.max_depth: + return "..." + if isinstance(term, Atom): + return self.format_atom(term.name) + elif isinstance(term, Number): + return self.format_number(term) + elif isinstance(term, Float): + return self.format_float(term) + elif isinstance(term, Term): + return self.format_term(term) + elif isinstance(term, Var): + return self.format_var(term) + + def format_atom(self, s): + from algorithm.automaton.deterministic import LexerError + if self.quoted: + try: + tokens = parsing.lexer.tokenize(s) + if (len(tokens) == 1 and tokens[0][0] == 'ATOM' and + tokens[0][1] == s): + return s + except LexerError: + pass + return "'%s'" % (s, ) + return s + + def format_number(self, num): + return str(num.num) + + def format_float(self, num): + return str(num.num) + + def format_var(self, var): + return "_G%s" % (var.index, ) + + + def format_term_normally(self, term): + return "%s(%s)" % (self.format_atom(term.name), + ", ".join([self.format(a) for a in term.args])) + + def format_term(self, term): + if self.ignore_ops: + return self.format_term_normally(term) + else: + return self.format_with_ops(term)[1] + + def format_with_ops(self, term): + if not isinstance(term, Term): + return (0, self.format(term)) + if term.signature == "./2": + result = ["["] + while isinstance(term, Term) and term.signature == "./2": + first = term.args[0] + second = term.args[1] + result.append(self.format(first)) + result.append(", ") + term = second + if isinstance(term, Atom) and term.name == "[]": + result[-1] = "]" + else: + result[-1] = "|" + result.append(self.format(term)) + result.append("]") + return (0, "".join(result)) + if (len(term.args), term.name) not in self.op_mapping: + return (0, self.format_term_normally(term)) + form, prec = self.op_mapping[(len(term.args), term.name)] + result = [] + assert 0 <= len(term.args) <= 2 + curr_index = 0 + for c in form: + if c == "f": + result.append(self.format_atom(term.name)) + else: + childprec, child = self.format_with_ops(term.args[curr_index]) + parentheses = (c == "x" and childprec >= prec or + c == "y" and childprec > prec) + if parentheses: + result.append("(") + result.append(child) + result.append(")") + else: + result.append(child) + curr_index += 1 + assert curr_index == len(term.args) + return (prec, "".join(result)) + + def _make_reverse_op_mapping(self): + m = {} + for prec, allops in self.engine.getoperations(): + for form, ops in allops: + for op in ops: + m[len(form) - 1, op] = (form, prec) + self.op_mapping = m + +def impl_write_term(engine, term, options): + f = TermFormatter.from_option_list(engine, options) + os.write(1, f.format(term)) +expose_builtin(impl_write_term, "write_term", unwrap_spec=["concrete", "list"]) Added: pypy/dist/pypy/lang/prolog/builtin/metacall.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/metacall.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,21 @@ +import py +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# meta-call predicates + +def impl_call(engine, call, continuation): + try: + return engine.call(call, continuation) + except error.CutException, e: + return e.continuation.call(engine) +expose_builtin(impl_call, "call", unwrap_spec=["callable"], + handles_continuation=True) + +def impl_once(engine, clause, continuation): + engine.call(clause) + return continuation.call(engine) +expose_builtin(impl_once, "once", unwrap_spec=["callable"], + handles_continuation=True) + Added: pypy/dist/pypy/lang/prolog/builtin/parseraccess.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/parseraccess.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,58 @@ +import py +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# operators + +def impl_current_op(engine, precedence, typ, name, continuation): + for prec, allops in engine.getoperations(): + for form, ops in allops: + for op in ops: + oldstate = engine.frame.branch() + try: + precedence.unify(term.Number(prec), engine.frame) + typ.unify(term.Atom(form), engine.frame) + name.unify(term.Atom(op), engine.frame) + return continuation.call(engine) + except error.UnificationFailed: + engine.frame.revert(oldstate) + raise error.UnificationFailed() +expose_builtin(impl_current_op, "current_op", unwrap_spec=["obj", "obj", "obj"], + handles_continuation=True) + +def impl_op(engine, precedence, typ, name): + from pypy.lang.prolog.interpreter import parsing + if engine.operations is None: + engine.operations = parsing.make_default_operations() + operations = engine.operations + precedence_to_ops = {} + for prec, allops in operations: + precedence_to_ops[prec] = allops + for form, ops in allops: + try: + index = ops.index(name) + del ops[index] + except ValueError: + pass + if precedence != 0: + if precedence in precedence_to_ops: + allops = precedence_to_ops[precedence] + for form, ops in allops: + if form == typ: + ops.append(name) + break + else: + allops.append((typ, [name])) + else: + for i in range(len(operations)): + (prec, allops) = operations[i] + if precedence > prec: + operations.insert(i, (precedence, [(typ, [name])])) + break + else: + operations.append((precedence, [(typ, [name])])) + engine.parser = parsing.make_parser_at_runtime(engine.operations) +expose_builtin(impl_op, "op", unwrap_spec=["int", "atom", "atom"]) + + Added: pypy/dist/pypy/lang/prolog/builtin/register.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/register.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,72 @@ +import py +from pypy.lang.prolog.interpreter import arithmetic +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin import builtins + +from pypy.rpython.objectmodel import we_are_translated + +def expose_builtin(func, name, unwrap_spec=None, handles_continuation=False, + translatable=True): + if isinstance(name, list): + expose_as = name + name = name[0] + else: + expose_as = [name] + if not name.isalnum(): + name = func.func_name + funcname = "wrap_%s_%s" % (name, len(unwrap_spec)) + code = ["def %s(engine, query, continuation):" % (funcname, )] + if not translatable: + code.append(" if we_are_translated():") + code.append(" raise error.UncatchableError('does not work in translated version')") + subargs = ["engine"] + for i, spec in enumerate(unwrap_spec): + varname = "var%s" % (i, ) + subargs.append(varname) + if spec in ("obj", "callable", "int", "atom", "arithmetic"): + code.append(" %s = query.args[%s].dereference(engine.frame)" % + (varname, i)) + elif spec in ("concrete", "list"): + code.append(" %s = query.args[%s].getvalue(engine.frame)" % + (varname, i)) + if spec in ("callable", "int", "atom", "arithmetic", "list"): + code.append( + " if isinstance(%s, term.Var):" % (varname,)) + code.append( + " error.throw_instantiation_error()") + if spec == "obj": + pass + elif spec == "concrete": + pass + elif spec == "callable": + code.append( + " if not isinstance(%s, term.Callable):" % (varname,)) + code.append( + " error.throw_type_error('callable', %s)" % (varname,)) + elif spec == "raw": + code.append(" %s = query.args[%s]" % (varname, i)) + elif spec == "int": + code.append(" %s = helper.unwrap_int(%s)" % (varname, varname)) + elif spec == "atom": + code.append(" %s = helper.unwrap_atom(%s)" % (varname, varname)) + elif spec == "arithmetic": + code.append(" %s = arithmetic.eval_arithmetic(engine, %s)" % + (varname, varname)) + elif spec == "list": + code.append(" %s = helper.unwrap_list(%s)" % (varname, varname)) + else: + assert 0, "not implemented " + spec + if handles_continuation: + subargs.append("continuation") + call = " result = %s(%s)" % (func.func_name, ", ".join(subargs)) + code.append(call) + if not handles_continuation: + code.append(" return continuation.call(engine)") + miniglobals = globals().copy() + miniglobals[func.func_name] = func + exec py.code.Source("\n".join(code)).compile() in miniglobals + for name in expose_as: + signature = "%s/%s" % (name, len(unwrap_spec)) + builtins[signature] = miniglobals[funcname] + Added: pypy/dist/pypy/lang/prolog/builtin/source.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/source.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,34 @@ +import py +from pypy.lang.prolog.interpreter import arithmetic +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.interpreter.error import UnificationFailed, FunctionNotFound +from pypy.rpython.objectmodel import we_are_translated +from pypy.lang.prolog.builtin.register import expose_builtin + + +# ___________________________________________________________________ +# loading prolog source files + +def impl_consult(engine, var): + import os + if isinstance(var, term.Atom): + try: + fd = os.open(var.name, os.O_RDONLY, 0777) + except OSError, e: + error.throw_existence_error("source_sink", var) + assert 0, "unreachable" # make the flow space happy + try: + content = [] + while 1: + s = os.read(fd, 4096) + if not s: + break + content.append(s) + file_content = "".join(content) + finally: + os.close(fd) + engine.runstring(file_content) +expose_builtin(impl_consult, "consult", unwrap_spec=["obj"]) + + Added: pypy/dist/pypy/lang/prolog/builtin/termconstruction.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/termconstruction.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,100 @@ +import py +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# analysing and construction terms + +def impl_functor(engine, t, functor, arity): + if helper.is_atomic(t): + functor.unify(t, engine.frame) + arity.unify(term.Number(0), engine.frame) + elif isinstance(t, term.Term): + functor.unify(term.Atom(t.name), engine.frame) + arity.unify(term.Number(len(t.args)), engine.frame) + elif isinstance(t, term.Var): + if isinstance(functor, term.Var): + error.throw_instantiation_error() + elif isinstance(functor, term.Var): + error.throw_instantiation_error() + a = helper.unwrap_int(arity) + if a < 0: + error.throw_domain_error("not_less_than_zero", arity) + else: + functor = helper.ensure_atomic(functor) + if a == 0: + t.unify(helper.ensure_atomic(functor), engine.frame) + else: + name = helper.unwrap_atom(functor) + start = engine.frame.needed_vars + engine.frame.extend(a) + t.unify( + term.Term(name, + [term.Var(i) for i in range(start, start + a)]), + engine.frame) +expose_builtin(impl_functor, "functor", unwrap_spec=["obj", "obj", "obj"]) + +def impl_arg(engine, first, second, third, continuation): + if isinstance(second, term.Var): + error.throw_instantiation_error() + if isinstance(second, term.Atom): + raise error.UnificationFailed() + if not isinstance(second, term.Term): + error.throw_type_error("compound", second) + if isinstance(first, term.Var): + for i in range(len(second.args)): + arg = second.args[i] + oldstate = engine.frame.branch() + try: + third.unify(arg, engine.frame) + first.unify(term.Number(i + 1), engine.frame) + return continuation.call(engine) + except error.UnificationFailed: + engine.frame.revert(oldstate) + raise error.UnificationFailed() + elif isinstance(first, term.Number): + num = first.num + if num == 0: + raise error.UnificationFailed + if num < 0: + error.throw_domain_error("not_less_than_zero", first) + if num > len(second.args): + raise error.UnificationFailed() + arg = second.args[num - 1] + third.unify(arg, engine.frame) + else: + error.throw_type_error("integer", first) + return continuation.call(engine) +expose_builtin(impl_arg, "arg", unwrap_spec=["obj", "obj", "obj"], + handles_continuation=True) + +def impl_univ(engine, first, second): + if not isinstance(first, term.Var): + if isinstance(first, term.Term): + l = [term.Atom(first.name)] + first.args + else: + l = [first] + u1 = helper.wrap_list(l) + if not isinstance(second, term.Var): + u1.unify(second, engine.frame) + else: + u1.unify(second, engine.frame) + else: + if isinstance(second, term.Var): + error.throw_instantiation_error() + else: + l = helper.unwrap_list(second) + head = l[0] + if not isinstance(head, term.Atom): + error.throw_type_error("atom", head) + term.Term(head.name, l[1:]).unify(first, engine.frame) +expose_builtin(impl_univ, "=..", unwrap_spec=["obj", "obj"]) + +def impl_copy_term(engine, interm, outterm): + d = {} + copy = interm.clone_compress_vars(d, engine.frame.maxvar()) + engine.frame.extend(len(d)) + outterm.unify(copy, engine.frame) +expose_builtin(impl_copy_term, "copy_term", unwrap_spec=["obj", "obj"]) + + Added: pypy/dist/pypy/lang/prolog/builtin/test/__init__.py ============================================================================== Added: pypy/dist/pypy/lang/prolog/builtin/test/test_formatting.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/test/test_formatting.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,21 @@ +from pypy.lang.prolog.builtin import formatting +from pypy.lang.prolog.interpreter.parsing import parse_query_term +from pypy.lang.prolog.interpreter.engine import Engine + +def test_list(): + f = formatting.TermFormatter(Engine(), quoted=False, ignore_ops=False) + t = parse_query_term("[1, 2, 3, 4, 5 | X].") + assert f.format(t) == "[1, 2, 3, 4, 5|_G0]" + t = parse_query_term("[a, b, 'A$%%$$'|[]].") + assert f.format(t) == "[a, b, A$%%$$]" + t = parse_query_term("'.'(a, b, c).") + assert f.format(t) == ".(a, b, c)" + +def test_op_formatting(): + f = formatting.TermFormatter(Engine(), quoted=False, ignore_ops=False) + t = parse_query_term("'+'(1, 2).") + assert f.format(t) == "1+2" + t = parse_query_term("'+'(1, *(3, 2)).") + assert f.format(t) == "1+3*2" + t = parse_query_term("'*'(1, *(3, 2)).") + assert f.format(t) == "1*(3*2)" Added: pypy/dist/pypy/lang/prolog/builtin/type.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/type.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,64 @@ +import py +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# type verifications + +def impl_nonvar(engine, var): + if isinstance(var, term.Var): + raise error.UnificationFailed() +expose_builtin(impl_nonvar, "nonvar", unwrap_spec=["obj"]) + +def impl_var(engine, var): + if not isinstance(var, term.Var): + raise error.UnificationFailed() +expose_builtin(impl_var, "var", unwrap_spec=["obj"]) + +def impl_integer(engine, var): + if isinstance(var, term.Var) or not isinstance(var, term.Number): + raise error.UnificationFailed() +expose_builtin(impl_integer, "integer", unwrap_spec=["obj"]) + +def impl_float(engine, var): + if isinstance(var, term.Var) or not isinstance(var, term.Float): + raise error.UnificationFailed() +expose_builtin(impl_float, "float", unwrap_spec=["obj"]) + +def impl_number(engine, var): + if (isinstance(var, term.Var) or + (not isinstance(var, term.Number) and not + isinstance(var, term.Float))): + raise error.UnificationFailed() +expose_builtin(impl_number, "number", unwrap_spec=["obj"]) + +def impl_atom(engine, var): + if isinstance(var, term.Var) or not isinstance(var, term.Atom): + raise error.UnificationFailed() +expose_builtin(impl_atom, "atom", unwrap_spec=["obj"]) + +def impl_atomic(engine, var): + if helper.is_atomic(var): + return + raise error.UnificationFailed() +expose_builtin(impl_atomic, "atomic", unwrap_spec=["obj"]) + +def impl_compound(engine, var): + if isinstance(var, term.Var) or not isinstance(var, term.Term): + raise error.UnificationFailed() +expose_builtin(impl_compound, "compound", unwrap_spec=["obj"]) + +def impl_callable(engine, var): + if not helper.is_callable(var, engine): + raise error.UnificationFailed() +expose_builtin(impl_callable, "callable", unwrap_spec=["obj"]) + +def impl_ground(engine, var): + if isinstance(var, term.Var): + raise error.UnificationFailed() + if isinstance(var, term.Term): + for arg in var.args: + impl_ground(engine, arg) +expose_builtin(impl_ground, "ground", unwrap_spec=["concrete"]) + + Added: pypy/dist/pypy/lang/prolog/builtin/unify.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/builtin/unify.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,41 @@ +import py +from pypy.lang.prolog.interpreter import arithmetic +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.builtin.register import expose_builtin + +# ___________________________________________________________________ +# comparison and unification of terms + +def impl_unify(engine, obj1, obj2): + obj1.unify(obj2, engine.frame) +expose_builtin(impl_unify, "=", unwrap_spec=["raw", "raw"]) + +def impl_unify_with_occurs_check(engine, obj1, obj2): + obj1.unify(obj2, engine.frame, occurs_check=True) +expose_builtin(impl_unify_with_occurs_check, "unify_with_occurs_check", + unwrap_spec=["raw", "raw"]) + +def impl_does_not_unify(engine, obj1, obj2): + try: + obj1.unify(obj2, engine.frame) + except error.UnificationFailed: + return + raise error.UnificationFailed() +expose_builtin(impl_does_not_unify, "\\=", unwrap_spec=["raw", "raw"]) + + +for ext, prolog, python in [("eq", "==", "== 0"), + ("ne", "\\==", "!= 0"), + ("lt", "@<", "== -1"), + ("le", "@=<", "!= 1"), + ("gt", "@>", "== 1"), + ("ge", "@>=", "!= -1")]: + exec py.code.Source(""" +def impl_standard_comparison_%s(engine, obj1, obj2): + c = term.cmp_standard_order(obj1, obj2, engine.frame) + if not c %s: + raise error.UnificationFailed()""" % (ext, python)).compile() + expose_builtin(globals()["impl_standard_comparison_%s" % (ext, )], prolog, + unwrap_spec=["obj", "obj"]) + Added: pypy/dist/pypy/lang/prolog/interpreter/__init__.py ============================================================================== Added: pypy/dist/pypy/lang/prolog/interpreter/arithmetic.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/arithmetic.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,87 @@ +import py +import math +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter import engine, helper, term, error +from pypy.lang.prolog.interpreter.error import UnificationFailed, FunctionNotFound +from pypy.rlib.rarithmetic import intmask + +arithmetic_functions = {} + +pattern_to_function = {} + +def wrap_builtin_operation(pattern, unwrap_spec, can_overflow): + code = ["def f(engine, query):"] + for i, spec in enumerate(unwrap_spec): + varname = "var%s" % (i, ) + code.append( + " %s = eval_arithmetic(engine, query.args[%s])" % (varname, i)) + code.append( + " v%s = 0" % (i, )) + code.append(" if isinstance(%s, term.Number):" % (varname, )) + code.append(" v%s = %s.num" % (i, varname)) + if spec == "expr": + code.append(" elif isinstance(%s, term.Float):" % (varname, )) + code.append(" v%s = %s.num" % (i, varname)) + code.append(" else:") + code.append(" error.throw_type_error('int', %s)" % (varname, )) + code.append(" return norm_float(%s)" % pattern) + miniglobals = globals().copy() + exec py.code.Source("\n".join(code)).compile() in miniglobals + return miniglobals['f'] + +wrap_builtin_operation._annspecialcase_ = 'specialize:memo' + +def eval_arithmetic(engine, query): + query = query.getvalue(engine.frame) + if isinstance(query, term.Number): + return query + if isinstance(query, term.Float): + return norm_float(query.num) + if isinstance(query, term.Atom): + #XXX beautify that + if query.name == "pi": + return term.Float(math.pi) + if query.name == "e": + return term.Float(math.e) + raise error.UncatchableError("not implemented") + if isinstance(query, term.Term): + func = arithmetic_functions.get(query.signature, None) + if func is None: + error.throw_type_error("evaluable", query.get_prolog_signature()) + return func(engine, query) + raise error.UncatchableError("not implemented") + +def norm_float(v): + if v == int(v): + return term.Number(int(v)) + else: + return term.Float(v) + +simple_functions = [ + ("+", ["expr", "expr"], "v0 + v1", True), + ("-", ["expr", "expr"], "v0 - v1", True), + ("*", ["expr", "expr"], "v0 * v1", True), + ("//", ["int", "int"], "v0 / v1", True), + ("**", ["expr", "expr"], "v0 ** v1", True), + (">>", ["int", "int"], "v0 >> v1", False), + ("<<", ["int", "int"], "intmask(v0 << v1)", False), + ("\\/", ["int", "int"], "v0 | v1", False), + ("/\\", ["int", "int"], "v0 & v1", False), + ("xor", ["int", "int"], "v0 ^ v1", False), + ("mod", ["int", "int"], "v0 % v1", False), + ("\\", ["int"], "v0 ^ 0", False), + ("abs", ["expr"], "abs(v0)", True), +# ("max", ["expr", "expr"], "max(v0, v1)", False), +# ("min", ["expr", "expr"], "min(v0, v1)", False), + ("round", ["expr"], "int(v0 + 0.5)", False), + ("floor", ["expr"], "math.floor(v0)", False), + ("ceiling", ["expr"], "math.ceil(v0)", False), + ("floor", ["expr"], "math.floor(v0)", False), + ("float_fractional_part", ["expr"], "v0 - int(v0)", False), + ("float_integer_part", ["expr"], "int(v0)", False), +] + +for prolog_name, unwrap_spec, pattern, overflow in simple_functions: + f = wrap_builtin_operation(pattern, unwrap_spec, overflow) + signature = "%s/%s" % (prolog_name, len(unwrap_spec)) + arithmetic_functions[signature] = f Added: pypy/dist/pypy/lang/prolog/interpreter/choice.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/choice.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,102 @@ +import os +import py + +from py.magic import greenlet +from pypy.rpython.objectmodel import we_are_translated +from pypy.rpython.rstack import yield_current_frame_to_caller +from pypy.translator.c.test.test_stackless import StacklessTest + +from pypy.lang.prolog.interpreter.error import UnificationFailed, CutException + +def make_llframe(choice_point, func, args): + llframe = yield_current_frame_to_caller() + try: + choice_point.current = llframe + try: + func(*args) + except UnificationFailed: + choice_point.no_choice() + except Exception, e: + choice_point.exception = e + choice_point.switch_back() + except: + pass + os.write(0, "bad\n") + return llframe # will nexer be executed, help the translator +make_llframe._annspecialcase_ = "specialize:arg(1)" + +class ChoicePoint(object): + def __init__(self, engine, continuation, stop_cut=False): + self._init_current() + self.engine = engine + self.oldstate = engine.frame.branch() + self.continuation = continuation + self.stop_cut = stop_cut + self.any_choice = True + self.exception = None + + def _init_current(self): + if we_are_translated(): + self.current = None + else: + self.current = greenlet.getcurrent() + + def choose(self, last=False): + try: + self.do_continue() + except CutException, e: + if self.stop_cut: + self.continuation = e.continuation + else: + self.exception = e + except UnificationFailed: + self.engine.frame.revert(self.oldstate) + if last: + raise + return + self.switch_back() + assert 0 + + def chooselast(self): + self.do_continue() + + def no_choice(self): + self.exception = UnificationFailed() + + def switch(self, func, *args): + if we_are_translated(): + llframe = make_llframe(self, func, args) + llframe.switch() + else: + g = greenlet(func) + try: + g.switch(*args) + except UnificationFailed: + self.no_choice() + if self.exception is not None: + raise self.exception + switch._annspecialcase_ = "specialize:arg(1)" + + def switch_back(self): + self.current.switch() + + def do_continue(self): + self.continuation.run(self.engine) + +class RuleChoicePoint(ChoicePoint): + def __init__(self, query, engine, continuation, stop_cut=False): + ChoicePoint.__init__(self, engine, continuation, stop_cut) + self.query = query + self.rule = None + + def choose_rule(self, rule): + self.rule = rule + self.choose() + + def choose_last_rule(self, rule): + self.rule = rule + self.chooselast() + + def do_continue(self): + continuation = self.continuation + self.engine.try_rule(self.rule, self.query, continuation) Added: pypy/dist/pypy/lang/prolog/interpreter/conftest.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/conftest.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,10 @@ +import py, sys + +rootdir = py.magic.autopath().dirpath() + +Option = py.test.Config.Option + +option = py.test.Config.addoptions("prolog options", + Option('--slow', action="store_true", dest="slow", default=False, + help="view translation tests' flow graphs with Pygame"), + ) Added: pypy/dist/pypy/lang/prolog/interpreter/engine.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/engine.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,255 @@ +from pypy.lang.prolog.interpreter.term import Var, Term, Rule, Atom, debug_print, \ + Callable +from pypy.lang.prolog.interpreter.error import UnificationFailed, FunctionNotFound, \ + CutException +from pypy.lang.prolog.interpreter import error + +DEBUG = True + +class Continuation(object): + def call(self, engine): + pass + +DONOTHING = Continuation() + +class LimitedScopeContinuation(Continuation): + def __init__(self, continuation): + self.scope_active = True + self.continuation = continuation + + def call(self, engine): + self.scope_active = False + return self.continuation.call(engine) + +START_NUMBER_OF_VARS = 4096 + + +class Frame(object): + def __init__(self): + self.vars = [None] * START_NUMBER_OF_VARS + self.trail = [] + self.needed_vars = 0 + self.last_branch = 0 + + def clear(self, length): + l = max(START_NUMBER_OF_VARS, length) + self.vars = [None] * l + self.needed_vars = length + self.last_branch = length + self.trail = [] + + def getvar(self, index): + return self.vars[index] + + def setvar(self, index, val): + oldval = self.vars[index] + self.vars[index] = val + # only trail for variables that have a chance to get restored + # on the last choice point + if index < self.last_branch: + self.trail.append((index, oldval)) + + def branch(self): + old_last_branch = self.last_branch + self.last_branch = self.needed_vars + return len(self.trail), self.needed_vars, old_last_branch + + def revert(self, state): + trails, length, old_last_branch = state + assert length == self.last_branch + for i in range(len(self.trail) - 1, trails - 1, -1): + index, val = self.trail[i] + if index >= length: + val = None + self.vars[index] = val + for i in range(length, self.needed_vars): + self.vars[i] = None + del self.trail[trails:] + self.needed_vars = length + + def discard(self, state): + old_last_branch = state[2] + self.last_branch = old_last_branch + + def extend(self, numvars): + if numvars: + self.needed_vars += numvars + newvars = max(0, numvars - (len(self.vars) - self.needed_vars)) + if newvars == 0: + return + self.vars.extend([None] * (2 * newvars)) # allocate a bit more + assert self.needed_vars <= len(self.vars) + + def maxvar(self): + return self.needed_vars + +class Engine(object): + def __init__(self): + self.frame = Frame() + self.signature2rules = {} + self.parser = None + self.operations = None + + def add_rule(self, rule, end=True): + from prolog import builtin + if DEBUG: + debug_print("add_rule", rule) + if isinstance(rule, Term): + if rule.name == ":-": + rule = Rule(rule.args[0], rule.args[1]) + else: + rule = Rule(rule, None) + signature = rule.signature + elif isinstance(rule, Atom): + rule = Rule(rule, None) + signature = rule.signature + else: + error.throw_type_error("callable", rule) + assert 0, "unreachable" # XXX make annotator happy + if signature in builtin.builtins: + error.throw_permission_error( + "modify", "static_procedure", rule.head.get_prolog_signature()) + # it's important to not update the list in place, because + # there might be references to it in the stack somewhere + rules = self.signature2rules.get(signature, []) + if end: + self.signature2rules[signature] = rules + [rule] + else: + self.signature2rules[signature] = [rule] + rules + + def run(self, query, continuation=DONOTHING): + if not isinstance(query, Callable): + error.throw_type_error("callable", query) + vars = query.get_max_var() + 1 + self.frame.clear(vars) + try: + return self.call(query, continuation) + except CutException, e: + self.continue_after_cut(e.continuation) + + def _build_and_run(self, tree): + from pypy.lang.prolog.interpreter.parsing import TermBuilder + builder = TermBuilder() + term = builder.build_query(tree) + if isinstance(term, Term) and term.name == ":-" and len(term.args) == 1: + self.run(term.args[0]) + else: + self.add_rule(term) + return self.parser + + def runstring(self, s): + from pypy.lang.prolog.interpreter.parsing import parse_file + trees = parse_file(s, self.parser, Engine._build_and_run, self) + + def call(self, query, continuation=DONOTHING): + assert isinstance(query, Callable) + from pypy.lang.prolog.builtin import builtins + if DEBUG: + debug_print("calling", query) + signature = query.signature + # check for builtins + builtin = builtins.get(signature, None) + if builtin is not None: + return builtin(self, query, continuation) + # do a real call + return self.user_call(query, continuation) + + def user_call(self, query, continuation): + #import pdb; pdb.set_trace() + signature = query.signature + rules = self.signature2rules.get(signature, None) + if rules is None: + error.throw_existence_error( + "procedure", query.get_prolog_signature()) + unify_hash = query.get_deeper_unify_hash(self.frame) + rule, i = self.find_applicable_rule(0, rules, query, unify_hash) + if rule is None: + # none of the rules apply + raise UnificationFailed() + oldstate = self.frame.branch() + while 1: + next, i = self.find_applicable_rule(i, rules, query, unify_hash) + if next is None: + self.frame.discard(oldstate) + break + if rule.contains_cut: + continuation = LimitedScopeContinuation(continuation) + try: + result = self.try_rule(rule, query, continuation) + self.frame.discard(oldstate) + return result + except UnificationFailed: + self.frame.revert(oldstate) + except CutException, e: + if continuation.scope_active: + return self.continue_after_cut(e.continuation, + continuation) + raise + else: + try: + result = self.try_rule(rule, query, continuation) + self.frame.discard(oldstate) + return result + except UnificationFailed: + self.frame.revert(oldstate) + rule = next + if rule.contains_cut: + continuation = LimitedScopeContinuation(continuation) + try: + return self.try_rule(rule, query, continuation) + except CutException, e: + if continuation.scope_active: + self.continue_after_cut(e.continuation, continuation) + raise + return self.try_rule(rule, query, continuation) + + def try_rule(self, rule, query, continuation=DONOTHING): + if DEBUG: + debug_print("trying rule", rule, query, self.frame.vars[:self.frame.needed_vars]) + try: + # standardizing apart + nextcall = rule.clone_and_unify_head(self.frame, query) + except UnificationFailed: + if DEBUG: + debug_print("didn't work", rule, query, self.frame.vars[:self.frame.needed_vars]) + raise + if DEBUG: + debug_print("worked", rule, query, self.frame.vars[:self.frame.needed_vars]) + if nextcall is not None: + return self.call(nextcall, continuation) + return continuation.call(self) + + def find_applicable_rule(self, startindex, rules, query, uh1): + i = startindex + while i < len(rules): + uh2 = rules[i].unify_hash + assert len(uh1) == len(uh2) + for j in range(len(uh1)): + if uh1[j] != 0 and uh2[j] != 0 and uh1[j] != uh2[j]: + break + else: + return rules[i], i + 1 + i += 1 + return None, 0 + + def continue_after_cut(self, continuation, lsc=None): + while 1: + try: + return continuation.call(self) + except CutException, e: + if lsc is not None and not lsc.scope_active: + raise + continuation = e.continuation + + def parse(self, s): + from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder, lexer + builder = TermBuilder() + trees = parse_file(s, self.parser) + terms = builder.build_many(trees) + return terms, builder.var_to_pos + + def getoperations(self): + from pypy.lang.prolog.interpreter.parsing import default_operations + if self.operations is None: + return default_operations + return self.operations Added: pypy/dist/pypy/lang/prolog/interpreter/error.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/error.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,73 @@ +class PrologError(Exception): + pass + +class CatchableError(PrologError): + def __init__(self, errorterm): + from pypy.lang.prolog.interpreter import term + self.term = term.Term("error", [errorterm]) + +class UserError(CatchableError): + def __init__(self, errorterm): + self.term = errorterm + +class UncatchableError(PrologError): + def __init__(self, message): + self.message = message + +class UnificationFailed(PrologError): + pass + +class FunctionNotFound(PrologError): + def __init__(self, signature): + self.signature = signature + +class CutException(PrologError): + def __init__(self, continuation): + self.continuation = continuation + + pass + +def throw_instantiation_error(): + from pypy.lang.prolog.interpreter import term + raise CatchableError(term.Atom("instantiation_error")) + +def throw_type_error(valid_type, obj): + from pypy.lang.prolog.interpreter import term + # valid types are: + # atom, atomic, byte, callable, character + # evaluable, in_byte, in_character, integer, list + # number, predicate_indicator, variable + from pypy.lang.prolog.interpreter import term + raise CatchableError( + term.Term("type_error", [term.Atom(valid_type), obj])) + +def throw_domain_error(valid_domain, obj): + from pypy.lang.prolog.interpreter import term + # valid domains are: + # character_code_list, close_option, flag_value, io_mode, + # not_empty_list, not_less_than_zero, operator_priority, + # operator_specifier, prolog_flag, read_option, source_sink, + # stream, stream_option, stream_or_alias, stream_position, + # stream_property, write_option + raise CatchableError( + term.Term("domain_error", [term.Atom(valid_domain), obj])) + +def throw_existence_error(object_type, obj): + from pypy.lang.prolog.interpreter import term + # valid types are: + # procedure, source_sink, stream + raise CatchableError( + term.Term("existence_error", [term.Atom(object_type), obj])) + +def throw_permission_error(operation, permission_type, obj): + from pypy.lang.prolog.interpreter import term + # valid operations are: + # access, create, input, modify, open, output, reposition + + # valid permission_types are: + # binary_stream, flag, operator, past_end_of_stream, private_procedure, + # static_procedure, source_sink, stream, text_stream. + raise CatchableError( + term.Term("permission_error", [term.Atom(operation), + term.Atom(permission_type), + obj])) Added: pypy/dist/pypy/lang/prolog/interpreter/helper.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/helper.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,76 @@ +""" Helper functions for dealing with prolog lists""" + +from pypy.lang.prolog.interpreter import term +from pypy.lang.prolog.interpreter import error + +def wrap_list(python_list): + curr = term.Atom("[]") + for i in range(len(python_list) - 1, -1, -1): + curr = term.Term(".", [python_list[i], curr]) + return curr + +def unwrap_list(prolog_list): + result = [] + curr = prolog_list + while isinstance(curr, term.Term): + if not curr.name == ".": + error.throw_type_error("list", prolog_list) + result.append(curr.args[0]) + curr = curr.args[1] + if isinstance(curr, term.Atom) and curr.name == "[]": + return result + error.throw_type_error("list", prolog_list) + +def is_callable(var, engine): + return isinstance(var, term.Callable) + +def ensure_callable(var): + if isinstance(var, term.Callable): + return var + error.throw_type_error("callable", var) + +def unwrap_int(obj): + if isinstance(obj, term.Number): + return obj.num + elif isinstance(obj, term.Float): + f = obj.num; i = int(f) + if f == i: + return i + error.throw_type_error('integer', obj) + +def unwrap_atom(obj): + if isinstance(obj, term.Atom): + return obj.name + error.throw_type_error('atom', obj) + +def unwrap_predicate_indicator(predicate): + if not isinstance(predicate, term.Term): + error.throw_type_error("predicate_indicator", predicate) + assert 0, "unreachable" + if not predicate.name == "/" or len(predicate.args) != 2: + error.throw_type_error("predicate_indicator", predicate) + name = unwrap_atom(predicate.args[0]) + arity = unwrap_int(predicate.args[1]) + return name, arity + +def ensure_atomic(obj): + if not is_atomic(obj): + error.throw_type_error('atomic', obj) + return obj + +def is_atomic(obj): + return (isinstance(obj, term.Atom) or isinstance(obj, term.Float) or + isinstance(obj, term.Number)) + + +def convert_to_str(obj): + if isinstance(obj, term.Var): + error.throw_instantiation_error() + if isinstance(obj, term.Atom): + return obj.name + elif isinstance(obj, term.Number): + return str(obj.num) + elif isinstance(obj, term.Float): + return str(obj.num) + error.throw_type_error("atomic", obj) + Added: pypy/dist/pypy/lang/prolog/interpreter/main.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/main.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,201 @@ +#!/usr/bin/env python +import py +import sys +sys.path.append(str(py.magic.autopath().dirpath().dirpath())) + +from pypy.rlib.parsing.parsing import ParseError +from pypy.rlib.parsing.deterministic import LexerError +from pypy.lang.prolog.interpreter.parsing import parse_file, get_query_and_vars +from pypy.lang.prolog.interpreter.parsing import get_engine +from pypy.lang.prolog.interpreter.engine import Engine +from pypy.lang.prolog.interpreter.engine import Continuation +from pypy.lang.prolog.interpreter import error +import pypy.lang.prolog.interpreter.term +pypy.lang.prolog.interpreter.term.DEBUG = False + +import code + +helptext = """ + ';': redo + 'p': print + 'h': help + +""" + +class StopItNow(Exception): + pass + +class ContinueContinuation(Continuation): + def __init__(self, var_to_pos, write): + self.var_to_pos = var_to_pos + self.write = write + + def call(self, engine): + self.write("yes\n") + var_representation(self.var_to_pos, engine, self.write) + while 1: + res = getch() + self.write(res+"\n") + if res in "\r\x04": + self.write("\n") + raise StopItNow() + if res in ";nr": + raise error.UnificationFailed + elif res in "h?": + self.write(helptext) + elif res in "p": + var_representation(self.var_to_pos, engine, self.write) + else: + self.write('unknown action. press "h" for help\n') + +def var_representation(var_to_pos, engine, write): + from pypy.lang.prolog.builtin.formatting import TermFormatter + f = TermFormatter(engine, quoted=True, max_depth=10) + vars = var_to_pos.items() + vars.sort() + frame = engine.frame + for var, real_var in vars: + if var.startswith("_"): + continue + val = real_var.getvalue(frame) + write("%s = %s\n" % (var, f.format(val))) + +class PrologConsole(code.InteractiveConsole): + def __init__(self, engine): + code.InteractiveConsole.__init__(self, {}) + del self.__dict__['compile'] + self.engine = engine + + def compile(self, source, filename="", symbol="single"): + try: + if not source.strip(): + return None, None + return get_query_and_vars(source) + except ParseError, e: + #print e + # fake a Python syntax error :-) + absoffset = e.args[1][-1] + lines = source.split("\n") + curroffset = 0 + for i, line in enumerate(lines): + if curroffset <= absoffset < curroffset + len(line) + 1: + break + curroffset = curroffset + len(line) + 1 + if source.strip().endswith("."): + raise SyntaxError( + "syntax error", + (filename, i+1, absoffset - curroffset, line)) + return None + except LexerError, e: + # fake a Python syntax error + absoffset = e.index + lines = source.split("\n") + curroffset = 0 + for i, line in enumerate(lines): + if curroffset <= absoffset < curroffset + len(line) + 1: + break + curroffset = curroffset + len(line) + 1 + raise SyntaxError( + "token error", (filename, i + 1, absoffset - curroffset, line)) + + def runcode(self, code): + try: + query, var_to_pos = code + if query is None: + return + self.engine.run(query, ContinueContinuation(var_to_pos, self.write)) + except error.UnificationFailed: + self.write("no\n") + except error.CatchableError, e: + self.write("ERROR: ") + if e.term.args[0].name == "instantiation_error": + print e.term + self.write("arguments not sufficiently instantiated\n") + elif e.term.args[0].name == "existence_error": + print e.term + self.write("Undefined %s: %s\n" % (e.term.args[0].args[0], + e.term.args[0].args[1])) + else: + self.write("of unknown type: %s\n" % (e.term, )) + except error.UncatchableError, e: + self.write("INTERNAL ERROR: %s\n" % (e.message, )) + except StopItNow: + self.write("yes\n") + + def showtracebach(self): + self.write("traceback. boooring. nothing to see here") + + +class _Getch(object): + """Gets a single character from standard input. Does not echo to the +screen.""" + def __init__(self): + try: + import msvcrt + self.impl = self.get_windows + except ImportError: + try: + import tty, sys, termios + self.impl = self.get_unix + except ImportError: + import Carbon, Carbon.Evt + self.impl = self.get_carbon + + def __call__(self): + return self.impl() + + def get_unix(self): + import sys, tty, termios + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch + + def get_windows(self): + import msvcrt + return msvcrt.getch() + + + def get_carbon(self): + """ + A function which returns the current ASCII key that is down; + if no ASCII key is down, the null string is returned. The + page http://www.mactech.com/macintosh-c/chap02-1.html was + very helpful in figuring out how to do this. + """ + import Carbon + if Carbon.Evt.EventAvail(0x0008)[0]==0: # 0x0008 is the keyDownMask + return '' + else: + # The message (msg) contains the ASCII char which is + # extracted with the 0x000000FF charCodeMask; this + # number is converted to an ASCII character with chr() and + # returned + (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1] + return chr(msg & 0x000000FF) + + +getch = _Getch() + + +if __name__ == '__main__': + import readline + oldps1 = getattr(sys, "ps1", ">>> ") + oldps2 = getattr(sys, "ps2", "... ") + try: + sys.ps1 = ">?- " + sys.ps2 = "... " + if not len(sys.argv) == 2: + e = Engine() + else: + e = get_engine(py.path.local(sys.argv[1]).read()) + c = PrologConsole(e) + c.interact("PyPy Prolog Console") + finally: + sys.ps1 = oldps1 + sys.ps2 = oldps2 + Added: pypy/dist/pypy/lang/prolog/interpreter/parsing.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/parsing.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,3416 @@ +import py +from pypy.rlib.parsing.ebnfparse import parse_ebnf +from pypy.rlib.parsing.regexparse import parse_regex +from pypy.rlib.parsing.lexer import Lexer, DummyLexer +from pypy.rlib.parsing.deterministic import DFA +from pypy.rlib.parsing.tree import Nonterminal, Symbol, RPythonVisitor +from pypy.rlib.parsing.parsing import PackratParser, LazyParseTable, Rule +from pypy.rlib.parsing.regex import StringExpression + +def make_regexes(): + regexs = [ + ("VAR", parse_regex("[A-Z_]([a-zA-Z0-9]|_)*|_")), + ("NUMBER", parse_regex("(0|[1-9][0-9]*)(\.[0-9]+)?")), + ("IGNORE", parse_regex( + "[ \\n\\t]|(/\\*[^\\*]*(\\*[^/][^\\*]*)*\\*/)|(%[^\\n]*)")), + ("ATOM", parse_regex("([a-z]([a-zA-Z0-9]|_)*)|('[^']*')|\[\]|!|\+|\-")), + ("(", parse_regex("\(")), + (")", parse_regex("\)")), + ("[", parse_regex("\[")), + ("]", parse_regex("\]")), + (".", parse_regex("\.")), + ("|", parse_regex("\|")), + ] + return zip(*regexs) + +basic_rules = [ + Rule('query', [['toplevel_op_expr', '.', 'EOF']]), + Rule('fact', [['toplevel_op_expr', '.']]), + Rule('complexterm', [['ATOM', '(', 'toplevel_op_expr', ')'], ['expr']]), + Rule('expr', + [['VAR'], + ['NUMBER'], + ['+', 'NUMBER'], + ['-', 'NUMBER'], + ['ATOM'], + ['(', 'toplevel_op_expr', ')'], + ['listexpr'], + ]), + Rule('listexpr', [['[', 'listbody', ']']]), + Rule('listbody', + [['toplevel_op_expr', '|', 'toplevel_op_expr'], + ['toplevel_op_expr']]) + ] + +# x: term with priority lower than f +# y: term with priority lower or equal than f +# possible types: xf yf xfx xfy yfx yfy fy fx +# priorities: A > B +# +# binaryops +# (1) xfx: A -> B f B | B +# (2) xfy: A -> B f A | B +# (3) yfx: A -> A f B | B +# (4) yfy: A -> A f A | B +# +# unaryops +# (5) fx: A -> f A | B +# (6) fy: A -> f B | B +# (7) xf: A -> B f | B +# (8) yf: A -> A f | B + +def make_default_operations(): + operations = [ + (1200, [("xfx", ["-->", ":-"]), + ("fx", [":-", "?-"])]), + (1100, [("xfy", [";"])]), + (1050, [("xfy", ["->"])]), + (1000, [("xfy", [","])]), + (900, [("fy", ["\\+"]), + ("fx", ["~"])]), + (700, [("xfx", ["<", "=", "=..", "=@=", "=:=", "=<", "==", "=\=", ">", + ">=", "@<", "@=<", "@>", "@>=", "\=", "\==", "is"])]), + (600, [("xfy", [":"])]), + (500, [("yfx", ["+", "-", "/\\", "\\/", "xor"]), + ( "fx", ["+", "-", "?", "\\"])]), + (400, [("yfx", ["*", "/", "//", "<<", ">>", "mod", "rem"])]), + (200, [("xfx", ["**"]), ("xfy", ["^"])]), + ] + return operations + +default_operations = make_default_operations() + +import sys +sys.setrecursionlimit(10000) + +def make_from_form(form, op, x, y): + result = [] + for c in form: + if c == 'x': + result.append(x) + if c == 'y': + result.append(y) + if c == 'f': + result.append(op) + return result + +def make_expansion(y, x, allops): + expansions = [] + for form, ops in allops: + for op in ops: + expansion = make_from_form(form, op, x, y) + expansions.append(expansion) + expansions.append([x]) + return expansions + +def eliminate_immediate_left_recursion(symbol, expansions): + newsymbol = "extra%s" % (symbol, ) + newexpansions = [] + with_recursion = [expansion for expansion in expansions + if expansion[0] == symbol] + without_recursion = [expansion for expansion in expansions + if expansion[0] != symbol] + expansions = [expansion + [newsymbol] for expansion in without_recursion] + newexpansions = [expansion[1:] + [newsymbol] + for expansion in with_recursion] + newexpansions.append([]) + return expansions, newexpansions, newsymbol + +def make_all_rules(standard_rules, operations=None): + if operations is None: + operations = default_operations + all_rules = standard_rules[:] + for i in range(len(operations)): + precedence, allops = operations[i] + if i == 0: + y = "toplevel_op_expr" + else: + y = "expr%s" % (precedence, ) + if i != len(operations) - 1: + x = "expr%s" % (operations[i + 1][0], ) + else: + x = "complexterm" + expansions = make_expansion(y, x, allops) + tup = eliminate_immediate_left_recursion(y, expansions) + expansions, extra_expansions, extra_symbol = tup + all_rules.append(Rule(extra_symbol, extra_expansions)) + all_rules.append(Rule(y, expansions)) + return all_rules + +def add_necessary_regexs(regexs, names, operations=None): + if operations is None: + operations = default_operations + regexs = regexs[:] + names = names[:] + for precedence, allops in operations: + for form, ops in allops: + for op in ops: + regexs.insert(-1, StringExpression(op)) + names.insert(-1, "ATOM") + return regexs, names + +class PrologParseTable(LazyParseTable): + def terminal_equality(self, symbol, input): + if input[0] == "ATOM": + return symbol == "ATOM" or symbol == input[1] + return symbol == input[0] + +class PrologPackratParser(PackratParser): + def __init__(self, rules, startsymbol): + PackratParser.__init__(self, rules, startsymbol, PrologParseTable, + check_for_left_recursion=False) + +def make_basic_rules(): + names, regexs = make_regexes() + return basic_rules, names, regexs + +def make_parser(basic_rules, names, regexs): + real_rules = make_all_rules(basic_rules) +# for r in real_rules: +# print r + regexs, names = add_necessary_regexs(list(regexs), list(names)) + lexer = Lexer(regexs, names, ignore=["IGNORE"]) + parser_fact = PrologPackratParser(real_rules, "fact") + parser_query = PrologPackratParser(real_rules, "query") + return lexer, parser_fact, parser_query, basic_rules + +def make_all(): + return make_parser(*make_basic_rules()) + +def make_parser_at_runtime(operations): + real_rules = make_all_rules(basic_rules, operations) + parser_fact = PrologPackratParser(real_rules, "fact") + return parser_fact + +def _dummyfunc(arg, tree): + return parser_fact + +def parse_file(s, parser=None, callback=_dummyfunc, arg=None): + tokens = lexer.tokenize(s) + lines = [] + line = [] + for tok in tokens: + line.append(tok) + if tok[0] == ".": + lines.append(line) + line = [] + if parser is None: + parser = parser_fact + trees = [] + for line in lines: + tree = parser.parse(line, lazy=False) + if callback is not None: + # XXX ugh + parser = callback(arg, tree) + if parser is None: + parser = parser_fact + trees.append(tree) + return trees + +def parse_query(s): + tokens = lexer.tokenize(s, eof=True) + s = parser_query.parse(tokens, lazy=False) + +def parse_query_term(s): + return get_query_and_vars(s)[0] + +def get_query_and_vars(s): + tokens = lexer.tokenize(s, eof=True) + s = parser_query.parse(tokens, lazy=False) + builder = TermBuilder() + query = builder.build(s) + return query, builder.var_to_pos + +class OrderTransformer(object): + def transform(self, node): + if isinstance(node, Symbol): + return node + if isinstance(node, Nonterminal): + if len(node.children) == 1: + return Nonterminal( + node.symbol, [self.transform(node.children[0])]) + if len(node.children) == 2 or len(node.children) == 3: + left = node.children[-2] + right = node.children[-1] + if (isinstance(right, Nonterminal) and + right.symbol.startswith("extraexpr")): + if len(node.children) == 2: + leftreplacement = self.transform(left) + else: + leftreplacement = Nonterminal( + node.symbol, + [self.transform(node.children[0]), + self.transform(left)]) + children = [leftreplacement, + self.transform(right.children[0]), + self.transform(right.children[1])] + + newnode = Nonterminal(node.symbol, children) + return self.transform_extra(right, newnode) + children = [self.transform(child) for child in node.children] + return Nonterminal(node.symbol, children) + + def transform_extra(self, extranode, child): + symbol = extranode.symbol[5:] + if len(extranode.children) == 2: + return child + right = extranode.children[2] + assert isinstance(right, Nonterminal) + children = [child, + self.transform(right.children[0]), + self.transform(right.children[1])] + newnode = Nonterminal(symbol, children) + return self.transform_extra(right, newnode) + +class TermBuilder(RPythonVisitor): + + def __init__(self): + self.var_to_pos = {} + self.freevar = 0 + + def build(self, s): + "NOT_RPYTHON" + if isinstance(s, list): + return self.build_many(s) + return self.build_query(s) + + def build_many(self, trees): + ot = OrderTransformer() + facts = [] + for tree in trees: + s = ot.transform(tree) + facts.append(self.build_fact(s)) + return facts + + def build_query(self, s): + ot = OrderTransformer() + s = ot.transform(s) + return self.visit(s.children[0]) + + def build_fact(self, node): + self.var_to_pos = {} + self.freevar = 0 + return self.visit(node.children[0]) + + def visit(self, node): + node = self.find_first_interesting(node) + return self.dispatch(node) + + def general_nonterminal_visit(self, node): + from pypy.lang.prolog.interpreter.term import Term, Number, Float + children = [] + name = "" + for child in node.children: + if isinstance(child, Symbol): + name = self.general_symbol_visit(child).name + else: + children.append(child) + children = [self.visit(child) for child in children] + if len(children) == 1 and (name == "-" or name == "+"): + if name == "-": + factor = -1 + else: + factor = 1 + child = children[0] + if isinstance(child, Number): + return Number(factor * child.num) + if isinstance(child, Float): + return Float(factor * child.num) + return Term(name, children) + + def build_list(self, node): + node = self.find_first_interesting(node) + if isinstance(node, Nonterminal): + child = node.children[1] + if (isinstance(child, Symbol) and + node.children[1].additional_info == ","): + element = self.visit(node.children[0]) + l = self.build_list(node.children[2]) + l.insert(0, element) + return l + return [self.visit(node)] + + def find_first_interesting(self, node): + if isinstance(node, Nonterminal) and len(node.children) == 1: + return self.find_first_interesting(node.children[0]) + return node + + def general_symbol_visit(self, node): + from pypy.lang.prolog.interpreter.term import Atom + if node.additional_info.startswith("'"): + end = len(node.additional_info) - 1 + assert end >= 0 + name = unescape(node.additional_info[1:end]) + else: + name = node.additional_info + return Atom(name) + + def visit_VAR(self, node): + from pypy.lang.prolog.interpreter.term import Var + varname = node.additional_info + if varname == "_": + pos = self.freevar + self.freevar += 1 + return Var(pos) + if varname in self.var_to_pos: + return self.var_to_pos[varname] + res = Var(self.freevar) + self.freevar += 1 + self.var_to_pos[varname] = res + return res + + def visit_NUMBER(self, node): + from pypy.lang.prolog.interpreter.term import Number, Float + s = node.additional_info + try: + return Number(int(s)) + except ValueError: + # XXX float is not supported by the rtyper yet :-( + # return Float(float(s)) + from pypy.objspace.std.strutil import break_up_float + from pypy.rlib.rarithmetic import parts_to_float + a, b, c, d = break_up_float(s) + return Float(parts_to_float(a, b, c, d)) + + def visit_complexterm(self, node): + from pypy.lang.prolog.interpreter.term import Term + name = self.general_symbol_visit(node.children[0]).name + children = self.build_list(node.children[2]) + return Term(name, children) + + def visit_expr(self, node): + from pypy.lang.prolog.interpreter.term import Number, Float + if node.children[0].additional_info == '-': + result = self.visit(node.children[1]) + if isinstance(result, Number): + return Number(-result.num) + elif isinstance(result, Float): + return Float(-result.num) + return self.visit(node.children[1]) + + def visit_listexpr(self, node): + from pypy.lang.prolog.interpreter.term import Atom, Term + node = node.children[1] + if len(node.children) == 1: + l = self.build_list(node) + start = Atom("[]") + else: + l = self.build_list(node.children[0]) + start = self.visit(node.children[2]) + l.reverse() + curr = start + for elt in l: + curr = Term(".", [elt, curr]) + return curr + + +ESCAPES = { + "\\a": "\a", + "\\b": "\b", + "\\f": "\f", + "\\n": "\n", + "\\r": "\r", + "\\t": "\t", + "\\v": "\v", + "\\\\": "\\" +} + + +def unescape(s): + if "\\" not in s: + return s + result = [] + i = 0 + escape = False + while i < len(s): + c = s[i] + if escape: + escape = False + f = "\\" + c + if f in ESCAPES: + result.append(ESCAPES[f]) + else: + result.append(c) + elif c == "\\": + escape = True + else: + result.append(c) + i += 1 + return "".join(result) + +def get_engine(source): + from pypy.lang.prolog.interpreter.engine import Engine + trees = parse_file(source) + builder = TermBuilder() + e = Engine() + for fact in builder.build_many(trees): + e.add_rule(fact) + return e + +# generated code between this line and its other occurence + +parser_fact = PrologPackratParser([Rule('query', [['toplevel_op_expr', '.', 'EOF']]), + Rule('fact', [['toplevel_op_expr', '.']]), + Rule('complexterm', [['ATOM', '(', 'toplevel_op_expr', ')'], ['expr']]), + Rule('expr', [['VAR'], ['NUMBER'], ['+', 'NUMBER'], ['-', 'NUMBER'], ['ATOM'], ['(', 'toplevel_op_expr', ')'], ['listexpr']]), + Rule('listexpr', [['[', 'listbody', ']']]), + Rule('listbody', [['toplevel_op_expr', '|', 'toplevel_op_expr'], ['toplevel_op_expr']]), + Rule('extratoplevel_op_expr', [[]]), + Rule('toplevel_op_expr', [['expr1100', '-->', 'expr1100', 'extratoplevel_op_expr'], ['expr1100', ':-', 'expr1100', 'extratoplevel_op_expr'], [':-', 'expr1100', 'extratoplevel_op_expr'], ['?-', 'expr1100', 'extratoplevel_op_expr'], ['expr1100', 'extratoplevel_op_expr']]), + Rule('extraexpr1100', [[]]), + Rule('expr1100', [['expr1050', ';', 'expr1100', 'extraexpr1100'], ['expr1050', 'extraexpr1100']]), + Rule('extraexpr1050', [[]]), + Rule('expr1050', [['expr1000', '->', 'expr1050', 'extraexpr1050'], ['expr1000', 'extraexpr1050']]), + Rule('extraexpr1000', [[]]), + Rule('expr1000', [['expr900', ',', 'expr1000', 'extraexpr1000'], ['expr900', 'extraexpr1000']]), + Rule('extraexpr900', [[]]), + Rule('expr900', [['\\+', 'expr900', 'extraexpr900'], ['~', 'expr700', 'extraexpr900'], ['expr700', 'extraexpr900']]), + Rule('extraexpr700', [[]]), + Rule('expr700', [['expr600', '<', 'expr600', 'extraexpr700'], ['expr600', '=', 'expr600', 'extraexpr700'], ['expr600', '=..', 'expr600', 'extraexpr700'], ['expr600', '=@=', 'expr600', 'extraexpr700'], ['expr600', '=:=', 'expr600', 'extraexpr700'], ['expr600', '=<', 'expr600', 'extraexpr700'], ['expr600', '==', 'expr600', 'extraexpr700'], ['expr600', '=\\=', 'expr600', 'extraexpr700'], ['expr600', '>', 'expr600', 'extraexpr700'], ['expr600', '>=', 'expr600', 'extraexpr700'], ['expr600', '@<', 'expr600', 'extraexpr700'], ['expr600', '@=<', 'expr600', 'extraexpr700'], ['expr600', '@>', 'expr600', 'extraexpr700'], ['expr600', '@>=', 'expr600', 'extraexpr700'], ['expr600', '\\=', 'expr600', 'extraexpr700'], ['expr600', '\\==', 'expr600', 'extraexpr700'], ['expr600', 'is', 'expr600', 'extraexpr700'], ['expr600', 'extraexpr700']]), + Rule('extraexpr600', [[]]), + Rule('expr600', [['expr500', ':', 'expr600', 'extraexpr600'], ['expr500', 'extraexpr600']]), + Rule('extraexpr500', [['+', 'expr400', 'extraexpr500'], ['-', 'expr400', 'extraexpr500'], ['/\\', 'expr400', 'extraexpr500'], ['\\/', 'expr400', 'extraexpr500'], ['xor', 'expr400', 'extraexpr500'], []]), + Rule('expr500', [['+', 'expr400', 'extraexpr500'], ['-', 'expr400', 'extraexpr500'], ['?', 'expr400', 'extraexpr500'], ['\\', 'expr400', 'extraexpr500'], ['expr400', 'extraexpr500']]), + Rule('extraexpr400', [['*', 'expr200', 'extraexpr400'], ['/', 'expr200', 'extraexpr400'], ['//', 'expr200', 'extraexpr400'], ['<<', 'expr200', 'extraexpr400'], ['>>', 'expr200', 'extraexpr400'], ['mod', 'expr200', 'extraexpr400'], ['rem', 'expr200', 'extraexpr400'], []]), + Rule('expr400', [['expr200', 'extraexpr400']]), + Rule('extraexpr200', [[]]), + Rule('expr200', [['complexterm', '**', 'complexterm', 'extraexpr200'], ['complexterm', '^', 'expr200', 'extraexpr200'], ['complexterm', 'extraexpr200']])], + 'fact') +parser_query = PrologPackratParser([Rule('query', [['toplevel_op_expr', '.', 'EOF']]), + Rule('fact', [['toplevel_op_expr', '.']]), + Rule('complexterm', [['ATOM', '(', 'toplevel_op_expr', ')'], ['expr']]), + Rule('expr', [['VAR'], ['NUMBER'], ['+', 'NUMBER'], ['-', 'NUMBER'], ['ATOM'], ['(', 'toplevel_op_expr', ')'], ['listexpr']]), + Rule('listexpr', [['[', 'listbody', ']']]), + Rule('listbody', [['toplevel_op_expr', '|', 'toplevel_op_expr'], ['toplevel_op_expr']]), + Rule('extratoplevel_op_expr', [[]]), + Rule('toplevel_op_expr', [['expr1100', '-->', 'expr1100', 'extratoplevel_op_expr'], ['expr1100', ':-', 'expr1100', 'extratoplevel_op_expr'], [':-', 'expr1100', 'extratoplevel_op_expr'], ['?-', 'expr1100', 'extratoplevel_op_expr'], ['expr1100', 'extratoplevel_op_expr']]), + Rule('extraexpr1100', [[]]), + Rule('expr1100', [['expr1050', ';', 'expr1100', 'extraexpr1100'], ['expr1050', 'extraexpr1100']]), + Rule('extraexpr1050', [[]]), + Rule('expr1050', [['expr1000', '->', 'expr1050', 'extraexpr1050'], ['expr1000', 'extraexpr1050']]), + Rule('extraexpr1000', [[]]), + Rule('expr1000', [['expr900', ',', 'expr1000', 'extraexpr1000'], ['expr900', 'extraexpr1000']]), + Rule('extraexpr900', [[]]), + Rule('expr900', [['\\+', 'expr900', 'extraexpr900'], ['~', 'expr700', 'extraexpr900'], ['expr700', 'extraexpr900']]), + Rule('extraexpr700', [[]]), + Rule('expr700', [['expr600', '<', 'expr600', 'extraexpr700'], ['expr600', '=', 'expr600', 'extraexpr700'], ['expr600', '=..', 'expr600', 'extraexpr700'], ['expr600', '=@=', 'expr600', 'extraexpr700'], ['expr600', '=:=', 'expr600', 'extraexpr700'], ['expr600', '=<', 'expr600', 'extraexpr700'], ['expr600', '==', 'expr600', 'extraexpr700'], ['expr600', '=\\=', 'expr600', 'extraexpr700'], ['expr600', '>', 'expr600', 'extraexpr700'], ['expr600', '>=', 'expr600', 'extraexpr700'], ['expr600', '@<', 'expr600', 'extraexpr700'], ['expr600', '@=<', 'expr600', 'extraexpr700'], ['expr600', '@>', 'expr600', 'extraexpr700'], ['expr600', '@>=', 'expr600', 'extraexpr700'], ['expr600', '\\=', 'expr600', 'extraexpr700'], ['expr600', '\\==', 'expr600', 'extraexpr700'], ['expr600', 'is', 'expr600', 'extraexpr700'], ['expr600', 'extraexpr700']]), + Rule('extraexpr600', [[]]), + Rule('expr600', [['expr500', ':', 'expr600', 'extraexpr600'], ['expr500', 'extraexpr600']]), + Rule('extraexpr500', [['+', 'expr400', 'extraexpr500'], ['-', 'expr400', 'extraexpr500'], ['/\\', 'expr400', 'extraexpr500'], ['\\/', 'expr400', 'extraexpr500'], ['xor', 'expr400', 'extraexpr500'], []]), + Rule('expr500', [['+', 'expr400', 'extraexpr500'], ['-', 'expr400', 'extraexpr500'], ['?', 'expr400', 'extraexpr500'], ['\\', 'expr400', 'extraexpr500'], ['expr400', 'extraexpr500']]), + Rule('extraexpr400', [['*', 'expr200', 'extraexpr400'], ['/', 'expr200', 'extraexpr400'], ['//', 'expr200', 'extraexpr400'], ['<<', 'expr200', 'extraexpr400'], ['>>', 'expr200', 'extraexpr400'], ['mod', 'expr200', 'extraexpr400'], ['rem', 'expr200', 'extraexpr400'], []]), + Rule('expr400', [['expr200', 'extraexpr400']]), + Rule('extraexpr200', [[]]), + Rule('expr200', [['complexterm', '**', 'complexterm', 'extraexpr200'], ['complexterm', '^', 'expr200', 'extraexpr200'], ['complexterm', 'extraexpr200']])], + 'query') +def recognize(runner, i): + assert i >= 0 + input = runner.text + state = 0 + while 1: + if state == 0: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 0 + return ~i + if char == '\t': + state = 1 + elif char == '\n': + state = 1 + elif char == ' ': + state = 1 + elif char == '(': + state = 2 + elif char == ',': + state = 3 + elif char == '0': + state = 4 + elif '1' <= char <= '9': + state = 5 + elif char == '<': + state = 6 + elif char == '@': + state = 7 + elif 'A' <= char <= 'Z': + state = 8 + elif char == '_': + state = 8 + elif char == '\\': + state = 9 + elif 'a' <= char <= 'h': + state = 10 + elif 'j' <= char <= 'l': + state = 10 + elif 'n' <= char <= 'q': + state = 10 + elif 's' <= char <= 'w': + state = 10 + elif char == 'y': + state = 10 + elif char == 'z': + state = 10 + elif char == 'x': + state = 11 + elif char == '|': + state = 12 + elif char == "'": + state = 13 + elif char == '+': + state = 14 + elif char == '/': + state = 15 + elif char == ';': + state = 16 + elif char == '?': + state = 17 + elif char == '[': + state = 18 + elif char == '*': + state = 19 + elif char == '.': + state = 20 + elif char == ':': + state = 21 + elif char == '>': + state = 22 + elif char == '^': + state = 23 + elif char == 'r': + state = 24 + elif char == '~': + state = 25 + elif char == '!': + state = 26 + elif char == '%': + state = 27 + elif char == ')': + state = 28 + elif char == '-': + state = 29 + elif char == '=': + state = 30 + elif char == ']': + state = 31 + elif char == 'i': + state = 32 + elif char == 'm': + state = 33 + else: + break + if state == 4: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 4 + return i + if char == '.': + state = 73 + else: + break + if state == 5: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 5 + return i + if char == '.': + state = 73 + elif '0' <= char <= '9': + state = 5 + continue + else: + break + if state == 6: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 6 + return i + if char == '<': + state = 72 + else: + break + if state == 7: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 7 + return ~i + if char == '=': + state = 67 + elif char == '<': + state = 68 + elif char == '>': + state = 69 + else: + break + if state == 8: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 8 + return i + if '0' <= char <= '9': + state = 8 + continue + elif 'A' <= char <= 'Z': + state = 8 + continue + elif char == '_': + state = 8 + continue + elif 'a' <= char <= 'z': + state = 8 + continue + else: + break + if state == 9: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 9 + return i + if char == '=': + state = 64 + elif char == '/': + state = 65 + elif char == '+': + state = 63 + else: + break + if state == 10: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 10 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'z': + state = 10 + continue + else: + break + if state == 11: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 11 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'n': + state = 10 + continue + elif 'p' <= char <= 'z': + state = 10 + continue + elif char == 'o': + state = 61 + else: + break + if state == 13: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 13 + return ~i + if char == "'": + state = 26 + elif '\x00' <= char <= '&': + state = 13 + continue + elif '(' <= char <= '\xff': + state = 13 + continue + else: + break + if state == 15: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 15 + return i + if char == '*': + state = 57 + elif char == '\\': + state = 58 + elif char == '/': + state = 59 + else: + break + if state == 17: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 17 + return i + if char == '-': + state = 56 + else: + break + if state == 18: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 18 + return i + if char == ']': + state = 26 + else: + break + if state == 19: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 19 + return i + if char == '*': + state = 55 + else: + break + if state == 21: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 21 + return i + if char == '-': + state = 54 + else: + break + if state == 22: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 22 + return i + if char == '=': + state = 52 + elif char == '>': + state = 53 + else: + break + if state == 24: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 24 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'd': + state = 10 + continue + elif 'f' <= char <= 'z': + state = 10 + continue + elif char == 'e': + state = 50 + else: + break + if state == 27: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 27 + return i + if '\x00' <= char <= '\t': + state = 27 + continue + elif '\x0b' <= char <= '\xff': + state = 27 + continue + else: + break + if state == 29: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 29 + return i + if char == '>': + state = 48 + elif char == '-': + state = 47 + else: + break + if state == 30: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 30 + return i + if char == '@': + state = 37 + elif char == '<': + state = 38 + elif char == '.': + state = 39 + elif char == ':': + state = 40 + elif char == '=': + state = 41 + elif char == '\\': + state = 42 + else: + break + if state == 32: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 32 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'r': + state = 10 + continue + elif 't' <= char <= 'z': + state = 10 + continue + elif char == 's': + state = 36 + else: + break + if state == 33: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 33 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'n': + state = 10 + continue + elif 'p' <= char <= 'z': + state = 10 + continue + elif char == 'o': + state = 34 + else: + break + if state == 34: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 34 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'c': + state = 10 + continue + elif 'e' <= char <= 'z': + state = 10 + continue + elif char == 'd': + state = 35 + else: + break + if state == 35: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 35 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'z': + state = 10 + continue + else: + break + if state == 36: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 36 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'z': + state = 10 + continue + else: + break + if state == 37: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 37 + return ~i + if char == '=': + state = 46 + else: + break + if state == 39: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 39 + return ~i + if char == '.': + state = 45 + else: + break + if state == 40: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 40 + return ~i + if char == '=': + state = 44 + else: + break + if state == 42: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 42 + return ~i + if char == '=': + state = 43 + else: + break + if state == 47: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 47 + return ~i + if char == '>': + state = 49 + else: + break + if state == 50: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 50 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'l': + state = 10 + continue + elif 'n' <= char <= 'z': + state = 10 + continue + elif char == 'm': + state = 51 + else: + break + if state == 51: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 51 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'z': + state = 10 + continue + else: + break + if state == 57: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 57 + return ~i + if '\x00' <= char <= ')': + state = 57 + continue + elif '+' <= char <= '\xff': + state = 57 + continue + elif char == '*': + state = 60 + else: + break + if state == 60: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 60 + return ~i + if '\x00' <= char <= '.': + state = 57 + continue + elif '0' <= char <= '\xff': + state = 57 + continue + elif char == '/': + state = 1 + else: + break + if state == 61: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 61 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'q': + state = 10 + continue + elif 's' <= char <= 'z': + state = 10 + continue + elif char == 'r': + state = 62 + else: + break + if state == 62: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 62 + return i + if '0' <= char <= '9': + state = 10 + continue + elif 'A' <= char <= 'Z': + state = 10 + continue + elif char == '_': + state = 10 + continue + elif 'a' <= char <= 'z': + state = 10 + continue + else: + break + if state == 64: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 64 + return i + if char == '=': + state = 66 + else: + break + if state == 67: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 67 + return ~i + if char == '<': + state = 71 + else: + break + if state == 69: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 69 + return i + if char == '=': + state = 70 + else: + break + if state == 73: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 73 + return ~i + if '0' <= char <= '9': + state = 74 + else: + break + if state == 74: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 74 + return i + if '0' <= char <= '9': + state = 74 + continue + else: + break + runner.last_matched_state = state + runner.last_matched_index = i - 1 + runner.state = state + if i == len(input): + return i + else: + return ~i + break + runner.state = state + return ~i +lexer = DummyLexer(recognize, DFA(75, + {(0, '\t'): 1, + (0, '\n'): 1, + (0, ' '): 1, + (0, '!'): 26, + (0, '%'): 27, + (0, "'"): 13, + (0, '('): 2, + (0, ')'): 28, + (0, '*'): 19, + (0, '+'): 14, + (0, ','): 3, + (0, '-'): 29, + (0, '.'): 20, + (0, '/'): 15, + (0, '0'): 4, + (0, '1'): 5, + (0, '2'): 5, + (0, '3'): 5, + (0, '4'): 5, + (0, '5'): 5, + (0, '6'): 5, + (0, '7'): 5, + (0, '8'): 5, + (0, '9'): 5, + (0, ':'): 21, + (0, ';'): 16, + (0, '<'): 6, + (0, '='): 30, + (0, '>'): 22, + (0, '?'): 17, + (0, '@'): 7, + (0, 'A'): 8, + (0, 'B'): 8, + (0, 'C'): 8, + (0, 'D'): 8, + (0, 'E'): 8, + (0, 'F'): 8, + (0, 'G'): 8, + (0, 'H'): 8, + (0, 'I'): 8, + (0, 'J'): 8, + (0, 'K'): 8, + (0, 'L'): 8, + (0, 'M'): 8, + (0, 'N'): 8, + (0, 'O'): 8, + (0, 'P'): 8, + (0, 'Q'): 8, + (0, 'R'): 8, + (0, 'S'): 8, + (0, 'T'): 8, + (0, 'U'): 8, + (0, 'V'): 8, + (0, 'W'): 8, + (0, 'X'): 8, + (0, 'Y'): 8, + (0, 'Z'): 8, + (0, '['): 18, + (0, '\\'): 9, + (0, ']'): 31, + (0, '^'): 23, + (0, '_'): 8, + (0, 'a'): 10, + (0, 'b'): 10, + (0, 'c'): 10, + (0, 'd'): 10, + (0, 'e'): 10, + (0, 'f'): 10, + (0, 'g'): 10, + (0, 'h'): 10, + (0, 'i'): 32, + (0, 'j'): 10, + (0, 'k'): 10, + (0, 'l'): 10, + (0, 'm'): 33, + (0, 'n'): 10, + (0, 'o'): 10, + (0, 'p'): 10, + (0, 'q'): 10, + (0, 'r'): 24, + (0, 's'): 10, + (0, 't'): 10, + (0, 'u'): 10, + (0, 'v'): 10, + (0, 'w'): 10, + (0, 'x'): 11, + (0, 'y'): 10, + (0, 'z'): 10, + (0, '|'): 12, + (0, '~'): 25, + (4, '.'): 73, + (5, '.'): 73, + (5, '0'): 5, + (5, '1'): 5, + (5, '2'): 5, + (5, '3'): 5, + (5, '4'): 5, + (5, '5'): 5, + (5, '6'): 5, + (5, '7'): 5, + (5, '8'): 5, + (5, '9'): 5, + (6, '<'): 72, + (7, '<'): 68, + (7, '='): 67, + (7, '>'): 69, + (8, '0'): 8, + (8, '1'): 8, + (8, '2'): 8, + (8, '3'): 8, + (8, '4'): 8, + (8, '5'): 8, + (8, '6'): 8, + (8, '7'): 8, + (8, '8'): 8, + (8, '9'): 8, + (8, 'A'): 8, + (8, 'B'): 8, + (8, 'C'): 8, + (8, 'D'): 8, + (8, 'E'): 8, + (8, 'F'): 8, + (8, 'G'): 8, + (8, 'H'): 8, + (8, 'I'): 8, + (8, 'J'): 8, + (8, 'K'): 8, + (8, 'L'): 8, + (8, 'M'): 8, + (8, 'N'): 8, + (8, 'O'): 8, + (8, 'P'): 8, + (8, 'Q'): 8, + (8, 'R'): 8, + (8, 'S'): 8, + (8, 'T'): 8, + (8, 'U'): 8, + (8, 'V'): 8, + (8, 'W'): 8, + (8, 'X'): 8, + (8, 'Y'): 8, + (8, 'Z'): 8, + (8, '_'): 8, + (8, 'a'): 8, + (8, 'b'): 8, + (8, 'c'): 8, + (8, 'd'): 8, + (8, 'e'): 8, + (8, 'f'): 8, + (8, 'g'): 8, + (8, 'h'): 8, + (8, 'i'): 8, + (8, 'j'): 8, + (8, 'k'): 8, + (8, 'l'): 8, + (8, 'm'): 8, + (8, 'n'): 8, + (8, 'o'): 8, + (8, 'p'): 8, + (8, 'q'): 8, + (8, 'r'): 8, + (8, 's'): 8, + (8, 't'): 8, + (8, 'u'): 8, + (8, 'v'): 8, + (8, 'w'): 8, + (8, 'x'): 8, + (8, 'y'): 8, + (8, 'z'): 8, + (9, '+'): 63, + (9, '/'): 65, + (9, '='): 64, + (10, '0'): 10, + (10, '1'): 10, + (10, '2'): 10, + (10, '3'): 10, + (10, '4'): 10, + (10, '5'): 10, + (10, '6'): 10, + (10, '7'): 10, + (10, '8'): 10, + (10, '9'): 10, + (10, 'A'): 10, + (10, 'B'): 10, + (10, 'C'): 10, + (10, 'D'): 10, + (10, 'E'): 10, + (10, 'F'): 10, + (10, 'G'): 10, + (10, 'H'): 10, + (10, 'I'): 10, + (10, 'J'): 10, + (10, 'K'): 10, + (10, 'L'): 10, + (10, 'M'): 10, + (10, 'N'): 10, + (10, 'O'): 10, + (10, 'P'): 10, + (10, 'Q'): 10, + (10, 'R'): 10, + (10, 'S'): 10, + (10, 'T'): 10, + (10, 'U'): 10, + (10, 'V'): 10, + (10, 'W'): 10, + (10, 'X'): 10, + (10, 'Y'): 10, + (10, 'Z'): 10, + (10, '_'): 10, + (10, 'a'): 10, + (10, 'b'): 10, + (10, 'c'): 10, + (10, 'd'): 10, + (10, 'e'): 10, + (10, 'f'): 10, + (10, 'g'): 10, + (10, 'h'): 10, + (10, 'i'): 10, + (10, 'j'): 10, + (10, 'k'): 10, + (10, 'l'): 10, + (10, 'm'): 10, + (10, 'n'): 10, + (10, 'o'): 10, + (10, 'p'): 10, + (10, 'q'): 10, + (10, 'r'): 10, + (10, 's'): 10, + (10, 't'): 10, + (10, 'u'): 10, + (10, 'v'): 10, + (10, 'w'): 10, + (10, 'x'): 10, + (10, 'y'): 10, + (10, 'z'): 10, + (11, '0'): 10, + (11, '1'): 10, + (11, '2'): 10, + (11, '3'): 10, + (11, '4'): 10, + (11, '5'): 10, + (11, '6'): 10, + (11, '7'): 10, + (11, '8'): 10, + (11, '9'): 10, + (11, 'A'): 10, + (11, 'B'): 10, + (11, 'C'): 10, + (11, 'D'): 10, + (11, 'E'): 10, + (11, 'F'): 10, + (11, 'G'): 10, + (11, 'H'): 10, + (11, 'I'): 10, + (11, 'J'): 10, + (11, 'K'): 10, + (11, 'L'): 10, + (11, 'M'): 10, + (11, 'N'): 10, + (11, 'O'): 10, + (11, 'P'): 10, + (11, 'Q'): 10, + (11, 'R'): 10, + (11, 'S'): 10, + (11, 'T'): 10, + (11, 'U'): 10, + (11, 'V'): 10, + (11, 'W'): 10, + (11, 'X'): 10, + (11, 'Y'): 10, + (11, 'Z'): 10, + (11, '_'): 10, + (11, 'a'): 10, + (11, 'b'): 10, + (11, 'c'): 10, + (11, 'd'): 10, + (11, 'e'): 10, + (11, 'f'): 10, + (11, 'g'): 10, + (11, 'h'): 10, + (11, 'i'): 10, + (11, 'j'): 10, + (11, 'k'): 10, + (11, 'l'): 10, + (11, 'm'): 10, + (11, 'n'): 10, + (11, 'o'): 61, + (11, 'p'): 10, + (11, 'q'): 10, + (11, 'r'): 10, + (11, 's'): 10, + (11, 't'): 10, + (11, 'u'): 10, + (11, 'v'): 10, + (11, 'w'): 10, + (11, 'x'): 10, + (11, 'y'): 10, + (11, 'z'): 10, + (13, '\x00'): 13, + (13, '\x01'): 13, + (13, '\x02'): 13, + (13, '\x03'): 13, + (13, '\x04'): 13, + (13, '\x05'): 13, + (13, '\x06'): 13, + (13, '\x07'): 13, + (13, '\x08'): 13, + (13, '\t'): 13, + (13, '\n'): 13, + (13, '\x0b'): 13, + (13, '\x0c'): 13, + (13, '\r'): 13, + (13, '\x0e'): 13, + (13, '\x0f'): 13, + (13, '\x10'): 13, + (13, '\x11'): 13, + (13, '\x12'): 13, + (13, '\x13'): 13, + (13, '\x14'): 13, + (13, '\x15'): 13, + (13, '\x16'): 13, + (13, '\x17'): 13, + (13, '\x18'): 13, + (13, '\x19'): 13, + (13, '\x1a'): 13, + (13, '\x1b'): 13, + (13, '\x1c'): 13, + (13, '\x1d'): 13, + (13, '\x1e'): 13, + (13, '\x1f'): 13, + (13, ' '): 13, + (13, '!'): 13, + (13, '"'): 13, + (13, '#'): 13, + (13, '$'): 13, + (13, '%'): 13, + (13, '&'): 13, + (13, "'"): 26, + (13, '('): 13, + (13, ')'): 13, + (13, '*'): 13, + (13, '+'): 13, + (13, ','): 13, + (13, '-'): 13, + (13, '.'): 13, + (13, '/'): 13, + (13, '0'): 13, + (13, '1'): 13, + (13, '2'): 13, + (13, '3'): 13, + (13, '4'): 13, + (13, '5'): 13, + (13, '6'): 13, + (13, '7'): 13, + (13, '8'): 13, + (13, '9'): 13, + (13, ':'): 13, + (13, ';'): 13, + (13, '<'): 13, + (13, '='): 13, + (13, '>'): 13, + (13, '?'): 13, + (13, '@'): 13, + (13, 'A'): 13, + (13, 'B'): 13, + (13, 'C'): 13, + (13, 'D'): 13, + (13, 'E'): 13, + (13, 'F'): 13, + (13, 'G'): 13, + (13, 'H'): 13, + (13, 'I'): 13, + (13, 'J'): 13, + (13, 'K'): 13, + (13, 'L'): 13, + (13, 'M'): 13, + (13, 'N'): 13, + (13, 'O'): 13, + (13, 'P'): 13, + (13, 'Q'): 13, + (13, 'R'): 13, + (13, 'S'): 13, + (13, 'T'): 13, + (13, 'U'): 13, + (13, 'V'): 13, + (13, 'W'): 13, + (13, 'X'): 13, + (13, 'Y'): 13, + (13, 'Z'): 13, + (13, '['): 13, + (13, '\\'): 13, + (13, ']'): 13, + (13, '^'): 13, + (13, '_'): 13, + (13, '`'): 13, + (13, 'a'): 13, + (13, 'b'): 13, + (13, 'c'): 13, + (13, 'd'): 13, + (13, 'e'): 13, + (13, 'f'): 13, + (13, 'g'): 13, + (13, 'h'): 13, + (13, 'i'): 13, + (13, 'j'): 13, + (13, 'k'): 13, + (13, 'l'): 13, + (13, 'm'): 13, + (13, 'n'): 13, + (13, 'o'): 13, + (13, 'p'): 13, + (13, 'q'): 13, + (13, 'r'): 13, + (13, 's'): 13, + (13, 't'): 13, + (13, 'u'): 13, + (13, 'v'): 13, + (13, 'w'): 13, + (13, 'x'): 13, + (13, 'y'): 13, + (13, 'z'): 13, + (13, '{'): 13, + (13, '|'): 13, + (13, '}'): 13, + (13, '~'): 13, + (13, '\x7f'): 13, + (13, '\x80'): 13, + (13, '\x81'): 13, + (13, '\x82'): 13, + (13, '\x83'): 13, + (13, '\x84'): 13, + (13, '\x85'): 13, + (13, '\x86'): 13, + (13, '\x87'): 13, + (13, '\x88'): 13, + (13, '\x89'): 13, + (13, '\x8a'): 13, + (13, '\x8b'): 13, + (13, '\x8c'): 13, + (13, '\x8d'): 13, + (13, '\x8e'): 13, + (13, '\x8f'): 13, + (13, '\x90'): 13, + (13, '\x91'): 13, + (13, '\x92'): 13, + (13, '\x93'): 13, + (13, '\x94'): 13, + (13, '\x95'): 13, + (13, '\x96'): 13, + (13, '\x97'): 13, + (13, '\x98'): 13, + (13, '\x99'): 13, + (13, '\x9a'): 13, + (13, '\x9b'): 13, + (13, '\x9c'): 13, + (13, '\x9d'): 13, + (13, '\x9e'): 13, + (13, '\x9f'): 13, + (13, '\xa0'): 13, + (13, '\xa1'): 13, + (13, '\xa2'): 13, + (13, '\xa3'): 13, + (13, '\xa4'): 13, + (13, '\xa5'): 13, + (13, '\xa6'): 13, + (13, '\xa7'): 13, + (13, '\xa8'): 13, + (13, '\xa9'): 13, + (13, '\xaa'): 13, + (13, '\xab'): 13, + (13, '\xac'): 13, + (13, '\xad'): 13, + (13, '\xae'): 13, + (13, '\xaf'): 13, + (13, '\xb0'): 13, + (13, '\xb1'): 13, + (13, '\xb2'): 13, + (13, '\xb3'): 13, + (13, '\xb4'): 13, + (13, '\xb5'): 13, + (13, '\xb6'): 13, + (13, '\xb7'): 13, + (13, '\xb8'): 13, + (13, '\xb9'): 13, + (13, '\xba'): 13, + (13, '\xbb'): 13, + (13, '\xbc'): 13, + (13, '\xbd'): 13, + (13, '\xbe'): 13, + (13, '\xbf'): 13, + (13, '\xc0'): 13, + (13, '\xc1'): 13, + (13, '\xc2'): 13, + (13, '\xc3'): 13, + (13, '\xc4'): 13, + (13, '\xc5'): 13, + (13, '\xc6'): 13, + (13, '\xc7'): 13, + (13, '\xc8'): 13, + (13, '\xc9'): 13, + (13, '\xca'): 13, + (13, '\xcb'): 13, + (13, '\xcc'): 13, + (13, '\xcd'): 13, + (13, '\xce'): 13, + (13, '\xcf'): 13, + (13, '\xd0'): 13, + (13, '\xd1'): 13, + (13, '\xd2'): 13, + (13, '\xd3'): 13, + (13, '\xd4'): 13, + (13, '\xd5'): 13, + (13, '\xd6'): 13, + (13, '\xd7'): 13, + (13, '\xd8'): 13, + (13, '\xd9'): 13, + (13, '\xda'): 13, + (13, '\xdb'): 13, + (13, '\xdc'): 13, + (13, '\xdd'): 13, + (13, '\xde'): 13, + (13, '\xdf'): 13, + (13, '\xe0'): 13, + (13, '\xe1'): 13, + (13, '\xe2'): 13, + (13, '\xe3'): 13, + (13, '\xe4'): 13, + (13, '\xe5'): 13, + (13, '\xe6'): 13, + (13, '\xe7'): 13, + (13, '\xe8'): 13, + (13, '\xe9'): 13, + (13, '\xea'): 13, + (13, '\xeb'): 13, + (13, '\xec'): 13, + (13, '\xed'): 13, + (13, '\xee'): 13, + (13, '\xef'): 13, + (13, '\xf0'): 13, + (13, '\xf1'): 13, + (13, '\xf2'): 13, + (13, '\xf3'): 13, + (13, '\xf4'): 13, + (13, '\xf5'): 13, + (13, '\xf6'): 13, + (13, '\xf7'): 13, + (13, '\xf8'): 13, + (13, '\xf9'): 13, + (13, '\xfa'): 13, + (13, '\xfb'): 13, + (13, '\xfc'): 13, + (13, '\xfd'): 13, + (13, '\xfe'): 13, + (13, '\xff'): 13, + (15, '*'): 57, + (15, '/'): 59, + (15, '\\'): 58, + (17, '-'): 56, + (18, ']'): 26, + (19, '*'): 55, + (21, '-'): 54, + (22, '='): 52, + (22, '>'): 53, + (24, '0'): 10, + (24, '1'): 10, + (24, '2'): 10, + (24, '3'): 10, + (24, '4'): 10, + (24, '5'): 10, + (24, '6'): 10, + (24, '7'): 10, + (24, '8'): 10, + (24, '9'): 10, + (24, 'A'): 10, + (24, 'B'): 10, + (24, 'C'): 10, + (24, 'D'): 10, + (24, 'E'): 10, + (24, 'F'): 10, + (24, 'G'): 10, + (24, 'H'): 10, + (24, 'I'): 10, + (24, 'J'): 10, + (24, 'K'): 10, + (24, 'L'): 10, + (24, 'M'): 10, + (24, 'N'): 10, + (24, 'O'): 10, + (24, 'P'): 10, + (24, 'Q'): 10, + (24, 'R'): 10, + (24, 'S'): 10, + (24, 'T'): 10, + (24, 'U'): 10, + (24, 'V'): 10, + (24, 'W'): 10, + (24, 'X'): 10, + (24, 'Y'): 10, + (24, 'Z'): 10, + (24, '_'): 10, + (24, 'a'): 10, + (24, 'b'): 10, + (24, 'c'): 10, + (24, 'd'): 10, + (24, 'e'): 50, + (24, 'f'): 10, + (24, 'g'): 10, + (24, 'h'): 10, + (24, 'i'): 10, + (24, 'j'): 10, + (24, 'k'): 10, + (24, 'l'): 10, + (24, 'm'): 10, + (24, 'n'): 10, + (24, 'o'): 10, + (24, 'p'): 10, + (24, 'q'): 10, + (24, 'r'): 10, + (24, 's'): 10, + (24, 't'): 10, + (24, 'u'): 10, + (24, 'v'): 10, + (24, 'w'): 10, + (24, 'x'): 10, + (24, 'y'): 10, + (24, 'z'): 10, + (27, '\x00'): 27, + (27, '\x01'): 27, + (27, '\x02'): 27, + (27, '\x03'): 27, + (27, '\x04'): 27, + (27, '\x05'): 27, + (27, '\x06'): 27, + (27, '\x07'): 27, + (27, '\x08'): 27, + (27, '\t'): 27, + (27, '\x0b'): 27, + (27, '\x0c'): 27, + (27, '\r'): 27, + (27, '\x0e'): 27, + (27, '\x0f'): 27, + (27, '\x10'): 27, + (27, '\x11'): 27, + (27, '\x12'): 27, + (27, '\x13'): 27, + (27, '\x14'): 27, + (27, '\x15'): 27, + (27, '\x16'): 27, + (27, '\x17'): 27, + (27, '\x18'): 27, + (27, '\x19'): 27, + (27, '\x1a'): 27, + (27, '\x1b'): 27, + (27, '\x1c'): 27, + (27, '\x1d'): 27, + (27, '\x1e'): 27, + (27, '\x1f'): 27, + (27, ' '): 27, + (27, '!'): 27, + (27, '"'): 27, + (27, '#'): 27, + (27, '$'): 27, + (27, '%'): 27, + (27, '&'): 27, + (27, "'"): 27, + (27, '('): 27, + (27, ')'): 27, + (27, '*'): 27, + (27, '+'): 27, + (27, ','): 27, + (27, '-'): 27, + (27, '.'): 27, + (27, '/'): 27, + (27, '0'): 27, + (27, '1'): 27, + (27, '2'): 27, + (27, '3'): 27, + (27, '4'): 27, + (27, '5'): 27, + (27, '6'): 27, + (27, '7'): 27, + (27, '8'): 27, + (27, '9'): 27, + (27, ':'): 27, + (27, ';'): 27, + (27, '<'): 27, + (27, '='): 27, + (27, '>'): 27, + (27, '?'): 27, + (27, '@'): 27, + (27, 'A'): 27, + (27, 'B'): 27, + (27, 'C'): 27, + (27, 'D'): 27, + (27, 'E'): 27, + (27, 'F'): 27, + (27, 'G'): 27, + (27, 'H'): 27, + (27, 'I'): 27, + (27, 'J'): 27, + (27, 'K'): 27, + (27, 'L'): 27, + (27, 'M'): 27, + (27, 'N'): 27, + (27, 'O'): 27, + (27, 'P'): 27, + (27, 'Q'): 27, + (27, 'R'): 27, + (27, 'S'): 27, + (27, 'T'): 27, + (27, 'U'): 27, + (27, 'V'): 27, + (27, 'W'): 27, + (27, 'X'): 27, + (27, 'Y'): 27, + (27, 'Z'): 27, + (27, '['): 27, + (27, '\\'): 27, + (27, ']'): 27, + (27, '^'): 27, + (27, '_'): 27, + (27, '`'): 27, + (27, 'a'): 27, + (27, 'b'): 27, + (27, 'c'): 27, + (27, 'd'): 27, + (27, 'e'): 27, + (27, 'f'): 27, + (27, 'g'): 27, + (27, 'h'): 27, + (27, 'i'): 27, + (27, 'j'): 27, + (27, 'k'): 27, + (27, 'l'): 27, + (27, 'm'): 27, + (27, 'n'): 27, + (27, 'o'): 27, + (27, 'p'): 27, + (27, 'q'): 27, + (27, 'r'): 27, + (27, 's'): 27, + (27, 't'): 27, + (27, 'u'): 27, + (27, 'v'): 27, + (27, 'w'): 27, + (27, 'x'): 27, + (27, 'y'): 27, + (27, 'z'): 27, + (27, '{'): 27, + (27, '|'): 27, + (27, '}'): 27, + (27, '~'): 27, + (27, '\x7f'): 27, + (27, '\x80'): 27, + (27, '\x81'): 27, + (27, '\x82'): 27, + (27, '\x83'): 27, + (27, '\x84'): 27, + (27, '\x85'): 27, + (27, '\x86'): 27, + (27, '\x87'): 27, + (27, '\x88'): 27, + (27, '\x89'): 27, + (27, '\x8a'): 27, + (27, '\x8b'): 27, + (27, '\x8c'): 27, + (27, '\x8d'): 27, + (27, '\x8e'): 27, + (27, '\x8f'): 27, + (27, '\x90'): 27, + (27, '\x91'): 27, + (27, '\x92'): 27, + (27, '\x93'): 27, + (27, '\x94'): 27, + (27, '\x95'): 27, + (27, '\x96'): 27, + (27, '\x97'): 27, + (27, '\x98'): 27, + (27, '\x99'): 27, + (27, '\x9a'): 27, + (27, '\x9b'): 27, + (27, '\x9c'): 27, + (27, '\x9d'): 27, + (27, '\x9e'): 27, + (27, '\x9f'): 27, + (27, '\xa0'): 27, + (27, '\xa1'): 27, + (27, '\xa2'): 27, + (27, '\xa3'): 27, + (27, '\xa4'): 27, + (27, '\xa5'): 27, + (27, '\xa6'): 27, + (27, '\xa7'): 27, + (27, '\xa8'): 27, + (27, '\xa9'): 27, + (27, '\xaa'): 27, + (27, '\xab'): 27, + (27, '\xac'): 27, + (27, '\xad'): 27, + (27, '\xae'): 27, + (27, '\xaf'): 27, + (27, '\xb0'): 27, + (27, '\xb1'): 27, + (27, '\xb2'): 27, + (27, '\xb3'): 27, + (27, '\xb4'): 27, + (27, '\xb5'): 27, + (27, '\xb6'): 27, + (27, '\xb7'): 27, + (27, '\xb8'): 27, + (27, '\xb9'): 27, + (27, '\xba'): 27, + (27, '\xbb'): 27, + (27, '\xbc'): 27, + (27, '\xbd'): 27, + (27, '\xbe'): 27, + (27, '\xbf'): 27, + (27, '\xc0'): 27, + (27, '\xc1'): 27, + (27, '\xc2'): 27, + (27, '\xc3'): 27, + (27, '\xc4'): 27, + (27, '\xc5'): 27, + (27, '\xc6'): 27, + (27, '\xc7'): 27, + (27, '\xc8'): 27, + (27, '\xc9'): 27, + (27, '\xca'): 27, + (27, '\xcb'): 27, + (27, '\xcc'): 27, + (27, '\xcd'): 27, + (27, '\xce'): 27, + (27, '\xcf'): 27, + (27, '\xd0'): 27, + (27, '\xd1'): 27, + (27, '\xd2'): 27, + (27, '\xd3'): 27, + (27, '\xd4'): 27, + (27, '\xd5'): 27, + (27, '\xd6'): 27, + (27, '\xd7'): 27, + (27, '\xd8'): 27, + (27, '\xd9'): 27, + (27, '\xda'): 27, + (27, '\xdb'): 27, + (27, '\xdc'): 27, + (27, '\xdd'): 27, + (27, '\xde'): 27, + (27, '\xdf'): 27, + (27, '\xe0'): 27, + (27, '\xe1'): 27, + (27, '\xe2'): 27, + (27, '\xe3'): 27, + (27, '\xe4'): 27, + (27, '\xe5'): 27, + (27, '\xe6'): 27, + (27, '\xe7'): 27, + (27, '\xe8'): 27, + (27, '\xe9'): 27, + (27, '\xea'): 27, + (27, '\xeb'): 27, + (27, '\xec'): 27, + (27, '\xed'): 27, + (27, '\xee'): 27, + (27, '\xef'): 27, + (27, '\xf0'): 27, + (27, '\xf1'): 27, + (27, '\xf2'): 27, + (27, '\xf3'): 27, + (27, '\xf4'): 27, + (27, '\xf5'): 27, + (27, '\xf6'): 27, + (27, '\xf7'): 27, + (27, '\xf8'): 27, + (27, '\xf9'): 27, + (27, '\xfa'): 27, + (27, '\xfb'): 27, + (27, '\xfc'): 27, + (27, '\xfd'): 27, + (27, '\xfe'): 27, + (27, '\xff'): 27, + (29, '-'): 47, + (29, '>'): 48, + (30, '.'): 39, + (30, ':'): 40, + (30, '<'): 38, + (30, '='): 41, + (30, '@'): 37, + (30, '\\'): 42, + (32, '0'): 10, + (32, '1'): 10, + (32, '2'): 10, + (32, '3'): 10, + (32, '4'): 10, + (32, '5'): 10, + (32, '6'): 10, + (32, '7'): 10, + (32, '8'): 10, + (32, '9'): 10, + (32, 'A'): 10, + (32, 'B'): 10, + (32, 'C'): 10, + (32, 'D'): 10, + (32, 'E'): 10, + (32, 'F'): 10, + (32, 'G'): 10, + (32, 'H'): 10, + (32, 'I'): 10, + (32, 'J'): 10, + (32, 'K'): 10, + (32, 'L'): 10, + (32, 'M'): 10, + (32, 'N'): 10, + (32, 'O'): 10, + (32, 'P'): 10, + (32, 'Q'): 10, + (32, 'R'): 10, + (32, 'S'): 10, + (32, 'T'): 10, + (32, 'U'): 10, + (32, 'V'): 10, + (32, 'W'): 10, + (32, 'X'): 10, + (32, 'Y'): 10, + (32, 'Z'): 10, + (32, '_'): 10, + (32, 'a'): 10, + (32, 'b'): 10, + (32, 'c'): 10, + (32, 'd'): 10, + (32, 'e'): 10, + (32, 'f'): 10, + (32, 'g'): 10, + (32, 'h'): 10, + (32, 'i'): 10, + (32, 'j'): 10, + (32, 'k'): 10, + (32, 'l'): 10, + (32, 'm'): 10, + (32, 'n'): 10, + (32, 'o'): 10, + (32, 'p'): 10, + (32, 'q'): 10, + (32, 'r'): 10, + (32, 's'): 36, + (32, 't'): 10, + (32, 'u'): 10, + (32, 'v'): 10, + (32, 'w'): 10, + (32, 'x'): 10, + (32, 'y'): 10, + (32, 'z'): 10, + (33, '0'): 10, + (33, '1'): 10, + (33, '2'): 10, + (33, '3'): 10, + (33, '4'): 10, + (33, '5'): 10, + (33, '6'): 10, + (33, '7'): 10, + (33, '8'): 10, + (33, '9'): 10, + (33, 'A'): 10, + (33, 'B'): 10, + (33, 'C'): 10, + (33, 'D'): 10, + (33, 'E'): 10, + (33, 'F'): 10, + (33, 'G'): 10, + (33, 'H'): 10, + (33, 'I'): 10, + (33, 'J'): 10, + (33, 'K'): 10, + (33, 'L'): 10, + (33, 'M'): 10, + (33, 'N'): 10, + (33, 'O'): 10, + (33, 'P'): 10, + (33, 'Q'): 10, + (33, 'R'): 10, + (33, 'S'): 10, + (33, 'T'): 10, + (33, 'U'): 10, + (33, 'V'): 10, + (33, 'W'): 10, + (33, 'X'): 10, + (33, 'Y'): 10, + (33, 'Z'): 10, + (33, '_'): 10, + (33, 'a'): 10, + (33, 'b'): 10, + (33, 'c'): 10, + (33, 'd'): 10, + (33, 'e'): 10, + (33, 'f'): 10, + (33, 'g'): 10, + (33, 'h'): 10, + (33, 'i'): 10, + (33, 'j'): 10, + (33, 'k'): 10, + (33, 'l'): 10, + (33, 'm'): 10, + (33, 'n'): 10, + (33, 'o'): 34, + (33, 'p'): 10, + (33, 'q'): 10, + (33, 'r'): 10, + (33, 's'): 10, + (33, 't'): 10, + (33, 'u'): 10, + (33, 'v'): 10, + (33, 'w'): 10, + (33, 'x'): 10, + (33, 'y'): 10, + (33, 'z'): 10, + (34, '0'): 10, + (34, '1'): 10, + (34, '2'): 10, + (34, '3'): 10, + (34, '4'): 10, + (34, '5'): 10, + (34, '6'): 10, + (34, '7'): 10, + (34, '8'): 10, + (34, '9'): 10, + (34, 'A'): 10, + (34, 'B'): 10, + (34, 'C'): 10, + (34, 'D'): 10, + (34, 'E'): 10, + (34, 'F'): 10, + (34, 'G'): 10, + (34, 'H'): 10, + (34, 'I'): 10, + (34, 'J'): 10, + (34, 'K'): 10, + (34, 'L'): 10, + (34, 'M'): 10, + (34, 'N'): 10, + (34, 'O'): 10, + (34, 'P'): 10, + (34, 'Q'): 10, + (34, 'R'): 10, + (34, 'S'): 10, + (34, 'T'): 10, + (34, 'U'): 10, + (34, 'V'): 10, + (34, 'W'): 10, + (34, 'X'): 10, + (34, 'Y'): 10, + (34, 'Z'): 10, + (34, '_'): 10, + (34, 'a'): 10, + (34, 'b'): 10, + (34, 'c'): 10, + (34, 'd'): 35, + (34, 'e'): 10, + (34, 'f'): 10, + (34, 'g'): 10, + (34, 'h'): 10, + (34, 'i'): 10, + (34, 'j'): 10, + (34, 'k'): 10, + (34, 'l'): 10, + (34, 'm'): 10, + (34, 'n'): 10, + (34, 'o'): 10, + (34, 'p'): 10, + (34, 'q'): 10, + (34, 'r'): 10, + (34, 's'): 10, + (34, 't'): 10, + (34, 'u'): 10, + (34, 'v'): 10, + (34, 'w'): 10, + (34, 'x'): 10, + (34, 'y'): 10, + (34, 'z'): 10, + (35, '0'): 10, + (35, '1'): 10, + (35, '2'): 10, + (35, '3'): 10, + (35, '4'): 10, + (35, '5'): 10, + (35, '6'): 10, + (35, '7'): 10, + (35, '8'): 10, + (35, '9'): 10, + (35, 'A'): 10, + (35, 'B'): 10, + (35, 'C'): 10, + (35, 'D'): 10, + (35, 'E'): 10, + (35, 'F'): 10, + (35, 'G'): 10, + (35, 'H'): 10, + (35, 'I'): 10, + (35, 'J'): 10, + (35, 'K'): 10, + (35, 'L'): 10, + (35, 'M'): 10, + (35, 'N'): 10, + (35, 'O'): 10, + (35, 'P'): 10, + (35, 'Q'): 10, + (35, 'R'): 10, + (35, 'S'): 10, + (35, 'T'): 10, + (35, 'U'): 10, + (35, 'V'): 10, + (35, 'W'): 10, + (35, 'X'): 10, + (35, 'Y'): 10, + (35, 'Z'): 10, + (35, '_'): 10, + (35, 'a'): 10, + (35, 'b'): 10, + (35, 'c'): 10, + (35, 'd'): 10, + (35, 'e'): 10, + (35, 'f'): 10, + (35, 'g'): 10, + (35, 'h'): 10, + (35, 'i'): 10, + (35, 'j'): 10, + (35, 'k'): 10, + (35, 'l'): 10, + (35, 'm'): 10, + (35, 'n'): 10, + (35, 'o'): 10, + (35, 'p'): 10, + (35, 'q'): 10, + (35, 'r'): 10, + (35, 's'): 10, + (35, 't'): 10, + (35, 'u'): 10, + (35, 'v'): 10, + (35, 'w'): 10, + (35, 'x'): 10, + (35, 'y'): 10, + (35, 'z'): 10, + (36, '0'): 10, + (36, '1'): 10, + (36, '2'): 10, + (36, '3'): 10, + (36, '4'): 10, + (36, '5'): 10, + (36, '6'): 10, + (36, '7'): 10, + (36, '8'): 10, + (36, '9'): 10, + (36, 'A'): 10, + (36, 'B'): 10, + (36, 'C'): 10, + (36, 'D'): 10, + (36, 'E'): 10, + (36, 'F'): 10, + (36, 'G'): 10, + (36, 'H'): 10, + (36, 'I'): 10, + (36, 'J'): 10, + (36, 'K'): 10, + (36, 'L'): 10, + (36, 'M'): 10, + (36, 'N'): 10, + (36, 'O'): 10, + (36, 'P'): 10, + (36, 'Q'): 10, + (36, 'R'): 10, + (36, 'S'): 10, + (36, 'T'): 10, + (36, 'U'): 10, + (36, 'V'): 10, + (36, 'W'): 10, + (36, 'X'): 10, + (36, 'Y'): 10, + (36, 'Z'): 10, + (36, '_'): 10, + (36, 'a'): 10, + (36, 'b'): 10, + (36, 'c'): 10, + (36, 'd'): 10, + (36, 'e'): 10, + (36, 'f'): 10, + (36, 'g'): 10, + (36, 'h'): 10, + (36, 'i'): 10, + (36, 'j'): 10, + (36, 'k'): 10, + (36, 'l'): 10, + (36, 'm'): 10, + (36, 'n'): 10, + (36, 'o'): 10, + (36, 'p'): 10, + (36, 'q'): 10, + (36, 'r'): 10, + (36, 's'): 10, + (36, 't'): 10, + (36, 'u'): 10, + (36, 'v'): 10, + (36, 'w'): 10, + (36, 'x'): 10, + (36, 'y'): 10, + (36, 'z'): 10, + (37, '='): 46, + (39, '.'): 45, + (40, '='): 44, + (42, '='): 43, + (47, '>'): 49, + (50, '0'): 10, + (50, '1'): 10, + (50, '2'): 10, + (50, '3'): 10, + (50, '4'): 10, + (50, '5'): 10, + (50, '6'): 10, + (50, '7'): 10, + (50, '8'): 10, + (50, '9'): 10, + (50, 'A'): 10, + (50, 'B'): 10, + (50, 'C'): 10, + (50, 'D'): 10, + (50, 'E'): 10, + (50, 'F'): 10, + (50, 'G'): 10, + (50, 'H'): 10, + (50, 'I'): 10, + (50, 'J'): 10, + (50, 'K'): 10, + (50, 'L'): 10, + (50, 'M'): 10, + (50, 'N'): 10, + (50, 'O'): 10, + (50, 'P'): 10, + (50, 'Q'): 10, + (50, 'R'): 10, + (50, 'S'): 10, + (50, 'T'): 10, + (50, 'U'): 10, + (50, 'V'): 10, + (50, 'W'): 10, + (50, 'X'): 10, + (50, 'Y'): 10, + (50, 'Z'): 10, + (50, '_'): 10, + (50, 'a'): 10, + (50, 'b'): 10, + (50, 'c'): 10, + (50, 'd'): 10, + (50, 'e'): 10, + (50, 'f'): 10, + (50, 'g'): 10, + (50, 'h'): 10, + (50, 'i'): 10, + (50, 'j'): 10, + (50, 'k'): 10, + (50, 'l'): 10, + (50, 'm'): 51, + (50, 'n'): 10, + (50, 'o'): 10, + (50, 'p'): 10, + (50, 'q'): 10, + (50, 'r'): 10, + (50, 's'): 10, + (50, 't'): 10, + (50, 'u'): 10, + (50, 'v'): 10, + (50, 'w'): 10, + (50, 'x'): 10, + (50, 'y'): 10, + (50, 'z'): 10, + (51, '0'): 10, + (51, '1'): 10, + (51, '2'): 10, + (51, '3'): 10, + (51, '4'): 10, + (51, '5'): 10, + (51, '6'): 10, + (51, '7'): 10, + (51, '8'): 10, + (51, '9'): 10, + (51, 'A'): 10, + (51, 'B'): 10, + (51, 'C'): 10, + (51, 'D'): 10, + (51, 'E'): 10, + (51, 'F'): 10, + (51, 'G'): 10, + (51, 'H'): 10, + (51, 'I'): 10, + (51, 'J'): 10, + (51, 'K'): 10, + (51, 'L'): 10, + (51, 'M'): 10, + (51, 'N'): 10, + (51, 'O'): 10, + (51, 'P'): 10, + (51, 'Q'): 10, + (51, 'R'): 10, + (51, 'S'): 10, + (51, 'T'): 10, + (51, 'U'): 10, + (51, 'V'): 10, + (51, 'W'): 10, + (51, 'X'): 10, + (51, 'Y'): 10, + (51, 'Z'): 10, + (51, '_'): 10, + (51, 'a'): 10, + (51, 'b'): 10, + (51, 'c'): 10, + (51, 'd'): 10, + (51, 'e'): 10, + (51, 'f'): 10, + (51, 'g'): 10, + (51, 'h'): 10, + (51, 'i'): 10, + (51, 'j'): 10, + (51, 'k'): 10, + (51, 'l'): 10, + (51, 'm'): 10, + (51, 'n'): 10, + (51, 'o'): 10, + (51, 'p'): 10, + (51, 'q'): 10, + (51, 'r'): 10, + (51, 's'): 10, + (51, 't'): 10, + (51, 'u'): 10, + (51, 'v'): 10, + (51, 'w'): 10, + (51, 'x'): 10, + (51, 'y'): 10, + (51, 'z'): 10, + (57, '\x00'): 57, + (57, '\x01'): 57, + (57, '\x02'): 57, + (57, '\x03'): 57, + (57, '\x04'): 57, + (57, '\x05'): 57, + (57, '\x06'): 57, + (57, '\x07'): 57, + (57, '\x08'): 57, + (57, '\t'): 57, + (57, '\n'): 57, + (57, '\x0b'): 57, + (57, '\x0c'): 57, + (57, '\r'): 57, + (57, '\x0e'): 57, + (57, '\x0f'): 57, + (57, '\x10'): 57, + (57, '\x11'): 57, + (57, '\x12'): 57, + (57, '\x13'): 57, + (57, '\x14'): 57, + (57, '\x15'): 57, + (57, '\x16'): 57, + (57, '\x17'): 57, + (57, '\x18'): 57, + (57, '\x19'): 57, + (57, '\x1a'): 57, + (57, '\x1b'): 57, + (57, '\x1c'): 57, + (57, '\x1d'): 57, + (57, '\x1e'): 57, + (57, '\x1f'): 57, + (57, ' '): 57, + (57, '!'): 57, + (57, '"'): 57, + (57, '#'): 57, + (57, '$'): 57, + (57, '%'): 57, + (57, '&'): 57, + (57, "'"): 57, + (57, '('): 57, + (57, ')'): 57, + (57, '*'): 60, + (57, '+'): 57, + (57, ','): 57, + (57, '-'): 57, + (57, '.'): 57, + (57, '/'): 57, + (57, '0'): 57, + (57, '1'): 57, + (57, '2'): 57, + (57, '3'): 57, + (57, '4'): 57, + (57, '5'): 57, + (57, '6'): 57, + (57, '7'): 57, + (57, '8'): 57, + (57, '9'): 57, + (57, ':'): 57, + (57, ';'): 57, + (57, '<'): 57, + (57, '='): 57, + (57, '>'): 57, + (57, '?'): 57, + (57, '@'): 57, + (57, 'A'): 57, + (57, 'B'): 57, + (57, 'C'): 57, + (57, 'D'): 57, + (57, 'E'): 57, + (57, 'F'): 57, + (57, 'G'): 57, + (57, 'H'): 57, + (57, 'I'): 57, + (57, 'J'): 57, + (57, 'K'): 57, + (57, 'L'): 57, + (57, 'M'): 57, + (57, 'N'): 57, + (57, 'O'): 57, + (57, 'P'): 57, + (57, 'Q'): 57, + (57, 'R'): 57, + (57, 'S'): 57, + (57, 'T'): 57, + (57, 'U'): 57, + (57, 'V'): 57, + (57, 'W'): 57, + (57, 'X'): 57, + (57, 'Y'): 57, + (57, 'Z'): 57, + (57, '['): 57, + (57, '\\'): 57, + (57, ']'): 57, + (57, '^'): 57, + (57, '_'): 57, + (57, '`'): 57, + (57, 'a'): 57, + (57, 'b'): 57, + (57, 'c'): 57, + (57, 'd'): 57, + (57, 'e'): 57, + (57, 'f'): 57, + (57, 'g'): 57, + (57, 'h'): 57, + (57, 'i'): 57, + (57, 'j'): 57, + (57, 'k'): 57, + (57, 'l'): 57, + (57, 'm'): 57, + (57, 'n'): 57, + (57, 'o'): 57, + (57, 'p'): 57, + (57, 'q'): 57, + (57, 'r'): 57, + (57, 's'): 57, + (57, 't'): 57, + (57, 'u'): 57, + (57, 'v'): 57, + (57, 'w'): 57, + (57, 'x'): 57, + (57, 'y'): 57, + (57, 'z'): 57, + (57, '{'): 57, + (57, '|'): 57, + (57, '}'): 57, + (57, '~'): 57, + (57, '\x7f'): 57, + (57, '\x80'): 57, + (57, '\x81'): 57, + (57, '\x82'): 57, + (57, '\x83'): 57, + (57, '\x84'): 57, + (57, '\x85'): 57, + (57, '\x86'): 57, + (57, '\x87'): 57, + (57, '\x88'): 57, + (57, '\x89'): 57, + (57, '\x8a'): 57, + (57, '\x8b'): 57, + (57, '\x8c'): 57, + (57, '\x8d'): 57, + (57, '\x8e'): 57, + (57, '\x8f'): 57, + (57, '\x90'): 57, + (57, '\x91'): 57, + (57, '\x92'): 57, + (57, '\x93'): 57, + (57, '\x94'): 57, + (57, '\x95'): 57, + (57, '\x96'): 57, + (57, '\x97'): 57, + (57, '\x98'): 57, + (57, '\x99'): 57, + (57, '\x9a'): 57, + (57, '\x9b'): 57, + (57, '\x9c'): 57, + (57, '\x9d'): 57, + (57, '\x9e'): 57, + (57, '\x9f'): 57, + (57, '\xa0'): 57, + (57, '\xa1'): 57, + (57, '\xa2'): 57, + (57, '\xa3'): 57, + (57, '\xa4'): 57, + (57, '\xa5'): 57, + (57, '\xa6'): 57, + (57, '\xa7'): 57, + (57, '\xa8'): 57, + (57, '\xa9'): 57, + (57, '\xaa'): 57, + (57, '\xab'): 57, + (57, '\xac'): 57, + (57, '\xad'): 57, + (57, '\xae'): 57, + (57, '\xaf'): 57, + (57, '\xb0'): 57, + (57, '\xb1'): 57, + (57, '\xb2'): 57, + (57, '\xb3'): 57, + (57, '\xb4'): 57, + (57, '\xb5'): 57, + (57, '\xb6'): 57, + (57, '\xb7'): 57, + (57, '\xb8'): 57, + (57, '\xb9'): 57, + (57, '\xba'): 57, + (57, '\xbb'): 57, + (57, '\xbc'): 57, + (57, '\xbd'): 57, + (57, '\xbe'): 57, + (57, '\xbf'): 57, + (57, '\xc0'): 57, + (57, '\xc1'): 57, + (57, '\xc2'): 57, + (57, '\xc3'): 57, + (57, '\xc4'): 57, + (57, '\xc5'): 57, + (57, '\xc6'): 57, + (57, '\xc7'): 57, + (57, '\xc8'): 57, + (57, '\xc9'): 57, + (57, '\xca'): 57, + (57, '\xcb'): 57, + (57, '\xcc'): 57, + (57, '\xcd'): 57, + (57, '\xce'): 57, + (57, '\xcf'): 57, + (57, '\xd0'): 57, + (57, '\xd1'): 57, + (57, '\xd2'): 57, + (57, '\xd3'): 57, + (57, '\xd4'): 57, + (57, '\xd5'): 57, + (57, '\xd6'): 57, + (57, '\xd7'): 57, + (57, '\xd8'): 57, + (57, '\xd9'): 57, + (57, '\xda'): 57, + (57, '\xdb'): 57, + (57, '\xdc'): 57, + (57, '\xdd'): 57, + (57, '\xde'): 57, + (57, '\xdf'): 57, + (57, '\xe0'): 57, + (57, '\xe1'): 57, + (57, '\xe2'): 57, + (57, '\xe3'): 57, + (57, '\xe4'): 57, + (57, '\xe5'): 57, + (57, '\xe6'): 57, + (57, '\xe7'): 57, + (57, '\xe8'): 57, + (57, '\xe9'): 57, + (57, '\xea'): 57, + (57, '\xeb'): 57, + (57, '\xec'): 57, + (57, '\xed'): 57, + (57, '\xee'): 57, + (57, '\xef'): 57, + (57, '\xf0'): 57, + (57, '\xf1'): 57, + (57, '\xf2'): 57, + (57, '\xf3'): 57, + (57, '\xf4'): 57, + (57, '\xf5'): 57, + (57, '\xf6'): 57, + (57, '\xf7'): 57, + (57, '\xf8'): 57, + (57, '\xf9'): 57, + (57, '\xfa'): 57, + (57, '\xfb'): 57, + (57, '\xfc'): 57, + (57, '\xfd'): 57, + (57, '\xfe'): 57, + (57, '\xff'): 57, + (60, '\x00'): 57, + (60, '\x01'): 57, + (60, '\x02'): 57, + (60, '\x03'): 57, + (60, '\x04'): 57, + (60, '\x05'): 57, + (60, '\x06'): 57, + (60, '\x07'): 57, + (60, '\x08'): 57, + (60, '\t'): 57, + (60, '\n'): 57, + (60, '\x0b'): 57, + (60, '\x0c'): 57, + (60, '\r'): 57, + (60, '\x0e'): 57, + (60, '\x0f'): 57, + (60, '\x10'): 57, + (60, '\x11'): 57, + (60, '\x12'): 57, + (60, '\x13'): 57, + (60, '\x14'): 57, + (60, '\x15'): 57, + (60, '\x16'): 57, + (60, '\x17'): 57, + (60, '\x18'): 57, + (60, '\x19'): 57, + (60, '\x1a'): 57, + (60, '\x1b'): 57, + (60, '\x1c'): 57, + (60, '\x1d'): 57, + (60, '\x1e'): 57, + (60, '\x1f'): 57, + (60, ' '): 57, + (60, '!'): 57, + (60, '"'): 57, + (60, '#'): 57, + (60, '$'): 57, + (60, '%'): 57, + (60, '&'): 57, + (60, "'"): 57, + (60, '('): 57, + (60, ')'): 57, + (60, '*'): 57, + (60, '+'): 57, + (60, ','): 57, + (60, '-'): 57, + (60, '.'): 57, + (60, '/'): 1, + (60, '0'): 57, + (60, '1'): 57, + (60, '2'): 57, + (60, '3'): 57, + (60, '4'): 57, + (60, '5'): 57, + (60, '6'): 57, + (60, '7'): 57, + (60, '8'): 57, + (60, '9'): 57, + (60, ':'): 57, + (60, ';'): 57, + (60, '<'): 57, + (60, '='): 57, + (60, '>'): 57, + (60, '?'): 57, + (60, '@'): 57, + (60, 'A'): 57, + (60, 'B'): 57, + (60, 'C'): 57, + (60, 'D'): 57, + (60, 'E'): 57, + (60, 'F'): 57, + (60, 'G'): 57, + (60, 'H'): 57, + (60, 'I'): 57, + (60, 'J'): 57, + (60, 'K'): 57, + (60, 'L'): 57, + (60, 'M'): 57, + (60, 'N'): 57, + (60, 'O'): 57, + (60, 'P'): 57, + (60, 'Q'): 57, + (60, 'R'): 57, + (60, 'S'): 57, + (60, 'T'): 57, + (60, 'U'): 57, + (60, 'V'): 57, + (60, 'W'): 57, + (60, 'X'): 57, + (60, 'Y'): 57, + (60, 'Z'): 57, + (60, '['): 57, + (60, '\\'): 57, + (60, ']'): 57, + (60, '^'): 57, + (60, '_'): 57, + (60, '`'): 57, + (60, 'a'): 57, + (60, 'b'): 57, + (60, 'c'): 57, + (60, 'd'): 57, + (60, 'e'): 57, + (60, 'f'): 57, + (60, 'g'): 57, + (60, 'h'): 57, + (60, 'i'): 57, + (60, 'j'): 57, + (60, 'k'): 57, + (60, 'l'): 57, + (60, 'm'): 57, + (60, 'n'): 57, + (60, 'o'): 57, + (60, 'p'): 57, + (60, 'q'): 57, + (60, 'r'): 57, + (60, 's'): 57, + (60, 't'): 57, + (60, 'u'): 57, + (60, 'v'): 57, + (60, 'w'): 57, + (60, 'x'): 57, + (60, 'y'): 57, + (60, 'z'): 57, + (60, '{'): 57, + (60, '|'): 57, + (60, '}'): 57, + (60, '~'): 57, + (60, '\x7f'): 57, + (60, '\x80'): 57, + (60, '\x81'): 57, + (60, '\x82'): 57, + (60, '\x83'): 57, + (60, '\x84'): 57, + (60, '\x85'): 57, + (60, '\x86'): 57, + (60, '\x87'): 57, + (60, '\x88'): 57, + (60, '\x89'): 57, + (60, '\x8a'): 57, + (60, '\x8b'): 57, + (60, '\x8c'): 57, + (60, '\x8d'): 57, + (60, '\x8e'): 57, + (60, '\x8f'): 57, + (60, '\x90'): 57, + (60, '\x91'): 57, + (60, '\x92'): 57, + (60, '\x93'): 57, + (60, '\x94'): 57, + (60, '\x95'): 57, + (60, '\x96'): 57, + (60, '\x97'): 57, + (60, '\x98'): 57, + (60, '\x99'): 57, + (60, '\x9a'): 57, + (60, '\x9b'): 57, + (60, '\x9c'): 57, + (60, '\x9d'): 57, + (60, '\x9e'): 57, + (60, '\x9f'): 57, + (60, '\xa0'): 57, + (60, '\xa1'): 57, + (60, '\xa2'): 57, + (60, '\xa3'): 57, + (60, '\xa4'): 57, + (60, '\xa5'): 57, + (60, '\xa6'): 57, + (60, '\xa7'): 57, + (60, '\xa8'): 57, + (60, '\xa9'): 57, + (60, '\xaa'): 57, + (60, '\xab'): 57, + (60, '\xac'): 57, + (60, '\xad'): 57, + (60, '\xae'): 57, + (60, '\xaf'): 57, + (60, '\xb0'): 57, + (60, '\xb1'): 57, + (60, '\xb2'): 57, + (60, '\xb3'): 57, + (60, '\xb4'): 57, + (60, '\xb5'): 57, + (60, '\xb6'): 57, + (60, '\xb7'): 57, + (60, '\xb8'): 57, + (60, '\xb9'): 57, + (60, '\xba'): 57, + (60, '\xbb'): 57, + (60, '\xbc'): 57, + (60, '\xbd'): 57, + (60, '\xbe'): 57, + (60, '\xbf'): 57, + (60, '\xc0'): 57, + (60, '\xc1'): 57, + (60, '\xc2'): 57, + (60, '\xc3'): 57, + (60, '\xc4'): 57, + (60, '\xc5'): 57, + (60, '\xc6'): 57, + (60, '\xc7'): 57, + (60, '\xc8'): 57, + (60, '\xc9'): 57, + (60, '\xca'): 57, + (60, '\xcb'): 57, + (60, '\xcc'): 57, + (60, '\xcd'): 57, + (60, '\xce'): 57, + (60, '\xcf'): 57, + (60, '\xd0'): 57, + (60, '\xd1'): 57, + (60, '\xd2'): 57, + (60, '\xd3'): 57, + (60, '\xd4'): 57, + (60, '\xd5'): 57, + (60, '\xd6'): 57, + (60, '\xd7'): 57, + (60, '\xd8'): 57, + (60, '\xd9'): 57, + (60, '\xda'): 57, + (60, '\xdb'): 57, + (60, '\xdc'): 57, + (60, '\xdd'): 57, + (60, '\xde'): 57, + (60, '\xdf'): 57, + (60, '\xe0'): 57, + (60, '\xe1'): 57, + (60, '\xe2'): 57, + (60, '\xe3'): 57, + (60, '\xe4'): 57, + (60, '\xe5'): 57, + (60, '\xe6'): 57, + (60, '\xe7'): 57, + (60, '\xe8'): 57, + (60, '\xe9'): 57, + (60, '\xea'): 57, + (60, '\xeb'): 57, + (60, '\xec'): 57, + (60, '\xed'): 57, + (60, '\xee'): 57, + (60, '\xef'): 57, + (60, '\xf0'): 57, + (60, '\xf1'): 57, + (60, '\xf2'): 57, + (60, '\xf3'): 57, + (60, '\xf4'): 57, + (60, '\xf5'): 57, + (60, '\xf6'): 57, + (60, '\xf7'): 57, + (60, '\xf8'): 57, + (60, '\xf9'): 57, + (60, '\xfa'): 57, + (60, '\xfb'): 57, + (60, '\xfc'): 57, + (60, '\xfd'): 57, + (60, '\xfe'): 57, + (60, '\xff'): 57, + (61, '0'): 10, + (61, '1'): 10, + (61, '2'): 10, + (61, '3'): 10, + (61, '4'): 10, + (61, '5'): 10, + (61, '6'): 10, + (61, '7'): 10, + (61, '8'): 10, + (61, '9'): 10, + (61, 'A'): 10, + (61, 'B'): 10, + (61, 'C'): 10, + (61, 'D'): 10, + (61, 'E'): 10, + (61, 'F'): 10, + (61, 'G'): 10, + (61, 'H'): 10, + (61, 'I'): 10, + (61, 'J'): 10, + (61, 'K'): 10, + (61, 'L'): 10, + (61, 'M'): 10, + (61, 'N'): 10, + (61, 'O'): 10, + (61, 'P'): 10, + (61, 'Q'): 10, + (61, 'R'): 10, + (61, 'S'): 10, + (61, 'T'): 10, + (61, 'U'): 10, + (61, 'V'): 10, + (61, 'W'): 10, + (61, 'X'): 10, + (61, 'Y'): 10, + (61, 'Z'): 10, + (61, '_'): 10, + (61, 'a'): 10, + (61, 'b'): 10, + (61, 'c'): 10, + (61, 'd'): 10, + (61, 'e'): 10, + (61, 'f'): 10, + (61, 'g'): 10, + (61, 'h'): 10, + (61, 'i'): 10, + (61, 'j'): 10, + (61, 'k'): 10, + (61, 'l'): 10, + (61, 'm'): 10, + (61, 'n'): 10, + (61, 'o'): 10, + (61, 'p'): 10, + (61, 'q'): 10, + (61, 'r'): 62, + (61, 's'): 10, + (61, 't'): 10, + (61, 'u'): 10, + (61, 'v'): 10, + (61, 'w'): 10, + (61, 'x'): 10, + (61, 'y'): 10, + (61, 'z'): 10, + (62, '0'): 10, + (62, '1'): 10, + (62, '2'): 10, + (62, '3'): 10, + (62, '4'): 10, + (62, '5'): 10, + (62, '6'): 10, + (62, '7'): 10, + (62, '8'): 10, + (62, '9'): 10, + (62, 'A'): 10, + (62, 'B'): 10, + (62, 'C'): 10, + (62, 'D'): 10, + (62, 'E'): 10, + (62, 'F'): 10, + (62, 'G'): 10, + (62, 'H'): 10, + (62, 'I'): 10, + (62, 'J'): 10, + (62, 'K'): 10, + (62, 'L'): 10, + (62, 'M'): 10, + (62, 'N'): 10, + (62, 'O'): 10, + (62, 'P'): 10, + (62, 'Q'): 10, + (62, 'R'): 10, + (62, 'S'): 10, + (62, 'T'): 10, + (62, 'U'): 10, + (62, 'V'): 10, + (62, 'W'): 10, + (62, 'X'): 10, + (62, 'Y'): 10, + (62, 'Z'): 10, + (62, '_'): 10, + (62, 'a'): 10, + (62, 'b'): 10, + (62, 'c'): 10, + (62, 'd'): 10, + (62, 'e'): 10, + (62, 'f'): 10, + (62, 'g'): 10, + (62, 'h'): 10, + (62, 'i'): 10, + (62, 'j'): 10, + (62, 'k'): 10, + (62, 'l'): 10, + (62, 'm'): 10, + (62, 'n'): 10, + (62, 'o'): 10, + (62, 'p'): 10, + (62, 'q'): 10, + (62, 'r'): 10, + (62, 's'): 10, + (62, 't'): 10, + (62, 'u'): 10, + (62, 'v'): 10, + (62, 'w'): 10, + (62, 'x'): 10, + (62, 'y'): 10, + (62, 'z'): 10, + (64, '='): 66, + (67, '<'): 71, + (69, '='): 70, + (73, '0'): 74, + (73, '1'): 74, + (73, '2'): 74, + (73, '3'): 74, + (73, '4'): 74, + (73, '5'): 74, + (73, '6'): 74, + (73, '7'): 74, + (73, '8'): 74, + (73, '9'): 74, + (74, '0'): 74, + (74, '1'): 74, + (74, '2'): 74, + (74, '3'): 74, + (74, '4'): 74, + (74, '5'): 74, + (74, '6'): 74, + (74, '7'): 74, + (74, '8'): 74, + (74, '9'): 74}, + set([1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 41, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 74]), + set([1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 41, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 74]), + ['0, start|, 0, start|, 0, 0, 0, 0, 0, start|, 0, 0, 0, start|, 0, start|, 0, start|, 0, 0, 0, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0', + 'IGNORE', + '(', + 'ATOM', + 'NUMBER', + 'NUMBER', + 'ATOM', + '1, 1, 1, 1', + 'VAR', + 'ATOM', + 'ATOM', + 'ATOM', + '|', + '0, 1, 0, start|, 0, final*, start*, 0, 0, 1, final|, start|, 0, final*, start*, 0, 0, final|, start|, 0, 1, final*, start*', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + '[', + 'ATOM', + '.', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'IGNORE', + ')', + 'ATOM', + 'ATOM', + ']', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + '2', + 'ATOM', + '2', + '2', + 'ATOM', + '2', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + '2', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'final*, start*, 1, 0, 0, start|, 0, final*, start*, 0, final*, start*, 0, 0, 1, final|, start|, 0, final*, start*, 0, final*, start*, 0, 0, final|, start|, 0, 1, final*, start*, 0, final*, 0, start|, 0, final*, start*, final*, start*, 0, 0, final*, 1, final|, final*, 0, start|, 0, final*, start*, final*, start*, 0, 0, final*, final|, 1, final*, 0, 1, final|, start|, 0, final*, start*, final*, start*, 0, 0, final*, final*, 0, final|, start|, 0, 1, final*, start*, final*, start*, 0, 0, final*', + 'ATOM', + 'ATOM', + '1, 0, 1, 0, start|', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + '2', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + 'ATOM', + '1, 0', + 'NUMBER']), {'IGNORE': None}) +basic_rules = [Rule('query', [['toplevel_op_expr', '.', 'EOF']]), Rule('fact', [['toplevel_op_expr', '.']]), Rule('complexterm', [['ATOM', '(', 'toplevel_op_expr', ')'], ['expr']]), Rule('expr', [['VAR'], ['NUMBER'], ['+', 'NUMBER'], ['-', 'NUMBER'], ['ATOM'], ['(', 'toplevel_op_expr', ')'], ['listexpr']]), Rule('listexpr', [['[', 'listbody', ']']]), Rule('listbody', [['toplevel_op_expr', '|', 'toplevel_op_expr'], ['toplevel_op_expr']])] +# generated code between this line and its other occurence + +if __name__ == '__main__': + f = py.magic.autopath() + oldcontent = f.read() + s = "# GENERATED CODE BETWEEN THIS LINE AND ITS OTHER OCCURENCE\n".lower() + pre, gen, after = oldcontent.split(s) + + lexer, parser_fact, parser_query, basic_rules = make_all() + newcontent = ("%s%s\nparser_fact = %r\nparser_query = %r\n%s\n" + "basic_rules = %r\n%s%s") % ( + pre, s, parser_fact, parser_query, lexer.get_dummy_repr(), + basic_rules, s, after) + print newcontent + f.write(newcontent) Added: pypy/dist/pypy/lang/prolog/interpreter/term.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/term.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,591 @@ +import math +from pypy.rpython.objectmodel import we_are_translated, UnboxedValue +from pypy.rlib.rarithmetic import intmask +from pypy.lang.prolog.interpreter.error import UnificationFailed, UncatchableError + +DEBUG = True + +TAGBITS = 3 +CURR_TAG = 1 +def tag(): + global CURR_TAG + CURR_TAG += 1 + assert CURR_TAG <= 2 ** TAGBITS + return CURR_TAG + +def debug_print(*args): + if DEBUG and not we_are_translated(): + print " ".join([str(a) for a in args]) + +class PrologObject(object): + __slots__ = () + def getvalue(self, frame): + return self + + def dereference(self, frame): + return self + + def get_max_var(self): + return -1 + + def clone(self, offset): + return self + + def clone_compress_vars(self, vars_new_indexes, offset): + return self + + def make_template(self, vars_new_indexes): + return self + + def instantiate_template(self, template_frame): + return self + + def get_unify_hash(self, frame=None): + # if two non-var objects return two different numbers + # they must not be unifiable + raise NotImplementedError("abstract base class") + + def get_deeper_unify_hash(self, frame=None): + return [self.get_unify_hash(frame)] + + def unify(self, other, frame, occurs_check=False): + pass + unify._annspecialcase_ = "specialize:arg(3)" + + def unify_with_template(self, other, frame, template_frame, to_instantiate): + raise NotImplementedError("abstract base class") + + def contains_var(self, var, frame): + return False + + def __eq__(self, other): + # for testing + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not (self == other) + + +class Var(PrologObject, UnboxedValue): + TAG = 0 + STANDARD_ORDER = 0 + + __slots__ = ('index', ) + + def unify(self, other, frame, occurs_check=False): + #debug_print("unify", self, other, frame.vars) + self, val = self.get_last_var_in_chain_and_val(frame) + if val is not None: + other.unify(val, frame, occurs_check) + elif isinstance(other, Var): + other, val = other.get_last_var_in_chain_and_val(frame) + if val is None: + if other.index != self.index: + frame.setvar(self.index, other) + else: + self.unify(val, frame, occurs_check) + else: + if occurs_check and other.contains_var(self, frame): + raise UnificationFailed() + frame.setvar(self.index, other) + unify._annspecialcase_ = "specialize:arg(3)" + + def unify_with_template(self, other, frame, template_frame, to_instantiate): + self, val = self.get_last_var_in_chain_and_val(frame) + if val is not None: + return val.unify_with_template(other, frame, template_frame, + to_instantiate) + if isinstance(other, Var): + other, otherval = other.get_last_var_in_chain_and_val(frame) + if otherval is None: + if other.index != self.index: + return frame.setvar(self.index, other) + else: + return self.unify_with_template(otherval, frame, + template_frame, to_instantiate) + else: + if isinstance(other, TemplateVar): + return other.unify_with_template(self, frame, template_frame, + to_instantiate) + if isinstance(other, Term): + to_instantiate.append((self.index, other)) + frame.setvar(self.index, other) + + def getvalue(self, frame): + var, res = self.get_last_var_in_chain_and_val(frame) + if res is not None: + return res.getvalue(frame) + return var + + def dereference(self, frame): + var, res = self.get_last_var_in_chain_and_val(frame) + if res is not None: + return res + return var + + def get_last_var_in_chain_and_val(self, frame): + next = frame.getvar(self.index) + if next is None or not isinstance(next, Var): + return self, next + # do path compression + last, val = next.get_last_var_in_chain_and_val(frame) + if val is None: + frame.setvar(self.index, last) + else: + frame.setvar(self.index, val) + return last, val + + def get_max_var(self): + return self.index + + def clone(self, offset): + return Var(self.index + offset) + + def clone_compress_vars(self, vars_new_indexes, offset): + if self.index in vars_new_indexes: + return Var(vars_new_indexes[self.index]) + index = len(vars_new_indexes) + offset + vars_new_indexes[self.index] = index + return Var(index) + + def make_template(self, vars_new_indexes): + if self.index in vars_new_indexes: + return TemplateVar(vars_new_indexes[self.index]) + index = len(vars_new_indexes) + vars_new_indexes[self.index] = index + return TemplateVar(index) + + def get_unify_hash(self, frame=None): + if frame is None: + return 0 + self = self.dereference(frame) + if isinstance(self, Var): + return 0 + return self.get_unify_hash(frame) + + def contains_var(self, var, frame): + self = self.dereference(frame) + if self is var: + return True + if not isinstance(self, Var): + return self.contains_var(var, frame) + return False + + def __repr__(self): + return "Var(%s)" % (self.index, ) + + +class TemplateVar(PrologObject): + TAG = 0 + STANDARD_ORDER = 0 + __slots__ = 'index' + + def __init__(self, index): + self.index = index + + def unify(self, other, frame, occurs_check=False): + raise UncatchableError("TemplateVar in wrong place") + + def unify_with_template(self, other, frame, template_frame, to_instantiate): + val = template_frame[self.index] + if val is None: + template_frame[self.index] = other + else: + val.unify_with_template(other, frame, template_frame, to_instantiate) + + def getvalue(self, frame): + raise UncatchableError("TemplateVar in wrong place") + + def dereference(self, frame): + raise UncatchableError("TemplateVar in wrong place") + + def get_max_var(self): + return self.index + + def clone(self, offset): + return TemplateVar(self.index + offset) + + def clone_compress_vars(self, vars_new_indexes, offset): + raise UncatchableError("TemplateVar in wrong place") + + def make_template(self, vars_new_indexes): + raise UncatchableError("TemplateVar in wrong place") + + def instantiate_template(self, template_frame): + return template_frame[self.index] + + def get_unify_hash(self, frame=None): + return 0 + + def contains_var(self, var, frame): + raise UncatchableError("TemplateVar in wrong place") + + def __repr__(self): + return "TemplateVar(%s)" % (self.index, ) + + +class Callable(PrologObject): + name = "" + signature = "" + + def get_prolog_signature(self): + raise NotImplementedError("abstract base") + +class Atom(Callable): + TAG = tag() + STANDARD_ORDER = 1 + def __init__(self, name): + self.name = name + self.signature = self.name + "/0" + + def __str__(self): + return self.name + + def __repr__(self): + return "Atom(%r)" % (self.name,) + + def unify(self, other, frame, occurs_check=False): + #debug_print("unify", self, other, type(other)) + if isinstance(other, Var): + return other.unify(self, frame, occurs_check) + elif isinstance(other, Atom): + if other.name != self.name: + raise UnificationFailed + return + raise UnificationFailed + unify._annspecialcase_ = "specialize:arg(3)" + + def unify_with_template(self, other, frame, template_frame, to_instantiate): + if isinstance(other, Var): + return other.unify_with_template(self, frame, template_frame, to_instantiate) + elif isinstance(other, TemplateVar): + return other.unify_with_template(self, frame, template_frame, to_instantiate) + elif isinstance(other, Atom): + if other.name != self.name: + raise UnificationFailed + return + raise UnificationFailed + + def get_unify_hash(self, frame=None): + return intmask(hash(self.name) << TAGBITS | self.TAG) + + def get_prolog_signature(self): + return Term("/", [self, Number(0)]) + +class Number(PrologObject): + TAG = tag() + STANDARD_ORDER = 2 + def __init__(self, num): + self.num = num + + def unify(self, other, frame, occurs_check=False): + #debug_print("unify", self, other, type(other)) + if isinstance(other, Var): + return other.unify(self, frame, occurs_check) + elif isinstance(other, Number): + if other.num != self.num: + raise UnificationFailed + return + raise UnificationFailed + unify._annspecialcase_ = "specialize:arg(3)" + + def unify_with_template(self, other, frame, template_frame, to_instantiate): + if isinstance(other, Var): + return other.unify_with_template(self, frame, template_frame, to_instantiate) + elif isinstance(other, TemplateVar): + return other.unify_with_template(self, frame, template_frame, to_instantiate) + elif isinstance(other, Number): + if other.num != self.num: + raise UnificationFailed + return + raise UnificationFailed + + def __str__(self): + return repr(self.num) + + def __repr__(self): + return "Number(%r)" % (self.num, ) + + def get_unify_hash(self, frame=None): + return intmask(self.num << TAGBITS | self.TAG) + + +class Float(PrologObject): + TAG = tag() + STANDARD_ORDER = 2 + def __init__(self, num): + self.num = num + + def unify(self, other, frame, occurs_check=False): + if isinstance(other, Var): + return other.unify(self, frame, occurs_check) + elif isinstance(other, Float): + if other.num != self.num: + raise UnificationFailed + return + raise UnificationFailed + unify._annspecialcase_ = "specialize:arg(3)" + + def unify_with_template(self, other, frame, template_frame, to_instantiate): + if isinstance(other, Var): + return other.unify_with_template(self, frame, template_frame, to_instantiate) + elif isinstance(other, TemplateVar): + return other.unify_with_template(self, frame, template_frame, to_instantiate) + elif isinstance(other, Float): + if other.num != self.num: + raise UnificationFailed + return + raise UnificationFailed + + def get_unify_hash(self, frame=None): + #XXX no clue whether this is a good idea... + m, e = math.frexp(self.num) + m = intmask(int(m / 2 * 2 ** (32 - TAGBITS))) + return intmask(m << TAGBITS | self.TAG) + + def __str__(self): + return repr(self.num) + + def __repr__(self): + return "Float(%r)" % (self.num, ) + + +# helper functions for various Term methods + +def _clone(obj, offset): + return obj.clone(offset) + +def _clone_compress_vars(obj, vars_new_indexes, offset): + return obj.clone_compress_vars(vars_new_indexes, offset) + +def _make_template(obj, vars_new_indexes): + return obj.make_template(vars_new_indexes) + +def _instantiate_template(obj, template_frame): + return obj.instantiate_template(template_frame) + +def _getvalue(obj, frame): + return obj.getvalue(frame) + +class Term(Callable): + TAG = tag() + STANDARD_ORDER = 3 + def __init__(self, name, args, signature=None): + self.name = name + self.args = args + if signature is None: + self.signature = name + "/" + str(len(args)) + else: + self.signature = signature + + def __repr__(self): + return "Term(%r, %r)" % (self.name, self.args) + + def __str__(self): + return "%s(%s)" % (self.name, ", ".join([str(a) for a in self.args])) + + def unify(self, other, frame, occurs_check=False): + if not isinstance(other, Term): + if isinstance(other, Var): + return other.unify(self, frame, occurs_check) + raise UnificationFailed + if (hash(self.name) != hash(other.name) or + self.name != other.name or len(self.args) != len(other.args)): + raise UnificationFailed + for i in range(len(self.args)): + self.args[i].unify(other.args[i], frame, occurs_check) + unify._annspecialcase_ = "specialize:arg(3)" + + def unify_with_template(self, other, frame, template_frame, to_instantiate): + if not isinstance(other, Term): + if isinstance(other, Var): + return other.unify_with_template(self, frame, template_frame, to_instantiate) + if isinstance(other, TemplateVar): + return other.unify_with_template(self, frame, template_frame, to_instantiate) + raise UnificationFailed + if (hash(self.name) != hash(other.name) or + self.name != other.name or len(self.args) != len(other.args)): + raise UnificationFailed + for i in range(len(self.args)): + self.args[i].unify_with_template(other.args[i], frame, + template_frame, to_instantiate) + + def get_max_var(self): + result = -1 + for subterm in self.args: + result = max(result, subterm.get_max_var()) + return result + + def clone(self, offset): + return self._copy_term(_clone, offset) + + def clone_compress_vars(self, vars_new_indexes, offset): + return self._copy_term(_clone_compress_vars, vars_new_indexes, offset) + + def make_template(self, vars_new_indexes): + return self._copy_term(_make_template, vars_new_indexes) + + def instantiate_template(self, template_frame): + return self._copy_term(_instantiate_template, template_frame) + + def getvalue(self, frame): + return self._copy_term(_getvalue, frame) + + def _copy_term(self, copy_individual, *extraargs): + args = [None] * len(self.args) + newinstance = False + for i in range(len(self.args)): + arg = self.args[i] + cloned = copy_individual(arg, *extraargs) + if cloned is not arg: + newinstance = True + args[i] = cloned + if newinstance: + return Term(self.name, args, self.signature) + else: + return self + _copy_term._annspecialcase_ = "specialize:arg(1)" + + def get_unify_hash(self, frame=None): + return intmask(hash(self.signature) << TAGBITS | self.TAG) + + def get_deeper_unify_hash(self, frame=None): + result = [0] * len(self.args) + for i in range(len(self.args)): + result[i] = self.args[i].get_unify_hash(frame) + return result + + def get_prolog_signature(self): + return Term("/", [Atom(self.name), Number(len(self.args))]) + + def contains_var(self, var, frame): + for arg in self.args: + if arg.contains_var(var, frame): + return True + return False + + +class Rule(object): + def __init__(self, head, body): + from pypy.lang.prolog.interpreter import helper + d = {} + head = head.make_template(d) + assert isinstance(head, Callable) + self.head = head + if body is not None: + body = helper.ensure_callable(body) + self.body = body.make_template(d) + else: + self.body = None + self.numvars = len(d) + self.signature = self.head.signature + self.unify_hash = self.head.get_deeper_unify_hash() + self._does_contain_cut() + + def _does_contain_cut(self): + if self.body is None: + self.contains_cut = False + return + stack = [self.body] + while stack: + current = stack.pop() + if isinstance(current, Atom): + if current.name == "!": + self.contains_cut = True + return + elif isinstance(current, Term): + stack.extend(current.args) + self.contains_cut = False + + def clone(self, offset): + if self.body is None: + body = None + else: + body = self.body.clone(offset) + return Rule(self.head.clone(offset), body) + + def clone_and_unify_head(self, frame, head): + template_frame = [None] * self.numvars + if isinstance(head, Term): + to_instantiate = [] + h2 = self.head + assert isinstance(h2, Term) + for i in range(len(h2.args)): + arg1 = h2.args[i] + arg2 = head.args[i] + if (isinstance(arg1, Term) or + isinstance(arg1, TemplateVar)): + h2.args[i].unify_with_template( + head.args[i], frame, template_frame, to_instantiate) + else: + h2.args[i].unify(head.args[i], frame) + extend_and_normalize_template_frame(template_frame, frame) + for index, obj in to_instantiate: + frame.vars[index] = obj.instantiate_template(template_frame) + body = self.body + if body is None: + return None + return body.instantiate_template(template_frame) + + def __repr__(self): + if self.body is None: + return "%s." % (self.head, ) + return "%s :- %s." % (self.head, self.body) + + +def extend_and_normalize_template_frame(template_frame, frame): + next_free = frame.maxvar() + for i in range(len(template_frame)): + val = template_frame[i] + if val is None: + template_frame[i] = Var(next_free) + next_free += 1 + elif isinstance(val, TemplateVar): + template_frame[i] = template_frame[val.index] + frame.extend(next_free - frame.maxvar()) + +def rcmp(a, b): # RPython does not support cmp... + if a == b: + return 0 + if a < b: + return -1 + return 1 +rcmp._annspecialcase_ = "specialize:argtype(0)" + +def cmp_standard_order(obj1, obj2, frame): + c = rcmp(obj1.STANDARD_ORDER, obj2.STANDARD_ORDER) + if c != 0: + return c + if isinstance(obj1, Var): + assert isinstance(obj2, Var) + return rcmp(obj1.index, obj2.index) + if isinstance(obj1, Atom): + assert isinstance(obj2, Atom) + return rcmp(obj1.name, obj2.name) + if isinstance(obj1, Term): + assert isinstance(obj2, Term) + c = rcmp(len(obj1.args), len(obj2.args)) + if c != 0: + return c + c = rcmp(obj1.name, obj2.name) + if c != 0: + return c + for i in range(len(obj1.args)): + a1 = obj1.args[i].dereference(frame) + a2 = obj2.args[i].dereference(frame) + c = cmp_standard_order(a1, a2, frame) + if c != 0: + return c + return 0 + # XXX hum + if isinstance(obj1, Number): + if isinstance(obj2, Number): + return rcmp(obj1.num, obj2.num) + elif isinstance(obj2, Float): + return rcmp(obj1.num, obj2.num) + if isinstance(obj1, Float): + if isinstance(obj2, Number): + return rcmp(obj1.num, obj2.num) + elif isinstance(obj2, Float): + return rcmp(obj1.num, obj2.num) + assert 0 Added: pypy/dist/pypy/lang/prolog/interpreter/test/__init__.py ============================================================================== Added: pypy/dist/pypy/lang/prolog/interpreter/test/dont_test_translate.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/test/dont_test_translate.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,51 @@ +from pypy.translator.interactive import Translation +from pypy.rpython.test.test_llinterp import interpret +from pypy.lang.prolog.interpreter import parsing +from pypy.lang.prolog.interpreter.term import Atom +from pypy.lang.prolog.interpreter.test.tool import * + +from pypy.lang.prolog.interpreter.conftest import option +if not option.slow: + py.test.skip("slow tests") + +def test_parser(): + def f(x): + if x: + s = "a(X, Y, Z)." + else: + s = "f(a, X, _, _, X, f(X, 2.455))." + term = parsing.parse_file(s) + assert isinstance(term, parsing.Nonterminal) + return term.symbol + assert f(True) == "file" + assert f(True) == "file" + t = Translation(f) + t.annotate([bool]) + t.rtype() + t.backendopt() + func = t.compile_c() + assert func(True) == "file" + assert func(False) == "file" + +def test_engine(): + e = get_engine(""" + g(a, a). + g(a, b). + g(b, c). + f(X, Z) :- g(X, Y), g(Y, Z). + """) + t1 = parse_query_term("f(a, c).") + t2 = parse_query_term("f(X, c).") + def run(): + e.run(t1) + e.run(t2) + v0 = e.frame.getvar(0) + if isinstance(v0, Atom): + return v0.name + return "no!" + assert run() == "a" + t = Translation(run) + t.annotate() + t.rtype() + func = t.compile_c() + assert func() == "a" Added: pypy/dist/pypy/lang/prolog/interpreter/test/test_arithmetic.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/test/test_arithmetic.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,24 @@ +import py +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter.parsing import parse_query_term, get_engine +from pypy.lang.prolog.interpreter.error import UnificationFailed, CutException +from pypy.lang.prolog.interpreter.engine import Frame, Engine +from pypy.lang.prolog.interpreter import error +from pypy.lang.prolog.interpreter.test.tool import collect_all, assert_false, assert_true + +def test_simple(): + assert_true("X is 1 + 2, X = 3.") + assert_true("X is 1.2 + 2.8, X = 4.") + assert_false("X is 1.1 + 2.8, X = 4.0.") + assert_true("X is 2 * -2, X = -4.") + assert_true("X is 2 + -2, X = 0.") + assert_true("X is 2 // -2, X = -1.") + +def test_comparison(): + assert_true("1 =:= 1.0.") + assert_true("1 + 1 > 1.") + assert_true("1 + 0.001 >= 1 + 0.001.") + assert_true("1 + 0.001 =< 1 + 0.001.") + assert_false("1 > 1.") + assert_false("1 =\\= 1.0.") + assert_true("1 =\\= 32.") Added: pypy/dist/pypy/lang/prolog/interpreter/test/test_builtin.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/test/test_builtin.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,341 @@ +import py +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter.parsing import parse_query_term, get_engine +from pypy.lang.prolog.interpreter.error import UnificationFailed +from pypy.lang.prolog.interpreter.engine import Frame, Engine +from pypy.lang.prolog.interpreter import error +from pypy.lang.prolog.interpreter.test.tool import collect_all, assert_false, assert_true +from pypy.lang.prolog.interpreter.test.tool import prolog_raises + +def test_fail(): + e = get_engine(""" + g(a). + f(X) :- g(X), fail. + f(a). + """) + frames = collect_all(e, "f(X).") + assert len(frames) == 1 + +def test_not(): + e = get_engine(""" + g(a, a). + g(b, a). + g(b, b). + + m(o, a). + m(o, b). + m(o, c). + same(X, X). + + sibling(X, Y) :- m(Z, X), m(Z, Y), \\+same(X, Y). + """) + assert_true("not((!, fail)).", e) + assert_true("not(g(b, c)).", e) + assert_false("not(g(a, a)).", e) + assert_true("\\+(g(b, c)).", e) + assert_false("\\+(g(a, a)).", e) + assert_false("not(!).", e) + + frames = collect_all(e, "sibling(a, X).") + assert len(frames) == 2 + +def test_and(): + assert_false("fail, X.") + prolog_raises("type_error(callable, 1)", "(fail, 1)") + +def test_nonvar(): + e = get_engine(""" + g(X) :- nonvar(X). + g(x, X) :- nonvar(x), nonvar(X). + f(X, Y) :- nonvar(X), nonvar(Y). + """) + assert_true("g(a).", e) + assert_false("g(X).", e) + assert_true("g(x).", e) + assert_true("g(x, a).", e) + assert_true("g(X, X).", e) + assert_false("f(X, X).", e) + +def test_consult(): + p = py.test.ensuretemp("prolog") + f = p.join("test.pl") + f.write("g(a, a). g(a, b).") + e = get_engine("g(c, c).") + assert_true("g(c, c).", e) + assert_true("consult('%s')." % (f, ), e) + assert_true("g(c, c).", e) + assert_true("g(a, a).", e) + assert_true("g(a, b).", e) + py.test.raises( + error.CatchableError, + assert_true, "consult('/hopefully/does/not/exist').") + +def test_assert_retract(): + e = get_engine("g(b, b).") + assert_true("g(B, B).", e) + assert_true("assert(g(c, d)).", e) + assert_true("assert(g(a, b)).", e) + assert_true("assert(g(a, b)).", e) # assert the same rule multiple times + assert_true("g(B, B).", e) + assert_true("g(a, b).", e) + assert_true("g(c, d).", e) + assert_true("retract(g(B, B)).", e) + assert_false("g(B, B).", e) + assert_true("retract(g(a, b)).", e) + assert_true("g(a, b).", e) + assert_true("retract(g(a, b)).", e) + assert_false("retract(g(a, b)).", e) + assert_false("g(a, b).", e) + assert_true("g(c, d).", e) + e = get_engine(""" + g(b, b). + f(X) :- g(X, b). + f(a). + """) + assert_true("f(b).", e) + assert_true("f(a).", e) + assert_true("retract(f(X) :- g(X, Y)), Y == b.", e) + assert_false("f(b).", e) + assert_true("f(a).", e) + prolog_raises("permission_error(X, Y, Z)", "retract(atom(X))") + +def test_assert_at_right_end(): + e = get_engine("g(b, b). f(b, b). h(b, b).") + assert_true("assert(g(a, a)).", e) + assert_true("assertz(f(a, a)).", e) + assert_true("A = a, asserta(h(A, A)).", e) + f = assert_true("g(B, B).", e) + assert f.vars[0].name == "b" + f = assert_true("f(B, B).", e) + assert f.vars[0].name == "b" + assert_false("h(c, c).", e) + f = assert_true("h(B, B).", e) + assert f.vars[0].name == "a" + +def test_assert_logical_update_view(): + e = get_engine(""" + g(a). + g(c) :- assertz(g(d)). + g(b). + """) + frames = collect_all(e, "g(X).") + assert len(frames) == 3 + +def test_abolish(): + e = get_engine("g(b, b). g(c, c). g(a). f(b, b). h(b, b).") + assert_true("abolish(g/2).", e) + assert_true("g(a).", e) + prolog_raises("existence_error(X, Y)", "g(A, B)", e) + prolog_raises("type_error(predicate_indicator, a)", "abolish(a)", e) + +def test_unify(): + assert_true("g(b, B) = g(b, b).") + assert_true("X = Y.") + assert_true("X = f(X).") + assert_false("g(b, B) \\= g(b, b).") + assert_false("X \\= Y.") + assert_false("X \\= f(X).") + assert_true("x \\= y.") + assert_true("unify_with_occurs_check(X, Y).") + assert_true("unify_with_occurs_check(X, X).") + assert_false("unify_with_occurs_check(X, f(X)).") + assert_false("unify_with_occurs_check(X, f(g(h(a, b, c, d(X, e), e)))).") + assert_false("unify_with_occurs_check(g(X), X).") + assert_false("X = Y, unify_with_occurs_check(X, f(d(Y), Y)).") + +def test_call(): + e = get_engine("g(b, b).") + assert_true("call(g(X, X)).", e) + assert_true("X =.. [g, b, b], call(X).", e) + e = get_engine(""" + g(X) :- call(f(X)). + g(a). + g(b). + f(X) :- !, h(X). + f(a). + f(b). + h(X) :- fail. + withcut(X) :- call(!), fail. + withcut(a). + """) + frames = collect_all(e, "g(X).") + assert len(frames) == 2 + assert_true("withcut(a).", e) + assert_true("call((!, true)).") + +def test_or_with_cut(): + assert_false("((X = 1, !); X = 2), X = 2.") + assert_true("((X = 1, !); X = 2), X = 1.") + +def test_cut(): + e = get_engine(""" + f(0). + f(X) :- Y is X - 1, !, f(Y). + f(X) :- Y is X - 2, !, f(Y). + """) + assert_true("f(20).", e) + +def test_term_construction(): + assert_true("g(a, b, c) =.. [G, A, B, C].") + assert_true("g(a, b, c) =.. [g, a, b, c].") + assert_true("X =.. [g, a, b, c], X = g(a, b, c).") + assert_true("arg(1, g(a, b, c), a).") + assert_true("arg(2, g(a, b, c), b).") + assert_true("arg(3, g(a, b, c), c).") + assert_false("arg(3, g(a, b, c), d).") + assert_false("arg(0, g(a, b, c), X).") + assert_false("arg(10, g(a, b, c), X).") + assert_true("arg(1, g(a, b, c), X), X = a.") + assert_true("arg(2, f(a, b, c), X), X = b.") + assert_true("arg(3, h(a, b, c), X), X = c.") + e = get_engine(""" + f(1, a). + f(2, b). + f(3, c). + """) + frames = collect_all(e, "arg(X, g(a, b, c), A), f(X, A).") + assert len(frames) == 3 + assert_true("arg(X, h(a, b, c), b), X = 2.") + assert_true("arg(X, h(a, b, g(X, b)), g(3, B)), X = 3, B = b.") + assert_true("copy_term(X, Y), X = 1, Y = 2.") + assert_true("copy_term(a, a).") + assert_false("copy_term(f(X), g(X)).") + assert_true("copy_term(f(X), f(a)), X = b.") + +def test_type_checks(): + assert_true("integer(123).") + assert_false("integer(a).") + assert_false("integer(X).") + assert_true("float(123.12).") + assert_false("float(a).") + assert_false("float(12).") + assert_true("number(123).") + assert_true("number(42.42).") + assert_false("integer(a).") + assert_false("integer(X).") + assert_true("var(X).") + assert_false("X = a, var(X).") + assert_true("compound(g(a)).") + assert_false("compound(gxx).") + assert_false("compound(123).") + assert_false("compound([]).") + assert_false("compound(X).") + assert_true("atom(a).") + assert_true("atom('asdf').") + assert_false("atom(12).") + assert_false("atom(X).") + assert_true("atomic('asdf').") + assert_true("atomic(12.5).") + assert_false("atomic(f(1, 2, 3)).") + assert_false("atomic(X).") + assert_false("callable(X).") + assert_false("callable(1).") + assert_true("callable(asdf).") + assert_true("callable(asdf(a, b, c, d, e, f)).") + assert_true("ground(a).") + assert_true("ground(t(a, b, f(a, b, g(a, b)))).") + assert_false("ground(t(a, b, f(a, b, g(a, X)))).") + assert_true("X = 13, ground(t(a, b, f(a, b, g(a, X)))).") + assert_false("ground(X).") + +def test_repeat(): + assert_true("repeat, true.") + py.test.raises(UnificationFailed, + Engine().run, parse_query_term("repeat, !, fail.")) + # hard to test repeat differently + +def test_exception_handling(): + assert_true("catch(f, E, true).") + assert_true("catch(throw(error), E, true).") + py.test.raises(error.CatchableError, + assert_true, "catch(true, E, fail), f.") + py.test.raises(error.CatchableError, + assert_true, "catch(throw(error), failure, fail).") + assert_true("catch(catch(throw(error), failure, fail), error, true).") + +def test_between(): + assert_true("between(12, 15, 12).") + assert_true("between(-5, 15, 0).") + assert_false("between(12, 15, 6).") + assert_false("between(12, 15, 16).") + frames = collect_all(Engine(), "between(1, 4, X).") + assert len(frames) == 4 + assert frames[0].vars[0].num == 1 + +def test_is(): + assert_true("5 is 1 + 1 + 1 + 1 + 1.") + +def test_parser_access(): + assert_true("current_op(200, xfx, **).") + f = collect_all(Engine(), "current_op(200, Form, X).") + assert len(f) == 2 + e = get_engine(""" + foo(a, b). + """) + assert_true("op(450, xfy, foo).", e) + assert_true("a foo b.", e) + assert_true("op(0, xfy, foo).", e) + # XXX really a ParseError + py.test.raises(Exception, assert_false, "a foo b.", e) + # change precedence of + for funny results :-) + assert_true("14 is 2 + 3 * 4.", e) + assert_true("op(350, xfy, +).", e) + assert_true("20 is 2 + 3 * 4.", e) + assert_true("op(500, xfy, +).", e) + +def test_functor(): + assert_true("functor(f(a, b, c), f, 3).") + assert_true("functor(f(a, b, c), X, Y), X=f, Y=3.") + assert_true("functor(f, X, Y), X=f, Y=0.") + assert_true("functor(1, X, Y), X=1, Y=0.") + assert_true("functor(F, a, 0), F=a.") + assert_true("functor(F, 12, 0), F=12.") + assert_true("functor(F, 12.5, 0), F=12.5.") + assert_true("functor(F, f, 4), F=f(1, 2, 3, 4).") + assert_true("functor(F, g, 1), F=g(asdf).") + assert_true("functor(F, g, 3), F=g(X, Y, 1), X = 12, Y = 34, ground(F).") + +def test_standard_comparison(): + assert_true("X = Y, f(X, Y, X, Y) == f(X, X, Y, Y).") + assert_true("X = Y, f(X, Y, X, Z) \\== f(X, X, Y, Y).") + assert_true("X @< Y, X @=< X, X @=< Y, Y @> X.") + assert_true("'\\\\=='(f(X, Y), 12).") + assert_true("X = f(a), Y = f(b), Y @> X.") + +def test_atom_length(): + assert_true("atom_length('abc', 3).") + assert_true("atom_length('\\\\', 1).") + assert_true("atom_length('abc', X), X = 3.") + +def test_atom_concat(): + assert_true("atom_concat(ab, cdef, abcdef).") + assert_true("atom_concat(ab, cdef, X), X = abcdef.") + assert_true("atom_concat(ab, X, abcdef), X = cdef.") + assert_true("atom_concat(X, cdef, abcdef), X = ab.") + assert_true("atom_concat(1, Y, '1def'), Y = def.") + frames = collect_all( + Engine(), + "atom_concat(X, Y, abcd), atom(X), atom(Y).") + assert len(frames) == 5 + +def test_sub_atom(): + assert_true("sub_atom(abc, B, L, A, bc), B=1, L=2, A=0.") + +def test_findall(): + assert_true("findall(X, (X = a; X = b; X = c), L), L = [a, b, c].") + assert_true("findall(X + Y, (X = 1), L), L = [1+_].") + +def test_ifthenelse(): + e = get_engine("f(x). f(y). f(z).") + assert_false("f(c) -> true.", e) + assert_true("f(X) -> X \\= x; f(z).", e) + assert_false("true -> fail.", e) + +def test_once(): + assert_true("once(repeat).") + +def test_write_term(): + prolog_raises("domain_error(write_option, E)", + "write_term(a, [quoted(af)])") + prolog_raises("type_error(list, E)", + "write_term(a, asdf)") Added: pypy/dist/pypy/lang/prolog/interpreter/test/test_engine.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/test/test_engine.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,243 @@ +import py +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter.parsing import parse_query_term, get_engine +from pypy.lang.prolog.interpreter.error import UnificationFailed, CatchableError +from pypy.lang.prolog.interpreter.test.tool import collect_all, assert_true, assert_false +from pypy.lang.prolog.interpreter.test.tool import prolog_raises + +def test_and(): + e = get_engine(""" + g(a, a). + g(a, b). + g(b, c). + f(X, Z) :- g(X, Y), g(Y, Z). + """) + e.run(parse_query_term("f(a, c).")) + e.run(parse_query_term("f(X, c).")) + print e.frame.vars + assert e.frame.getvar(0).name == "a" + +def test_and_long(): + e = get_engine(""" + f(x). f(y). f(z). + g(a). g(b). g(c). + h(d). h(e). h(f). + f(X, Y, Z) :- f(X), g(Y), h(Z). + """) + frames = collect_all(e, "f(X, Y, Z).") + assert len(frames) == 27 + +def test_numeral(): + e = get_engine(""" + num(0). + num(succ(X)) :- num(X). + add(X, 0, X). + add(X, succ(Y), Z) :- add(succ(X), Y, Z). + mul(X, 0, 0). + mul(X, succ(0), X). + mul(X, succ(Y), Z) :- mul(X, Y, A), add(A, X, Z). + factorial(0, succ(0)). + factorial(succ(X), Y) :- factorial(X, Z), mul(Z, succ(X), Y). + """) + def nstr(n): + if n == 0: + return "0" + return "succ(%s)" % nstr(n - 1) + e.run(parse_query_term("num(0).")) + e.run(parse_query_term("num(succ(0)).")) + e.run(parse_query_term("num(X).")) + assert e.frame.getvar(0).num == 0 + e.run(parse_query_term("add(0, 0, 0).")) + py.test.raises(UnificationFailed, e.run, parse_query_term(""" + add(0, 0, succ(0)).""")) + e.run(parse_query_term("add(succ(0), succ(0), succ(succ(0))).")) + e.run(parse_query_term("mul(succ(0), 0, 0).")) + e.run(parse_query_term("mul(succ(succ(0)), succ(0), succ(succ(0))).")) + e.run(parse_query_term("mul(succ(succ(0)), succ(succ(0)), succ(succ(succ(succ(0))))).")) + e.run(parse_query_term("factorial(0, succ(0)).")) + e.run(parse_query_term("factorial(succ(0), succ(0)).")) + e.run(parse_query_term("factorial(%s, %s)." % (nstr(5), nstr(120)))) + +def test_or(): + e = get_engine(""" + g(a, b). + g(b, a). + f(X, Y) :- g(X, b); g(a, Y). + """) + e.run(parse_query_term("f(a, c).")) + e.run(parse_query_term("f(d, b).")) + prolog_raises("ERROR", "foo(X); X = 1") + + +def test_or_and_call_with_cut(): + assert_false("(!, fail); true.") + assert_true("(call(!), fail); true.") + +def test_or_backtrack(): + e = get_engine(""" + a(a). + b(b). + g(a, b). + g(a, a). + f(X, Y, Z) :- (g(X, Z); g(X, Z); g(Z, Y)), a(Z). + """) + e.run(parse_query_term("f(a, b, Z).")) + assert e.frame.getvar(0).name == "a" + f = collect_all(e, "X = 1; X = 2.") + assert len(f) == 2 + +def test_backtrack_to_same_choice_point(): + e = get_engine(""" + a(a). + b(b). + start(Z) :- Z = X, f(X, b), X == b, Z == b. + f(X, Y) :- a(Y). + f(X, Y) :- X = a, a(Y). + f(X, Y) :- X = b, b(Y). + """) + assert_true("start(Z).", e) + +def test_equivalent_with_quotes(): + e = get_engine(""" + g('a', X). + g('b', 'c'). + """) + e.run(parse_query_term("g(a, b).")) + e.run(parse_query_term("g(b, c).")) + +def test_error_unknown_function(): + e = get_engine(""" + g(a). + f(X) :- g(X), h(X). + """) + prolog_raises("existence_error(procedure, h/1)", "f(X)", e) + +def test_collect_all(): + e = get_engine(""" + g(a). + g(b). + g(c). + """) + frames = collect_all(e, "g(X).") + assert len(frames) == 3 + assert frames[0].getvar(0).name == "a" + assert frames[1].getvar(0).name == "b" + assert frames[2].getvar(0).name == "c" + +def test_cut(): + e = get_engine(""" + g(a). + g(b). + a(a). + b(b). + f(X) :- g(X),!,b(X). + f(x). + f(y). + """) + frames = collect_all(e, "f(X).") + assert len(frames) == 0 + assert_true("!.") + +def test_cut2(): + e = get_engine(""" + g(a). + g(b). + h(a, x). + h(a, y). + f(X, Y) :- g(X), !, !, !, !, !, h(X, Y). + """) + frames = collect_all(e, "f(X, Y).") + assert len(frames) == 2 + +def test_cut3(): + e = get_engine(""" + member(H, [H | _]). + member(H, [_ | T]) :- member(H, T). + + s(a, L) :- !, fail. + s(b, L). + s(X, L) :- + member(Y, L), + L = [_| S], + s(Y, S). + """) + # import pdb; pdb.set_trace() + assert_true("s(d, [a, b]).", e) + +def test_rule_with_cut_calling_rule_with_cut(): + e = get_engine(""" + f(b) :- !. + f(c). + g(X) :- f(X), !. + g(a). + """) + frames = collect_all(e, "g(X).") + assert len(frames) == 1 + +def test_not_with_cut(): + e = get_engine(""" + p1 :- \\+ q1. + q1 :- fail. + q1 :- true. + + p2:- \\+ q2. + q2 :- !, fail. + q2 :- true. + """) + assert_false("p1.", e) + assert_true("p2.", e) + +def test_numbers(): + e = get_engine(""" + g(1, 2). + g(X, Y) :- g(1, X), g(1, Y). + """) + e.run(parse_query_term("g(2, 2).")) + +def test_lists(): + e = get_engine(""" + nrev([],[]). + nrev([X|Y],Z) :- nrev(Y,Z1), + append(Z1,[X],Z). + + append([],L,L). + append([X|Y],L,[X|Z]) :- append(Y,L,Z). + """) + e.run(parse_query_term("nrev(%s, X)." % (range(15), ))) + e.run(parse_query_term("nrev(%s, %s)." % (range(8), range(7, -1, -1)))) + +def test_indexing(): + # this test is quite a lot faster if indexing works properly. hrmrm + e = get_engine("g(a, b, c, d, e, f, g, h, i, j, k, l). " + + "".join(["f(%s, g(%s)) :- g(A, B, C, D, E, F, G, H, I ,J, K, l). " + % (chr(i), chr(i + 1)) + for i in range(97, 122)])) + t = parse_query_term("f(x, g(y)).") + for i in range(200): + e.run(t) + t = parse_query_term("f(x, g(y, a)).") + for i in range(200): + py.test.raises(UnificationFailed, e.run, t) + +def test_indexing2(): + e = get_engine(""" + mother(o, j). + mother(o, m). + mother(o, b). + + sibling(X, Y) :- mother(Z, X), mother(Z, Y). + """) + frames = collect_all(e, "sibling(m, X).") + assert len(frames) == 3 + +def test_runstring(): + e = get_engine("foo(a, c).") + e.runstring(""" + :- op(450, xfy, foo). + a foo b. + b foo X :- a foo X. + """) + assert_true("foo(a, b).", e) + +def test_handle_non_callable(): + py.test.raises(CatchableError, assert_true, "1.") Added: pypy/dist/pypy/lang/prolog/interpreter/test/test_parsing.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/test/test_parsing.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,110 @@ +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder, OrderTransformer +from pypy.lang.prolog.interpreter.parsing import parse_query_term + + +def test_simple(): + t = parse_file(""" +h(X, Y, Z) :- -Y = Z. +""") + builder = TermBuilder() + facts = builder.build(t) + assert len(facts) == 1 + +def test_numeral(): + from pypy.lang.prolog.interpreter.term import Term, Atom, Var + from pypy.lang.prolog.interpreter.engine import Engine + t = parse_file(""" +numeral(null). % end of line comment +numeral(succ(X)) :- numeral(X). % another one + +add_numeral(X, null, X). +add_numeral(X, succ(Y), Z) :- add_numeral(succ(X), Y, Z). + +greater_than(succ(null), null). +greater_than(succ(X), null) :- greater_than(X, null). +greater_than(succ(X), succ(Y)) :- greater_than(X, Y). +""") + builder = TermBuilder() + facts = builder.build(t) + e = Engine() + for fact in facts: + print fact + e.add_rule(fact) + assert e.signature2rules["add_numeral/3"][0].head.args[1].name == "null" + four = Term("succ", [Term("succ", [Term("succ", + [Term("succ", [Atom("null")])])])]) + e.run(parse_query_term("numeral(succ(succ(null))).")) + term = parse_query_term( + """add_numeral(succ(succ(null)), succ(succ(null)), X).""") + e.run(term) + var = Var(0).getvalue(e.frame) + print var, e.frame + # does not raise + var.unify(four, e.frame) + term = parse_query_term( + """greater_than(succ(succ(succ(null))), succ(succ(null))).""") + e.run(term) + +def test_quoted_atoms(): + t = parse_file(""" + g('ASa0%!!231@~!@#%', a, []). /* /* /* * * * / a mean comment */ + """) + builder = TermBuilder() + facts = builder.build(t) + +def test_parenthesis(): + t = parse_file(""" + g(X, Y) :- (g(x, y); g(a, b)), /* this too is a comment +*/ g(x, z). + """) + builder = TermBuilder() + facts = builder.build(t) + +def test_cut(): + t = parse_file(""" + g(X, /* this is some comment */ + Y) :- g(X), !, h(Y). + """) + builder = TermBuilder() + facts = builder.build(t) + +def test_noparam(): + t = parse_file(""" + test. + """) + builder = TermBuilder() + facts = builder.build(t) + +def test_list(): + t = parse_file(""" + W = []. + X = [a, b, c, d, e, f, g, h]. + Y = [a|T]. + Z = [a,b,c|T]. + """) + builder = TermBuilder() + facts = builder.build(t) + +def test_number(): + t = parse_file(""" + X = -1. + Y = -1.345. + """) + builder = TermBuilder() + facts = builder.build(t) + assert len(facts) == 2 + assert facts[0].args[1].num == -1 + assert facts[1].args[1].num == -1.345 + t = parse_file(""" + X = -1. + arg(X, h(a, b, c), b), X = 2. + arg(X, h(a, b, g(X, b)), g(3, B)), X = 3, B = b. + """) + +def test_chaining(): + t = parse_file("f(X) = X + X + 1 + 2.") + builder = TermBuilder() + facts = builder.build(t) + t = parse_file("f(X) = X + X * 1 + 23 / 13.") + facts = builder.build(t) + t = parse_file("-X + 1.") Added: pypy/dist/pypy/lang/prolog/interpreter/test/test_standard.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/test/test_standard.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,13 @@ +# some tests stolen from the standard test suite +# XXX find a way to more systematically test these test suites +import py +from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder +from pypy.lang.prolog.interpreter.test.tool import collect_all, assert_true, assert_false + +class TestSec78(object): + def test_common(self): + assert_false('fail.') + assert_true('true.') + + def DONOTtest_cut(self): + assert_true('!.') Added: pypy/dist/pypy/lang/prolog/interpreter/test/test_unification.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/test/test_unification.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,64 @@ +import py +from pypy.lang.prolog.interpreter.error import UnificationFailed +from pypy.lang.prolog.interpreter.term import Atom, Var, Number, Term, Rule +from pypy.lang.prolog.interpreter.engine import Frame, Engine + +def test_atom(): + a = Atom("hallo") + b = Atom("hallo") + # does not raise + a.unify(b, None) + py.test.raises(UnificationFailed, "a.unify(Atom('xxx'), None)") + +def test_var(): + b = Var(0) + frame = Frame() + frame.clear(1) + b.unify(Atom("hallo"), frame) + assert b.getvalue(frame).name == "hallo" + a = Var(0) + b = Var(1) + frame.clear(2) + a.unify(b, frame) + a.unify(Atom("hallo"), frame) + assert a.getvalue(frame).name == "hallo" + assert b.getvalue(frame).name == "hallo" + +def test_unify_var(): + b = Var(0) + frame = Frame() + frame.clear(1) + b.unify(b, frame) + b.unify(Atom("hallo"), frame) + py.test.raises(UnificationFailed, b.unify, Atom("bye"), frame) + +def test_recursive(): + b = Var(0) + frame = Frame() + frame.clear(1) + b.unify(Term("hallo", [b]), frame) + + +def test_term(): + X = Var(0) + Y = Var(1) + t1 = Term("f", [Atom("hallo"), X]) + t2 = Term("f", [Y, Atom("HALLO")]) + frame = Frame() + frame.clear(2) + print t1, t2 + t1.unify(t2, frame) + assert X.getvalue(frame).name == "HALLO" + assert Y.getvalue(frame).name == "hallo" + +def test_run(): + e = Engine() + e.add_rule(Term("f", [Atom("a"), Atom("b")])) + e.add_rule(Term("f", [Var(0), Var(0)])) + e.add_rule(Term(":-", [Term("f", [Var(0), Var(1)]), + Term("f", [Var(1), Var(0)])])) + assert e.run(Term("f", [Atom("b"), Var(0)])) is None + assert e.frame.getvar(0).name == "b" + assert e.run(Term("f", [Atom("b"), Atom("a")])) is None + + Added: pypy/dist/pypy/lang/prolog/interpreter/test/tool.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/test/tool.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,43 @@ +import py +from pypy.lang.prolog.interpreter.error import UnificationFailed, FunctionNotFound +from pypy.lang.prolog.interpreter.parsing import parse_query_term, get_engine +from pypy.lang.prolog.interpreter.engine import Continuation, Frame, Engine + +def assert_true(query, e=None): + if e is None: + e = Engine() + term = e.parse(query)[0][0] + e.run(term) + f = Frame() + f.vars = e.frame.vars[:] + return f + +def assert_false(query, e=None): + if e is None: + e = Engine() + term = e.parse(query)[0][0] + py.test.raises(UnificationFailed, e.run, term) + +def prolog_raises(exc, query, e=None): + return assert_true("catch(((%s), fail), error(%s), true)." % + (query, exc), e) + +class CollectAllContinuation(Continuation): + def __init__(self): + self.frames = [] + + def call(self, engine): + f = Frame() + f.vars = engine.frame.vars[:] + self.frames.append(f) +# import pdb; pdb.set_trace() + print "restarting computation" + raise UnificationFailed + +def collect_all(engine, s): + collector = CollectAllContinuation() + term = engine.parse(s)[0][0] + py.test.raises(UnificationFailed, engine.run, term, + collector) + return collector.frames + Added: pypy/dist/pypy/lang/prolog/interpreter/translatedmain.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lang/prolog/interpreter/translatedmain.py Sun Nov 12 22:16:10 2006 @@ -0,0 +1,144 @@ +import os, sys +from pypy.rlib.parsing.parsing import ParseError +from pypy.rlib.parsing.deterministic import LexerError +from pypy.lang.prolog.interpreter.main import helptext +from pypy.lang.prolog.interpreter.parsing import parse_file, get_query_and_vars +from pypy.lang.prolog.interpreter.parsing import get_engine +from pypy.lang.prolog.interpreter.engine import Engine +from pypy.lang.prolog.interpreter.engine import Continuation +from pypy.lang.prolog.interpreter import error, term +import pypy.lang.prolog.interpreter.term +pypy.lang.prolog.interpreter.term.DEBUG = False + + +class StopItNow(Exception): + pass + +class ContinueContinuation(Continuation): + def __init__(self, var_to_pos, write): + self.var_to_pos = var_to_pos + self.write = write + + def call(self, engine): + self.write("yes\n") + var_representation(self.var_to_pos, engine, self.write) + while 1: + res = getch() + #self.write(res+"\n") + if res in "\r\x04\n": + self.write("\n") + raise StopItNow() + if res in ";nr": + raise error.UnificationFailed + elif res in "h?": + self.write(helptext) + elif res in "p": + var_representation(self.var_to_pos, engine, self.write) + else: + self.write('unknown action. press "h" for help\n') + +def var_representation(var_to_pos, engine, write): + from pypy.lang.prolog.builtin import formatting + f = formatting.TermFormatter(engine, quoted=True, max_depth=20) + for var, real_var in var_to_pos.iteritems(): + if var.startswith("_"): + continue + val = f.format(real_var.getvalue(engine.frame)) + write("%s = %s\n" % (var, val)) + +def getch(): + line = readline() + return line[0] + +def debug(msg): + os.write(2, "debug: " + msg + '\n') + +def printmessage(msg): + os.write(1, msg) + +def readline(): + result = [] + while 1: + s = os.read(0, 1) + result.append(s) + if s == "\n": + break + if s == '': + if len(result) > 1: + break + raise SystemExit + return "".join(result) + +def run(goal, var_to_pos, e): + from pypy.lang.prolog.interpreter.error import UnificationFailed, CatchableError + from pypy.lang.prolog.interpreter.error import UncatchableError, UserError + from pypy.lang.prolog.builtin import formatting + f = formatting.TermFormatter(e, quoted=True, max_depth=20) + try: + e.run(goal, ContinueContinuation(var_to_pos, printmessage)) + except UnificationFailed: + printmessage("no\n") + except UncatchableError, e: + printmessage("INTERNAL ERROR: %s\n" % (e.message, )) + except UserError, e: + printmessage("ERROR: ") + f._make_reverse_op_mapping() + printmessage("Unhandled exception: ") + printmessage(f.format(e.term)) + except CatchableError, e: + f._make_reverse_op_mapping() + printmessage("ERROR: ") + t = e.term + if isinstance(t, term.Term): + errorterm = t.args[0] + if isinstance(errorterm, term.Callable): + if errorterm.name == "instantiation_error": + printmessage("arguments not sufficiently instantiated\n") + return + elif errorterm.name == "existence_error": + if isinstance(errorterm, term.Term): + printmessage("Undefined %s: %s\n" % ( + f.format(errorterm.args[0]), + f.format(errorterm.args[1]))) + return + elif errorterm.name == "domain_error": + if isinstance(errorterm, term.Term): + printmessage( + "Domain error: '%s' expected, found '%s'\n" % ( + f.format(errorterm.args[0]), + f.format(errorterm.args[1]))) + return + elif errorterm.name == "type_error": + if isinstance(errorterm, term.Term): + printmessage( + "Type error: '%s' expected, found '%s'\n" % ( + f.format(errorterm.args[0]), + f.format(errorterm.args[1]))) + return + printmessage(" (but I cannot tell you which one)\n") + except StopItNow: + pass + else: + printmessage("yes\n") + +def repl(e): + printmessage("welcome!\n") + while 1: + printmessage(">?- ") + line = readline() + if line == "halt.\n": + break + try: + goals, var_to_pos = e.parse(line) + except ParseError: + printmessage("parse error\n") + continue + for goal in goals: + run(goal, var_to_pos, e) + +def execute(e, filename): + e.run(term.Term("consult", [term.Atom(filename)])) + +if __name__ == '__main__': + e = Engine() + repl(e) From cfbolz at codespeak.net Sun Nov 12 22:19:27 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 22:19:27 +0100 (CET) Subject: [pypy-svn] r34537 - pypy/dist/pypy/rlib/parsing Message-ID: <20061112211927.69D761016A@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 22:19:26 2006 New Revision: 34537 Modified: pypy/dist/pypy/rlib/parsing/tree.py Log: remove print Modified: pypy/dist/pypy/rlib/parsing/tree.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/tree.py (original) +++ pypy/dist/pypy/rlib/parsing/tree.py Sun Nov 12 22:19:26 2006 @@ -102,7 +102,6 @@ code.append(" else:") code.append(" return self.dispatch_table[node.symbol](self, node)") code.append(" raise VisitError(node)") - print "\n".join(code) exec py.code.Source("\n".join(code)).compile() return dispatch From cfbolz at codespeak.net Sun Nov 12 22:32:30 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 22:32:30 +0100 (CET) Subject: [pypy-svn] r34538 - pypy/dist/pypy/translator/goal Message-ID: <20061112213230.1565110166@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 22:32:27 2006 New Revision: 34538 Added: pypy/dist/pypy/translator/goal/targetprologstandalone.py Log: add a target for the prolog interpreter Added: pypy/dist/pypy/translator/goal/targetprologstandalone.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/goal/targetprologstandalone.py Sun Nov 12 22:32:27 2006 @@ -0,0 +1,35 @@ +""" +A simple standalone target for the prolog interpreter. +""" + +import sys +from pypy.lang.prolog.interpreter.translatedmain import repl, execute + +# __________ Entry point __________ + +from pypy.lang.prolog.interpreter.engine import Engine +from pypy.lang.prolog.interpreter import engine, term +e = Engine() +engine.DEBUG = False +term.DEBUG = False + +def entry_point(argv): + if len(argv) == 2: + execute(e, argv[1]) + try: + repl(e) + except SystemExit: + return 1 + return 0 + +# _____ Define and setup target ___ + +def handle_config(config): + config.translation.stackless = True + +def target(driver, args): + driver.exe_name = 'pyrolog-%(backend)s' + return entry_point, None + +if __name__ == '__main__': + entry_point(sys.argv) From pedronis at codespeak.net Sun Nov 12 22:52:38 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 12 Nov 2006 22:52:38 +0100 (CET) Subject: [pypy-svn] r34539 - pypy/dist/pypy/translator Message-ID: <20061112215238.339641016C@code0.codespeak.net> Author: pedronis Date: Sun Nov 12 22:52:36 2006 New Revision: 34539 Modified: pypy/dist/pypy/translator/simplify.py Log: the keepalive removal code was making assumptions that made sense only if keepalives are used in the context of inner non-gc structure out of gc structure. We now have usages of keepalive about keeping alive things whose destruction has side-effects in terms of resource/raw allocated memory release. Remove the keepalive removal code. Modified: pypy/dist/pypy/translator/simplify.py ============================================================================== --- pypy/dist/pypy/translator/simplify.py (original) +++ pypy/dist/pypy/translator/simplify.py Sun Nov 12 22:52:36 2006 @@ -468,10 +468,6 @@ read_vars = {} # set of variables really used variable_flow = {} # map {Var: list-of-Vars-it-depends-on} - transport_flow = {} # map {Var: list-of-Vars-depending-on-it-through-links-or-indentity-ops} - - keepalive_vars = {} # set of variables in keepalives - def canremove(op, block): if op.opname not in CanRemove: return False @@ -484,9 +480,7 @@ for block in blocks: # figure out which variables are ever read for op in block.operations: - if op.opname == 'keepalive': - keepalive_vars[op.args[0]] = True - elif not canremove(op, block): # mark the inputs as really needed + if not canremove(op, block): # mark the inputs as really needed for arg in op.args: read_vars[arg] = True else: @@ -494,8 +488,6 @@ # on the input variables deps = variable_flow.setdefault(op.result, []) deps.extend(op.args) - if op.opname in ('cast_pointer', 'same_as'): - transport_flow.setdefault(op.args[0], []).append(op.result) if isinstance(block.exitswitch, Variable): read_vars[block.exitswitch] = True @@ -510,7 +502,6 @@ for arg, targetarg in zip(link.args, link.target.inputargs): deps = variable_flow.setdefault(targetarg, []) deps.append(arg) - transport_flow.setdefault(arg, []).append(targetarg) else: # return and except blocks implicitely use their input variable(s) for arg in block.inputargs: @@ -533,31 +524,6 @@ flow_read_var_backward(read_vars) - # compute vars depending on a read-var through the transport-flow - read_var_aliases = {} - pending = [] - for var in transport_flow: - if var in read_vars: - pending.append(var) - read_var_aliases[var] = True - for var in pending: - for nextvar in transport_flow.get(var, []): - if nextvar not in read_var_aliases: - read_var_aliases[nextvar] = True - pending.append(nextvar) - - # a keepalive var is read-var if it's an alias reached from some read-var - # through the transport flow - new_read_vars = {} - for var in keepalive_vars: - if var in read_var_aliases: - read_vars[var] = True - new_read_vars[var] = True - - # flow backward the new read-vars - flow_read_var_backward(new_read_vars) - - for block in blocks: # look for removable operations whose result is never used @@ -566,9 +532,6 @@ if op.result not in read_vars: if canremove(op, block): del block.operations[i] - elif op.opname == 'keepalive': - if op.args[0] not in read_vars: - del block.operations[i] elif op.opname == 'simple_call': # XXX we want to have a more effective and safe # way to check if this operation has side effects From pedronis at codespeak.net Sun Nov 12 22:58:13 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 12 Nov 2006 22:58:13 +0100 (CET) Subject: [pypy-svn] r34540 - pypy/dist/pypy/rlib/test Message-ID: <20061112215813.AF4921016E@code0.codespeak.net> Author: pedronis Date: Sun Nov 12 22:58:12 2006 New Revision: 34540 Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py Log: this now passes. I took me a bit to understand what exactly is going on here: this depends on explcit keepalive in very delicate ways, which means even if we move away from automatic keepalive, things like malloc removal will indeed still need to be very careful and insert/preserve keepalives. Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Sun Nov 12 22:58:12 2006 @@ -119,7 +119,7 @@ assert res == 26 def test_char_p_in_struct(self): - py.test.skip("keepalive problem in malloc removal?") + #py.test.skip("keepalive problem in malloc removal?") S2 = RStruct('S2', [('p', rc_char_p)]) def func(): s = S2.allocate() From pedronis at codespeak.net Sun Nov 12 23:29:05 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 12 Nov 2006 23:29:05 +0100 (CET) Subject: [pypy-svn] r34541 - pypy/dist/pypy/jit/timeshifter Message-ID: <20061112222905.247DE1016E@code0.codespeak.net> Author: pedronis Date: Sun Nov 12 23:29:04 2006 New Revision: 34541 Modified: pypy/dist/pypy/jit/timeshifter/transform.py Log: we are not really using the "at end of the loop" style of global-merge point hint. It should be a separate hint if really needed. Comment out the supporting code for now. Modified: pypy/dist/pypy/jit/timeshifter/transform.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/transform.py (original) +++ pypy/dist/pypy/jit/timeshifter/transform.py Sun Nov 12 23:29:04 2006 @@ -80,17 +80,17 @@ if len(entrymap[prevblock]) > 1: global_merge_blocks[prevblock] = True cand += 1 - op = block.operations[-1] - if (op.opname == 'hint' and - op.args[1].value == {'global_merge_point': True}): - hashint = True - for link in block.exits: - if len(entrymap[link.target]) > 1: - global_merge_blocks[link.target] = True - cand += 1 + #op = block.operations[-1] + #if (op.opname == 'hint' and + # op.args[1].value == {'global_merge_point': True}): + # hashint = True + # for link in block.exits: + # if len(entrymap[link.target]) > 1: + # global_merge_blocks[link.target] = True + # cand += 1 assert not hashint or cand==1, ( "ambigous global merge point hint: %r" % block) - for op in block.operations[1:-1]: + for op in block.operations[1:]: assert not (op.opname == 'hint' and op.args[1].value == {'global_merge_point': True}), ( "stranded global merge point hint: %r" % block) From cfbolz at codespeak.net Sun Nov 12 23:39:22 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 23:39:22 +0100 (CET) Subject: [pypy-svn] r34542 - pypy/dist/pypy/rlib/parsing Message-ID: <20061112223922.2CF5110172@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 23:39:21 2006 New Revision: 34542 Modified: pypy/dist/pypy/rlib/parsing/deterministic.py pypy/dist/pypy/rlib/parsing/parsing.py Log: splitlines is not rpython, it seems Modified: pypy/dist/pypy/rlib/parsing/deterministic.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/deterministic.py (original) +++ pypy/dist/pypy/rlib/parsing/deterministic.py Sun Nov 12 23:39:21 2006 @@ -31,7 +31,7 @@ def nice_error_message(self, filename=""): result = [" File %s, line %s" % (filename, self.lineno)] - result.append(self.input.splitlines()[self.lineno]) + result.append(self.input.split("\n")[self.lineno]) result.append(" " * self.columnno + "^") result.append("LexerError") return "\n".join(result) Modified: pypy/dist/pypy/rlib/parsing/parsing.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/parsing.py (original) +++ pypy/dist/pypy/rlib/parsing/parsing.py Sun Nov 12 23:39:21 2006 @@ -48,7 +48,7 @@ def nice_error_message(self, filename="", source=""): result = [" File %s, line %s" % (filename, self.source_pos.lineno)] if source: - result.append(source.splitlines()[self.source_pos.lineno]) + result.append(source.split("\n")[self.source_pos.lineno]) result.append(" " * self.source_pos.columnno + "^") else: result.append("") From cfbolz at codespeak.net Sun Nov 12 23:43:59 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 12 Nov 2006 23:43:59 +0100 (CET) Subject: [pypy-svn] r34543 - pypy/dist/pypy/lang/prolog/interpreter Message-ID: <20061112224359.D28B110174@code0.codespeak.net> Author: cfbolz Date: Sun Nov 12 23:43:58 2006 New Revision: 34543 Modified: pypy/dist/pypy/lang/prolog/interpreter/translatedmain.py Log: better error reporting for in case of parse errors Modified: pypy/dist/pypy/lang/prolog/interpreter/translatedmain.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/translatedmain.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/translatedmain.py Sun Nov 12 23:43:58 2006 @@ -121,7 +121,7 @@ else: printmessage("yes\n") -def repl(e): +def repl(engine): printmessage("welcome!\n") while 1: printmessage(">?- ") @@ -129,12 +129,15 @@ if line == "halt.\n": break try: - goals, var_to_pos = e.parse(line) - except ParseError: - printmessage("parse error\n") + goals, var_to_pos = engine.parse(line) + except ParseError, exc: + printmessage(exc.nice_error_message("", line) + "\n") + continue + except LexerError, exc: + printmessage(exc.nice_error_message("") + "\n") continue for goal in goals: - run(goal, var_to_pos, e) + run(goal, var_to_pos, engine) def execute(e, filename): e.run(term.Term("consult", [term.Atom(filename)])) From guido at codespeak.net Mon Nov 13 09:20:47 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 13 Nov 2006 09:20:47 +0100 (CET) Subject: [pypy-svn] r34544 - in pypy/dist/pypy/translator/js/modules: . test Message-ID: <20061113082047.DD48710174@code0.codespeak.net> Author: guido Date: Mon Nov 13 09:20:45 2006 New Revision: 34544 Modified: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: More shuffling and cleanups, added basic support for events. Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Mon Nov 13 09:20:45 2006 @@ -1,11 +1,11 @@ """Document Object Model support - this provides a mock browser API, both the standard DOM l. 1 and 2 stuff as - the browser-specific (level 0) additions + this provides a mock browser API, both the standard DOM level 2 stuff as + the browser-specific additions note that the API is not and will not be complete: more exotic features - will most probably not behave as expected + will most probably not behave as expected, or are not implemented at all http://www.w3.org/DOM/ - main standard http://www.w3schools.com/dhtml/dhtml_dom.asp - more informal stuff @@ -45,58 +45,114 @@ original = getattr(other, '_original', other) return original is self._original -def _quote_html(text): - for char, e in [('&', 'amp'), ('<', 'lt'), ('>', 'gt'), ('"', 'quot'), - ("'", 'apos')]: - text = text.replace(char, '&%s;' % (e,)) - return text +class Element(Node): + nodeType = 1 -_singletons = ['link', 'meta'] -def _serialize_html(node): - ret = [] - if node.nodeType == 1: - nodeName = getattr(node, '_original', node).nodeName - ret += ['<', nodeName] - if len(node.attributes): - for aname in node.attributes.keys(): - attr = node.attributes[aname] - ret.append(' %s="%s"' % (attr.nodeName, attr.nodeValue)) - if len(node.childNodes) or nodeName not in _singletons: - ret.append('>') - for child in node.childNodes: - if child.nodeType == 1: - ret.append(_serialize_html(child)) - else: - ret.append(_quote_html(child.nodeValue)) - ret += [''] - else: - ret.append(' />') - return ''.join(ret) +class Attribute(Node): + nodeType = 2 -class HTMLNode(Node): - def getElementsByTagName(self, name): - name = name.lower() - return self.__getattr__('getElementsByTagName')(name) +class Text(Node): + nodeType = 3 - def _get_innerHTML(self): - ret = [] - for child in self.childNodes: - ret.append(_serialize_html(child)) - return ''.join(ret) +class Document(Node): + nodeType = 9 + + def __init__(self, docnode=None): + super(Document, self).__init__(docnode) + self._original = docnode - def _set_innerHTML(self, html): - dom = minidom.parseString('%s' % (html,)) - while self.childNodes: - self.removeChild(self.lastChild) - for child in dom.documentElement.childNodes: - child = self.ownerDocument.importNode(child, True) - self.appendChild(child) - del dom + def createEvent(self, group=''): + """create an event - innerHTML = property(_get_innerHTML, _set_innerHTML) + note that the group argument is ignored + """ + if group in ('KeyboardEvent', 'KeyboardEvents'): + return KeyEvent() + elif group in ('MouseEvent', 'MouseEvents'): + return MouseEvent() + return Event() -class Element(Node): - nodeType = 1 +# the standard DOM stuff that doesn't directly deal with XML +# note that we're mimicking the standard (Mozilla) APIs, so things tested +# against this code may not work in Internet Explorer + +# XXX note that we store the events on the wrapped minidom node to avoid losing +# them on re-wrapping +class EventTarget(BasicExternal): # XXX mixin... is the super correct?!? + def addEventListener(self, type, listener, useCapture): + if not hasattr(self._original, '_events'): + self._original._events = [] + # XXX note that useCapture is ignored... + self._original._events.append((type, listener, useCapture)) + + def dispatchEvent(self, event): + if event._cancelled: + return + event.currentTarget = self + if event.target is None: + event.target = self + if event.originalTarget is None: + event.originalTarget = self + if hasattr(self._original, '_events'): + for etype, handler, capture in self._original._events: + if etype == event.type: + handler(event) + if event._cancelled or event.cancelBubble: + return + parent = getattr(self, 'parentNode', None) + if parent is not None: + parent.dispatchEvent(event) + + def removeEventListener(self, type, listener, useCapture): + if not hasattr(self._original, '_events'): + raise ValueError('no registration for listener') + filtered = [] + for data in self._original._events: + if data != (type, listener, useCapture): + filtered.append(data) + if filtered == self._original._events: + raise ValueError('no registration for listener') + self._original._events = filtered + +class Event(BasicExternal): + def initEvent(self, type, bubbles, cancelable): + self.type = type + self.cancelBubble = not bubbles + self.cancelable = cancelable + self.target = None + self.currentTarget = None + self.originalTarget = None + self._cancelled = False + + def preventDefault(self): + if not self.cancelable: + raise TypeError('event can not be canceled') + self._cancelled = True + + def stopPropagation(self): + self.cancelBubble = True + +class KeyEvent(Event): + pass + +class MouseEvent(Event): + pass + +class Style(BasicExternal): + def __getattr__(self, name): + if name not in self._fields: + raise AttributeError, name + return None + +# HTML DOM + +class HTMLNode(Node, EventTarget): + def getElementsByTagName(self, name): + name = name.lower() + return self.__getattr__('getElementsByTagName')(name) + + def __str__(self): + return '<%s %s>' % (self.__class__.__name__, self.nodeName) class HTMLElement(HTMLNode, Element): id = '' @@ -115,31 +171,42 @@ return self._original.nodeName.upper() nodeName = property(_nodeName) -class Attribute(Node): - nodeType = 2 + def _get_innerHTML(self): + ret = [] + for child in self.childNodes: + ret.append(_serialize_html(child)) + return ''.join(ret) -class Text(Node): - nodeType = 3 + def _set_innerHTML(self, html): + dom = minidom.parseString('%s' % (html,)) + while self.childNodes: + self.removeChild(self.lastChild) + for child in dom.documentElement.childNodes: + child = self.ownerDocument.importNode(child, True) + self._original.appendChild(child) + del dom -class Document(HTMLNode): - nodeType = 9 - - def __init__(self, docnode=None): - super(Document, self).__init__(docnode) - self._original = docnode + innerHTML = property(_get_innerHTML, _set_innerHTML) +class HTMLDocument(Document, HTMLNode): def getElementById(self, id): nodes = self.getElementsByTagName('*') for node in nodes: if node.getAttribute('id') == id: return node +# non-DOM ('DOM level 0') stuff + +# Window is the main environment, the root node of the JS object tree + class Window(BasicExternal): def __init__(self, html=('Untitled document' - ''), parent=None): + ''), parent=None, + emit_events=False): global document self._html = html - self.document = document = Document(minidom.parseString(html)) + self._emit_events = emit_events + self.document = document = HTMLDocument(minidom.parseString(html)) # references to windows self.content = self @@ -154,68 +221,12 @@ # other properties self.closed = True + if self._emit_events: + _emit_event(self, 'onload') def __getattr__(self, name): return globals()[name] -# the following code wraps minidom nodes with Node classes, and makes -# sure all methods on the nodes return wrapped nodes - -class _FunctionWrapper(object): - """makes sure function return values are wrapped if appropriate""" - def __init__(self, callable): - self._original = callable - - def __call__(self, *args, **kwargs): - args = list(args) - for i, arg in enumerate(args): - if isinstance(arg, Node): - args[i] = arg._original - for name, arg in kwargs.iteritems(): - if isinstance(arg, Node): - kwargs[arg] = arg._original - value = self._original(*args, **kwargs) - return _wrap(value) - -_typetoclass = { - 1: HTMLElement, - 2: Attribute, - 3: Text, - 9: Document, -} -def _wrap(value): - if isinstance(value, minidom.Node): - nodeclass = _typetoclass[value.nodeType] - return nodeclass(value) - elif callable(value): - return _FunctionWrapper(value) - # nothing fancier in minidom, i hope... - # XXX and please don't add anything fancier either ;) - elif isinstance(value, list): - return [_wrap(x) for x in value] - return value - -# more DOM API, the stuff that doesn't directly deal with XML -# note that we're mimicking the standard (Mozilla) APIs, so things tested -# against this code may not work in Internet Explorer - -class Event(BasicExternal): - pass - -class KeyEvent(Event): - pass - -class MouseEvent(Event): - pass - -class Style(BasicExternal): - def __getattr__(self, name): - if name not in self._fields: - raise AttributeError, name - return None - -# non-DOM ('DOM level 0') stuff - def setTimeout(func, delay): # scheduler call, but we don't want to mess with threads right now if one(): @@ -227,7 +238,7 @@ def alert(msg): pass -# some helper functions (XXX imo these can go, but the code seem to use them +# some helper functions (XXX imo these can go, but the code seems to use them # a lot... isn't it possible to just use dom.window and dom.document instead?) def get_document(): @@ -257,12 +268,44 @@ 'previousSibling' : Element(), 'tagName' : "aa", 'textContent' : "aa", - 'value' : "aa", +} + +Node._methods = { + 'appendChild' : MethodDesc([Element()]), + 'cloneNode' : MethodDesc([12], Element()), + 'getElementsByTagName' : MethodDesc(["aa"], [Element(), Element()]), + 'hasChildNodes' : MethodDesc([], True), + 'insertBefore' : MethodDesc([Element(), Element()], Element()), + 'removeChild' : MethodDesc([Element()], Element()), + 'replaceChild' : MethodDesc([Element(), Element()], Element()), } Element._fields = Node._fields.copy() -Element._fields.update({ +Element._methods = Node._methods.copy() +Element._methods.update({ + 'getAttribute' : MethodDesc(["aa"], "aa"), + 'getAttributeNS' : MethodDesc(["aa", "aa"], "aa"), + 'getAttributeNode' : MethodDesc(["aa"], Element()), + 'getAttributeNodeNS' : MethodDesc(["aa", "aa"], Element()), + 'hasAttribute' : MethodDesc(["aa"], True), + 'hasAttributeNS' : MethodDesc(["aa", "aa"], True), + 'hasAttributes' : MethodDesc([], True), + 'removeAttribute' : MethodDesc(['aa']), + 'removeAttributeNS' : MethodDesc(["aa", "aa"]), + 'removeAttributeNode' : MethodDesc([Element()], "aa"), + 'setAttribute' : MethodDesc(["aa", "aa"]), + 'setAttributeNS' : MethodDesc(["aa", "aa", "aa"]), + 'setAttributeNode' : MethodDesc([Element()], Element()), + 'setAttributeNodeNS' : MethodDesc(["ns", Element()], Element()), +}) + +HTMLNode._fields = Node._fields.copy() +HTMLNode._methods = Node._methods.copy() + +HTMLElement._fields = HTMLNode._fields.copy() +HTMLElement._fields.update(Element._fields.copy()) +HTMLElement._fields.update({ 'className' : "aa", 'clientHeight' : 12, 'clientWidth' : 12, @@ -270,8 +313,8 @@ 'clientTop' : 12, 'dir' : "aa", 'innerHTML' : "asd", - 'lang' : "asd", 'id' : "aa", + 'lang' : "asd", 'offsetHeight' : 12, 'offsetLeft' : 12, 'offsetParent' : 12, @@ -283,62 +326,30 @@ 'scrollWidth' : 12, 'style' : Style(), 'tabIndex' : 12, - 'onblur' : MethodDesc([Event()]), - 'onclick' : MethodDesc([MouseEvent()]), - 'ondblclick' : MethodDesc([MouseEvent()]), - 'onfocus' : MethodDesc([Event()]), - 'onkeydown' : MethodDesc([KeyEvent()]), - 'onkeypress' : MethodDesc([KeyEvent()]), - 'onkeyup' : MethodDesc([KeyEvent()]), - 'onmousedown' : MethodDesc([MouseEvent()]), - 'onmousemove' : MethodDesc([MouseEvent()]), - 'onmouseup' : MethodDesc([MouseEvent()]), - 'onmouseover' : MethodDesc([MouseEvent()]), - 'onmouseup' : MethodDesc([MouseEvent()]), - 'onresize' : MethodDesc([Event()]), + 'value' : "aa", # XXX? }) -HTMLElement._fields = Element._fields.copy() -Node._methods = { - 'appendChild' : MethodDesc([HTMLElement()]), - 'cloneNode' : MethodDesc([12], HTMLElement()), - 'hasChildNodes' : MethodDesc([], True), - 'insertBefore' : MethodDesc([HTMLElement(), HTMLElement()], HTMLElement()), - 'removeChild' : MethodDesc([HTMLElement()], HTMLElement()), - 'replaceChild' : MethodDesc([HTMLElement(), HTMLElement()], HTMLElement()), -} - -Element._methods = Node._methods.copy() -Element._methods.update({ - 'addEventListener' : MethodDesc(["aa", lambda : None, True]), - 'getAttribute' : MethodDesc(["aa"], "aa"), - 'getAttributeNS' : MethodDesc(["aa", "aa"], "aa"), - 'getAttributeNode' : MethodDesc(["aa"], Element()), - 'getAttributeNodeNS' : MethodDesc(["aa", "aa"], Element()), - 'getElementsByTagName' : MethodDesc(["aa"], [Element(), Element()]), - 'hasAttribute' : MethodDesc(["aa"], True), - 'hasAttributeNS' : MethodDesc(["aa", "aa"], True), - 'hasAttributes' : MethodDesc([], True), - 'removeAttribute' : MethodDesc(['aa']), - 'removeAttributeNS' : MethodDesc(["aa", "aa"]), - 'removeAttributeNode' : MethodDesc([Element()], "aa"), - 'removeEventListener' : MethodDesc(["aa", lambda : None, True]), - 'setAttribute' : MethodDesc(["aa", "aa"]), - 'setAttributeNS' : MethodDesc(["aa", "aa", "aa"]), - 'setAttributeNode' : MethodDesc([Element()], Element()), - 'setAttributeNodeNS' : MethodDesc(["ns", Element()], Element()), +HTMLElement._methods = HTMLNode._methods.copy() +HTMLElement._methods.update(Element._methods.copy()) +HTMLElement._methods.update({ 'blur' : MethodDesc([]), 'click' : MethodDesc([]), - 'dispatchEvent' : MethodDesc(["aa"], True), 'focus' : MethodDesc([]), 'normalize' : MethodDesc([]), 'scrollIntoView' : MethodDesc([12]), 'supports' : MethodDesc(["aa", 1.0]), }) -HTMLElement._methods = Element._methods.copy() +Document._fields = Node._fields.copy() +Document._fields.update({ + 'characterSet' : "aa", + 'contentWindow' : Window(), + 'doctype' : "aa", + 'documentElement' : Element(), + 'styleSheets' : [Style(), Style()], +}) -Document._methods = Element._methods.copy() +Document._methods = Node._methods.copy() Document._methods.update({ 'clear' : MethodDesc([]), 'close' : MethodDesc([]), @@ -346,8 +357,8 @@ 'createDocumentFragment' : MethodDesc([], Element()), 'createElement' : MethodDesc(["aa"], Element()), 'createElementNS' : MethodDesc(["aa", "aa"], Element()), - 'createTextNode' : MethodDesc(["aa"], Element()), 'createEvent' : MethodDesc(["aa"], Event()), + 'createTextNode' : MethodDesc(["aa"], Element()), #'createRange' : MethodDesc(["aa"], Range()) - don't know what to do here 'getElementById' : MethodDesc(["aa"], Element()), 'getElementsByName' : MethodDesc(["aa"], [Element(), Element()]), @@ -357,21 +368,16 @@ 'writeln' : MethodDesc(["aa"]), }) -Document._fields = Element._fields.copy() -Document._fields.update({ +HTMLDocument._fields = Document._fields.copy() +HTMLDocument._fields.update({ 'alinkColor' : "aa", 'bgColor' : "aa", 'body' : Element(), - 'characterSet' : "aa", 'cookie' : "aa", - 'contentWindow' : Window(), 'defaultView' : Window(), - 'doctype' : "aa", - 'documentElement' : Element(), 'domain' : "aa", 'embeds' : [Element(), Element()], 'fgColor' : "aa", - 'firstChild' : Element(), 'forms' : [Element(), Element()], 'height' : 123, 'images' : [Element(), Element()], @@ -380,13 +386,14 @@ 'links' : [Element(), Element()], 'location' : "aa", 'referrer' : "aa", - 'styleSheets' : [Style(), Style()], 'title' : "aa", 'URL' : "aa", 'vlinkColor' : "aa", 'width' : 123, }) +HTMLDocument._methods = Document._methods.copy() + Window._fields = { 'content' : Window(), 'closed' : True, @@ -422,8 +429,7 @@ 'window' : Window(), } -Window._methods = Element._methods.copy() -Window._methods.update({ +Window._methods = { 'alert' : MethodDesc(["aa"]), 'atob' : MethodDesc(["aa"], "aa"), 'back' : MethodDesc([]), @@ -461,7 +467,7 @@ 'onselect' : MethodDesc([MouseEvent()]), 'onsubmit' : MethodDesc([MouseEvent()]), 'onunload' : MethodDesc([Event()]), -}) +} Style._fields = { 'azimuth' : 'aa', @@ -593,16 +599,124 @@ 'zIndex' : 'aa', } -KeyEvent_fields = { +EventTarget._fields = { + 'onblur' : MethodDesc([Event()]), + 'onclick' : MethodDesc([MouseEvent()]), + 'ondblclick' : MethodDesc([MouseEvent()]), + 'onfocus' : MethodDesc([Event()]), + 'onkeydown' : MethodDesc([KeyEvent()]), + 'onkeypress' : MethodDesc([KeyEvent()]), + 'onkeyup' : MethodDesc([KeyEvent()]), + 'onmousedown' : MethodDesc([MouseEvent()]), + 'onmousemove' : MethodDesc([MouseEvent()]), + 'onmouseup' : MethodDesc([MouseEvent()]), + 'onmouseover' : MethodDesc([MouseEvent()]), + 'onmouseup' : MethodDesc([MouseEvent()]), + 'onresize' : MethodDesc([Event()]), +} + +EventTarget._methods = { + 'addEventListener' : MethodDesc(["aa", lambda : None, True]), + 'dispatchEvent' : MethodDesc(["aa"], True), + 'removeEventListener' : MethodDesc(["aa", lambda : None, True]), +} + +Event._fields = { + 'bubbles': True, + 'cancelBubble': True, + 'cancelable': True, + 'currentTarget': Element(), + 'detail': 1, + 'relatedTarget': Element(), + 'target': Element(), + 'type': 'aa', +} + +Event._methods = { + 'initEvent': MethodDesc(["aa", True, True]), + 'preventDefault': MethodDesc([]), + 'stopPropagation': MethodDesc([]), +} + +KeyEvent._fields = Event._fields.copy() +KeyEvent._fields.update({ 'keyCode' : 12, 'charCode' : 12, -} +}) get_window.suggested_primitive = True get_document.suggested_primitive = True setTimeout.suggested_primitive = True alert.suggested_primitive = True +# the following code wraps minidom nodes with Node classes, and makes +# sure all methods on the nodes return wrapped nodes + +class _FunctionWrapper(object): + """makes sure function return values are wrapped if appropriate""" + def __init__(self, callable): + self._original = callable + + def __call__(self, *args, **kwargs): + args = list(args) + for i, arg in enumerate(args): + if isinstance(arg, Node): + args[i] = arg._original + for name, arg in kwargs.iteritems(): + if isinstance(arg, Node): + kwargs[arg] = arg._original + value = self._original(*args, **kwargs) + return _wrap(value) + +_typetoclass = { + 1: HTMLElement, + 2: Attribute, + 3: Text, + 9: HTMLDocument, +} +def _wrap(value): + if isinstance(value, minidom.Node): + nodeclass = _typetoclass[value.nodeType] + return nodeclass(value) + elif callable(value): + return _FunctionWrapper(value) + # nothing fancier in minidom, i hope... + # XXX and please don't add anything fancier either ;) + elif isinstance(value, list): + return [_wrap(x) for x in value] + return value + +# some helper functions + +def _quote_html(text): + for char, e in [('&', 'amp'), ('<', 'lt'), ('>', 'gt'), ('"', 'quot'), + ("'", 'apos')]: + text = text.replace(char, '&%s;' % (e,)) + return text + +_singletons = ['link', 'meta'] +def _serialize_html(node): + ret = [] + if node.nodeType == 1: + nodeName = getattr(node, '_original', node).nodeName + ret += ['<', nodeName] + if len(node.attributes): + for aname in node.attributes.keys(): + attr = node.attributes[aname] + ret.append(' %s="%s"' % (attr.nodeName, + _quote_html(attr.nodeValue))) + if len(node.childNodes) or nodeName not in _singletons: + ret.append('>') + for child in node.childNodes: + if child.nodeType == 1: + ret.append(_serialize_html(child)) + else: + ret.append(_quote_html(child.nodeValue)) + ret += [''] + else: + ret.append(' />') + return ''.join(ret) + # initialization # set the global 'window' instance to an empty HTML document, override using Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 13 09:20:45 2006 @@ -1,8 +1,27 @@ import py from pypy.translator.js.modules import dom from pypy.translator.js.main import rpython2javascript +from xml.dom.minidom import parseString import sys +def test_quote_html(): + assert dom._quote_html('foo&bar') == 'foo&bar' + assert dom._quote_html('foo"&bar') == 'foo"&bar' + +def test_serialize_html(): + def roundtrip(html): + return dom._serialize_html(parseString(html).documentElement) + html = '
content
' + assert roundtrip(html) == html + html = '' + assert roundtrip(html) == html + html = '' + assert roundtrip(html) == '' + html = '
\n
foo
\n
' + assert roundtrip(html) == html + html = '
foo&bar
' + assert roundtrip(html) == html + def test_init(): window = dom.Window('foo') nodeType = window.document.nodeType @@ -13,6 +32,9 @@ somediv = window.document.getElementsByTagName('body')[0].childNodes[0] assert somediv.nodeValue == 'foo' + py.test.raises(py.std.xml.parsers.expat.ExpatError, + 'dom.Window("")') + def test_wrap(): window = dom.Window() document = window.document @@ -84,6 +106,93 @@ assert body.innerHTML == '' body.innerHTML = '
some content
' assert body.innerHTML == '
some content
' + assert body.childNodes[0].nodeName == 'DIV' + +def test_event_init(): + window = dom.Window() + e = dom.Event() + e.initEvent('click', True, True) + assert e.cancelable == True + assert e.target == None + body = window.document.getElementsByTagName('body')[0] + body.dispatchEvent(e) + assert e.target is body + +def test_event_handling(): + class handler: + called = False + def __call__(self, e): + self.called = True + h = handler() + window = dom.Window() + body = window.document.getElementsByTagName('body')[0] + body.addEventListener('click', h, False) + e = dom.Event() + e.initEvent('click', True, True) + body.dispatchEvent(e) + assert h.called == True + +def test_event_bubbling(): + class handler: + called = False + def __call__(self, e): + self.called = True + h = handler() + window = dom.Window() + body = window.document.getElementsByTagName('body')[0] + div = window.document.createElement('div') + body.appendChild(div) + body.addEventListener('click', h, False) + e = dom.Event() + e.initEvent('click', False, True) + div.dispatchEvent(e) + assert h.called == False + e = dom.Event() + e.initEvent('click', True, True) + div.dispatchEvent(e) + assert h.called == True + +def test_remove_event_listener(): + class handler: + called = False + def __call__(self, e): + self.called = True + window = dom.Window() + body = window.document.getElementsByTagName('body')[0] + div = window.document.createElement('div') + body.appendChild(div) + py.test.raises(Exception, 'body.removeEventListener("click", h, False)') + h = handler() + body.addEventListener('click', h, False) + e = dom.Event() + e.initEvent('click', True, True) + body.dispatchEvent(e) + assert h.called == True + h.called = False + body.removeEventListener('click', h, False) + e = dom.Event() + e.initEvent('click', True, True) + body.dispatchEvent(e) + assert h.called == False + +def test_event_vars(): + class handler: + event = None # XXX annotator problem? + def __call__(self, e): + self.event = e + e.stopPropagation() + window = dom.Window() + body = window.document.getElementsByTagName('body')[0] + div = window.document.createElement('div') + body.appendChild(div) + h = handler() + body.addEventListener('click', h, False) + e = dom.Event() + e.initEvent('click', True, True) + div.dispatchEvent(e) + assert h.event.target == div + assert h.event.originalTarget == div + assert h.event.currentTarget == body def test_build(): py.test.skip("Not implemented yet") @@ -91,3 +200,4 @@ if var.startswith('test_') and var != 'test_build': # just build it rpython2javascript(sys.modules[__name__], [var]) + From guido at codespeak.net Mon Nov 13 10:23:32 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 13 Nov 2006 10:23:32 +0100 (CET) Subject: [pypy-svn] r34545 - in pypy/dist/pypy/translator/js/modules: . test Message-ID: <20061113092332.430BE10176@code0.codespeak.net> Author: guido Date: Mon Nov 13 10:23:30 2006 New Revision: 34545 Modified: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Added proper support for window.location, HTMLNode.className and HTMLNode.id. Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Mon Nov 13 10:23:30 2006 @@ -151,20 +151,31 @@ name = name.lower() return self.__getattr__('getElementsByTagName')(name) - def __str__(self): + def __repr__(self): return '<%s %s>' % (self.__class__.__name__, self.nodeName) + def _getClassName(self): + return self.getAttribute('class') + + def _setClassName(self, name): + self.setAttribute('class', name) + + className = property(_getClassName, _setClassName) + + def _getId(self): + return self.getAttribute('id') + + def _setId(self, id): + self.setAttribute('id', id) + + id = property(_getId, _setId) + class HTMLElement(HTMLNode, Element): id = '' style = None def __init__(self, node=None): super(Element, self).__init__(node) - if node is not None: - self._init(node) - - def _init(self, node): - self.id = node.getAttribute('id') self.style = Style() def _nodeName(self): @@ -199,14 +210,11 @@ # Window is the main environment, the root node of the JS object tree -class Window(BasicExternal): +class Window(EventTarget): def __init__(self, html=('Untitled document' - ''), parent=None, - emit_events=False): - global document + ''), parent=None): self._html = html - self._emit_events = emit_events - self.document = document = HTMLDocument(minidom.parseString(html)) + self.document = HTMLDocument(minidom.parseString(html)) # references to windows self.content = self @@ -221,12 +229,23 @@ # other properties self.closed = True - if self._emit_events: - _emit_event(self, 'onload') + self._location = 'about:blank' + + self._original = self # for EventTarget interface (XXX a bit nasty) def __getattr__(self, name): return globals()[name] + def _getLocation(self): + return self._location + + def _setLocation(self, newloc): + url = urllib.urlopen(newloc) + html = url.read() + self.document = HTMLDocument(minidom.parseString(html)) + + location = property(_getLocation, _setLocation) + def setTimeout(func, delay): # scheduler call, but we don't want to mess with threads right now if one(): @@ -242,7 +261,7 @@ # a lot... isn't it possible to just use dom.window and dom.document instead?) def get_document(): - return NonConstant(document) + return NonConstant(window.document) def get_window(): return NonConstant(window) @@ -251,7 +270,6 @@ # the Node base class contains just about all XML-related properties Node._fields = { - 'attributes' : [Attribute()], 'childNodes' : [Element()], 'firstChild' : Element(), 'lastChild' : Element(), @@ -276,11 +294,15 @@ 'getElementsByTagName' : MethodDesc(["aa"], [Element(), Element()]), 'hasChildNodes' : MethodDesc([], True), 'insertBefore' : MethodDesc([Element(), Element()], Element()), + 'normalize' : MethodDesc([]), 'removeChild' : MethodDesc([Element()], Element()), 'replaceChild' : MethodDesc([Element(), Element()], Element()), } Element._fields = Node._fields.copy() +Element._fields.update({ + 'attributes' : [Attribute()], +}) Element._methods = Node._methods.copy() Element._methods.update({ @@ -335,7 +357,6 @@ 'blur' : MethodDesc([]), 'click' : MethodDesc([]), 'focus' : MethodDesc([]), - 'normalize' : MethodDesc([]), 'scrollIntoView' : MethodDesc([12]), 'supports' : MethodDesc(["aa", 1.0]), }) @@ -343,7 +364,7 @@ Document._fields = Node._fields.copy() Document._fields.update({ 'characterSet' : "aa", - 'contentWindow' : Window(), + # 'contentWindow' : Window(), XXX doesn't exist, only on iframe 'doctype' : "aa", 'documentElement' : Element(), 'styleSheets' : [Style(), Style()], @@ -351,8 +372,6 @@ Document._methods = Node._methods.copy() Document._methods.update({ - 'clear' : MethodDesc([]), - 'close' : MethodDesc([]), 'createAttribute' : MethodDesc(["aa"], Element()), 'createDocumentFragment' : MethodDesc([], Element()), 'createElement' : MethodDesc(["aa"], Element()), @@ -363,9 +382,6 @@ 'getElementById' : MethodDesc(["aa"], Element()), 'getElementsByName' : MethodDesc(["aa"], [Element(), Element()]), 'importNode' : MethodDesc([Element(), True], Element()), - 'open' : MethodDesc([]), - 'write' : MethodDesc(["aa"]), - 'writeln' : MethodDesc(["aa"]), }) HTMLDocument._fields = Document._fields.copy() @@ -393,11 +409,18 @@ }) HTMLDocument._methods = Document._methods.copy() +HTMLDocument._methods.update({ + 'clear' : MethodDesc([]), + 'close' : MethodDesc([]), + 'open' : MethodDesc([]), + 'write' : MethodDesc(["aa"]), + 'writeln' : MethodDesc(["aa"]), +}) Window._fields = { 'content' : Window(), 'closed' : True, - #'crypto' : Crypto() - not implemented in Gecko, leave alone + # 'crypto' : Crypto() - not implemented in Gecko, leave alone 'defaultStatus' : "aa", 'document' : Document(), # 'frameElement' : - leave alone @@ -445,28 +468,6 @@ 'getComputedStyle' : MethodDesc([Element(), "aa"], Style()), 'home' : MethodDesc([]), 'open' : MethodDesc(["aa", "aa"]), - 'onabort' : MethodDesc([Event()]), - 'onblur' : MethodDesc([Event()]), - 'onchange' : MethodDesc([Event()]), - 'onclick' : MethodDesc([MouseEvent()]), - 'onclose' : MethodDesc([MouseEvent()]), - 'ondragdrop' : MethodDesc([MouseEvent()]), - 'onerror' : MethodDesc([MouseEvent()]), - 'onfocus' : MethodDesc([Event()]), - 'onkeydown' : MethodDesc([KeyEvent()]), - 'onkeypress' : MethodDesc([KeyEvent()]), - 'onkeyup' : MethodDesc([KeyEvent()]), - 'onload' : MethodDesc([KeyEvent()]), - 'onmousedown' : MethodDesc([MouseEvent()]), - 'onmousemove' : MethodDesc([MouseEvent()]), - 'onmouseup' : MethodDesc([MouseEvent()]), - 'onmouseover' : MethodDesc([MouseEvent()]), - 'onmouseup' : MethodDesc([MouseEvent()]), - 'onresize' : MethodDesc([MouseEvent()]), - 'onscroll' : MethodDesc([MouseEvent()]), - 'onselect' : MethodDesc([MouseEvent()]), - 'onsubmit' : MethodDesc([MouseEvent()]), - 'onunload' : MethodDesc([Event()]), } Style._fields = { @@ -600,19 +601,29 @@ } EventTarget._fields = { + 'onabort' : MethodDesc([Event()]), 'onblur' : MethodDesc([Event()]), + 'onchange' : MethodDesc([Event()]), 'onclick' : MethodDesc([MouseEvent()]), + 'onclose' : MethodDesc([MouseEvent()]), 'ondblclick' : MethodDesc([MouseEvent()]), + 'ondragdrop' : MethodDesc([MouseEvent()]), + 'onerror' : MethodDesc([MouseEvent()]), 'onfocus' : MethodDesc([Event()]), 'onkeydown' : MethodDesc([KeyEvent()]), 'onkeypress' : MethodDesc([KeyEvent()]), 'onkeyup' : MethodDesc([KeyEvent()]), + 'onload' : MethodDesc([KeyEvent()]), 'onmousedown' : MethodDesc([MouseEvent()]), 'onmousemove' : MethodDesc([MouseEvent()]), 'onmouseup' : MethodDesc([MouseEvent()]), 'onmouseover' : MethodDesc([MouseEvent()]), 'onmouseup' : MethodDesc([MouseEvent()]), 'onresize' : MethodDesc([Event()]), + 'onscroll' : MethodDesc([MouseEvent()]), + 'onselect' : MethodDesc([MouseEvent()]), + 'onsubmit' : MethodDesc([MouseEvent()]), + 'onunload' : MethodDesc([Event()]), } EventTarget._methods = { Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 13 10:23:30 2006 @@ -44,6 +44,14 @@ document.documentElement.appendChild(div) assert document.documentElement.childNodes[-1]._original is div._original +def test_node_eq(): + window = dom.Window() + body = window.document.getElementsByTagName('body')[0] + ref = body.parentNode.lastChild + assert ref == body + ref = window.document.createElement('body') + assert ref != body + def test_get_element_by_id(): window = dom.Window('
') div = window.document.getElementById('foo') @@ -194,8 +202,17 @@ assert h.event.originalTarget == div assert h.event.currentTarget == body +def test_class_name(): + window = dom.Window('
foo
') + div = window.document.getElementsByTagName('div')[0] + assert div.className == 'foo' + body = div.parentNode + assert not body.className + div.className = 'bar' + assert div.className == 'bar' + assert body.innerHTML == '
foo
' + def test_build(): - py.test.skip("Not implemented yet") for var in globals(): if var.startswith('test_') and var != 'test_build': # just build it From fijal at codespeak.net Mon Nov 13 10:33:53 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 13 Nov 2006 10:33:53 +0100 (CET) Subject: [pypy-svn] r34546 - pypy/dist/pypy/tool Message-ID: <20061113093353.CDE4E1017A@code0.codespeak.net> Author: fijal Date: Mon Nov 13 10:33:52 2006 New Revision: 34546 Modified: pypy/dist/pypy/tool/error.py Log: Added flag which silently breaks instead of running pdb. Modified: pypy/dist/pypy/tool/error.py ============================================================================== --- pypy/dist/pypy/tool/error.py (original) +++ pypy/dist/pypy/tool/error.py Mon Nov 13 10:33:52 2006 @@ -122,7 +122,7 @@ msg += source_lines(graph, None, offset=offset) return "\n".join(msg) -def debug(drv): +def debug(drv, use_pdb=True): # XXX unify some code with pypy.translator.goal.translate from pypy.translator.tool.pdbplus import PdbPlusShow from pypy.translator.driver import log @@ -156,5 +156,6 @@ from pypy.translator.tool.graphserver import run_server_for_inprocess_client return run_server_for_inprocess_client(t, options) - pdb_plus_show = PdbPlusShow(t) - pdb_plus_show.start(tb, server_setup, graphic=True) + if use_pdb: + pdb_plus_show = PdbPlusShow(t) + pdb_plus_show.start(tb, server_setup, graphic=True) From fijal at codespeak.net Mon Nov 13 10:34:15 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 13 Nov 2006 10:34:15 +0100 (CET) Subject: [pypy-svn] r34547 - pypy/dist/pypy/translator/js Message-ID: <20061113093415.118DA1017C@code0.codespeak.net> Author: fijal Date: Mon Nov 13 10:34:14 2006 New Revision: 34547 Modified: pypy/dist/pypy/translator/js/main.py Log: Forwarding use_pdb flag a bit. Modified: pypy/dist/pypy/translator/js/main.py ============================================================================== --- pypy/dist/pypy/translator/js/main.py (original) +++ pypy/dist/pypy/translator/js/main.py Mon Nov 13 10:34:14 2006 @@ -106,7 +106,7 @@ print retval return retval -def rpython2javascript(mod, function_names, opts=Options): +def rpython2javascript(mod, function_names, opts=Options, use_pdb=True): module_name = mod.__name__ if not function_names and 'main' in mod.__dict__: function_names.append('main') @@ -141,4 +141,4 @@ # XXX: Add some possibility to write down selected file except Exception, e: # do something nice with it - debug(driver) + debug(driver, use_pdb) From fijal at codespeak.net Mon Nov 13 10:34:34 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 13 Nov 2006 10:34:34 +0100 (CET) Subject: [pypy-svn] r34548 - pypy/dist/pypy/translator/js/modules/test Message-ID: <20061113093434.C3ACF1017F@code0.codespeak.net> Author: fijal Date: Mon Nov 13 10:34:33 2006 New Revision: 34548 Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Added first test which additionally builds itself. Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 13 10:34:33 2006 @@ -4,6 +4,10 @@ from xml.dom.minidom import parseString import sys +TRANSLATING = False +USE_PDB = False +# XXX: How to get it from config.option??? + def test_quote_html(): assert dom._quote_html('foo&bar') == 'foo&bar' assert dom._quote_html('foo"&bar') == 'foo"&bar' @@ -22,19 +26,32 @@ html = '
foo&bar
' assert roundtrip(html) == html -def test_init(): - window = dom.Window('foo') +def init(): + if TRANSLATING: + window = dom.get_window() + else: + window = dom.Window('foo') nodeType = window.document.nodeType - assert nodeType == 9 docel = window.document.documentElement.nodeName + somediv = window.document.getElementsByTagName('body')[0].childNodes[0] + + return nodeType, docel, somediv + + +def test_init(): + nodeType, docel, somediv = init() + assert nodeType == 9 assert docel == 'HTML' # XXX gotta love the DOM API ;) - somediv = window.document.getElementsByTagName('body')[0].childNodes[0] assert somediv.nodeValue == 'foo' - py.test.raises(py.std.xml.parsers.expat.ExpatError, 'dom.Window("")') +def test_build_init(): + global TRANSLATING + TRANSLATING = True + assert rpython2javascript(sys.modules[__name__], ['init'], use_pdb=USE_PDB) + def test_wrap(): window = dom.Window() document = window.document @@ -213,6 +230,7 @@ assert body.innerHTML == '
foo
' def test_build(): + py.test.skip("Fails") for var in globals(): if var.startswith('test_') and var != 'test_build': # just build it From mwh at codespeak.net Mon Nov 13 12:13:25 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 13 Nov 2006 12:13:25 +0100 (CET) Subject: [pypy-svn] r34549 - pypy/dist/pypy/jit/codegen/i386/test Message-ID: <20061113111325.77DBC1017D@code0.codespeak.net> Author: mwh Date: Mon Nov 13 12:13:24 2006 New Revision: 34549 Modified: pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py Log: use the tests from rgenop_tests for the i386 test_rgenop too Modified: pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/i386/test/test_rgenop.py Mon Nov 13 12:13:24 2006 @@ -1,479 +1,5 @@ -from pypy.rpython.lltypesystem import lltype -from pypy.rpython.llinterp import LLInterpreter -from pypy.rlib.objectmodel import keepalive_until_here -from pypy.rpython.annlowlevel import MixLevelAnnotatorPolicy -from pypy.translator.c.test import test_boehm from pypy.jit.codegen.i386.rgenop import RI386GenOp +from pypy.jit.codegen.test.rgenop_tests import AbstractRGenOpTests -from ctypes import c_void_p, cast, CFUNCTYPE, c_int - -# ____________________________________________________________ - -FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) - -def make_adder(rgenop, n): - # 'return x+n' - sigtoken = rgenop.sigToken(FUNC) - builder, entrypoint, [gv_x] = rgenop.newgraph(sigtoken) - gv_result = builder.genop2("int_add", gv_x, rgenop.genconst(n)) - builder.finish_and_return(sigtoken, gv_result) - gv_add_one = rgenop.gencallableconst(sigtoken, "adder", entrypoint) - return gv_add_one - -def runner(x, y): - rgenop = RI386GenOp() - gv_add_x = make_adder(rgenop, x) - add_x = gv_add_x.revealconst(lltype.Ptr(FUNC)) - res = add_x(y) - keepalive_until_here(rgenop) # to keep the code blocks alive - return res - -def test_adder_interpret(): - from pypy.jit.codegen.llgraph.rgenop import rgenop - gv_add_5 = make_adder(rgenop, 5) - add_5 = gv_add_5.revealconst(lltype.Ptr(FUNC)) - llinterp = LLInterpreter(None) - res = llinterp.eval_graph(add_5._obj.graph, [12]) - assert res == 17 - -def test_adder_direct(): - rgenop = RI386GenOp() - gv_add_5 = make_adder(rgenop, 5) - print gv_add_5.value - fnptr = cast(c_void_p(gv_add_5.value), CFUNCTYPE(c_int, c_int)) - res = fnptr(37) # <== the segfault is here - assert res == 42 - - -# ____________________________________________________________ - -FUNC2 = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed) - -def make_dummy(rgenop): - # 'return x - (y - (x-1))' - signed_kind = rgenop.kindToken(lltype.Signed) - sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) - gv_z = builder.genop2("int_sub", gv_x, rgenop.genconst(1)) - - args_gv = [gv_y, gv_z, gv_x] - builder.enter_next_block([signed_kind, signed_kind, signed_kind], args_gv) - [gv_y2, gv_z2, gv_x2] = args_gv - - gv_s2 = builder.genop2("int_sub", gv_y2, gv_z2) - gv_t2 = builder.genop2("int_sub", gv_x2, gv_s2) - builder.finish_and_return(sigtoken, gv_t2) - - gv_dummyfn = rgenop.gencallableconst(sigtoken, "dummy", entrypoint) - return gv_dummyfn - -def dummy_runner(x, y): - rgenop = RI386GenOp() - gv_dummyfn = make_dummy(rgenop) - dummyfn = gv_dummyfn.revealconst(lltype.Ptr(FUNC2)) - res = dummyfn(x, y) - keepalive_until_here(rgenop) # to keep the code blocks alive - return res - -def test_dummy_interpret(): - from pypy.jit.codegen.llgraph.rgenop import rgenop - gv_dummyfn = make_dummy(rgenop) - dummyfn = gv_dummyfn.revealconst(lltype.Ptr(FUNC2)) - llinterp = LLInterpreter(None) - res = llinterp.eval_graph(dummyfn._obj.graph, [30, 17]) - assert res == 42 - -def test_dummy_direct(): - rgenop = RI386GenOp() - gv_dummyfn = make_dummy(rgenop) - print gv_dummyfn.value - fnptr = cast(c_void_p(gv_dummyfn.value), CFUNCTYPE(c_int, c_int, c_int)) - res = fnptr(30, 17) # <== the segfault is here - assert res == 42 - -# ____________________________________________________________ - -def make_branching(rgenop): - # 'if x > 5: return x-1 - # else: return y' - signed_kind = rgenop.kindToken(lltype.Signed) - sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) - gv_cond = builder.genop2("int_gt", gv_x, rgenop.genconst(5)) - false_builder = builder.jump_if_false(gv_cond) - - # true path - args_gv = [rgenop.genconst(1), gv_x, gv_y] - builder.enter_next_block([signed_kind, signed_kind, signed_kind], args_gv) - [gv_one, gv_x2, gv_y2] = args_gv - - gv_s2 = builder.genop2("int_sub", gv_x2, gv_one) - builder.finish_and_return(sigtoken, gv_s2) - - # false path - false_builder.finish_and_return(sigtoken, gv_y) - - # done - gv_branchingfn = rgenop.gencallableconst(sigtoken, - "branching", entrypoint) - return gv_branchingfn - -def branching_runner(x, y): - rgenop = RI386GenOp() - gv_branchingfn = make_branching(rgenop) - branchingfn = gv_branchingfn.revealconst(lltype.Ptr(FUNC2)) - res = branchingfn(x, y) - keepalive_until_here(rgenop) # to keep the code blocks alive - return res - -def test_branching_interpret(): - from pypy.jit.codegen.llgraph.rgenop import rgenop - gv_branchingfn = make_branching(rgenop) - branchingfn = gv_branchingfn.revealconst(lltype.Ptr(FUNC2)) - llinterp = LLInterpreter(None) - res = llinterp.eval_graph(branchingfn._obj.graph, [30, 17]) - assert res == 29 - res = llinterp.eval_graph(branchingfn._obj.graph, [3, 17]) - assert res == 17 - -def test_branching_direct(): - rgenop = RI386GenOp() - gv_branchingfn = make_branching(rgenop) - print gv_branchingfn.value - fnptr = cast(c_void_p(gv_branchingfn.value), CFUNCTYPE(c_int, c_int, c_int)) - res = fnptr(30, 17) # <== the segfault is here - assert res == 29 - res = fnptr(3, 17) # <== or here - assert res == 17 - -# ____________________________________________________________ - -def make_goto(rgenop): - # while x > 0: - # y += x - # x -= 1 - # return y - signed_kind = rgenop.kindToken(lltype.Signed) - sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) - - # loop start block - args_gv = [gv_x, gv_y] - loopblock = builder.enter_next_block([signed_kind, signed_kind], args_gv) - [gv_x, gv_y] = args_gv - - gv_cond = builder.genop2("int_gt", gv_x, rgenop.genconst(0)) - bodybuilder = builder.jump_if_true(gv_cond) - builder.finish_and_return(sigtoken, gv_y) - - # loop body - args_gv = [gv_y, gv_x] - bodybuilder.enter_next_block([signed_kind, signed_kind], args_gv) - [gv_y, gv_x] = args_gv - - gv_y2 = bodybuilder.genop2("int_add", gv_x, gv_y) - gv_x2 = bodybuilder.genop2("int_sub", gv_x, rgenop.genconst(1)) - bodybuilder.finish_and_goto([gv_x2, gv_y2], loopblock) - - # done - gv_gotofn = rgenop.gencallableconst(sigtoken, "goto", entrypoint) - return gv_gotofn - -def goto_runner(x, y): - rgenop = RI386GenOp() - gv_gotofn = make_goto(rgenop) - gotofn = gv_gotofn.revealconst(lltype.Ptr(FUNC2)) - res = gotofn(x, y) - keepalive_until_here(rgenop) # to keep the code blocks alive - return res - -def test_goto_interpret(): - from pypy.jit.codegen.llgraph.rgenop import rgenop - gv_gotofn = make_goto(rgenop) - gotofn = gv_gotofn.revealconst(lltype.Ptr(FUNC2)) - llinterp = LLInterpreter(None) - res = llinterp.eval_graph(gotofn._obj.graph, [30, 17]) - assert res == 31 * 15 + 17 - res = llinterp.eval_graph(gotofn._obj.graph, [3, 17]) - assert res == 23 - -def test_goto_direct(): - rgenop = RI386GenOp() - gv_gotofn = make_goto(rgenop) - print gv_gotofn.value - fnptr = cast(c_void_p(gv_gotofn.value), CFUNCTYPE(c_int, c_int, c_int)) - res = fnptr(30, 17) # <== the segfault is here - assert res == 31 * 15 + 17 - res = fnptr(3, 17) # <== or here - assert res == 23 - -# ____________________________________________________________ - -def make_if(rgenop): - # a = x - # if x > 5: - # x //= 2 - # return x + a - signed_kind = rgenop.kindToken(lltype.Signed) - sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x1, gv_unused] = rgenop.newgraph(sigtoken) - - # check - args_gv = [gv_x1, gv_unused] - builder.enter_next_block([signed_kind, signed_kind], args_gv) - [gv_x1, gv_unused] = args_gv - - gv_cond = builder.genop2("int_gt", gv_x1, rgenop.genconst(5)) - elsebuilder = builder.jump_if_false(gv_cond) - elseargs_gv = [gv_x1] - - # 'then' block - args_gv = [gv_x1] - builder.enter_next_block([signed_kind], args_gv) - [gv_x1] = args_gv - gv_x2 = builder.genop2("int_floordiv", gv_x1, rgenop.genconst(2)) - - # end block - args_gv = [gv_x2, gv_x1] - label = builder.enter_next_block([signed_kind, signed_kind], args_gv) - [gv_x2, gv_a] = args_gv - gv_res = builder.genop2("int_add", gv_x2, gv_a) - builder.finish_and_return(sigtoken, gv_res) - - # now the else branch - elsebuilder.enter_next_block([signed_kind], elseargs_gv) - [gv_x3] = elseargs_gv - elsebuilder.finish_and_goto([gv_x3, gv_x3], label) - - # done - gv_gotofn = rgenop.gencallableconst(sigtoken, "goto", entrypoint) - return gv_gotofn - -def if_runner(x, y): - rgenop = RI386GenOp() - gv_iffn = make_if(rgenop) - iffn = gv_iffn.revealconst(lltype.Ptr(FUNC2)) - res = iffn(x, y) - keepalive_until_here(rgenop) # to keep the code blocks alive - return res - -def test_if_interpret(): - from pypy.jit.codegen.llgraph.rgenop import rgenop - gv_iffn = make_if(rgenop) - iffn = gv_iffn.revealconst(lltype.Ptr(FUNC2)) - llinterp = LLInterpreter(None) - res = llinterp.eval_graph(iffn._obj.graph, [30, 0]) - assert res == 45 - res = llinterp.eval_graph(iffn._obj.graph, [3, 0]) - assert res == 6 - -def test_if_direct(): - rgenop = RI386GenOp() - gv_iffn = make_if(rgenop) - print gv_iffn.value - fnptr = cast(c_void_p(gv_iffn.value), CFUNCTYPE(c_int, c_int, c_int)) - res = fnptr(30, 0) - assert res == 45 - res = fnptr(3, 0) - assert res == 6 - -# ____________________________________________________________ - -def build_switch(rgenop): - """ - def f(v0, v1): - if v0 == 0: # switch - return 21*v1 - elif v0 == 1: - return 21+v1 - else: - return v1 - """ - signed_tok = rgenop.kindToken(lltype.Signed) - f2_token = rgenop.sigToken(FUNC2) - builder, graph, (gv0, gv1) = rgenop.newgraph(f2_token) - - flexswitch = builder.flexswitch(gv0) - const21 = rgenop.genconst(21) - - # case == 0 - const0 = rgenop.genconst(0) - case_builder = flexswitch.add_case(const0) - case_args_gv = [gv1] - case_builder.enter_next_block([signed_tok], case_args_gv) - [gv1_case0] = case_args_gv - gv_res_case0 = case_builder.genop2('int_mul', const21, gv1_case0) - case_builder.finish_and_return(f2_token, gv_res_case0) - # default - default_builder = flexswitch.add_default() - default_args_gv = [gv1] - default_builder.enter_next_block([signed_tok], default_args_gv) - [gv1_default] = default_args_gv - default_builder.finish_and_return(f2_token, gv1_default) - # case == 1 - const1 = rgenop.genconst(1) - case_builder = flexswitch.add_case(const1) - case_args_gv = [gv1] - case_builder.enter_next_block([signed_tok], case_args_gv) - [gv1_case1] = case_args_gv - gv_res_case1 = case_builder.genop2('int_add', const21, gv1_case1) - case_builder.finish_and_return(f2_token, gv_res_case1) - - gv_switch = rgenop.gencallableconst(f2_token, "switch", graph) - return gv_switch - -def switch_runner(x, y): - rgenop = RI386GenOp() - gv_switchfn = build_switch(rgenop) - switchfn = gv_switchfn.revealconst(lltype.Ptr(FUNC2)) - res = switchfn(x, y) - keepalive_until_here(rgenop) # to keep the code blocks alive - return res - -def test_switch_direct(): - rgenop = RI386GenOp() - gv_switchfn = build_switch(rgenop) - print gv_switchfn.value - fnptr = cast(c_void_p(gv_switchfn.value), CFUNCTYPE(c_int, c_int, c_int)) - res = fnptr(0, 2) - assert res == 42 - res = fnptr(1, 16) - assert res == 37 - res = fnptr(42, 16) - assert res == 16 - -def build_large_switch(rgenop): - """ - def f(v0, v1): - if v0 == 0: # switch - return 21*v1 - elif v0 == 1: - return 2+v1 - elif v0 == 2: - return 4+v1 - ... - elif v0 == 10: - return 2**10+v1 - else: - return v1 - """ - signed_tok = rgenop.kindToken(lltype.Signed) - f2_token = rgenop.sigToken(FUNC2) - builder, graph, (gv0, gv1) = rgenop.newgraph(f2_token) - - flexswitch = builder.flexswitch(gv0) - const21 = rgenop.genconst(21) - - # case == 0 - const0 = rgenop.genconst(0) - case_builder = flexswitch.add_case(const0) - case_args_gv = [gv1] - case_builder.enter_next_block([signed_tok], case_args_gv) - [gv1_case0] = case_args_gv - gv_res_case0 = case_builder.genop2('int_mul', const21, gv1_case0) - case_builder.finish_and_return(f2_token, gv_res_case0) - # default - default_builder = flexswitch.add_default() - default_args_gv = [gv1] - default_builder.enter_next_block([signed_tok], default_args_gv) - [gv1_default] = default_args_gv - default_builder.finish_and_return(f2_token, gv1_default) - # case == x - for x in range(1,11): - constx = rgenop.genconst(x) - case_builder = flexswitch.add_case(constx) - case_args_gv = [gv1] - case_builder.enter_next_block([signed_tok], case_args_gv) - [gv1_casex] = case_args_gv - const2px= rgenop.genconst(1< Author: arigo Date: Mon Nov 13 12:34:38 2006 New Revision: 34552 Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py Log: This test passes now that the keepalive is not removed too eagerly. Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Mon Nov 13 12:34:38 2006 @@ -119,7 +119,6 @@ assert res == 26 def test_char_p_in_struct(self): - #py.test.skip("keepalive problem in malloc removal?") S2 = RStruct('S2', [('p', rc_char_p)]) def func(): s = S2.allocate() From guido at codespeak.net Mon Nov 13 13:16:23 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 13 Nov 2006 13:16:23 +0100 (CET) Subject: [pypy-svn] r34553 - in pypy/dist/pypy/translator/js/modules: . test Message-ID: <20061113121623.467061018A@code0.codespeak.net> Author: guido Date: Mon Nov 13 13:16:21 2006 New Revision: 34553 Modified: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Simplified inheritance, there's no distinction anymore between XML and HTML nodes, and split tests up for translation testing (currently still broken). Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Mon Nov 13 13:16:21 2006 @@ -19,66 +19,8 @@ from pypy.translator.stackless.test.test_transform import one from xml.dom import minidom -# XML node (level 2 basically) implementation -# the following classes are mostly wrappers around minidom nodes that try to -# mimic HTML DOM behaviour by implementing browser API and changing the -# behaviour a bit - -class Node(BasicExternal): - """base class of all node types""" - - def __init__(self, node=None): - self._original = node - - def __getattr__(self, name): - """attribute access gets proxied to the contained minidom node - - all returned minidom nodes are wrapped as Nodes - """ - if (name not in self._fields and - (not hasattr(self, '_methods') or name not in self._methods)): - raise NameError, name - value = getattr(self._original, name) - return _wrap(value) - - def __eq__(self, other): - original = getattr(other, '_original', other) - return original is self._original - -class Element(Node): - nodeType = 1 - -class Attribute(Node): - nodeType = 2 - -class Text(Node): - nodeType = 3 - -class Document(Node): - nodeType = 9 - - def __init__(self, docnode=None): - super(Document, self).__init__(docnode) - self._original = docnode - - def createEvent(self, group=''): - """create an event - - note that the group argument is ignored - """ - if group in ('KeyboardEvent', 'KeyboardEvents'): - return KeyEvent() - elif group in ('MouseEvent', 'MouseEvents'): - return MouseEvent() - return Event() - -# the standard DOM stuff that doesn't directly deal with XML -# note that we're mimicking the standard (Mozilla) APIs, so things tested -# against this code may not work in Internet Explorer - -# XXX note that we store the events on the wrapped minidom node to avoid losing -# them on re-wrapping -class EventTarget(BasicExternal): # XXX mixin... is the super correct?!? +# EventTarget is the base class for Nodes and Window +class EventTarget(BasicExternal): def addEventListener(self, type, listener, useCapture): if not hasattr(self._original, '_events'): self._original._events = [] @@ -114,39 +56,36 @@ raise ValueError('no registration for listener') self._original._events = filtered -class Event(BasicExternal): - def initEvent(self, type, bubbles, cancelable): - self.type = type - self.cancelBubble = not bubbles - self.cancelable = cancelable - self.target = None - self.currentTarget = None - self.originalTarget = None - self._cancelled = False - - def preventDefault(self): - if not self.cancelable: - raise TypeError('event can not be canceled') - self._cancelled = True - - def stopPropagation(self): - self.cancelBubble = True - -class KeyEvent(Event): - pass - -class MouseEvent(Event): - pass +# XML node (level 2 basically) implementation +# the following classes are mostly wrappers around minidom nodes that try to +# mimic HTML DOM behaviour by implementing browser API and changing the +# behaviour a bit -class Style(BasicExternal): +class Node(EventTarget): + """base class of all node types""" + + def __init__(self, node=None): + self._original = node + def __getattr__(self, name): - if name not in self._fields: - raise AttributeError, name - return None + """attribute access gets proxied to the contained minidom node + + all returned minidom nodes are wrapped as Nodes + """ + try: + return super(Node, self).__getattr__(name) + except AttributeError: + pass + if (name not in self._fields and + (not hasattr(self, '_methods') or name not in self._methods)): + raise NameError, name + value = getattr(self._original, name) + return _wrap(value) -# HTML DOM + def __eq__(self, other): + original = getattr(other, '_original', other) + return original is self._original -class HTMLNode(Node, EventTarget): def getElementsByTagName(self, name): name = name.lower() return self.__getattr__('getElementsByTagName')(name) @@ -170,8 +109,8 @@ id = property(_getId, _setId) -class HTMLElement(HTMLNode, Element): - id = '' +class Element(Node): + nodeType = 1 style = None def __init__(self, node=None): @@ -199,13 +138,72 @@ innerHTML = property(_get_innerHTML, _set_innerHTML) -class HTMLDocument(Document, HTMLNode): +class Attribute(Node): + nodeType = 2 + +class Text(Node): + nodeType = 3 + +class Document(Node): + nodeType = 9 + + def __init__(self, docnode=None): + super(Document, self).__init__(docnode) + self._original = docnode + + def createEvent(self, group=''): + """create an event + + note that the group argument is ignored + """ + if group in ('KeyboardEvent', 'KeyboardEvents'): + return KeyEvent() + elif group in ('MouseEvent', 'MouseEvents'): + return MouseEvent() + return Event() + def getElementById(self, id): nodes = self.getElementsByTagName('*') for node in nodes: if node.getAttribute('id') == id: return node +# the standard DOM stuff that doesn't directly deal with XML +# note that we're mimicking the standard (Mozilla) APIs, so things tested +# against this code may not work in Internet Explorer + +# XXX note that we store the events on the wrapped minidom node to avoid losing +# them on re-wrapping +class Event(BasicExternal): + def initEvent(self, type, bubbles, cancelable): + self.type = type + self.cancelBubble = not bubbles + self.cancelable = cancelable + self.target = None + self.currentTarget = None + self.originalTarget = None + self._cancelled = False + + def preventDefault(self): + if not self.cancelable: + raise TypeError('event can not be canceled') + self._cancelled = True + + def stopPropagation(self): + self.cancelBubble = True + +class KeyEvent(Event): + pass + +class MouseEvent(Event): + pass + +class Style(BasicExternal): + def __getattr__(self, name): + if name not in self._fields: + raise AttributeError, name + return None + # non-DOM ('DOM level 0') stuff # Window is the main environment, the root node of the JS object tree @@ -213,8 +211,9 @@ class Window(EventTarget): def __init__(self, html=('Untitled document' ''), parent=None): + super(Window, self).__init__() self._html = html - self.document = HTMLDocument(minidom.parseString(html)) + self.document = Document(minidom.parseString(html)) # references to windows self.content = self @@ -242,7 +241,7 @@ def _setLocation(self, newloc): url = urllib.urlopen(newloc) html = url.read() - self.document = HTMLDocument(minidom.parseString(html)) + self.document = Document(minidom.parseString(html)) location = property(_getLocation, _setLocation) @@ -261,15 +260,47 @@ # a lot... isn't it possible to just use dom.window and dom.document instead?) def get_document(): - return NonConstant(window.document) + return NonConstant(Window().document) def get_window(): - return NonConstant(window) + return NonConstant(Window()) # rtyper stuff -# the Node base class contains just about all XML-related properties -Node._fields = { +EventTarget._fields = { + 'onabort' : MethodDesc([Event()]), + 'onblur' : MethodDesc([Event()]), + 'onchange' : MethodDesc([Event()]), + 'onclick' : MethodDesc([MouseEvent()]), + 'onclose' : MethodDesc([MouseEvent()]), + 'ondblclick' : MethodDesc([MouseEvent()]), + 'ondragdrop' : MethodDesc([MouseEvent()]), + 'onerror' : MethodDesc([MouseEvent()]), + 'onfocus' : MethodDesc([Event()]), + 'onkeydown' : MethodDesc([KeyEvent()]), + 'onkeypress' : MethodDesc([KeyEvent()]), + 'onkeyup' : MethodDesc([KeyEvent()]), + 'onload' : MethodDesc([KeyEvent()]), + 'onmousedown' : MethodDesc([MouseEvent()]), + 'onmousemove' : MethodDesc([MouseEvent()]), + 'onmouseup' : MethodDesc([MouseEvent()]), + 'onmouseover' : MethodDesc([MouseEvent()]), + 'onmouseup' : MethodDesc([MouseEvent()]), + 'onresize' : MethodDesc([Event()]), + 'onscroll' : MethodDesc([MouseEvent()]), + 'onselect' : MethodDesc([MouseEvent()]), + 'onsubmit' : MethodDesc([MouseEvent()]), + 'onunload' : MethodDesc([Event()]), +} + +EventTarget._methods = { + 'addEventListener' : MethodDesc(["aa", lambda : None, True]), + 'dispatchEvent' : MethodDesc(["aa"], True), + 'removeEventListener' : MethodDesc(["aa", lambda : None, True]), +} + +Node._fields = EventTarget._fields.copy() +Node._fields.update({ 'childNodes' : [Element()], 'firstChild' : Element(), 'lastChild' : Element(), @@ -283,51 +314,27 @@ 'ownerDocument' : Document(), 'parentNode' : Element(), 'prefix' : "aa", - 'previousSibling' : Element(), + 'previousSibling': Element(), 'tagName' : "aa", 'textContent' : "aa", -} +}) -Node._methods = { +Node._methods = EventTarget._methods.copy() +Node._methods.update({ 'appendChild' : MethodDesc([Element()]), 'cloneNode' : MethodDesc([12], Element()), - 'getElementsByTagName' : MethodDesc(["aa"], [Element(), Element()]), + 'getElementsByTagName' : MethodDesc(["aa"], [Element(), + Element()]), 'hasChildNodes' : MethodDesc([], True), 'insertBefore' : MethodDesc([Element(), Element()], Element()), 'normalize' : MethodDesc([]), 'removeChild' : MethodDesc([Element()], Element()), 'replaceChild' : MethodDesc([Element(), Element()], Element()), -} +}) Element._fields = Node._fields.copy() Element._fields.update({ 'attributes' : [Attribute()], -}) - -Element._methods = Node._methods.copy() -Element._methods.update({ - 'getAttribute' : MethodDesc(["aa"], "aa"), - 'getAttributeNS' : MethodDesc(["aa", "aa"], "aa"), - 'getAttributeNode' : MethodDesc(["aa"], Element()), - 'getAttributeNodeNS' : MethodDesc(["aa", "aa"], Element()), - 'hasAttribute' : MethodDesc(["aa"], True), - 'hasAttributeNS' : MethodDesc(["aa", "aa"], True), - 'hasAttributes' : MethodDesc([], True), - 'removeAttribute' : MethodDesc(['aa']), - 'removeAttributeNS' : MethodDesc(["aa", "aa"]), - 'removeAttributeNode' : MethodDesc([Element()], "aa"), - 'setAttribute' : MethodDesc(["aa", "aa"]), - 'setAttributeNS' : MethodDesc(["aa", "aa", "aa"]), - 'setAttributeNode' : MethodDesc([Element()], Element()), - 'setAttributeNodeNS' : MethodDesc(["ns", Element()], Element()), -}) - -HTMLNode._fields = Node._fields.copy() -HTMLNode._methods = Node._methods.copy() - -HTMLElement._fields = HTMLNode._fields.copy() -HTMLElement._fields.update(Element._fields.copy()) -HTMLElement._fields.update({ 'className' : "aa", 'clientHeight' : 12, 'clientWidth' : 12, @@ -346,14 +353,28 @@ 'scrollLeft' : 12, 'scrollTop' : 12, 'scrollWidth' : 12, + # HTML specific 'style' : Style(), 'tabIndex' : 12, - 'value' : "aa", # XXX? }) -HTMLElement._methods = HTMLNode._methods.copy() -HTMLElement._methods.update(Element._methods.copy()) -HTMLElement._methods.update({ +Element._methods = Node._methods.copy() +Element._methods.update({ + 'getAttribute' : MethodDesc(["aa"], "aa"), + 'getAttributeNS' : MethodDesc(["aa", "aa"], "aa"), + 'getAttributeNode' : MethodDesc(["aa"], Element()), + 'getAttributeNodeNS' : MethodDesc(["aa", "aa"], Element()), + 'hasAttribute' : MethodDesc(["aa"], True), + 'hasAttributeNS' : MethodDesc(["aa", "aa"], True), + 'hasAttributes' : MethodDesc([], True), + 'removeAttribute' : MethodDesc(['aa']), + 'removeAttributeNS' : MethodDesc(["aa", "aa"]), + 'removeAttributeNode' : MethodDesc([Element()], "aa"), + 'setAttribute' : MethodDesc(["aa", "aa"]), + 'setAttributeNS' : MethodDesc(["aa", "aa", "aa"]), + 'setAttributeNode' : MethodDesc([Element()], Element()), + 'setAttributeNodeNS' : MethodDesc(["ns", Element()], Element()), + # HTML specific 'blur' : MethodDesc([]), 'click' : MethodDesc([]), 'focus' : MethodDesc([]), @@ -368,24 +389,6 @@ 'doctype' : "aa", 'documentElement' : Element(), 'styleSheets' : [Style(), Style()], -}) - -Document._methods = Node._methods.copy() -Document._methods.update({ - 'createAttribute' : MethodDesc(["aa"], Element()), - 'createDocumentFragment' : MethodDesc([], Element()), - 'createElement' : MethodDesc(["aa"], Element()), - 'createElementNS' : MethodDesc(["aa", "aa"], Element()), - 'createEvent' : MethodDesc(["aa"], Event()), - 'createTextNode' : MethodDesc(["aa"], Element()), - #'createRange' : MethodDesc(["aa"], Range()) - don't know what to do here - 'getElementById' : MethodDesc(["aa"], Element()), - 'getElementsByName' : MethodDesc(["aa"], [Element(), Element()]), - 'importNode' : MethodDesc([Element(), True], Element()), -}) - -HTMLDocument._fields = Document._fields.copy() -HTMLDocument._fields.update({ 'alinkColor' : "aa", 'bgColor' : "aa", 'body' : Element(), @@ -408,8 +411,18 @@ 'width' : 123, }) -HTMLDocument._methods = Document._methods.copy() -HTMLDocument._methods.update({ +Document._methods = Node._methods.copy() +Document._methods.update({ + 'createAttribute' : MethodDesc(["aa"], Element()), + 'createDocumentFragment' : MethodDesc([], Element()), + 'createElement' : MethodDesc(["aa"], Element()), + 'createElementNS' : MethodDesc(["aa", "aa"], Element()), + 'createEvent' : MethodDesc(["aa"], Event()), + 'createTextNode' : MethodDesc(["aa"], Element()), + #'createRange' : MethodDesc(["aa"], Range()) - don't know what to do here + 'getElementById' : MethodDesc(["aa"], Element()), + 'getElementsByName' : MethodDesc(["aa"], [Element(), Element()]), + 'importNode' : MethodDesc([Element(), True], Element()), 'clear' : MethodDesc([]), 'close' : MethodDesc([]), 'open' : MethodDesc([]), @@ -417,7 +430,8 @@ 'writeln' : MethodDesc(["aa"]), }) -Window._fields = { +Window._fields = EventTarget._fields.copy() +Window._fields.update({ 'content' : Window(), 'closed' : True, # 'crypto' : Crypto() - not implemented in Gecko, leave alone @@ -450,9 +464,10 @@ 'status' : "asd", 'top' : Window(), 'window' : Window(), -} +}) -Window._methods = { +Window._methods = Node._methods.copy() +Window._methods.update({ 'alert' : MethodDesc(["aa"]), 'atob' : MethodDesc(["aa"], "aa"), 'back' : MethodDesc([]), @@ -468,7 +483,7 @@ 'getComputedStyle' : MethodDesc([Element(), "aa"], Style()), 'home' : MethodDesc([]), 'open' : MethodDesc(["aa", "aa"]), -} +}) Style._fields = { 'azimuth' : 'aa', @@ -600,38 +615,6 @@ 'zIndex' : 'aa', } -EventTarget._fields = { - 'onabort' : MethodDesc([Event()]), - 'onblur' : MethodDesc([Event()]), - 'onchange' : MethodDesc([Event()]), - 'onclick' : MethodDesc([MouseEvent()]), - 'onclose' : MethodDesc([MouseEvent()]), - 'ondblclick' : MethodDesc([MouseEvent()]), - 'ondragdrop' : MethodDesc([MouseEvent()]), - 'onerror' : MethodDesc([MouseEvent()]), - 'onfocus' : MethodDesc([Event()]), - 'onkeydown' : MethodDesc([KeyEvent()]), - 'onkeypress' : MethodDesc([KeyEvent()]), - 'onkeyup' : MethodDesc([KeyEvent()]), - 'onload' : MethodDesc([KeyEvent()]), - 'onmousedown' : MethodDesc([MouseEvent()]), - 'onmousemove' : MethodDesc([MouseEvent()]), - 'onmouseup' : MethodDesc([MouseEvent()]), - 'onmouseover' : MethodDesc([MouseEvent()]), - 'onmouseup' : MethodDesc([MouseEvent()]), - 'onresize' : MethodDesc([Event()]), - 'onscroll' : MethodDesc([MouseEvent()]), - 'onselect' : MethodDesc([MouseEvent()]), - 'onsubmit' : MethodDesc([MouseEvent()]), - 'onunload' : MethodDesc([Event()]), -} - -EventTarget._methods = { - 'addEventListener' : MethodDesc(["aa", lambda : None, True]), - 'dispatchEvent' : MethodDesc(["aa"], True), - 'removeEventListener' : MethodDesc(["aa", lambda : None, True]), -} - Event._fields = { 'bubbles': True, 'cancelBubble': True, @@ -680,10 +663,10 @@ return _wrap(value) _typetoclass = { - 1: HTMLElement, + 1: Element, 2: Attribute, 3: Text, - 9: HTMLDocument, + 9: Document, } def _wrap(value): if isinstance(value, minidom.Node): @@ -732,6 +715,4 @@ # set the global 'window' instance to an empty HTML document, override using # dom.window = Window(html) (this will also set dom.document) -window = Window() -this = window Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 13 13:16:21 2006 @@ -8,6 +8,17 @@ USE_PDB = False # XXX: How to get it from config.option??? +class handler: + called = False + event = dom.Event() + def __call__(self, e): + self.called = True + self.event = e + e.stopPropagation() + +def get_window(): + return dom.get_window() + def test_quote_html(): assert dom._quote_html('foo&bar') == 'foo&bar' assert dom._quote_html('foo"&bar') == 'foo"&bar' @@ -26,68 +37,90 @@ html = '
foo&bar
' assert roundtrip(html) == html -def init(): - if TRANSLATING: - window = dom.get_window() - else: - window = dom.Window('foo') +def code_init(): + window = dom.get_window() nodeType = window.document.nodeType docel = window.document.documentElement.nodeName - somediv = window.document.getElementsByTagName('body')[0].childNodes[0] + children = len(window.document.documentElement.childNodes) - return nodeType, docel, somediv - + return nodeType, docel, children def test_init(): - nodeType, docel, somediv = init() + nodeType, docel, children = code_init() assert nodeType == 9 assert docel == 'HTML' - # XXX gotta love the DOM API ;) - assert somediv.nodeValue == 'foo' - py.test.raises(py.std.xml.parsers.expat.ExpatError, - 'dom.Window("")') + assert children == 2 -def test_build_init(): - global TRANSLATING - TRANSLATING = True - assert rpython2javascript(sys.modules[__name__], ['init'], use_pdb=USE_PDB) +def test_init_failing(): + py.test.raises(py.std.xml.parsers.expat.ExpatError, + 'dom.Window(html="")') -def test_wrap(): - window = dom.Window() +def code_wrap(): + window = get_window() document = window.document div = document.createElement('div') + document.documentElement.appendChild(div) + return document, div + +def test_wrap(): + document, div = code_wrap() assert isinstance(div, dom.Element) # wrapped node assert div.nodeType == 1 - document.documentElement.appendChild(div) assert document.documentElement.childNodes[-1]._original is div._original -def test_node_eq(): - window = dom.Window() +def code_node_eq(): + window = get_window() body = window.document.getElementsByTagName('body')[0] - ref = body.parentNode.lastChild - assert ref == body - ref = window.document.createElement('body') - assert ref != body + firstref = body.parentNode.lastChild + secondref = window.document.createElement('body') + return body, firstref, secondref -def test_get_element_by_id(): - window = dom.Window('
') +def test_node_eq(): + body, ref1, ref2 = code_node_eq() + assert ref1 == body + assert ref2 != body + +def code_get_element_by_id(): + window = get_window() + document = window.document + div = document.createElement('div') + div.id = 'foo' + window.document.getElementsByTagName('body')[0].appendChild(div) div = window.document.getElementById('foo') + return div + +def test_get_element_by_id(): + div = code_get_element_by_id() assert div.nodeName == 'DIV' -def test_element_style(): - window = dom.Window() +def code_element_style(): + window = get_window() document = window.document div = document.createElement('div') - assert div.style - assert not div.style.backgroundColor div.style.backgroundColor = 'green' + return div + +def test_element_style(): + div = code_element_style() + assert div.style + assert not div.style.color assert div.style.backgroundColor == 'green' py.test.raises(AttributeError, 'div.style.nonExistent') -def test_get_elements_by_tag_name(): - window = dom.Window('
foo
' - '
bar
') +def code_get_elements_by_tag_name(): + window = get_window() document = window.document + div1 = document.createElement('div') + div1.appendChild(document.createTextNode('foo')) + div2 = document.createElement('div') + div2.appendChild(document.createTextNode('bar')) + body = document.getElementsByTagName('body')[0] + body.appendChild(div1) + body.appendChild(div2) + return document + +def test_get_elements_by_tag_name(): + document = code_get_elements_by_tag_name() divs = document.getElementsByTagName('div') assert len(divs) == 2 divs = document.getElementsByTagName('DIV') @@ -108,131 +141,177 @@ assert window3.parent is window2 assert window3.top is window +def code_read_innerHTML(): + window = get_window() + document = window.document + h1 = document.createElement('h1') + h1.appendChild(document.createTextNode('some document')) + p = document.createElement('p') + p.id = 'content' + p.appendChild(document.createTextNode('some content')) + body = document.getElementsByTagName('body')[0] + body.appendChild(h1) + body.appendChild(p) + return document.documentElement.innerHTML + def test_read_innerHTML(): - window = dom.Window('

some document

' - '

some content

') + html = code_read_innerHTML() + assert html == ('Untitled document' + '

some document

' + '

some content

') + +def code_read_innerHTML_singletons(): + window = get_window() document = window.document - nodeName = window.document.documentElement.nodeName - assert nodeName == 'HTML' - html = window.document.documentElement.innerHTML - assert html == ('

some document

' - '

some content

') + head = document.getElementsByTagName('head')[0] + meta = document.createElement('meta') + meta.setAttribute('name', 'foo') + meta.setAttribute('content', 'bar') + head.appendChild(meta) + headhtml = window.document.getElementsByTagName('head')[0].innerHTML + return headhtml def test_read_innerHTML_singletons(): - window = dom.Window('' - '') - metahtml = window.document.getElementsByTagName('head')[0].innerHTML - assert py.std.re.match('^$', - '') + headhtml = code_read_innerHTML_singletons() + assert py.std.re.search(']*\/>', headhtml) -def test_set_innerHTML(): - window = dom.Window('initial content') +def code_set_innerHTML(): + window = get_window() body = window.document.getElementsByTagName('body')[0] - assert body.innerHTML == '' body.innerHTML = '
some content
' + return body + +def test_set_innerHTML(): + body = code_set_innerHTML() assert body.innerHTML == '
some content
' assert body.childNodes[0].nodeName == 'DIV' -def test_event_init(): - window = dom.Window() - e = dom.Event() +def code_event_init_1(): + window = get_window() + e = window.document.createEvent() e.initEvent('click', True, True) + return window, e + +def code_event_init_2(): + window, event = code_event_init_1() + body = window.document.getElementsByTagName('body')[0] + body.dispatchEvent(event) + return body, event + +def test_event_init(): + window, e = code_event_init_1() assert e.cancelable == True assert e.target == None - body = window.document.getElementsByTagName('body')[0] - body.dispatchEvent(e) + body, e = code_event_init_2() assert e.target is body -def test_event_handling(): - class handler: - called = False - def __call__(self, e): - self.called = True +def code_event_handling(): h = handler() - window = dom.Window() + window = get_window() body = window.document.getElementsByTagName('body')[0] body.addEventListener('click', h, False) - e = dom.Event() + e = window.document.createEvent() e.initEvent('click', True, True) body.dispatchEvent(e) + return h + +def test_event_handling(): + h = code_event_handling() assert h.called == True -def test_event_bubbling(): - class handler: - called = False - def __call__(self, e): - self.called = True +def code_event_bubbling_1(): h = handler() - window = dom.Window() + window = get_window() body = window.document.getElementsByTagName('body')[0] div = window.document.createElement('div') body.appendChild(div) body.addEventListener('click', h, False) - e = dom.Event() + e = window.document.createEvent() e.initEvent('click', False, True) div.dispatchEvent(e) - assert h.called == False - e = dom.Event() + return div, h + +def code_event_bubbling_2(): + div, h = code_event_bubbling_1() + e = div.ownerDocument.createEvent() e.initEvent('click', True, True) div.dispatchEvent(e) + return h + +def test_event_bubbling(): + div, h = code_event_bubbling_1() + assert not h.called + h = code_event_bubbling_2() assert h.called == True -def test_remove_event_listener(): - class handler: - called = False - def __call__(self, e): - self.called = True - window = dom.Window() +def code_remove_event_listener(): + window = get_window() body = window.document.getElementsByTagName('body')[0] div = window.document.createElement('div') body.appendChild(div) - py.test.raises(Exception, 'body.removeEventListener("click", h, False)') h = handler() body.addEventListener('click', h, False) - e = dom.Event() + e = window.document.createEvent() e.initEvent('click', True, True) body.dispatchEvent(e) - assert h.called == True + return body, h + +def code_remove_event_listener_2(): + body, h = code_remove_event_listener() h.called = False body.removeEventListener('click', h, False) - e = dom.Event() + e = body.ownerDocument.createEvent() e.initEvent('click', True, True) body.dispatchEvent(e) + return h + +def test_remove_event_listener(): + body, h = code_remove_event_listener() + assert h.called == True + h = code_remove_event_listener_2() assert h.called == False -def test_event_vars(): - class handler: - event = None # XXX annotator problem? - def __call__(self, e): - self.event = e - e.stopPropagation() - window = dom.Window() +def code_event_vars(): + window = get_window() body = window.document.getElementsByTagName('body')[0] div = window.document.createElement('div') body.appendChild(div) h = handler() body.addEventListener('click', h, False) - e = dom.Event() + e = window.document.createEvent() e.initEvent('click', True, True) div.dispatchEvent(e) + return body, div, h + +def test_event_vars(): + body, div, h = code_event_vars() assert h.event.target == div assert h.event.originalTarget == div assert h.event.currentTarget == body -def test_class_name(): - window = dom.Window('
foo
') +def code_class_name(): + window = get_window() + document = window.document + body = document.getElementsByTagName('body')[0] + div = document.createElement('div') + div.appendChild(document.createTextNode('foo')) + div.setAttribute('class', 'foo') + body.appendChild(div) div = window.document.getElementsByTagName('div')[0] + return body, div + +def test_class_name(): + body, div = code_class_name() assert div.className == 'foo' - body = div.parentNode assert not body.className div.className = 'bar' assert div.className == 'bar' assert body.innerHTML == '
foo
' def test_build(): - py.test.skip("Fails") + py.test.skip('Borken') for var in globals(): - if var.startswith('test_') and var != 'test_build': + if var.startswith('code_'): # just build it rpython2javascript(sys.modules[__name__], [var]) From arigo at codespeak.net Mon Nov 13 13:17:50 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 13 Nov 2006 13:17:50 +0100 (CET) Subject: [pypy-svn] r34554 - in pypy/dist/pypy: rlib/test translator/backendopt translator/backendopt/test Message-ID: <20061113121750.A69FE1018D@code0.codespeak.net> Author: arigo Date: Mon Nov 13 13:17:45 2006 New Revision: 34554 Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py pypy/dist/pypy/translator/backendopt/malloc.py pypy/dist/pypy/translator/backendopt/test/test_malloc.py Log: Stop being "clever" about which keepalives must be kept during malloc removal, and which ones can be removed. Modified: pypy/dist/pypy/rlib/test/test_rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_rctypesobject.py (original) +++ pypy/dist/pypy/rlib/test/test_rctypesobject.py Mon Nov 13 13:17:45 2006 @@ -1,8 +1,9 @@ import py from pypy.rlib.rctypesobject import * -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, get_interpreter from pypy.translator.c.test.test_genc import compile from pypy.annotation.policy import AnnotatorPolicy +from pypy.objspace.flow.model import mkentrymap class TestBasic: @@ -194,6 +195,24 @@ def do(self, func): return interpret(func, [], policy=POLICY, backendopt=True) + def test_simple_struct(self): + S0 = RStruct('S0', [('x', rc_int)]) + def func(): + s = S0.allocate() + s.ref_x().set_value(12) + return s.ref_x().get_value() + + interp, graph = get_interpreter(func, [], policy=POLICY, + backendopt=True) + res = interp.eval_graph(graph, []) + assert res == 12 + # after inlining the get_value() call, there is a getarrayitem + # at the end of the main graph. However, the memory it accesses + # must be protected by a following keepalive... + entrymap = mkentrymap(graph) + [link] = entrymap[graph.returnblock] + assert link.prevblock.operations[-1].opname == 'keepalive' + class TestCompiled(TestBasic): Modified: pypy/dist/pypy/translator/backendopt/malloc.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/malloc.py (original) +++ pypy/dist/pypy/translator/backendopt/malloc.py Mon Nov 13 13:17:45 2006 @@ -267,7 +267,7 @@ for block, vars in variables_by_block.items(): - def flowin(var, newvarsmap, insert_keepalive=False): + def flowin(var, newvarsmap): # in this 'block', follow where the 'var' goes to and replace # it by a flattened-out family of variables. This family is given # by newvarsmap, whose keys are the 'flatnames'. @@ -383,12 +383,11 @@ for arg in link.args: if arg in vars: newargs += list_newvars() - insert_keepalive = False # kept alive by the link else: newargs.append(arg) link.args[:] = newargs - if insert_keepalive and last_removed_access is not None: + if last_removed_access is not None: keepalives = [] for v in list_newvars(): T = v.concretetype @@ -415,7 +414,7 @@ newinputargs += block.inputargs[i+1:] block.inputargs[:] = newinputargs assert var not in block.inputargs - flowin(var, newvarsmap, insert_keepalive=True) + flowin(var, newvarsmap) # look for variables created inside the block by a malloc vars_created_here = [] 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 Mon Nov 13 13:17:45 2006 @@ -5,9 +5,10 @@ from pypy.translator.backendopt.all import backend_optimizations from pypy.translator.translator import TranslationContext, graphof from pypy.translator import simplify -from pypy.objspace.flow.model import checkgraph, flatten, Block +from pypy.objspace.flow.model import checkgraph, flatten, Block, mkentrymap from pypy.rpython.llinterp import LLInterpreter -from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import lltype, llmemory +from pypy.rlib import objectmodel from pypy.conftest import option @@ -48,6 +49,7 @@ break if must_be_removed: check_malloc_removed(graph) + return graph def test_fn1(): @@ -280,3 +282,35 @@ x.u2.b = 6 return x.u1.b * x.u2.a check(fn, [], [], Ellipsis) + +def test_keep_all_keepalives(): + SIZE = llmemory.sizeof(lltype.Signed) + PARRAY = lltype.Ptr(lltype.FixedSizeArray(lltype.Signed, 1)) + class A: + def __init__(self): + self.addr = llmemory.raw_malloc(SIZE) + def __del__(self): + llmemory.raw_free(self.addr) + class B: + pass + def myfunc(): + b = B() + b.keep = A() + b.data = llmemory.cast_adr_to_ptr(b.keep.addr, PARRAY) + b.data[0] = 42 + ptr = b.data + # normally 'b' could go away as early as here, which would free + # the memory held by the instance of A in b.keep... + res = ptr[0] + # ...so we explicitly keep 'b' alive until here + objectmodel.keepalive_until_here(b) + return res + graph = check(myfunc, [], [], 42, + must_be_removed=False) # 'A' instance left + + # there is a getarrayitem near the end of the graph of myfunc. + # However, the memory it accesses must still be protected by the + # following keepalive, even after malloc removal + entrymap = mkentrymap(graph) + [link] = entrymap[graph.returnblock] + assert link.prevblock.operations[-1].opname == 'keepalive' From cfbolz at codespeak.net Mon Nov 13 14:08:43 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 13 Nov 2006 14:08:43 +0100 (CET) Subject: [pypy-svn] r34559 - in pypy/dist/pypy/lang/prolog: builtin interpreter Message-ID: <20061113130843.83C8F10198@code0.codespeak.net> Author: cfbolz Date: Mon Nov 13 14:08:42 2006 New Revision: 34559 Modified: pypy/dist/pypy/lang/prolog/builtin/formatting.py pypy/dist/pypy/lang/prolog/interpreter/choice.py pypy/dist/pypy/lang/prolog/interpreter/engine.py pypy/dist/pypy/lang/prolog/interpreter/term.py Log: fix some imports Modified: pypy/dist/pypy/lang/prolog/builtin/formatting.py ============================================================================== --- pypy/dist/pypy/lang/prolog/builtin/formatting.py (original) +++ pypy/dist/pypy/lang/prolog/builtin/formatting.py Mon Nov 13 14:08:42 2006 @@ -57,7 +57,7 @@ return self.format_var(term) def format_atom(self, s): - from algorithm.automaton.deterministic import LexerError + from pypy.rlib.parsing.deterministic import LexerError if self.quoted: try: tokens = parsing.lexer.tokenize(s) Modified: pypy/dist/pypy/lang/prolog/interpreter/choice.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/choice.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/choice.py Mon Nov 13 14:08:42 2006 @@ -2,7 +2,7 @@ import py from py.magic import greenlet -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated from pypy.rpython.rstack import yield_current_frame_to_caller from pypy.translator.c.test.test_stackless import StacklessTest Modified: pypy/dist/pypy/lang/prolog/interpreter/engine.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/engine.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/engine.py Mon Nov 13 14:08:42 2006 @@ -91,7 +91,7 @@ self.operations = None def add_rule(self, rule, end=True): - from prolog import builtin + from pypy.lang.prolog import builtin if DEBUG: debug_print("add_rule", rule) if isinstance(rule, Term): Modified: pypy/dist/pypy/lang/prolog/interpreter/term.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/term.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/term.py Mon Nov 13 14:08:42 2006 @@ -1,5 +1,5 @@ import math -from pypy.rpython.objectmodel import we_are_translated, UnboxedValue +from pypy.rlib.objectmodel import we_are_translated, UnboxedValue from pypy.rlib.rarithmetic import intmask from pypy.lang.prolog.interpreter.error import UnificationFailed, UncatchableError From cfbolz at codespeak.net Mon Nov 13 14:08:57 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 13 Nov 2006 14:08:57 +0100 (CET) Subject: [pypy-svn] r34560 - pypy/dist/pypy/rlib/parsing Message-ID: <20061113130857.D26421019C@code0.codespeak.net> Author: cfbolz Date: Mon Nov 13 14:08:55 2006 New Revision: 34560 Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py Log: remove unused import Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/ebnfparse.py Mon Nov 13 14:08:55 2006 @@ -5,7 +5,6 @@ import string from pypy.rlib.parsing.regex import * from pypy.rlib.parsing.deterministic import DFA -from algorithm.tool.makeondemand import make_on_demand from pypy.rlib.parsing.lexer import Lexer, DummyLexer def make_ebnf_parser(): From arigo at codespeak.net Mon Nov 13 14:19:55 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 13 Nov 2006 14:19:55 +0100 (CET) Subject: [pypy-svn] r34561 - pypy/dist/pypy/translator/c/src Message-ID: <20061113131955.E835F1019B@code0.codespeak.net> Author: arigo Date: Mon Nov 13 14:19:55 2006 New Revision: 34561 Modified: pypy/dist/pypy/translator/c/src/exception.h Log: Eagerly normalize the exceptions escaping from RPython to CPython. This works around obscure troubles with non-normalized py.magic.AssertionError exceptions. 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 Mon Nov 13 14:19:55 2006 @@ -79,19 +79,25 @@ /* XXX 1. uses officially bad fishing */ /* XXX 2. looks for exception classes by name, fragile */ char* clsname; - PyObject* pycls; + PyObject *pycls, *v, *tb; assert(RPyExceptionOccurred()); assert(!PyErr_Occurred()); clsname = RPyFetchExceptionType()->ov_name->items; pycls = PyDict_GetItemString(PyEval_GetBuiltins(), clsname); if (pycls != NULL && PyExceptionClass_Check(pycls) && PyObject_IsSubclass(pycls, PyExc_Exception)) { - PyErr_SetNone(pycls); + v = NULL; } else { - PyErr_SetString(RPythonError, clsname); + pycls = RPythonError; + v = PyString_FromString(clsname); } + Py_INCREF(pycls); + tb = NULL; RPyClearException(); + + PyErr_NormalizeException(&pycls, &v, &tb); + PyErr_Restore(pycls, v, tb); } #endif /* !PYPY_STANDALONE */ From fijal at codespeak.net Mon Nov 13 15:21:01 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 13 Nov 2006 15:21:01 +0100 (CET) Subject: [pypy-svn] r34562 - in pypy/dist/pypy/translator/js/modules: . test Message-ID: <20061113142101.48A9B10186@code0.codespeak.net> Author: fijal Date: Mon Nov 13 15:20:58 2006 New Revision: 34562 Modified: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Modified a test to suit translation needs. Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Mon Nov 13 15:20:58 2006 @@ -259,11 +259,15 @@ # some helper functions (XXX imo these can go, but the code seems to use them # a lot... isn't it possible to just use dom.window and dom.document instead?) +window = Window() + def get_document(): - return NonConstant(Window().document) + return window.document +get_document.suggested_primitive = True def get_window(): - return NonConstant(Window()) + return window +get_window.suggested_primitive = True # rtyper stuff Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 13 15:20:58 2006 @@ -17,7 +17,10 @@ e.stopPropagation() def get_window(): - return dom.get_window() + if TRANSLATING: + return dom.get_window() + else: + return dom.Window() def test_quote_html(): assert dom._quote_html('foo&bar') == 'foo&bar' @@ -38,7 +41,7 @@ assert roundtrip(html) == html def code_init(): - window = dom.get_window() + window = get_window() nodeType = window.document.nodeType docel = window.document.documentElement.nodeName children = len(window.document.documentElement.childNodes) @@ -310,8 +313,12 @@ def test_build(): py.test.skip('Borken') + global TRANSLATING + TRANSLATING = True for var in globals(): if var.startswith('code_'): # just build it - rpython2javascript(sys.modules[__name__], [var]) - + def f(): + assert rpython2javascript(sys.modules[__name__], [var], use_pdb=False) + + yield f From pedronis at codespeak.net Mon Nov 13 15:32:45 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Nov 2006 15:32:45 +0100 (CET) Subject: [pypy-svn] r34563 - pypy/dist/pypy/module/__builtin__/test Message-ID: <20061113143245.67EAF10075@code0.codespeak.net> Author: pedronis Date: Mon Nov 13 15:32:43 2006 New Revision: 34563 Modified: pypy/dist/pypy/module/__builtin__/test/test_import.py pypy/dist/pypy/module/__builtin__/test/test_special.py Log: make module/__builtin__ tests behave when run with pypy-c py.test -A Modified: pypy/dist/pypy/module/__builtin__/test/test_import.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/test_import.py (original) +++ pypy/dist/pypy/module/__builtin__/test/test_import.py Mon Nov 13 15:32:43 2006 @@ -9,6 +9,8 @@ from pypy.module.__builtin__ import importing +from pypy import conftest + def setuppkg(pkgname, **entries): p = udir.join('impsubdir') if pkgname: @@ -56,19 +58,22 @@ # create compiled/x.py and a corresponding pyc file p = setuppkg("compiled", x = "x = 84") - w = space.wrap - w_modname = w("compiled.x") - filename = str(p.join("x.py")) - fd = os.open(filename, os.O_RDONLY, 0666) - osfile = importing.OsFileWrapper(fd) - try: - importing.load_source_module(space, - w_modname, - w(importing.Module(space, w_modname)), - filename, - osfile) - finally: - osfile.close() + if conftest.option.runappdirect: + pass + else: + w = space.wrap + w_modname = w("compiled.x") + filename = str(p.join("x.py")) + fd = os.open(filename, os.O_RDONLY, 0666) + osfile = importing.OsFileWrapper(fd) + try: + importing.load_source_module(space, + w_modname, + w(importing.Module(space, w_modname)), + filename, + osfile) + finally: + osfile.close() return str(root) Modified: pypy/dist/pypy/module/__builtin__/test/test_special.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/test_special.py (original) +++ pypy/dist/pypy/module/__builtin__/test/test_special.py Mon Nov 13 15:32:43 2006 @@ -1,5 +1,11 @@ import py +from pypy import conftest + +def setup_module(mod): + if conftest.option.runappdirect: + py.test.skip("doesn't make sense with -A") + def app_test__isfake(): assert not _isfake(map) assert not _isfake(object) From fijal at codespeak.net Mon Nov 13 15:34:27 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 13 Nov 2006 15:34:27 +0100 (CET) Subject: [pypy-svn] r34564 - pypy/dist/pypy/translator/js/modules/test Message-ID: <20061113143427.68E4E10091@code0.codespeak.net> Author: fijal Date: Mon Nov 13 15:34:25 2006 New Revision: 34564 Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Fixed the test. Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 13 15:34:25 2006 @@ -312,13 +312,13 @@ assert body.innerHTML == '
foo
' def test_build(): - py.test.skip('Borken') + #py.test.skip('Borken') global TRANSLATING TRANSLATING = True for var in globals(): if var.startswith('code_'): # just build it - def f(): - assert rpython2javascript(sys.modules[__name__], [var], use_pdb=False) + #def f(): + assert rpython2javascript(sys.modules[__name__], [var]) - yield f + TRANSLATING = False From pedronis at codespeak.net Mon Nov 13 15:48:25 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Nov 2006 15:48:25 +0100 (CET) Subject: [pypy-svn] r34565 - pypy/dist/pypy Message-ID: <20061113144825.1CD4A101A0@code0.codespeak.net> Author: pedronis Date: Mon Nov 13 15:48:24 2006 New Revision: 34565 Modified: pypy/dist/pypy/conftest.py Log: forgot this change. Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Mon Nov 13 15:48:24 2006 @@ -102,7 +102,7 @@ "while pypy-c was built with %s" % (key, value, has)) def appexec(self, args, body): - src = py.code.Source("def anonymous" + body) + src = py.code.Source("def anonymous" + body.lstrip()) d = {} exec src.compile() in d return d['anonymous'](*args) From pedronis at codespeak.net Mon Nov 13 15:56:29 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Nov 2006 15:56:29 +0100 (CET) Subject: [pypy-svn] r34566 - pypy/dist/pypy/module/_sre/test Message-ID: <20061113145629.2FE41101A1@code0.codespeak.net> Author: pedronis Date: Mon Nov 13 15:56:27 2006 New Revision: 34566 Modified: pypy/dist/pypy/module/_sre/test/test_app_sre.py Log: make module/_sre tests work with pypy-c py.test -A. One test is really failing with a MemoryError !? to investigate later. Modified: pypy/dist/pypy/module/_sre/test/test_app_sre.py ============================================================================== --- pypy/dist/pypy/module/_sre/test/test_app_sre.py (original) +++ pypy/dist/pypy/module/_sre/test/test_app_sre.py Mon Nov 13 15:56:27 2006 @@ -2,7 +2,8 @@ from py.test import raises, skip from pypy.interpreter.gateway import app2interp_temp -def app_init_globals_hack(): +def init_globals_hack(space): + space.appexec([], """(): import __builtin__ as b import sys, os.path # Uh-oh, ugly hack @@ -12,7 +13,7 @@ import support_test_app_sre b.s = support_test_app_sre sys.path.pop(0) - + """) class AppTestSrePy: @@ -224,7 +225,7 @@ def setup_class(cls): # This imports support_test_sre as the global "s" - app2interp_temp(app_init_globals_hack)(cls.space) + init_globals_hack(cls.space) def setup_method(self, method): import locale @@ -481,7 +482,7 @@ def setup_class(cls): # This imports support_test_sre as the global "s" - app2interp_temp(app_init_globals_hack)(cls.space) + init_globals_hack(cls.space) def test_length_optimization(self): pattern = "bla" From arigo at codespeak.net Mon Nov 13 16:08:32 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 13 Nov 2006 16:08:32 +0100 (CET) Subject: [pypy-svn] r34567 - pypy/dist/pypy/rlib Message-ID: <20061113150832.7B7701018B@code0.codespeak.net> Author: arigo Date: Mon Nov 13 16:08:31 2006 New Revision: 34567 Modified: pypy/dist/pypy/rlib/rctypesobject.py Log: Add some keepalive_until_here() to keep the result of ll_ref() alive. Modified: pypy/dist/pypy/rlib/rctypesobject.py ============================================================================== --- pypy/dist/pypy/rlib/rctypesobject.py (original) +++ pypy/dist/pypy/rlib/rctypesobject.py Mon Nov 13 16:08:31 2006 @@ -93,6 +93,7 @@ def set_value(self, value): ptr = self.ll_ref(cls.CDATATYPE) ptr[0] = cls.value2llvalue(value) + keepalive_until_here(self) cls.set_value = set_value def sameaddr(self, otherbox): @@ -114,6 +115,10 @@ return targetmemblock def ll_ref(self, CDATATYPE): + # Return a ptr to the memory that this object references. + # WARNING: always use 'keepalive_until_here(self)' when you + # are done using this ptr! Otherwise the memory might be + # deallocated. return llmemory.cast_adr_to_ptr(self.addr, lltype.Ptr(CDATATYPE)) ll_ref._annspecialcase_ = 'specialize:arg(1)' @@ -209,6 +214,7 @@ a.char[0] = '\x00' ptr = self.ll_ref(RCTypesCharP.CDATATYPE) ptr[0] = llmemory.cast_adr_to_ptr(targetaddr, RCTypesCharP.LLTYPE) + keepalive_until_here(self) self._keepalivememblock(0, targetmemblock) rc_char_p = RCTypesCharP @@ -235,6 +241,7 @@ def get_contents(self): ptr = self.ll_ref(RCTypesPtr.CDATATYPE) targetaddr = llmemory.cast_ptr_to_adr(ptr[0]) + keepalive_until_here(self) targetkeepalives = contentscls.num_keepalives targetmemblock = self._getmemblock(0, targetkeepalives) return contentscls(targetaddr, targetmemblock) @@ -245,6 +252,7 @@ ptr = self.ll_ref(RCTypesPtr.CDATATYPE) ptr[0] = llmemory.cast_adr_to_ptr(targetaddr, RCTypesPtr.LLTYPE) + keepalive_until_here(self) self._keepalivememblock(0, targetmemblock) contentscls._ptrcls = RCTypesPtr @@ -412,17 +420,24 @@ def get_value(self): p = as_ll_charptr(self) n = strnlen(p, self.length) - return charp2string(p, n) + res = charp2string(p, n) + keepalive_until_here(self) + return res def set_value(self, string): string2charp(as_ll_charptr(self), self.length, string) + keepalive_until_here(self) def get_raw(self): - return charp2string(as_ll_charptr(self), self.length) + res = charp2string(as_ll_charptr(self), self.length) + keepalive_until_here(self) + return res def get_substring(self, start, length): p = lltype.direct_ptradd(as_ll_charptr(self), start) - return charp2string(p, length) + res = charp2string(p, length) + keepalive_until_here(self) + return res RCClass.get_value = get_value RCClass.set_value = set_value From pedronis at codespeak.net Mon Nov 13 16:09:17 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Nov 2006 16:09:17 +0100 (CET) Subject: [pypy-svn] r34568 - pypy/dist/pypy/module/sys/test Message-ID: <20061113150917.C826A101A2@code0.codespeak.net> Author: pedronis Date: Mon Nov 13 16:09:15 2006 New Revision: 34568 Modified: pypy/dist/pypy/module/sys/test/test_sysmodule.py Log: make sys module work with pypy-c py.test -A, one tests fail if py.test is doing stdout capture, it works with -s Modified: pypy/dist/pypy/module/sys/test/test_sysmodule.py ============================================================================== --- pypy/dist/pypy/module/sys/test/test_sysmodule.py (original) +++ pypy/dist/pypy/module/sys/test/test_sysmodule.py Mon Nov 13 16:09:15 2006 @@ -3,11 +3,13 @@ from py.test import raises from pypy.interpreter.gateway import app2interp_temp -def app_init_globals_via_builtins_hack(): +def init_globals_via_builtins_hack(space): + space.appexec([], """(): import __builtin__ as b import cStringIO, sys b.cStringIO = cStringIO b.sys = sys + """) def test_stdin_exists(space): space.sys.get('stdin') @@ -80,7 +82,7 @@ class AppTestSysModulePortedFromCPython: def setup_class(cls): - app2interp_temp(app_init_globals_via_builtins_hack)(cls.space) + init_globals_via_builtins_hack(cls.space) def test_original_displayhook(self): import __builtin__ From guido at codespeak.net Mon Nov 13 16:14:52 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 13 Nov 2006 16:14:52 +0100 (CET) Subject: [pypy-svn] r34569 - pypy/dist/pypy/translator/js/doc Message-ID: <20061113151452.4CA1A101A6@code0.codespeak.net> Author: guido Date: Mon Nov 13 16:14:51 2006 New Revision: 34569 Added: pypy/dist/pypy/translator/js/doc/dom.txt Log: Quick description of the js/modules/dom.py. Added: pypy/dist/pypy/translator/js/doc/dom.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/js/doc/dom.txt Mon Nov 13 16:14:51 2006 @@ -0,0 +1,92 @@ +pypy/translator/js/modules/dom.py +================================= + +This document describes the module 'dom' that can be imported in CPython to +allow testing code that should be translated to JavaScript and run in a +browser. The dom library contains a subset of the DOM implementation in +the Mozilla browser (and other standard-compliant browsers), in such a way +that the results of DOM manipulations and (some of the more common) browser +API calls can be tested. + +What is supported? +------------------ + +Currently supported are: + + * DOM level 2 + + This is provided by wrapping the 'xml.dom.minidom' library as found in + core Python. Some functionality was changed a bit to behave more like the + browser's DOM, for instance 'getElementById()' explicitly checks for + attributes called 'id' and 'getElementsByTagName()' ignores the nodeName + argument's case. + + Example:: + + >>> from pypy.translator.js.modules.dom import get_window + >>> window = get_window() + >>> document = window.document + >>> div = document.createElement('div') + >>> div.appendChild(document.createTextNode('foo')) + + >>> body = document.getElementsByTagName('body')[0] + >>> body.appendChild(div) + + >>> len(body.childNodes) + 1 + + * EventTarget + + This is implemented in Python, and is a simplified version of what is + provided by Mozilla. There is an EventTarget interface that is implemented + by all Node types and the Window object, that provides the standard + addEventListener, removeEventListener and dispatchEvents methods, and + the API allows instantiating an event with standard arguments. Groups are + ignored (as they mostly are in browsers), and additional information on + MouseEvent and KeyEvent are not supported (so there is no information about + the physical location of the event and such). + + Currently events aren't fired automatically, to test event handling an + event must be explicitly instantiated and dispatched:: + + >>> from pypy.translator.js.modules.dom import get_window + >>> window = get_window() + >>> document = window.document + >>> e = document.createEvent('group is ignored') + >>> e.initEvent('click', True, True) + >>> document.getElementsByTagName('body')[0].dispatchEvent(e) + + (This would result in all handlers for the 'click' event registered on + body (and if not cancelled, bubbling up to the document node) getting + called, with the event as argument.) + + * Window + + There is a function 'get_window()' that returns a reference to a global + Window object. This provides (again a subset of) the functionality that + is available on the 'window' object in browsers (the default namespace). + + Example:: + + >>> from pypy.translator.js.modules.dom import get_window + >>> window.location + 'about:blank' + >>> window.self is window + True + >>> document = window.document + + * Additional HTML functionality on Element and Document + + There is some additional functionality available that is browser-specific, + such as the .innerHTML property (note that setting .innerHTML to a string + that is not well-formed will result in a failure!) and .className and .id + properties. + + Example:: + + >>> from pypy.translator.js.modules.dom import get_window + >>> document = get_window().document + >>> body = document.getElementsByTagName('body')[0] + >>> body.nodeName + u'BODY' + From arigo at codespeak.net Mon Nov 13 16:46:44 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 13 Nov 2006 16:46:44 +0100 (CET) Subject: [pypy-svn] r34570 - pypy/dist/pypy/lang/prolog/interpreter Message-ID: <20061113154644.1AF50101A8@code0.codespeak.net> Author: arigo Date: Mon Nov 13 16:46:43 2006 New Revision: 34570 Modified: pypy/dist/pypy/lang/prolog/interpreter/main.py Log: remove tab. Modified: pypy/dist/pypy/lang/prolog/interpreter/main.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/main.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/main.py Mon Nov 13 16:46:43 2006 @@ -136,7 +136,7 @@ except ImportError: try: import tty, sys, termios - self.impl = self.get_unix + self.impl = self.get_unix except ImportError: import Carbon, Carbon.Evt self.impl = self.get_carbon From pedronis at codespeak.net Mon Nov 13 16:51:28 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Nov 2006 16:51:28 +0100 (CET) Subject: [pypy-svn] r34571 - pypy/dist/pypy/module/thread/test Message-ID: <20061113155128.12137101AC@code0.codespeak.net> Author: pedronis Date: Mon Nov 13 16:51:27 2006 New Revision: 34571 Modified: pypy/dist/pypy/module/thread/test/support.py Log: make module/thread tests work with pypy-c py.test -A too. 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 Mon Nov 13 16:51:27 2006 @@ -1,6 +1,6 @@ import py import time, gc -from pypy.conftest import gettestobjspace +from pypy.conftest import gettestobjspace, option from pypy.interpreter.gateway import ObjSpace, W_Root, interp2app_temp @@ -24,7 +24,21 @@ space = gettestobjspace(usemodules=('thread', 'time')) cls.space = space - cls.w_waitfor = space.wrap(interp2app_temp(waitfor)) + if option.runappdirect: + def plain_waitfor(condition, timeout=300.0): + adaptivedelay = 0.04 + limit = time.time() + timeout + while time.time() <= limit: + time.sleep(adaptivedelay) + gc.collect() + if condition(): + return + adaptivedelay *= 1.05 + print '*** timed out ***' + + cls.w_waitfor = plain_waitfor + else: + cls.w_waitfor = space.wrap(interp2app_temp(waitfor)) cls.w_busywait = space.appexec([], """(): import time return time.sleep From pedronis at codespeak.net Mon Nov 13 17:02:34 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 13 Nov 2006 17:02:34 +0100 (CET) Subject: [pypy-svn] r34573 - pypy/dist/pypy Message-ID: <20061113160234.C8977101B3@code0.codespeak.net> Author: pedronis Date: Mon Nov 13 17:02:33 2006 New Revision: 34573 Modified: pypy/dist/pypy/conftest.py Log: make lib/test2/test_optimizers.py pass with pypy-c py.test -A. Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Mon Nov 13 17:02:33 2006 @@ -110,6 +110,9 @@ def wrap(self, obj): return obj + def unpackiterable(self, itr): + return list(itr) + class OpErrKeyboardInterrupt(KeyboardInterrupt): pass From mwh at codespeak.net Mon Nov 13 17:20:15 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 13 Nov 2006 17:20:15 +0100 (CET) Subject: [pypy-svn] r34575 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061113162015.18E3A101A9@code0.codespeak.net> Author: mwh Date: Mon Nov 13 17:20:06 2006 New Revision: 34575 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: an untested AddrConst implementation, and some other bits Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Mon Nov 13 17:20:06 2006 @@ -60,6 +60,41 @@ def fits_in_immediate(self): return abs(self.value) < 2**16 +class AddrConst(GenConst): + + def __init__(self, addr): + self.addr = addr + + @specialize.arg(1) + def revealconst(self, T): + if T is llmemory.Address: + return self.addr + elif isinstance(T, lltype.Ptr): + return llmemory.cast_adr_to_ptr(self.addr, T) + elif T is lltype.Signed: + return llmemory.cast_adr_to_int(self.addr) + else: + assert 0, "XXX not implemented" + + def fits_in_immediate(self): + return False + + def load(self, insns, var): + i = IntConst(llmemory.cast_adr_to_int(self.addr)) + insns.append( + insn.Insn_GPR__IMM(RPPCAssembler.load_word, + var, [i])) + + def load_now(self, asm, loc): + value = llmemory.cast_adr_to_int(self.addr) + if loc.is_register: + assert isinstance(loc, insn.GPR) + asm.load_word(loc.number, value) + else: + asm.load_word(rSCRATCH, value) + asm.stw(rSCRATCH, rFP, loc.offset) + + class JumpPatchupGenerator(object): def __init__(self, asm, min_offset): @@ -160,6 +195,9 @@ genmethod = getattr(self, 'op_' + opname) return genmethod(gv_arg1, gv_arg2) + def genop_call(self, sigtoken, gv_fnptr, args_gv): + pass + ## def genop_getfield(self, fieldtoken, gv_ptr): ## def genop_setfield(self, fieldtoken, gv_ptr, gv_value): ## def genop_getsubstruct(self, fieldtoken, gv_ptr): @@ -168,7 +206,6 @@ ## def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): ## def genop_malloc_fixedsize(self, alloctoken): ## def genop_malloc_varsize(self, varsizealloctoken, gv_size): -## def genop_call(self, sigtoken, gv_fnptr, args_gv): ## def genop_same_as(self, kindtoken, gv_x): ## def genop_debug_pdb(self): # may take an args_gv later @@ -492,6 +529,7 @@ def __init__(self): self.mcs = [] # machine code blocks where no-one is currently writing + self.keepalive_gc_refs = [] # ---------------------------------------------------------------- # the public RGenOp interface @@ -503,16 +541,18 @@ inputargs_gv = builder._write_prologue(sigtoken) return builder, entrypoint, inputargs_gv - @staticmethod - @specialize.genconst(0) - def genconst(llvalue): + @specialize.genconst(1) + def genconst(self, llvalue): T = lltype.typeOf(llvalue) if isinstance(T, lltype.Primitive): return IntConst(lltype.cast_primitive(lltype.Signed, llvalue)) -## elif T is llmemory.Address: -## return AddrConst(llvalue) -## elif isinstance(T, lltype.Ptr): -## return AddrConst(llmemory.cast_ptr_to_adr(llvalue)) + elif T is llmemory.Address: + return AddrConst(llvalue) + elif isinstance(T, lltype.Ptr): + lladdr = llmemory.cast_ptr_to_adr(llvalue) + if T.TO._gckind == 'gc': + self.keepalive_gc_refs.append(lltype.cast_opaque_ptr(llmemory.GCREF, llvalue)) + return AddrConst(lladdr) else: assert 0, "XXX not implemented" @@ -646,3 +686,6 @@ self.asm.mtctr(rSCRATCH) self.asm.bctr() self.asm.mc.setpos(pos) + +global_rgenop = RPPCGenOp() +RPPCGenOp.constPrebuiltGlobal = global_rgenop.genconst From mwh at codespeak.net Mon Nov 13 17:21:23 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 13 Nov 2006 17:21:23 +0100 (CET) Subject: [pypy-svn] r34576 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061113162123.7F5D0101AA@code0.codespeak.net> Author: mwh Date: Mon Nov 13 17:21:22 2006 New Revision: 34576 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: waste a little bit less stack, and expand a docstring. Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Mon Nov 13 17:21:22 2006 @@ -361,8 +361,9 @@ """ Returns the required stack size to store all data, assuming that there are 'param' bytes of parameters for callee functions and 'lv' is the largest (wrt to abs() :) rFP-relative byte offset of - any variable on the stack.""" - return ((24 + param - lv + 15) & ~15) + any variable on the stack. Plus 4 because the rFP actually points + into our caller's linkage area.""" + return ((4 + param - lv + 15) & ~15) def _close(self): self.rgenop.close_mc(self.asm.mc) From xoraxax at codespeak.net Mon Nov 13 21:13:21 2006 From: xoraxax at codespeak.net (xoraxax at codespeak.net) Date: Mon, 13 Nov 2006 21:13:21 +0100 (CET) Subject: [pypy-svn] r34581 - pypy/dist/pypy/lang/prolog/interpreter Message-ID: <20061113201321.631CF101BE@code0.codespeak.net> Author: xoraxax Date: Mon Nov 13 21:13:20 2006 New Revision: 34581 Added: pypy/dist/pypy/lang/prolog/interpreter/autopath.py - copied unchanged from r34580, pypy/dist/pypy/bin/autopath.py Modified: pypy/dist/pypy/lang/prolog/interpreter/main.py Log: Use autopath in the prolog interpreter. Modified: pypy/dist/pypy/lang/prolog/interpreter/main.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/main.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/main.py Mon Nov 13 21:13:20 2006 @@ -1,7 +1,13 @@ #!/usr/bin/env python + +try: + import autopath +except ImportError: + pass + import py import sys -sys.path.append(str(py.magic.autopath().dirpath().dirpath())) +#sys.path.append(str(py.magic.autopath().dirpath().dirpath())) from pypy.rlib.parsing.parsing import ParseError from pypy.rlib.parsing.deterministic import LexerError From cfbolz at codespeak.net Mon Nov 13 21:14:12 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 13 Nov 2006 21:14:12 +0100 (CET) Subject: [pypy-svn] r34582 - pypy/dist/pypy/lang/prolog/builtin Message-ID: <20061113201412.4EA48101C1@code0.codespeak.net> Author: cfbolz Date: Mon Nov 13 21:14:10 2006 New Revision: 34582 Modified: pypy/dist/pypy/lang/prolog/builtin/register.py pypy/dist/pypy/lang/prolog/builtin/source.py Log: more wrong imports Modified: pypy/dist/pypy/lang/prolog/builtin/register.py ============================================================================== --- pypy/dist/pypy/lang/prolog/builtin/register.py (original) +++ pypy/dist/pypy/lang/prolog/builtin/register.py Mon Nov 13 21:14:10 2006 @@ -4,7 +4,7 @@ from pypy.lang.prolog.interpreter import engine, helper, term, error from pypy.lang.prolog.builtin import builtins -from pypy.rpython.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated def expose_builtin(func, name, unwrap_spec=None, handles_continuation=False, translatable=True): Modified: pypy/dist/pypy/lang/prolog/builtin/source.py ============================================================================== --- pypy/dist/pypy/lang/prolog/builtin/source.py (original) +++ pypy/dist/pypy/lang/prolog/builtin/source.py Mon Nov 13 21:14:10 2006 @@ -3,7 +3,6 @@ from pypy.lang.prolog.interpreter.parsing import parse_file, TermBuilder from pypy.lang.prolog.interpreter import engine, helper, term, error from pypy.lang.prolog.interpreter.error import UnificationFailed, FunctionNotFound -from pypy.rpython.objectmodel import we_are_translated from pypy.lang.prolog.builtin.register import expose_builtin From cfbolz at codespeak.net Mon Nov 13 21:31:06 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 13 Nov 2006 21:31:06 +0100 (CET) Subject: [pypy-svn] r34583 - pypy/dist/pypy/lang/prolog/interpreter Message-ID: <20061113203106.1B7D0101C4@code0.codespeak.net> Author: cfbolz Date: Mon Nov 13 21:31:04 2006 New Revision: 34583 Modified: pypy/dist/pypy/lang/prolog/interpreter/main.py Log: use new parser features to show parse and lex errors Modified: pypy/dist/pypy/lang/prolog/interpreter/main.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/main.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/main.py Mon Nov 13 21:31:04 2006 @@ -77,32 +77,12 @@ if not source.strip(): return None, None return get_query_and_vars(source) - except ParseError, e: - #print e - # fake a Python syntax error :-) - absoffset = e.args[1][-1] - lines = source.split("\n") - curroffset = 0 - for i, line in enumerate(lines): - if curroffset <= absoffset < curroffset + len(line) + 1: - break - curroffset = curroffset + len(line) + 1 - if source.strip().endswith("."): - raise SyntaxError( - "syntax error", - (filename, i+1, absoffset - curroffset, line)) - return None - except LexerError, e: - # fake a Python syntax error - absoffset = e.index - lines = source.split("\n") - curroffset = 0 - for i, line in enumerate(lines): - if curroffset <= absoffset < curroffset + len(line) + 1: - break - curroffset = curroffset + len(line) + 1 - raise SyntaxError( - "token error", (filename, i + 1, absoffset - curroffset, line)) + except ParseError, exc: + self.write(exc.nice_error_message("", source) + "\n") + raise SyntaxError + except LexerError, exc: + self.write(exc.nice_error_message("") + "\n") + raise SyntaxError def runcode(self, code): try: From cfbolz at codespeak.net Mon Nov 13 22:03:50 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 13 Nov 2006 22:03:50 +0100 (CET) Subject: [pypy-svn] r34584 - pypy/dist/pypy/lang/prolog/interpreter Message-ID: <20061113210350.09FD3101C3@code0.codespeak.net> Author: cfbolz Date: Mon Nov 13 22:03:48 2006 New Revision: 34584 Modified: pypy/dist/pypy/lang/prolog/interpreter/main.py Log: better error messages for here too Modified: pypy/dist/pypy/lang/prolog/interpreter/main.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/main.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/main.py Mon Nov 13 22:03:48 2006 @@ -178,7 +178,15 @@ if not len(sys.argv) == 2: e = Engine() else: - e = get_engine(py.path.local(sys.argv[1]).read()) + try: + source = py.path.local(sys.argv[1]).read() + e = get_engine(source) + except ParseError, exc: + print exc.nice_error_message("", source) + "\n" + sys.exit(1) + except LexerError, exc: + print exc.nice_error_message("") + "\n" + sys.exit(1) c = PrologConsole(e) c.interact("PyPy Prolog Console") finally: From cfbolz at codespeak.net Mon Nov 13 22:04:15 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 13 Nov 2006 22:04:15 +0100 (CET) Subject: [pypy-svn] r34585 - in pypy/dist/pypy/lang/prolog/interpreter: . test Message-ID: <20061113210415.A75FD101C5@code0.codespeak.net> Author: cfbolz Date: Mon Nov 13 22:04:13 2006 New Revision: 34585 Modified: pypy/dist/pypy/lang/prolog/interpreter/term.py pypy/dist/pypy/lang/prolog/interpreter/test/test_engine.py Log: test and fix for calling functions without arguments. Modified: pypy/dist/pypy/lang/prolog/interpreter/term.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/term.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/term.py Mon Nov 13 22:04:13 2006 @@ -522,6 +522,12 @@ extend_and_normalize_template_frame(template_frame, frame) for index, obj in to_instantiate: frame.vars[index] = obj.instantiate_template(template_frame) + else: + next_free = frame.maxvar() + for i in range(self.numvars): + template_frame[i] = Var(next_free) + next_free += 1 + frame.extend(next_free - frame.maxvar()) body = self.body if body is None: return None Modified: pypy/dist/pypy/lang/prolog/interpreter/test/test_engine.py ============================================================================== --- pypy/dist/pypy/lang/prolog/interpreter/test/test_engine.py (original) +++ pypy/dist/pypy/lang/prolog/interpreter/test/test_engine.py Mon Nov 13 22:04:13 2006 @@ -241,3 +241,12 @@ def test_handle_non_callable(): py.test.raises(CatchableError, assert_true, "1.") + +def test_call_atom(): + e = get_engine(""" + test(a). + test :- test(_). + """) + assert_true("test.", e) + + From guido at codespeak.net Mon Nov 13 22:04:27 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 13 Nov 2006 22:04:27 +0100 (CET) Subject: [pypy-svn] r34586 - in pypy/dist/pypy/translator/js: . modules modules/test Message-ID: <20061113210427.7B24F101CA@code0.codespeak.net> Author: guido Date: Mon Nov 13 22:04:26 2006 New Revision: 34586 Modified: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py pypy/dist/pypy/translator/js/support.py Log: Improved support for inline styles, they're now read from the 'style' attribute and saved on serialization (.innerHTML). Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Mon Nov 13 22:04:26 2006 @@ -13,6 +13,7 @@ """ import time +import re from pypy.rpython.ootypesystem.bltregistry import BasicExternal, MethodDesc from pypy.rlib.nonconst import NonConstant @@ -115,7 +116,23 @@ def __init__(self, node=None): super(Element, self).__init__(node) - self.style = Style() + + def _style(self): + style = getattr(self._original, '_style', None) + if style is not None: + return style + styles = {} + if self._original.hasAttribute('style'): + for t in self._original.getAttribute('style').split(';'): + name, value = t.split(':') + dashcharpairs = re.findall('-\w', name) + for p in dashcharpairs: + name = name.replace(p, p[1].upper()) + styles[name.strip()] = value.strip() + style = Style(styles) + self._original._style = style + return style + style = property(_style) def _nodeName(self): return self._original.nodeName.upper() @@ -199,11 +216,28 @@ pass class Style(BasicExternal): + def __init__(self, styles={}): + for name, value in styles.iteritems(): + setattr(self, name, value) + def __getattr__(self, name): if name not in self._fields: raise AttributeError, name return None + def _tostring(self): + ret = [] + for name in sorted(self._fields): + value = getattr(self, name, None) + if value is not None: + ret.append(' ') + for char in name: + if char.upper() == char: + char = '-%s' % (char.lower(),) + ret.append(char) + ret.append(': %s;' % (value,)) + return ''.join(ret[1:]) + # non-DOM ('DOM level 0') stuff # Window is the main environment, the root node of the JS object tree @@ -696,13 +730,19 @@ def _serialize_html(node): ret = [] if node.nodeType == 1: - nodeName = getattr(node, '_original', node).nodeName + original = getattr(node, '_original', node) + nodeName = original.nodeName ret += ['<', nodeName] if len(node.attributes): for aname in node.attributes.keys(): + if aname == 'style': + continue attr = node.attributes[aname] ret.append(' %s="%s"' % (attr.nodeName, _quote_html(attr.nodeValue))) + styles = getattr(original, '_style', None) + if styles: + ret.append(' style="%s"' % (_quote_html(styles._tostring()),)) if len(node.childNodes) or nodeName not in _singletons: ret.append('>') for child in node.childNodes: Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 13 22:04:26 2006 @@ -311,6 +311,31 @@ assert div.className == 'bar' assert body.innerHTML == '
foo
' +def code_read_styles(): + window = get_window() + body = window.document.getElementsByTagName('body')[0] + body.innerHTML = ('
foo' + '
') + return body.childNodes[0].style + +def test_read_styles(): + style = code_read_styles() + assert style.color == 'red' + bgcolor = style.backgroundColor + assert bgcolor == 'green' + +def code_write_styles(): + window = get_window() + body = window.document.getElementsByTagName('body')[0] + body.style.color = 'green' + body.style.backgroundColor = 'red' + return body + +def test_write_styles(): + body = code_write_styles() + assert dom._serialize_html(body) == ('') + def test_build(): #py.test.skip('Borken') global TRANSLATING Modified: pypy/dist/pypy/translator/js/support.py ============================================================================== --- pypy/dist/pypy/translator/js/support.py (original) +++ pypy/dist/pypy/translator/js/support.py Mon Nov 13 22:04:26 2006 @@ -23,6 +23,9 @@ self.reserved[name] = True #http://javascript.about.com/library/blclassobj.htm + # XXX WAAAHHH!!! IE alert :( there are a lot of objects here that are + # _not_ in standard JS, see + # http://devedge-temp.mozilla.org/library/manuals/2000/javascript/1.5/reference/ predefined_classes_and_objects = ''' Anchor anchors Applet applets Area Array Body Button Checkbox Date document Error EvalError FileUpload From cfbolz at codespeak.net Mon Nov 13 22:22:28 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 13 Nov 2006 22:22:28 +0100 (CET) Subject: [pypy-svn] r34587 - pypy/dist/pypy/lang/prolog/builtin Message-ID: <20061113212228.1270D101D0@code0.codespeak.net> Author: cfbolz Date: Mon Nov 13 22:22:25 2006 New Revision: 34587 Modified: pypy/dist/pypy/lang/prolog/builtin/formatting.py Log: add nl and write :-) Modified: pypy/dist/pypy/lang/prolog/builtin/formatting.py ============================================================================== --- pypy/dist/pypy/lang/prolog/builtin/formatting.py (original) +++ pypy/dist/pypy/lang/prolog/builtin/formatting.py Mon Nov 13 22:22:25 2006 @@ -140,5 +140,15 @@ def impl_write_term(engine, term, options): f = TermFormatter.from_option_list(engine, options) - os.write(1, f.format(term)) + os.write(1, f.format(term)) # XXX use streams expose_builtin(impl_write_term, "write_term", unwrap_spec=["concrete", "list"]) + +def impl_nl(engine): + os.write(1, "\n") # XXX use streams +expose_builtin(impl_nl, "nl", unwrap_spec=[]) + +def impl_write(engine, term): + impl_write_term(engine, term, []) +expose_builtin(impl_write, "write", unwrap_spec=["raw"]) + + From mwh at codespeak.net Tue Nov 14 13:30:46 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 14 Nov 2006 13:30:46 +0100 (CET) Subject: [pypy-svn] r34593 - in pypy/dist/pypy/jit/codegen: ppc/test test Message-ID: <20061114123046.D2828101D8@code0.codespeak.net> Author: mwh Date: Tue Nov 14 13:30:44 2006 New Revision: 34593 Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Log: a direct test for genop_call(), passing on i386 and skipped on ppc Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Tue Nov 14 13:30:44 2006 @@ -57,6 +57,8 @@ res = fnptr(2, 1) assert res == 100101 + def test_fact_direct(self): + py.test.skip("wip") class TestRPPCGenopNoRegs(TestRPPCGenop): RGenOp = FewRegisters Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py ============================================================================== --- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py (original) +++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Tue Nov 14 13:30:44 2006 @@ -325,6 +325,39 @@ return res return large_switch_runner +def make_fact(rgenop): + # def fact(x): + # if x: + # y = x-1 + # z = fact(y) + # w = x*z + # return w + # return 1 + signed_kind = rgenop.kindToken(lltype.Signed) + sigtoken = rgenop.sigToken(FUNC) + builder, entrypoint, [gv_x] = rgenop.newgraph(sigtoken) + + gv_fact = rgenop.gencallableconst(sigtoken, "fact", entrypoint) + + gv_cond = builder.genop1("int_is_true", gv_x) + + true_builder = builder.jump_if_true(gv_cond) + + args_gv = [gv_x] + true_builder.enter_next_block([signed_kind], args_gv) + [gv_x2] = args_gv + + gv_y = true_builder.genop2("int_sub", gv_x, rgenop.genconst(1)) + gv_z = true_builder.genop_call(sigtoken, gv_fact, [gv_y]) + gv_w = true_builder.genop2("int_mul", gv_x, gv_z) + + true_builder.finish_and_return(sigtoken, gv_w) + + builder.enter_next_block([], []) + + builder.finish_and_return(sigtoken, rgenop.genconst(1)) + return gv_fact + class AbstractRGenOpTests(test_boehm.AbstractGCTestClass): RGenOp = None @@ -452,3 +485,13 @@ assert res == 2**x+7 res = fn(42, 18) assert res == 18 + + def test_fact_direct(self): + rgenop = self.RGenOp() + gv_fact = make_fact(rgenop) + print gv_fact.value + fnptr = cast(c_void_p(gv_fact.value), CFUNCTYPE(c_int)) + res = fnptr(2) + assert res == 2 + res = fnptr(10) + assert res == 3628800 From mwh at codespeak.net Tue Nov 14 13:46:33 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 14 Nov 2006 13:46:33 +0100 (CET) Subject: [pypy-svn] r34594 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061114124633.341BC10092@code0.codespeak.net> Author: mwh Date: Tue Nov 14 13:46:30 2006 New Revision: 34594 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: baby steps towards genop_call for ppc Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Tue Nov 14 13:46:30 2006 @@ -187,8 +187,10 @@ # ---------------------------------------------------------------- # the public Builder interface: -## @specialize.arg(1) -## def genop1(self, opname, gv_arg): + @specialize.arg(1) + def genop1(self, opname, gv_arg): + genmethod = getattr(self, 'op_' + opname) + return genmethod(gv_arg) @specialize.arg(1) def genop2(self, opname, gv_arg1, gv_arg2): @@ -196,7 +198,7 @@ return genmethod(gv_arg1, gv_arg2) def genop_call(self, sigtoken, gv_fnptr, args_gv): - pass + return Var() ## def genop_getfield(self, fieldtoken, gv_ptr): ## def genop_setfield(self, fieldtoken, gv_ptr, gv_value): @@ -454,35 +456,36 @@ gv_result, [gv_x, gv_y])) return gv_result + cmp2info = { + # bit-in-crf negated + 'gt': ( 1, 0 ), + 'lt': ( 0, 0 ), + 'le': ( 1, 1 ), + 'ge': ( 0, 1 ), + 'eq': ( 2, 0 ), + 'ne': ( 2, 1 ), + } + cmp2info_flipped = { + # bit-in-crf negated + 'gt': ( 1, 1 ), + 'lt': ( 0, 1 ), + 'le': ( 1, 0 ), + 'ge': ( 0, 0 ), + 'eq': ( 2, 0 ), + 'ne': ( 2, 1 ), + } + def _compare(self, op, gv_x, gv_y): - cmp2info = { - # bit-in-crf negated - 'gt': ( 1, 0 ), - 'lt': ( 0, 0 ), - 'le': ( 1, 1 ), - 'ge': ( 0, 1 ), - 'eq': ( 2, 0 ), - 'ne': ( 2, 1 ), - } - cmp2info_flipped = { - # bit-in-crf negated - 'gt': ( 1, 1 ), - 'lt': ( 0, 1 ), - 'le': ( 1, 0 ), - 'ge': ( 0, 0 ), - 'eq': ( 2, 0 ), - 'ne': ( 2, 1 ), - } gv_result = Var() if gv_y.fits_in_immediate(): self.insns.append( - insn.CMPWI(cmp2info[op], gv_result, [gv_x, gv_y])) + insn.CMPWI(self.cmp2info[op], gv_result, [gv_x, gv_y])) elif gv_x.fits_in_immediate(): self.insns.append( - insn.CMPWI(cmp2info_flipped[op], gv_result, [gv_y, gv_x])) + insn.CMPWI(self.cmp2info_flipped[op], gv_result, [gv_y, gv_x])) else: self.insns.append( - insn.CMPW(cmp2info[op], gv_result, [gv_x, gv_y])) + insn.CMPW(self.cmp2info[op], gv_result, [gv_x, gv_y])) return gv_result def op_int_gt(self, gv_x, gv_y): @@ -517,6 +520,12 @@ return targetbuilder + def op_int_is_true(self, gv_arg): + gv_result = Var() + self.insns.append( + insn.CMPWI(self.cmp2info['eq'], gv_result, [gv_arg, self.rgenop.genconst(0)])) + return gv_result + class RPPCGenOp(AbstractRGenOp): From fijal at codespeak.net Tue Nov 14 15:16:24 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 14 Nov 2006 15:16:24 +0100 (CET) Subject: [pypy-svn] r34598 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20061114141624.AD7B4101C2@code0.codespeak.net> Author: fijal Date: Tue Nov 14 15:16:22 2006 New Revision: 34598 Modified: pypy/dist/pypy/objspace/std/proxy_helpers.py pypy/dist/pypy/objspace/std/test/test_proxy.py Log: Fixed mm resolution and test for that. Modified: pypy/dist/pypy/objspace/std/proxy_helpers.py ============================================================================== --- pypy/dist/pypy/objspace/std/proxy_helpers.py (original) +++ pypy/dist/pypy/objspace/std/proxy_helpers.py Tue Nov 14 15:16:22 2006 @@ -14,8 +14,10 @@ s += "list_" s += mm.name + "__" s += "_".join([classname] + ["ANY"] * (mm.arity - 1)) - if '__' + mm.name + '__' in mm.specialnames: - return s, '__' + mm.name + '__' + #if '__' + mm.name + '__' in mm.specialnames: + # return s, '__' + mm.name + '__' + if mm.specialnames: + return s, mm.specialnames[0] return s, mm.name def install_general_args_trampoline(type_, mm, is_local, op_name): Modified: pypy/dist/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/dist/pypy/objspace/std/test/test_proxy.py Tue Nov 14 15:16:22 2006 @@ -82,6 +82,12 @@ pass else: fail("Accessing outside a list didn't raise") + + def test_list_inplace_add(self): + c = self.Controller([1,2,3]) + lst = self.proxy(list, c.perform) + lst += [1,2,3] + assert len(lst) == 6 class AppTestDictProxy(AppProxyBasic): def test_dict(self): From mwh at codespeak.net Tue Nov 14 16:27:29 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 14 Nov 2006 16:27:29 +0100 (CET) Subject: [pypy-svn] r34599 - in pypy/dist/pypy/jit/codegen: ppc ppc/test test Message-ID: <20061114152729.6735610070@code0.codespeak.net> Author: mwh Date: Tue Nov 14 16:27:27 2006 New Revision: 34599 Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/regalloc.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Log: genop_call for ppc, and a couple of assorted bugfixes. not especially optimal register usage, to put it mildly. Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Tue Nov 14 16:27:27 2006 @@ -219,6 +219,72 @@ BO = 4 # jump if relavent bit is NOT set in the CR asm.bcctr(BO, self.crf.number*4 + self.bit) +class SpillCalleeSaves(Insn): + def __init__(self): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result = None + self.result_regclass = NO_REGISTER + def allocate(self, allocator): + # cough cough cough + callersave = gprs[3:13] + for v in allocator.var2loc: + loc = allocator.loc_of(v) + if loc in callersave: + #print "spilling", v, "from", loc, "to", + allocator.spill(loc, v) + #print allocator.loc_of(v) + allocator.freeregs[GP_REGISTER].append(loc) + def emit(self, asm): + pass + +class LoadArg(Insn): + def __init__(self, argnumber, arg): + Insn.__init__(self) + self.reg_args = [] + self.reg_arg_regclasses = [] + self.result = None + self.result_regclass = NO_REGISTER + + self.argnumber = argnumber + self.arg = arg + def allocate(self, allocator): + self.loc = allocator.loc_of(self.arg) + def emit(self, asm): + targetreg = 3+self.argnumber + if self.loc.is_register: + asm.mr(targetreg, self.loc.number) + else: + asm.lwz(targetreg, rFP, self.loc.offset) + +class CALL(Insn): + def __init__(self, result, target): + Insn.__init__(self) + from pypy.jit.codegen.ppc.rgenop import Var + if isinstance(target, Var): + self.reg_args = [target] + self.reg_arg_regclasses = [CT_REGISTER] + else: + self.reg_args = [] + self.reg_arg_regclasses = [] + self.target = target + self.result = result + self.result_regclass = GP_REGISTER + def allocate(self, allocator): + if self.reg_args: + assert allocator.loc_of(self.reg_args[0]) is ctr + self.resultreg = allocator.loc_of(self.result) + def emit(self, asm): + if not self.reg_args: + self.target.load_now(asm, gprs[0]) + asm.mtctr(0) + asm.bctrl() + asm.lwz(rFP, rSP, 0) + if self.resultreg != gprs[3]: + asm.mr(self.resultreg.number, 3) + + class AllocTimeInsn(Insn): def __init__(self): Insn.__init__(self) @@ -293,7 +359,7 @@ self.result_regclass = NO_REGISTER self.reg = None def allocate(self, allocator): - self.reg = allocator.loc_of(self.var) + self.reg = allocator.loc_of(self.reg_args[0]) def emit(self, asm): if self.reg.number != 3: asm.mr(r3, self.reg.number) Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Tue Nov 14 16:27:27 2006 @@ -55,6 +55,17 @@ self.spill_offset -= 4 return stack_slot(self.spill_offset) + def spill(self, reg, argtospill): + if argtospill in self.lru: + self.lru.remove(argtospill) + self.forget(argtospill, reg) + spillslot = self.spill_slot() + if reg.regclass != GP_REGISTER: + self.insns.append(reg.move_to_gpr(self, 0)) + reg = gprs[0] + self.insns.append(Spill(argtospill, reg, spillslot)) + self.set(argtospill, spillslot) + def _allocate_reg(self, regclass, newarg): # check if there is a register available @@ -80,17 +91,9 @@ # Move the value we are spilling onto the stack, both in the # data structures and in the instructions: - self.forget(argtospill, reg) - spill = self.spill_slot() - if regclass != GP_REGISTER: - self.insns.append(reg.move_to_gpr(self, 0)) - spillfrom_reg = gprs[0] - else: - spillfrom_reg = reg - self.insns.append(Spill(argtospill, spillfrom_reg, spill)) - self.set(argtospill, spill) + self.spill(reg, argtospill) - #print "allocate_reg: Spilled %r to %r." % (argtospill, spill) + #print "allocate_reg: Spilled %r to %r." % (argtospill, self.loc_of(argtospill)) # update data structures to put newarg into the register self.set(newarg, reg) @@ -143,17 +146,20 @@ argcls = insn.reg_arg_regclasses[i] #print "Allocating register for", arg, "..." argloc = self.loc_of(arg) + #print "currently in", argloc if not argloc.is_register: # It has no register now because it has been spilled self.forget(arg, argloc) newargloc = self._allocate_reg(argcls, arg) + #print "unspilling to", newargloc self.insns.append(Unspill(arg, newargloc, argloc)) self.free_stack_slots.append(argloc) elif argloc.regclass != argcls: # it's in the wrong kind of register # (this code is excessively confusing) self.forget(arg, argloc) + self.freeregs[argloc.regclass].append(argloc) if argloc.regclass != GP_REGISTER: if argcls == GP_REGISTER: gpr = self._allocate_reg(GP_REGISTER, arg).number Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Tue Nov 14 16:27:27 2006 @@ -183,6 +183,7 @@ self.initial_spill_offset = 0 self.initial_var2loc = None self.fresh_from_jump = False + self.max_param_space = -1 # ---------------------------------------------------------------- # the public Builder interface: @@ -198,7 +199,13 @@ return genmethod(gv_arg1, gv_arg2) def genop_call(self, sigtoken, gv_fnptr, args_gv): - return Var() + self.insns.append(insn.SpillCalleeSaves()) + for i in range(len(args_gv)): + self.insns.append(insn.LoadArg(i, args_gv[i])) + gv_result = Var() + self.max_param_space = len(args_gv)*4 + self.insns.append(insn.CALL(gv_result, gv_fnptr)) + return gv_result ## def genop_getfield(self, fieldtoken, gv_ptr): ## def genop_setfield(self, fieldtoken, gv_ptr, gv_value): @@ -291,7 +298,7 @@ min_offset = min(allocator.spill_offset, target.min_stack_offset) min_offset = prepare_for_jump( self.asm, min_offset, outputargs_gv, allocator.var2loc, target) - self.patch_stack_adjustment(self._stack_size(0, min_offset)) + self.patch_stack_adjustment(self._stack_size(min_offset)) self.asm.load_word(rSCRATCH, target.startaddr) self.asm.mtctr(rSCRATCH) self.asm.bctr() @@ -315,6 +322,7 @@ def make_fresh_from_jump(self, initial_var2loc): self.fresh_from_jump = True self.initial_var2loc = initial_var2loc + self.max_param_space = -1 def _write_prologue(self, sigtoken): numargs = sigtoken # for now @@ -338,7 +346,7 @@ # Initially, we set params == lv == 0 and allow each basic block to # ensure it has enough space to continue. - minspace = self._stack_size(0, self._var_offset(0)) + minspace = self._stack_size(self._var_offset(0)) # save Link Register self.asm.mflr(rSCRATCH) self.asm.stw(rSCRATCH, rSP, 8) @@ -359,12 +367,16 @@ this returns the offset relative to rFP""" return -(4*NSAVEDREGISTERS+4+v) - def _stack_size(self, param, lv): + def _stack_size(self, lv): """ Returns the required stack size to store all data, assuming that there are 'param' bytes of parameters for callee functions and 'lv' is the largest (wrt to abs() :) rFP-relative byte offset of any variable on the stack. Plus 4 because the rFP actually points into our caller's linkage area.""" + if self.max_param_space >= 0: + param = self.max_param_space + 24 + else: + param = 0 return ((4 + param - lv + 15) & ~15) def _close(self): @@ -377,7 +389,7 @@ self.rgenop.freeregs, self.initial_var2loc, self.initial_spill_offset) self.insns = allocator.allocate_for_insns(self.insns) if self.insns: - self.patch_stack_adjustment(self._stack_size(0, allocator.spill_offset)) + self.patch_stack_adjustment(self._stack_size(allocator.spill_offset)) for insn in self.insns: insn.emit(self.asm) return allocator @@ -523,7 +535,7 @@ def op_int_is_true(self, gv_arg): gv_result = Var() self.insns.append( - insn.CMPWI(self.cmp2info['eq'], gv_result, [gv_arg, self.rgenop.genconst(0)])) + insn.CMPWI(self.cmp2info['ne'], gv_result, [gv_arg, self.rgenop.genconst(0)])) return gv_result Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Tue Nov 14 16:27:27 2006 @@ -57,9 +57,6 @@ res = fnptr(2, 1) assert res == 100101 - def test_fact_direct(self): - py.test.skip("wip") - class TestRPPCGenopNoRegs(TestRPPCGenop): RGenOp = FewRegisters Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py ============================================================================== --- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py (original) +++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Tue Nov 14 16:27:27 2006 @@ -358,6 +358,16 @@ builder.finish_and_return(sigtoken, rgenop.genconst(1)) return gv_fact +def get_fact_runner(RGenOp): + def fact_runner(x): + rgenop = RGenOp() + gv_large_switchfn = make_fact(rgenop) + largeswitchfn = gv_large_switchfn.revealconst(lltype.Ptr(FUNC)) + res = largeswitchfn(x) + keepalive_until_here(rgenop) # to keep the code blocks alive + return res + return fact_runner + class AbstractRGenOpTests(test_boehm.AbstractGCTestClass): RGenOp = None @@ -495,3 +505,11 @@ assert res == 2 res = fnptr(10) assert res == 3628800 + + def test_fact_compile(self): + fn = self.compile(get_fact_runner(self.RGenOp), [int]) + res = fn(2) + assert res == 2 + res = fn(11) + assert res == 39916800 + From fijal at codespeak.net Tue Nov 14 16:32:25 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 14 Nov 2006 16:32:25 +0100 (CET) Subject: [pypy-svn] r34600 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061114153225.0CBEF1007E@code0.codespeak.net> Author: fijal Date: Tue Nov 14 16:32:22 2006 New Revision: 34600 Added: pypy/dist/pypy/lib/distributed.py (contents, props changed) pypy/dist/pypy/lib/test2/test_distributed.py (contents, props changed) Log: First concept how I see distributed access (works locally anyway) Added: pypy/dist/pypy/lib/distributed.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/distributed.py Tue Nov 14 16:32:22 2006 @@ -0,0 +1,129 @@ + +""" Distributed controller(s) for use with transparent proxy objects + +First idea: + +1. We use py.execnet to create a connection to wherever +2. We run some code there (RSync in advance makes some sense) +3. We access remote objects like normal ones, with a special protocol + +Local side: + - Request an object from remote side from global namespace as simple + --- request(name) ---> + - Receive an object which is in protocol described below which is + constructed as shallow copy of the remote type. + + Shallow copy is defined as follows: + + - for interp-level object that we know we can provide transparent proxy + we just do that + + - for others we fake or fail depending on object + + - for user objects, we create a class which fakes all attributes of + a class as transparent proxies of remote objects, we create an instance + of that class and populate __dict__ + + - for immutable types, we just copy that + +Remote side: + - we run code, whatever we like + - additionally, we've got thread exporting stuff (or just exporting + globals, whatever) + - for every object, we just send an object, or provide a protocol for + sending it in a different way. + +""" + +try: + from pypymagic import transparent_proxy as proxy +except ImportError: + raise ImportError("Cannot work without transparent proxy functional") + +# XXX We do not make any garbage collection. We'll need it at some point + +import types + +class AbstractProtocol(object): + letter_types = { + 'l' : list, + 'd' : dict, + 't' : tuple, + 'i' : int, + 'f' : float, + 'u' : unicode, + 'l' : long, + 's' : str, + 'lst' : list, + 'fun' : types.FunctionType + } + type_letters = dict([(value, key) for key, value in letter_types.items()]) + assert len(type_letters) == len(letter_types) + + def __init__(self): + self.objs = [] # we just store everything, maybe later + # we'll need some kind of garbage collection + + def register_obj(self, obj): + self.objs.append(obj) + return len(self.objs) - 1 + + def wrap(self, obj): + """ Wrap an object as sth prepared for sending + """ + tp = type(obj) + if tp in (str, int, float, long, unicode): + # simple, immutable object, just copy + return (self.type_letters[tp], obj) + elif tp is tuple: + # we just pack all of the items + return ('t', tuple([self.wrap(elem) for elem in obj])) + elif tp in (list, dict, types.FunctionType): + id = self.register_obj(obj) + return (self.type_letters[tp], id) + else: + raise NotImplementedError("Cannot wrap %s: unsupported type %s" % + (obj, tp)) + + def unwrap(self, data): + """ Unwrap an object + """ + tp_letter, obj_data = data + tp = self.letter_types[tp_letter] + if tp in (str, int, float, long, unicode): + return obj_data # this is the object + elif tp is tuple: + return tuple([self.unwrap(i) for i in obj_data]) + elif tp in (list, dict, types.FunctionType): + return proxy(tp, RemoteObject(self, obj_data).perform) + else: + raise NotImplementedError("Cannot unwrap %s" % (data,)) + + def perform(self, *args, **kwargs): + raise NotImplementedError("Abstract only protocol") + +class LocalProtocol(AbstractProtocol): + """ This is stupid protocol for testing purposes only + """ + def perform(self, id, name, *args, **kwargs): + obj = self.objs[id] + return getattr(obj, name)(*args, **kwargs) + +class RemoteObject(object): + def __init__(self, protocol, id): + self.id = id + self.protocol = protocol + + def perform(self, name, *args, **kwargs): + return self.protocol.perform(self.id, name, *args, **kwargs) + +##class RemoteFunction(object): +## def __init__(self, channel, name): +## channel.send(protocol.get(name)) +## self.channel = channel +## self.id = protocol.id(channel.receive()) +## self.fun = proxy(types.FunctionType, self.perform) +## +## def perform(self, name, *args, **kwargs): +## self.channel.send(protocol.pack_call(self.id, name, args, kwargs)) +## return protocol.unpack(self.channel.receive()) Added: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/test2/test_distributed.py Tue Nov 14 16:32:22 2006 @@ -0,0 +1,43 @@ + +""" Controllers tests +""" + +from pypy.conftest import gettestobjspace + +class AppTestNoProxy(object): + disabled = True + def test_init(self): + raises(ImportError, "import distributed") + +class AppTestDistributed(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withtproxy": True}) + + def test_init(self): + import distributed + distributed.proxy + + def test_protocol(self): + from distributed import AbstractProtocol + protocol = AbstractProtocol() + for item in ("aaa", 3, u"aa", 344444444444444444L, 1.2, (1, "aa")): + assert protocol.unwrap(protocol.wrap(item)) == item + assert type(protocol.unwrap(protocol.wrap([1,2,3]))) is list + assert type(protocol.unwrap(protocol.wrap({"a":3}))) is dict + + def f(): + pass + + assert type(protocol.unwrap(protocol.wrap(f))) is type(f) + + def test_protocol_run(self): + l = [1,2,3] + from distributed import LocalProtocol + protocol = LocalProtocol() + wrap = protocol.wrap + unwrap = protocol.unwrap + item = unwrap(wrap(l)) + assert len(item) == 3 + assert item[2] == 3 + item += [1,1,1] + assert len(item) == 6 From fijal at codespeak.net Tue Nov 14 16:52:11 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 14 Nov 2006 16:52:11 +0100 (CET) Subject: [pypy-svn] r34601 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061114155211.54529101AA@code0.codespeak.net> Author: fijal Date: Tue Nov 14 16:52:08 2006 New Revision: 34601 Modified: pypy/dist/pypy/lib/distributed.py pypy/dist/pypy/lib/test2/test_distributed.py Log: Added full wrap/unwrap logic. Modified: pypy/dist/pypy/lib/distributed.py ============================================================================== --- pypy/dist/pypy/lib/distributed.py (original) +++ pypy/dist/pypy/lib/distributed.py Tue Nov 14 16:52:08 2006 @@ -43,6 +43,7 @@ # XXX We do not make any garbage collection. We'll need it at some point import types +from marshal import dumps class AbstractProtocol(object): letter_types = { @@ -101,12 +102,28 @@ def perform(self, *args, **kwargs): raise NotImplementedError("Abstract only protocol") + + # some simple wrappers + def pack_args(self, args, kwargs): + args = [self.wrap(i) for i in args] + kwargs = dict([(self.wrap(key), self.wrap(val)) for key, val in kwargs.items()]) + return args, kwargs + + def unpack_args(self, args, kwargs): + args = [self.unwrap(i) for i in args] + kwargs = dict([(self.unwrap(key), self.unwrap(val)) for key, val in kwargs.items()]) + return args, kwargs class LocalProtocol(AbstractProtocol): """ This is stupid protocol for testing purposes only """ def perform(self, id, name, *args, **kwargs): obj = self.objs[id] + # we pack and than unpack, for tests + args, kwargs = self.pack_args(args, kwargs) + assert isinstance(name, str) + dumps((args, kwargs)) + args, kwargs = self.unpack_args(args, kwargs) return getattr(obj, name)(*args, **kwargs) class RemoteObject(object): Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Tue Nov 14 16:52:08 2006 @@ -41,3 +41,14 @@ assert item[2] == 3 item += [1,1,1] assert len(item) == 6 + + def test_protocol_call(self): + def f(x, y): + return x + y + + from distributed import LocalProtocol + protocol = LocalProtocol() + wrap = protocol.wrap + unwrap = protocol.unwrap + item = unwrap(wrap(f)) + assert item(3, 2) == 5 From antocuni at codespeak.net Tue Nov 14 17:09:52 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 14 Nov 2006 17:09:52 +0100 (CET) Subject: [pypy-svn] r34602 - in pypy/dist/pypy/translator: cli cli/test oosupport Message-ID: <20061114160952.0EAD5101C2@code0.codespeak.net> Author: antocuni Date: Tue Nov 14 17:09:50 2006 New Revision: 34602 Modified: pypy/dist/pypy/translator/cli/cts.py pypy/dist/pypy/translator/cli/dotnet.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/support.py pypy/dist/pypy/translator/cli/test/test_dotnet.py pypy/dist/pypy/translator/oosupport/function.py Log: Added support for handling native exceptions when using .NET-types. It's a bit involved because .NET exceptions don't share a common root with RPython exceptions, so we need to cheat a bit by creating a fake class that will be recognized by the backend and rendered as appropriate. This means, for example, that instead of writing something like this: try: f() except CLR.System.Exception: ... we need to create the fake object first. SystemException = NativeException(CLR.System.Exception) try: f() except SystemException: ... Please note that the call to NativeException is *not* RPython, so you need to call it at initialization-time. Thanks to pedronis for the original idea. Modified: pypy/dist/pypy/translator/cli/cts.py ============================================================================== --- pypy/dist/pypy/translator/cli/cts.py (original) +++ pypy/dist/pypy/translator/cli/cts.py Tue Nov 14 17:09:50 2006 @@ -147,8 +147,12 @@ elif isinstance(t, lltype.Ptr) and isinstance(t.TO, lltype.OpaqueType): return self.__class('[mscorlib]System.Object', include_class) elif isinstance(t, ootype.Instance): - name = self.db.pending_class(t) - return self.__class(name, include_class) + native_class = t._hints.get('native_class', None) + if native_class: + return self.__class(native_class, include_class) + else: + name = self.db.pending_class(t) + return self.__class(name, include_class) elif isinstance(t, ootype.Record): name = self.db.pending_record(t) return self.__class(name, include_class) Modified: pypy/dist/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/dotnet.py (original) +++ pypy/dist/pypy/translator/cli/dotnet.py Tue Nov 14 17:09:50 2006 @@ -1,3 +1,5 @@ +import types + from pypy.annotation.pairtype import pair, pairtype from pypy.annotation.model import SomeObject, SomeOOInstance, SomeInteger, s_None,\ s_ImpossibleValue, lltype_to_annotation, annotation_to_lltype, SomeChar, SomeString @@ -66,6 +68,7 @@ INSTANCE = hop.args_r[0].cli_class._INSTANCE cINST = hop.inputconst(ootype.Void, INSTANCE) vlist = hop.inputargs(*hop.args_r)[1:] # discard the first argument + hop.exception_is_here() return hop.genop("new", [cINST]+vlist, resulttype=hop.r_result.lowleveltype) class CliStaticMethodRepr(Repr): @@ -265,6 +268,7 @@ # TODO: check that x is really of type TYPE return x + class Entry(ExtRegistryEntry): _about_ = box @@ -298,3 +302,27 @@ return hop.genop('oodowncast', [v_obj], hop.r_result.lowleveltype) else: return hop.genop('cliunbox', [v_obj, v_type], hop.r_result.lowleveltype) + + + +native_exc = {} +def NativeException(cliClass): + try: + return native_exc[cliClass._name] + except KeyError: + res = _create_NativeException(cliClass) + native_exc[cliClass._name] = res + return res + +def _create_NativeException(cliClass): + from pypy.translator.cli.query import getattr_ex + TYPE = cliClass._INSTANCE + if PythonNet.__name__ == 'CLR': + # we are using pythonnet -- use the .NET class + name = '%s.%s' % (TYPE._namespace, TYPE._classname) + res = getattr_ex(PythonNet, name) + else: + # we are not using pythonnet -- create a fake class + res = types.ClassType(TYPE._classname, (Exception,), {}) + res._rpython_hints = {'native_class': cliClass._name} + return res Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Tue Nov 14 17:09:50 2006 @@ -25,6 +25,13 @@ def _create_generator(self, ilasm): return self # Function implements the Generator interface + def record_ll_meta_exc(self, ll_meta_exc): + # record the type only if it doesn't belong to a native_class + ll_exc = ll_meta_exc._inst.class_._INSTANCE + native_class = ll_exc._hints.get('native_class', None) + if native_class is None: + OOFunction.record_ll_meta_exc(self, ll_meta_exc) + def begin_try(self): self.ilasm.begin_try() Modified: pypy/dist/pypy/translator/cli/support.py ============================================================================== --- pypy/dist/pypy/translator/cli/support.py (original) +++ pypy/dist/pypy/translator/cli/support.py Tue Nov 14 17:09:50 2006 @@ -9,6 +9,7 @@ import CLR as PythonNet except ImportError: class _PythonNet: + __name__ = None def __getattr__(self, attr): py.test.skip('Must use pythonnet for being able to access .NET libraries') PythonNet = _PythonNet() Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Tue Nov 14 17:09:50 2006 @@ -6,7 +6,7 @@ ROOT, overload, Instance, new from pypy.translator.cli.test.runtest import CliTest from pypy.translator.cli.dotnet import SomeCliClass, SomeCliStaticMethod,\ - NativeInstance, CLR, box, unbox, OverloadingResolver + NativeInstance, CLR, box, unbox, OverloadingResolver, NativeException System = CLR.System Math = CLR.System.Math @@ -199,6 +199,29 @@ return x.get_Item(0) assert self.interpret(fn, []) is None + def test_native_exception_precise(self): + ArgumentOutOfRangeException = NativeException(CLR.System.ArgumentOutOfRangeException) + def fn(): + x = ArrayList() + try: + x.get_Item(0) + return False + except ArgumentOutOfRangeException: + return True + assert self.interpret(fn, []) == True + + def test_native_exception_superclass(self): + SystemException = NativeException(CLR.System.Exception) + def fn(): + x = ArrayList() + try: + x.get_Item(0) + return False + except SystemException: + return True + assert self.interpret(fn, []) == True + + class TestPythonnet(TestDotnetRtyping): # don't interpreter functions but execute them directly through pythonnet def interpret(self, f, args): Modified: pypy/dist/pypy/translator/oosupport/function.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/function.py (original) +++ pypy/dist/pypy/translator/oosupport/function.py Tue Nov 14 17:09:50 2006 @@ -132,12 +132,15 @@ continue # see above assert issubclass(link.exitcase, Exception) ll_meta_exc = link.llexitcase - self.db.constant_generator.record_const(ll_meta_exc) + self.record_ll_meta_exc(ll_meta_exc) self.begin_catch(link.llexitcase) self.store_exception_and_link(link) target_label = self._get_block_name(link.target) self.end_catch(target_label) + def record_ll_meta_exc(self, ll_meta_exc): + self.db.constant_generator.record_const(ll_meta_exc) + def store_exception_and_link(self, link): raise NotImplementedError From cfbolz at codespeak.net Tue Nov 14 17:24:52 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 14 Nov 2006 17:24:52 +0100 (CET) Subject: [pypy-svn] r34603 - pypy/dist/pypy/translator/stackless Message-ID: <20061114162452.2D02C101D5@code0.codespeak.net> Author: cfbolz Date: Tue Nov 14 17:24:46 2006 New Revision: 34603 Modified: pypy/dist/pypy/translator/stackless/transform.py Log: fix for python2.3 Modified: pypy/dist/pypy/translator/stackless/transform.py ============================================================================== --- pypy/dist/pypy/translator/stackless/transform.py (original) +++ pypy/dist/pypy/translator/stackless/transform.py Tue Nov 14 17:24:46 2006 @@ -744,7 +744,7 @@ if i == len(block.operations) - 1 \ and block.exitswitch == model.c_last_exception: link = block.exits[0] - exitcases = dict.fromkeys(l.exitcase for l in block.exits) + exitcases = dict.fromkeys([l.exitcase for l in block.exits]) nextblock = None else: link = support.split_block_with_keepalive(block, i+1) From mwh at codespeak.net Tue Nov 14 17:43:59 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 14 Nov 2006 17:43:59 +0100 (CET) Subject: [pypy-svn] r34604 - pypy/dist/pypy/rpython/lltypesystem Message-ID: <20061114164359.AE6C61008E@code0.codespeak.net> Author: mwh Date: Tue Nov 14 17:43:56 2006 New Revision: 34604 Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py pypy/dist/pypy/rpython/lltypesystem/rstr.py Log: don't crash when asked to print a NULL instance, say "NULL" instead. Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rclass.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rclass.py Tue Nov 14 17:43:56 2006 @@ -569,8 +569,10 @@ return hop.genop('ptr_nonzero', [vinst], resulttype=Bool) def ll_str(self, i): # doesn't work for non-gc classes! - instance = cast_pointer(OBJECTPTR, i) from pypy.rpython.lltypesystem import rstr + if not i: + return rstr.null_str + instance = cast_pointer(OBJECTPTR, i) nameLen = len(instance.typeptr.name) nameString = rstr.mallocstr(nameLen-1) i = 0 Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rstr.py Tue Nov 14 17:43:56 2006 @@ -767,6 +767,8 @@ instance_str_prefix = string_repr.convert_const("<") instance_str_suffix = string_repr.convert_const(" object>") +null_str = string_repr.convert_const("NULL") + unboxed_instance_str_prefix = string_repr.convert_const("") From antocuni at codespeak.net Tue Nov 14 17:46:48 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Tue, 14 Nov 2006 17:46:48 +0100 (CET) Subject: [pypy-svn] r34605 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20061114164648.D238E1012F@code0.codespeak.net> Author: antocuni Date: Tue Nov 14 17:46:47 2006 New Revision: 34605 Modified: pypy/dist/pypy/translator/cli/cts.py pypy/dist/pypy/translator/cli/dotnet.py pypy/dist/pypy/translator/cli/function.py pypy/dist/pypy/translator/cli/test/test_dotnet.py Log: Added the possibility to inspect the native exception objects. Modified: pypy/dist/pypy/translator/cli/cts.py ============================================================================== --- pypy/dist/pypy/translator/cli/cts.py (original) +++ pypy/dist/pypy/translator/cli/cts.py Tue Nov 14 17:46:47 2006 @@ -147,9 +147,9 @@ elif isinstance(t, lltype.Ptr) and isinstance(t.TO, lltype.OpaqueType): return self.__class('[mscorlib]System.Object', include_class) elif isinstance(t, ootype.Instance): - native_class = t._hints.get('native_class', None) - if native_class: - return self.__class(native_class, include_class) + NATIVE_INSTANCE = t._hints.get('NATIVE_INSTANCE', None) + if NATIVE_INSTANCE: + return self.__class(NATIVE_INSTANCE._name, include_class) else: name = self.db.pending_class(t) return self.__class(name, include_class) Modified: pypy/dist/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/dotnet.py (original) +++ pypy/dist/pypy/translator/cli/dotnet.py Tue Nov 14 17:46:47 2006 @@ -1,7 +1,7 @@ import types from pypy.annotation.pairtype import pair, pairtype -from pypy.annotation.model import SomeObject, SomeOOInstance, SomeInteger, s_None,\ +from pypy.annotation.model import SomeObject, SomeInstance, SomeOOInstance, SomeInteger, s_None,\ s_ImpossibleValue, lltype_to_annotation, annotation_to_lltype, SomeChar, SomeString from pypy.rpython.error import TyperError from pypy.rpython.extregistry import ExtRegistryEntry @@ -305,13 +305,13 @@ -native_exc = {} +native_exc_cache = {} def NativeException(cliClass): try: - return native_exc[cliClass._name] + return native_exc_cache[cliClass._name] except KeyError: res = _create_NativeException(cliClass) - native_exc[cliClass._name] = res + native_exc_cache[cliClass._name] = res return res def _create_NativeException(cliClass): @@ -324,5 +324,22 @@ else: # we are not using pythonnet -- create a fake class res = types.ClassType(TYPE._classname, (Exception,), {}) - res._rpython_hints = {'native_class': cliClass._name} + res._rpython_hints = {'NATIVE_INSTANCE': TYPE} return res + +def native_exc(exc): + return exc + +class Entry(ExtRegistryEntry): + _about_ = native_exc + + def compute_result_annotation(self, exc_s): + assert isinstance(exc_s, SomeInstance) + cls = exc_s.classdef.classdesc.pyobj + assert issubclass(cls, Exception) + NATIVE_INSTANCE = cls._rpython_hints['NATIVE_INSTANCE'] + return SomeOOInstance(NATIVE_INSTANCE) + + def specialize_call(self, hop): + v_obj, = hop.inputargs(*hop.args_r) + return hop.genop('same_as', [v_obj], hop.r_result.lowleveltype) Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Tue Nov 14 17:46:47 2006 @@ -28,8 +28,8 @@ def record_ll_meta_exc(self, ll_meta_exc): # record the type only if it doesn't belong to a native_class ll_exc = ll_meta_exc._inst.class_._INSTANCE - native_class = ll_exc._hints.get('native_class', None) - if native_class is None: + NATIVE_INSTANCE = ll_exc._hints.get('NATIVE_INSTANCE', None) + if NATIVE_INSTANCE is None: OOFunction.record_ll_meta_exc(self, ll_meta_exc) def begin_try(self): Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Tue Nov 14 17:46:47 2006 @@ -6,7 +6,8 @@ ROOT, overload, Instance, new from pypy.translator.cli.test.runtest import CliTest from pypy.translator.cli.dotnet import SomeCliClass, SomeCliStaticMethod,\ - NativeInstance, CLR, box, unbox, OverloadingResolver, NativeException + NativeInstance, CLR, box, unbox, OverloadingResolver, NativeException,\ + native_exc System = CLR.System Math = CLR.System.Math @@ -221,6 +222,18 @@ return True assert self.interpret(fn, []) == True + def test_native_exception_object(self): + SystemException = NativeException(CLR.System.Exception) + def fn(): + x = ArrayList() + try: + x.get_Item(0) + return "Impossible!" + except SystemException, e: + ex = native_exc(e) + return ex.get_Message() + res = self.ll_to_string(self.interpret(fn, [])) + assert res.startswith("Index is less than 0") class TestPythonnet(TestDotnetRtyping): # don't interpreter functions but execute them directly through pythonnet From mwh at codespeak.net Tue Nov 14 20:22:41 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 14 Nov 2006 20:22:41 +0100 (CET) Subject: [pypy-svn] r34611 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061114192241.12F3F101AE@code0.codespeak.net> Author: mwh Date: Tue Nov 14 20:22:38 2006 New Revision: 34611 Modified: pypy/dist/pypy/jit/codegen/ppc/emit_moves.py pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: a couple more operations to get some test_genc_ts tests running, and a fix to handle Constant arguments to finish_and_goto. Modified: pypy/dist/pypy/jit/codegen/ppc/emit_moves.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/emit_moves.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/emit_moves.py Tue Nov 14 20:22:38 2006 @@ -61,10 +61,15 @@ if tarvar in data.emitted: return + #print "tarvar in data.tar2loc", tarvar in data.tar2loc tarloc = data.tar2loc[tarvar] + #print "tarvar in data.tar2src", tarvar in data.tar2src srcvar = data.tar2src[tarvar] + #print "srcvar in data.src2loc", srcvar, srcvar in data.src2loc srcloc = data.src2loc[srcvar] + + # if location we are about to write to is not going to be read # by anyone, we are safe if tarloc not in data.loc2src: @@ -73,12 +78,15 @@ return # Find source node that conflicts with us + #print "tarloc in data.loc2src", tarloc in data.loc2src conflictsrcvar = data.loc2src[tarloc] if conflictsrcvar not in data.srcstack: # No cycle on our stack yet data.srcstack.append(srcvar) + #print "conflictsrcvar in data.src2tar", conflictsrcvar in data.src2tar _cycle_walk(gen, data.src2tar[conflictsrcvar], data) + #print "srcvar in data.src2loc", srcvar in data.src2loc srcloc = data.src2loc[srcvar] # warning: may have changed, so reload gen.emit_move(tarloc, srcloc) data.emitted.append(tarvar) @@ -87,6 +95,7 @@ # Cycle detected, break it by moving the other node's source data # somewhere else so we can overwrite it freshloc = gen.create_fresh_location() + #print "conflictsrcvar in data.src2loc", conflictsrcvar in data.src2loc conflictsrcloc = data.src2loc[conflictsrcvar] gen.emit_move(freshloc, conflictsrcloc) data.src2loc[conflictsrcvar] = freshloc Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Tue Nov 14 20:22:38 2006 @@ -123,6 +123,23 @@ self.arg_reg.number, self.imm.value) +class Insn_GPR__GPR(Insn): + def __init__(self, methptr, result, arg): + Insn.__init__(self) + self.methptr = methptr + + self.result = result + self.result_regclass = GP_REGISTER + self.reg_args = [arg] + self.reg_arg_regclasses = [GP_REGISTER] + def allocate(self, allocator): + self.result_reg = allocator.loc_of(self.result) + self.arg_reg = allocator.loc_of(self.reg_args[0]) + def emit(self, asm): + self.methptr(asm, + self.result_reg.number, + self.arg_reg.number) + class Insn_GPR__IMM(Insn): def __init__(self, methptr, result, args): Insn.__init__(self) Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Tue Nov 14 20:22:38 2006 @@ -128,8 +128,12 @@ targetlocs = target.arg_locations for i in range(len(targetlocs)): tloc = targetlocs[i] - tar2loc[tloc] = tloc - tar2src[tloc] = sourcevars[i] + src = sourcevars[i] + if isinstance(src, Var): + tar2loc[tloc] = tloc + tar2src[tloc] = src + else: + src.load_now(asm, tloc) gen = JumpPatchupGenerator(asm, min_offset) emit_moves(gen, tar2src, tar2loc, src2loc) @@ -215,7 +219,14 @@ ## def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): ## def genop_malloc_fixedsize(self, alloctoken): ## def genop_malloc_varsize(self, varsizealloctoken, gv_size): -## def genop_same_as(self, kindtoken, gv_x): + + def genop_same_as(self, kindtoken, gv_arg): + if not isinstance(gv_arg, Var): + gv_result = Var() + gv_arg.load(self.insns, gv_result) + else: + return gv_arg + ## def genop_debug_pdb(self): # may take an args_gv later def enter_next_block(self, kinds, args_gv): @@ -537,7 +548,13 @@ self.insns.append( insn.CMPWI(self.cmp2info['ne'], gv_result, [gv_arg, self.rgenop.genconst(0)])) return gv_result - + + def op_int_neg(self, gv_arg): + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR(RPPCAssembler.neg, gv_result, gv_arg)) + return gv_result + class RPPCGenOp(AbstractRGenOp): From antocuni at codespeak.net Wed Nov 15 11:12:10 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 15 Nov 2006 11:12:10 +0100 (CET) Subject: [pypy-svn] r34618 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20061115101210.CFD831007F@code0.codespeak.net> Author: antocuni Date: Wed Nov 15 11:12:09 2006 New Revision: 34618 Modified: pypy/dist/pypy/translator/cli/dotnet.py pypy/dist/pypy/translator/cli/metavm.py pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/cli/query.py pypy/dist/pypy/translator/cli/test/test_dotnet.py Log: Added support for creating arrays to .NET-types Modified: pypy/dist/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/dotnet.py (original) +++ pypy/dist/pypy/translator/cli/dotnet.py Wed Nov 15 11:12:09 2006 @@ -343,3 +343,34 @@ def specialize_call(self, hop): v_obj, = hop.inputargs(*hop.args_r) return hop.genop('same_as', [v_obj], hop.r_result.lowleveltype) + + +def init_array(type, *args): + # PythonNet doesn't provide a straightforward way to create arrays... fake it with a list + return args + +class Entry(ExtRegistryEntry): + _about_ = init_array + + def compute_result_annotation(self, type_s, *args_s): + from pypy.translator.cli.query import load_class_maybe + assert type_s.is_constant() + TYPE = type_s.const._INSTANCE + for i, arg_s in enumerate(args_s): + if TYPE is not arg_s.ootype: + raise TypeError, 'Wrong type of arg #%d: %s expected, %s found' % \ + (i, TYPE, arg_s.ootype) + fullname = '%s.%s[]' % (TYPE._namespace, TYPE._classname) + cliArray = load_class_maybe(fullname) + return SomeOOInstance(cliArray._INSTANCE) + + def specialize_call(self, hop): + vlist = hop.inputargs(*hop.args_r) + c_type, v_elems = vlist[0], vlist[1:] + c_length = hop.inputconst(ootype.Signed, len(v_elems)) + hop.exception_cannot_occur() + v_array = hop.genop('cli_newarray', [c_type, c_length], hop.r_result.lowleveltype) + for i, v_elem in enumerate(v_elems): + c_index = hop.inputconst(ootype.Signed, i) + hop.genop('cli_setelem', [v_array, c_index, v_elem], ootype.Void) + return v_array Modified: pypy/dist/pypy/translator/cli/metavm.py ============================================================================== --- pypy/dist/pypy/translator/cli/metavm.py (original) +++ pypy/dist/pypy/translator/cli/metavm.py Wed Nov 15 11:12:09 2006 @@ -185,6 +185,15 @@ generator.load(v_obj) generator.ilasm.opcode('unbox.any', boxtype) +class _NewArray(MicroInstruction): + def render(self, generator, op): + v_type, v_length = op.args + assert v_type.concretetype is ootype.Void + TYPE = v_type.value._INSTANCE + typetok = generator.cts.lltype_to_cts(TYPE) + generator.load(v_length) + generator.ilasm.opcode('newarr', typetok) + class _GetArrayElem(MicroInstruction): def render(self, generator, op): generator.load(op.args[0]) @@ -192,6 +201,16 @@ rettype = generator.cts.lltype_to_cts(op.result.concretetype) generator.ilasm.opcode('ldelem', rettype) +class _SetArrayElem(MicroInstruction): + def render(self, generator, op): + v_array, v_index, v_elem = op.args + generator.load(v_array) + generator.load(v_index) + generator.load(v_elem) + elemtype = generator.cts.lltype_to_cts(v_array.concretetype) + generator.ilasm.opcode('stelem', elemtype) + + Call = _Call() CallMethod = _CallMethod() IndirectCall = _IndirectCall() @@ -202,4 +221,6 @@ CastWeakAdrToPtr = _CastWeakAdrToPtr() Box = _Box() Unbox = _Unbox() +NewArray = _NewArray() GetArrayElem = _GetArrayElem() +SetArrayElem = _SetArrayElem() Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Wed Nov 15 11:12:09 2006 @@ -1,6 +1,6 @@ from pypy.translator.cli.metavm import Call, CallMethod, \ IndirectCall, GetField, SetField, CastTo, OOString, DownCast, NewCustomDict,\ - CastWeakAdrToPtr, MapException, Box, Unbox, GetArrayElem + CastWeakAdrToPtr, MapException, Box, Unbox, NewArray, GetArrayElem, SetArrayElem from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\ New, RuntimeNew from pypy.translator.cli.cts import WEAKREF @@ -36,7 +36,9 @@ 'oodowncast': [DownCast], 'clibox': [Box], 'cliunbox': [Unbox], + 'cli_newarray': [NewArray], 'cli_getelem': [GetArrayElem], + 'cli_setelem': [SetArrayElem], 'oois': 'ceq', 'oononnull': [PushAllArgs, 'ldnull', 'ceq']+Not, 'instanceof': [CastTo, 'ldnull', 'cgt.un'], Modified: pypy/dist/pypy/translator/cli/query.py ============================================================================== --- pypy/dist/pypy/translator/cli/query.py (original) +++ pypy/dist/pypy/translator/cli/query.py Wed Nov 15 11:12:09 2006 @@ -63,7 +63,9 @@ except KeyError: desc = query_description(name) Descriptions[name] = desc - setattr_ex(CLR, name, desc.build()) + res = desc.build() + setattr_ex(CLR, name, res) + return res def query_description(name): log.query('Loading description for %s' % name) @@ -84,9 +86,13 @@ def load_class_maybe(name): if name.startswith('System.Array+InternalArray'): - ClassCache[name] = ClassCache['System.Array'] + res = ClassCache['System.Array'] + ClassCache[name] = res + return res elif name not in ClassCache: - load_class_or_namespace(name) + return load_class_or_namespace(name) + else: + return ClassCache[name] class Desc: Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Wed Nov 15 11:12:09 2006 @@ -7,7 +7,7 @@ from pypy.translator.cli.test.runtest import CliTest from pypy.translator.cli.dotnet import SomeCliClass, SomeCliStaticMethod,\ NativeInstance, CLR, box, unbox, OverloadingResolver, NativeException,\ - native_exc + native_exc, init_array System = CLR.System Math = CLR.System.Math @@ -188,6 +188,12 @@ return unbox(array[0], ootype.Signed) assert self.interpret(fn, []) == 42 + def test_init_array(self): + def fn(): + array = init_array(System.Object, box(42), box(43)) + return unbox(array[0], ootype.Signed) + unbox(array[1], ootype.Signed) + assert self.interpret(fn, []) == 42+43 + def test_null(self): def fn(): return System.Object.Equals(None, None) @@ -235,6 +241,7 @@ res = self.ll_to_string(self.interpret(fn, [])) assert res.startswith("Index is less than 0") + class TestPythonnet(TestDotnetRtyping): # don't interpreter functions but execute them directly through pythonnet def interpret(self, f, args): From ale at codespeak.net Wed Nov 15 13:29:36 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Wed, 15 Nov 2006 13:29:36 +0100 (CET) Subject: [pypy-svn] r34625 - in pypy/dist/pypy/lib/pyontology: . test Message-ID: <20061115122936.27C4A10092@code0.codespeak.net> Author: ale Date: Wed Nov 15 13:29:34 2006 New Revision: 34625 Added: pypy/dist/pypy/lib/pyontology/test/testinconst.rdf pypy/dist/pypy/lib/pyontology/test/testont2.rdf Modified: pypy/dist/pypy/lib/pyontology/pyontology.py pypy/dist/pypy/lib/pyontology/test/test_ontology.py pypy/dist/pypy/lib/pyontology/test/test_sparql.py Log: Added more tests and fixes to SPARQL Modified: pypy/dist/pypy/lib/pyontology/pyontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/pyontology.py (original) +++ pypy/dist/pypy/lib/pyontology/pyontology.py Wed Nov 15 13:29:34 2006 @@ -467,6 +467,8 @@ self.store_path = py.path.local().join("db").strpath self.variables = {} self.constraints = [] + self.variables['owl_Thing'] = Thing('owl_Thing') + self.variables['owl_Literal'] = Literal('owl_Literal') self.seen = {} self.var2ns ={} self.nr_of_triples = 0 @@ -514,6 +516,9 @@ constraint.narrow(self.variables) # except ConsistencyFailure, e: # print "FAilure", e + things = self.variables['owl_Thing'].getValues() + things += self.variables['owl_Literal'].getValues() + self.variables['owl_Thing'].setValues(things) def _sparql(self, query): qe = SP.Query.parseString(query) @@ -585,9 +590,13 @@ raise ConsistencyFailure elif case == 1: # Add a HasValue constraint - var = self.make_var(Restriction, URIRef(trip[0])) - self.onProperty(var, URIRef(trip[1])) - self.hasValue(var, trip[2]) + ns,pred = trip[1].split("#") + if ns in namespaces.values(): + self.consider_triple(trip) + else: + var = self.make_var(Restriction, URIRef(trip[0])) + self.onProperty(var, URIRef(trip[1])) + self.hasValue(var, trip[2]) elif case == 2: # for all p's return p if p[0]==s and p[1]==o @@ -640,28 +649,33 @@ elif case == 5: # return the values of p prop = self.make_var(Property, URIRef(trip[1])) + query_dom[prop] = self.variables[prop] p_vals = self.variables[prop].getValues() - var = self.make_var(Thing, trip[0]) - self.variables[var].setValues([v[0] for v in p_vals]) - p_vals = self.variables[prop].getValues() - var = self.make_var(Thing, trip[2]) - self.variables[var].setValues([v[1] for v in p_vals]) + sub = self.make_var(Thing, trip[0]) + self.variables[sub].setValues([v[0] for v in p_vals]) + obj = self.make_var(Thing, trip[2]) + self.variables[obj].setValues([v[1] for v in p_vals]) + con = Expression([sub,prop,obj], "%s == (%s, %s)" %(prop, sub, obj)) + query_constr.append(con) + elif case == 6: - # for all p's return p[1] if p[0]==s +# 6 bound var var ; for all p's return p[1] if p[0]==s + # for all p's return p[1] if p[0]==s + prop = self.make_var(Property, URIRef(trip[1])) + pass elif case == 7: # for all p's return p.getvalues p_vals = [] for p in self.variables['rdf_Property'].getValues(): p_vals += self.variables[p].getValues() - - things = self.variables['owl_Thing'].getValues() - things += self.variables['owl_Literal'].getValues() + prop = self.make_var(Property, URIRef(trip[1])) self.variables[prop].setValues(p_vals) sub = self.make_var(Thing, trip[0]) - self.variables[sub].setValues(things) obj = self.make_var(Thing, trip[2]) + things = self.variables['owl_Thing'].getValues() + things += self.variables['owl_Literal'].getValues() self.variables[obj].setValues(things) con = Expression([sub,prop,obj], "%s[0] == %s and %s[1] == %s" %(prop, sub, prop, obj)) query_constr.append(con) @@ -672,10 +686,12 @@ # Build a repository with the variables in the query dom = dict([(self.mangle_name(v),self.variables[self.mangle_name(v)]) for v in vars]) + dom.update(query_dom) + print dom # solve the repository and return the solution rep = Repository(dom.keys(), dom, query_constr) - res_s = Solver().solve(rep) + res_s = Solver().solve(rep, 3) #res_s = self.solve() res = [] for d in res_s: Modified: pypy/dist/pypy/lib/pyontology/test/test_ontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/test/test_ontology.py (original) +++ pypy/dist/pypy/lib/pyontology/test/test_ontology.py Wed Nov 15 13:29:34 2006 @@ -28,6 +28,12 @@ ont.rest(own, URIRef(namespaces['rdf']+'#nil')) return owllist +def test_equivalentProperty_inconst(): + O = Ontology() + O.add_file("testinconst.rdf") + O.attach_fd() + raises(ConsistencyFailure, O.consistency) + def test_XMLSchema_string(): O = Ontology() a = URIRef(u'A') Modified: pypy/dist/pypy/lib/pyontology/test/test_sparql.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/test/test_sparql.py (original) +++ pypy/dist/pypy/lib/pyontology/test/test_sparql.py Wed Nov 15 13:29:34 2006 @@ -161,7 +161,6 @@ def test_case_7(): """ for all p's return p[1] if p[0]==s """ - #py.test.skip("Doesn't work yet") query = qt_proto % ('?x ?y ?z', '?x ?y ?z .') O = Ontology() @@ -172,6 +171,49 @@ assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' assert res[0]['query_x_'] == u'http://example.org/ns#sub' +query1 = """ + PREFIX ltw : + PREFIX owl : + SELECT ?person ?activity + WHERE { + ?activity owl:subClassOf ltw:Active_Project . + ?person_obj owl:subClassOf ltw:Active_Person . + ?activity ltw:hasParticipant ?person_obj . + ?person_obj ltw:personName ?person . + } + ORDER BY ?person""" +#how many projects have been funded by BMBF in 2006 +query2 = """ + PREFIX ltw : + PREFIX owl : + SELECT ?project + WHERE { + ?project ltw:funded_by ltw:BMBF . + ?project ltw:date_begin ?date_begin . + ?project ltw:date_end ?date_end . + FILTER ( ?date_begin < 2007 ) . + FILTER ( ?date_end >= 2006) . + }""" +#which project is funded in a technological area (i.e. Semantic web), +query3 = """ + PREFIX ltw : + PREFIX owl : + SELECT ?project + WHERE { + ?project owl:subClassOf ltw:Active_Project . + ?project owl:subClassOf ltw:Semantic_Web . + ?project ltw:supportedby ?x . + }""" + +def test_query1(): + O = Ontology() + O.add_file("testont2.rdf") + O.attach_fd() + + res = O.sparql(query1) + assert len(res) == 1 + assert res[0]['query_activity_'] == u'http://www.lt-world.org/ltw.owl#obj_59754' + assert res[0]['query_person_'] == u'\nKlara Vicsi' import xmlrpclib, socket, os, signal @@ -198,7 +240,6 @@ os.kill(self.shell.pid, signal.SIGTERM) def test_xmlrpc(self): - #py.test.skip("WIP") print "test_xmlrpc" server = xmlrpclib.ServerProxy("http://localhost:9000", allow_none=True) result = server.sparql(qt_proto % ('?x', 'ns:sub ns:p ?x .')) Added: pypy/dist/pypy/lib/pyontology/test/testinconst.rdf ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/pyontology/test/testinconst.rdf Wed Nov 15 13:29:34 2006 @@ -0,0 +1,21 @@ + + + + + + + + + "Text 1" + "Text 22 + + Added: pypy/dist/pypy/lib/pyontology/test/testont2.rdf ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/pyontology/test/testont2.rdf Wed Nov 15 13:29:34 2006 @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + +http://sites.univ-lyon2.fr/langues_promodiinar/Accueil.htm + +The aim of DIINAR-MBS is to create a multilingual lexical database based on a large corpus of linguistic data + +joseph.dichy at univ-lyon2.fr + +joseph.dichy at univ-lyon2.fr + +joseph.dichy at univ-lyon2.fr + +NLP!Natural Language Processing!MT + +2000-08-01 + +1998-02-01 + +http://www.hltcentral.org/projects + +http://www.hltcentral.org/projects + +Electronic Arab Dictionary - Multilingual Corpus + +Electronic Arab Dictionary - Multilingual Corpus + +DIINAR-MBS + +DIINAR-MBS + +DIINAR-MBS + + + + + + + + + + + + + + + + + + + + + + + +1998-09-01 + +A Multimedia Multilingual Teaching and Training System for Speech Handicapped Children + +A Multimedia Multilingual Teaching and Training System for Speech Handicapped Children + +Development of a new audio-visual pronunciation teaching and training method and a software system for hearing and speech-handicapped persons to help them to control their speech production + +http://luna.ttt.bme.hu/speech/speco1.htm + +vicsi at ttt-202.ttt.bme.hu + +http://www.hltcentral.org/projects + +2001-08-31 + +http://www.hltcentral.org/projects/detail.php?acronym=SPECO + +SPECO + +SPECO + +SPECO + + + + + + + +Klara Vicsi + +Klara Vicsi + +Klara Vicsi + +vicsi at alpha.ttt.bme.hu + +Klara + +Vicsi + +Dr. + + + + + +Abdelkader Fassi Fehri + +Abdelkader Fassi Fehri + +Abdelkader Fassi Fehri + + From ale at codespeak.net Wed Nov 15 14:29:15 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Wed, 15 Nov 2006 14:29:15 +0100 (CET) Subject: [pypy-svn] r34627 - pypy/branch/mininal-c-backend Message-ID: <20061115132915.05CB61007F@code0.codespeak.net> Author: ale Date: Wed Nov 15 14:29:13 2006 New Revision: 34627 Added: pypy/branch/mininal-c-backend/ - copied from r34626, pypy/dist/ Log: A branch for making genc suiable for compiling to AVR micros From mwh at codespeak.net Wed Nov 15 15:24:50 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 15 Nov 2006 15:24:50 +0100 (CET) Subject: [pypy-svn] r34630 - pypy/dist/pypy/translator/asm/ppcgen Message-ID: <20061115142450.D59F51008F@code0.codespeak.net> Author: mwh Date: Wed Nov 15 15:24:49 2006 New Revision: 34630 Modified: pypy/dist/pypy/translator/asm/ppcgen/ppc_assembler.py Log: fix a grotty assembler bug where I tried to define two forms called "XS0". the funny part is that we were using one of the erroneous instructions but with a 0 rB/Rc so it didn't matter. Modified: pypy/dist/pypy/translator/asm/ppcgen/ppc_assembler.py ============================================================================== --- pypy/dist/pypy/translator/asm/ppcgen/ppc_assembler.py (original) +++ pypy/dist/pypy/translator/asm/ppcgen/ppc_assembler.py Wed Nov 15 15:24:49 2006 @@ -19,7 +19,7 @@ X = Form("XO1") XS = Form("rA", "rS", "rB", "XO1", "Rc") -XS0 = Form("rS", "rA", "rB", "XO1") +XSO = Form("rS", "rA", "rB", "XO1") XD = Form("rD", "rA", "rB", "XO1") XO = Form("rD", "rA", "rB", "OE", "XO2", "Rc") XO0 = Form("rD", "rA", "OE", "XO2", "Rc") @@ -405,22 +405,22 @@ srw = XS(31, XO1=536, Rc=0) srwx = XS(31, XO1=536, Rc=1) - stbux = XS0(31, XO1=247) - stbx = XS0(31, XO1=215) - stfdux = XS0(31, XO1=759) - stfdx = XS0(31, XO1=727) - stfiwx = XS0(31, XO1=983) - stfsux = XS0(31, XO1=695) - stfsx = XS0(31, XO1=663) - sthbrx = XS0(31, XO1=918) - sthux = XS0(31, XO1=439) - sthx = XS0(31, XO1=407) + stbux = XSO(31, XO1=247) + stbx = XSO(31, XO1=215) + stfdux = XSO(31, XO1=759) + stfdx = XSO(31, XO1=727) + stfiwx = XSO(31, XO1=983) + stfsux = XSO(31, XO1=695) + stfsx = XSO(31, XO1=663) + sthbrx = XSO(31, XO1=918) + sthux = XSO(31, XO1=439) + sthx = XSO(31, XO1=407) stswi = Form("rS", "rA", "NB", "XO1")(31, XO1=725) - stswx = XS0(31, XO1=661) - stwbrx = XS0(31, XO1=662) + stswx = XSO(31, XO1=661) + stwbrx = XSO(31, XO1=662) stwcxx = Form("rS", "rA", "rB", "XO1", "Rc")(31, XO1=150, Rc=1) - stwux = XS0(31, XO1=183) - stwx = XS0(31, XO1=151) + stwux = XSO(31, XO1=183) + stwx = XSO(31, XO1=151) subf = XO(31, XO2=40, OE=0, Rc=0) subfx = XO(31, XO2=40, OE=0, Rc=1) From mwh at codespeak.net Wed Nov 15 15:27:29 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 15 Nov 2006 15:27:29 +0100 (CET) Subject: [pypy-svn] r34631 - in pypy/dist/pypy/jit/codegen/ppc: . test Message-ID: <20061115142729.76B691008F@code0.codespeak.net> Author: mwh Date: Wed Nov 15 15:27:24 2006 New Revision: 34631 Added: pypy/dist/pypy/jit/codegen/ppc/test/test_genc_ts.py Modified: pypy/dist/pypy/jit/codegen/ppc/conftest.py pypy/dist/pypy/jit/codegen/ppc/instruction.py pypy/dist/pypy/jit/codegen/ppc/regalloc.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: lots and lots of new operations and fixes but now all the test_genc_ts tests pass with the ppc backend. Modified: pypy/dist/pypy/jit/codegen/ppc/conftest.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/conftest.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/conftest.py Wed Nov 15 15:27:24 2006 @@ -17,7 +17,10 @@ Option = py.test.Config.Option -option = py.test.Config.addoptions("ppc options", - Option('--trap', action="store_true", default=False, - dest="trap", +option = py.test.Config.addoptions("ppc options", + Option('--trap', action="store_true", default=False, + dest="trap", + help=""), + Option('--debug-print', action="store_true", default=False, + dest="debug_print", help="")) Modified: pypy/dist/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/instruction.py Wed Nov 15 15:27:24 2006 @@ -157,6 +157,44 @@ self.result_reg.number, self.imm.value) +class Insn_None__GPR_GPR_IMM(Insn): + def __init__(self, methptr, args): + Insn.__init__(self) + self.methptr = methptr + self.imm = args[2] + + self.result = None + self.result_regclass = NO_REGISTER + self.reg_args = args[:2] + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] + def allocate(self, allocator): + self.reg1 = allocator.loc_of(self.reg_args[0]) + self.reg2 = allocator.loc_of(self.reg_args[1]) + def emit(self, asm): + self.methptr(asm, + self.reg1.number, + self.reg2.number, + self.imm.value) + +class Insn_None__GPR_GPR_GPR(Insn): + def __init__(self, methptr, args): + Insn.__init__(self) + self.methptr = methptr + + self.result = None + self.result_regclass = NO_REGISTER + self.reg_args = args + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER, GP_REGISTER] + def allocate(self, allocator): + self.reg1 = allocator.loc_of(self.reg_args[0]) + self.reg2 = allocator.loc_of(self.reg_args[1]) + self.reg3 = allocator.loc_of(self.reg_args[2]) + def emit(self, asm): + self.methptr(asm, + self.reg1.number, + self.reg2.number, + self.reg3.number) + class CMPInsn(Insn): info = (0,0) # please the annotator for tests that don't use CMPW/CMPWI pass @@ -267,10 +305,16 @@ self.argnumber = argnumber self.arg = arg def allocate(self, allocator): - self.loc = allocator.loc_of(self.arg) + from pypy.jit.codegen.ppc.rgenop import Var + if isinstance(self.arg, Var): + self.loc = allocator.loc_of(self.arg) + else: + self.loc = None def emit(self, asm): targetreg = 3+self.argnumber - if self.loc.is_register: + if self.loc is None: + self.arg.load_now(asm, gprs[targetreg]) + elif self.loc.is_register: asm.mr(targetreg, self.loc.number) else: asm.lwz(targetreg, rFP, self.loc.offset) Modified: pypy/dist/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/regalloc.py Wed Nov 15 15:27:24 2006 @@ -4,10 +4,15 @@ CMPInsn, Spill, Unspill, stack_slot, \ rSCRATCH +from pypy.jit.codegen.ppc.conftest import option + +DEBUG_PRINT = option.debug_print + class RegisterAllocation: def __init__(self, freeregs, initial_mapping, initial_spill_offset): - #print - #print "RegisterAllocation __init__", initial_mapping + if DEBUG_PRINT: + print + print "RegisterAllocation __init__", initial_mapping.items() self.insns = [] # output list of instructions @@ -74,7 +79,8 @@ if freeregs: reg = freeregs.pop() self.set(newarg, reg) - #print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) + if DEBUG_PRINT: + print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) return reg # if not, find something to spill @@ -93,11 +99,13 @@ self.spill(reg, argtospill) - #print "allocate_reg: Spilled %r to %r." % (argtospill, self.loc_of(argtospill)) + if DEBUG_PRINT: + print "allocate_reg: Spilled %r to %r." % (argtospill, self.loc_of(argtospill)) # update data structures to put newarg into the register self.set(newarg, reg) - #print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) + if DEBUG_PRINT: + print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) return reg def _promote(self, arg): @@ -127,32 +135,37 @@ # Walk through instructions in forward order for insn in insns2: - #print "Processing instruction", insn, - #print "with args", insn.reg_args, "and result", insn.result, ":" + if DEBUG_PRINT: + print "Processing instruction", insn, + print "with args", insn.reg_args, "and result", insn.result, ":" - #print "LRU list was:", self.lru + print "LRU list was:", self.lru # put things into the lru for arg in insn.reg_args: self._promote(arg) if insn.result: self._promote(insn.result) - #print "LRU list is now:", self.lru + if DEBUG_PRINT: + print "LRU list is now:", self.lru # We need to allocate a register for each used # argument that is not already in one for i in range(len(insn.reg_args)): arg = insn.reg_args[i] argcls = insn.reg_arg_regclasses[i] - #print "Allocating register for", arg, "..." + if DEBUG_PRINT: + print "Allocating register for", arg, "..." argloc = self.loc_of(arg) - #print "currently in", argloc + if DEBUG_PRINT: + print "currently in", argloc if not argloc.is_register: # It has no register now because it has been spilled self.forget(arg, argloc) newargloc = self._allocate_reg(argcls, arg) - #print "unspilling to", newargloc + if DEBUG_PRINT: + print "unspilling to", newargloc self.insns.append(Unspill(arg, newargloc, argloc)) self.free_stack_slots.append(argloc) elif argloc.regclass != argcls: @@ -174,13 +187,15 @@ self.insns.append( newargloc.move_from_gpr(self, gpr)) else: - #print "it was in ", argloc + if DEBUG_PRINT: + print "it was in ", argloc pass # Need to allocate a register for the destination assert not insn.result or insn.result not in self.var2loc if insn.result_regclass != NO_REGISTER: - #print "Allocating register for result %r..." % (insn.result,) + if DEBUG_PRINT: + print "Allocating register for result %r..." % (insn.result,) resultreg = self._allocate_reg(insn.result_regclass, insn.result) if isinstance(insn, CMPInsn): self.crfinfo[resultreg.number] = insn.info Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Wed Nov 15 15:27:24 2006 @@ -14,12 +14,16 @@ from pypy.translator.asm.ppcgen.rassemblermaker import make_rassembler from pypy.translator.asm.ppcgen.ppc_assembler import MyPPCAssembler +from pypy.jit.codegen.i386.rgenop import gc_malloc_fnaddr + class RPPCAssembler(make_rassembler(MyPPCAssembler)): def emit(self, value): self.mc.write(value) NSAVEDREGISTERS = 19 +DEBUG_TRAP = option.trap + _var_index = [0] class Var(GenVar): def __init__(self): @@ -211,19 +215,85 @@ self.insns.append(insn.CALL(gv_result, gv_fnptr)) return gv_result -## def genop_getfield(self, fieldtoken, gv_ptr): -## def genop_setfield(self, fieldtoken, gv_ptr, gv_value): -## def genop_getsubstruct(self, fieldtoken, gv_ptr): -## def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index): -## def genop_getarraysize(self, arraytoken, gv_ptr): -## def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): -## def genop_malloc_fixedsize(self, alloctoken): -## def genop_malloc_varsize(self, varsizealloctoken, gv_size): + def genop_getfield(self, fieldtoken, gv_ptr): + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.lwz, + gv_result, [gv_ptr, IntConst(fieldtoken)])) + return gv_result + + def genop_setfield(self, fieldtoken, gv_ptr, gv_value): + gv_result = Var() + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(RPPCAssembler.stw, + [gv_value, gv_ptr, IntConst(fieldtoken)])) + return gv_result + + def genop_getsubstruct(self, fieldtoken, gv_ptr): + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_result, [gv_ptr, IntConst(fieldtoken)])) + return gv_result + + def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index): + _, _, itemsize = arraytoken + assert itemsize == 4 + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + gv_result = Var() + if gv_itemoffset.fits_in_immediate(): + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.lwz, + gv_result, [gv_ptr, gv_itemoffset])) + else: + self.insns.append( + insn.Insn_GPR__GPR_GPR(RPPCAssembler.lwzx, + gv_result, [gv_ptr, gv_itemoffset])) + return gv_result + + def genop_getarraysize(self, arraytoken, gv_ptr): + lengthoffset, _, _ = arraytoken + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.lwz, + gv_result, [gv_ptr, IntConst(lengthoffset)])) + return gv_result + + def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): + _, _, itemsize = arraytoken + assert itemsize == 4 + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + gv_result = Var() + if gv_itemoffset.fits_in_immediate(): + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(RPPCAssembler.stw, + [gv_value, gv_ptr, gv_itemoffset])) + else: + self.insns.append( + insn.Insn_None__GPR_GPR_GPR(RPPCAssembler.stwx, + [gv_value, gv_ptr, gv_itemoffset])) + + def genop_malloc_fixedsize(self, alloctoken): + return self.genop_call(1, # COUGH + IntConst(gc_malloc_fnaddr()), + [IntConst(alloctoken)]) + + def genop_malloc_varsize(self, varsizealloctoken, gv_size): + gv_itemoffset = self.itemoffset(varsizealloctoken, gv_size) + gv_result = self.genop_call(1, # COUGH + IntConst(gc_malloc_fnaddr()), + [gv_itemoffset]) + lengthoffset, _, _ = varsizealloctoken + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(RPPCAssembler.stw, + [gv_size, gv_result, IntConst(lengthoffset)])) + return gv_result def genop_same_as(self, kindtoken, gv_arg): if not isinstance(gv_arg, Var): gv_result = Var() gv_arg.load(self.insns, gv_result) + return gv_result else: return gv_arg @@ -330,6 +400,20 @@ # ---------------------------------------------------------------- # ppc-specific interface: + def itemoffset(self, arraytoken, gv_index): + # if gv_index is constant, this can return a constant... + lengthoffset, startoffset, itemsize = arraytoken + + gv_offset = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.mulli, + gv_offset, [gv_index, IntConst(itemsize)])) + gv_itemoffset = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_itemoffset, [gv_offset, IntConst(startoffset)])) + return gv_itemoffset + def make_fresh_from_jump(self, initial_var2loc): self.fresh_from_jump = True self.initial_var2loc = initial_var2loc @@ -337,7 +421,7 @@ def _write_prologue(self, sigtoken): numargs = sigtoken # for now - if not we_are_translated() and option.trap: + if DEBUG_TRAP: self.asm.trap() inputargs = [Var() for i in range(numargs)] assert self.initial_var2loc is None @@ -371,6 +455,8 @@ # save stack pointer into linkage area and set stack pointer for us. self.asm.stwu(rSP, rSP, -minspace) + self.emit_stack_adjustment() + return inputargs def _var_offset(self, v): @@ -399,8 +485,8 @@ allocator = RegisterAllocation( self.rgenop.freeregs, self.initial_var2loc, self.initial_spill_offset) self.insns = allocator.allocate_for_insns(self.insns) - if self.insns: - self.patch_stack_adjustment(self._stack_size(allocator.spill_offset)) + #if self.insns: + self.patch_stack_adjustment(self._stack_size(allocator.spill_offset)) for insn in self.insns: insn.emit(self.asm) return allocator @@ -549,12 +635,21 @@ insn.CMPWI(self.cmp2info['ne'], gv_result, [gv_arg, self.rgenop.genconst(0)])) return gv_result + def op_bool_not(self, gv_arg): + gv_result = Var() + self.insns.append( + insn.CMPWI(self.cmp2info['eq'], gv_result, [gv_arg, self.rgenop.genconst(0)])) + return gv_result + def op_int_neg(self, gv_arg): gv_result = Var() self.insns.append( insn.Insn_GPR__GPR(RPPCAssembler.neg, gv_result, gv_arg)) return gv_result + op_ptr_nonzero = op_int_is_true + op_ptr_iszero = op_bool_not # for now + class RPPCGenOp(AbstractRGenOp): @@ -607,21 +702,38 @@ ## @staticmethod ## def erasedType(T): -## @staticmethod -## @specialize.memo() -## def fieldToken(T, name): + @staticmethod + @specialize.memo() + def fieldToken(T, name): + return llmemory.offsetof(T, name) -## @staticmethod -## @specialize.memo() -## def allocToken(T): + @staticmethod + @specialize.memo() + def allocToken(T): + return llmemory.sizeof(T) -## @staticmethod -## @specialize.memo() -## def varsizeAllocToken(T): + @staticmethod + @specialize.memo() + def varsizeAllocToken(T): + if isinstance(T, lltype.Array): + return RPPCGenOp.arrayToken(T) + else: + # var-sized structs + arrayfield = T._arrayfld + ARRAYFIELD = getattr(T, arrayfield) + arraytoken = RPPCGenOp.arrayToken(ARRAYFIELD) + length_offset, items_offset, item_size = arraytoken + arrayfield_offset = llmemory.offsetof(T, arrayfield) + return (arrayfield_offset+length_offset, + arrayfield_offset+items_offset, + item_size) -## @staticmethod -## @specialize.memo() -## def arrayToken(A): + @staticmethod + @specialize.memo() + def arrayToken(A): + return (llmemory.ArrayLengthOffset(A), + llmemory.ArrayItemsOffset(A), + llmemory.ItemOffset(A.OF)) @staticmethod @specialize.memo() Added: pypy/dist/pypy/jit/codegen/ppc/test/test_genc_ts.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_genc_ts.py Wed Nov 15 15:27:24 2006 @@ -0,0 +1,15 @@ +from pypy.jit.codegen.i386.test.test_genc_ts import I386TimeshiftingTestMixin +from pypy.jit.timeshifter.test import test_timeshift +from pypy.jit.codegen.ppc.rgenop import RPPCGenOp + +class PPCTimeshiftingTestMixin(I386TimeshiftingTestMixin): + RGenOp = RPPCGenOp + +class TestTimeshiftI386(PPCTimeshiftingTestMixin, + test_timeshift.TestTimeshift): + + # for the individual tests see + # ====> ../../../timeshifter/test/test_timeshift.py + + pass + From fijal at codespeak.net Wed Nov 15 15:46:42 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Nov 2006 15:46:42 +0100 (CET) Subject: [pypy-svn] r34632 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061115144642.64FF810097@code0.codespeak.net> Author: fijal Date: Wed Nov 15 15:46:40 2006 New Revision: 34632 Modified: pypy/dist/pypy/lib/distributed.py pypy/dist/pypy/lib/test2/test_distributed.py Log: First tests of distributed function passes. Modified: pypy/dist/pypy/lib/distributed.py ============================================================================== --- pypy/dist/pypy/lib/distributed.py (original) +++ pypy/dist/pypy/lib/distributed.py Wed Nov 15 15:46:40 2006 @@ -42,6 +42,8 @@ # XXX We do not make any garbage collection. We'll need it at some point +from pypymagic import pypy_repr + import types from marshal import dumps @@ -126,6 +128,48 @@ args, kwargs = self.unpack_args(args, kwargs) return getattr(obj, name)(*args, **kwargs) +def remote_loop(send, receive, protocol=None): + # the simplest version possible, without any concurrency and such + if protocol is None: + protocol = RemoteProtocol(send, receive, {}) + wrap = protocol.wrap + unwrap = protocol.unwrap + # we need this for wrap/unwrap + while 1: + command, data = receive() + if command == 'get': + # XXX: Error recovery anyone??? + send(wrap(protocol.exported_names[data])) + elif command == 'call': + id, name, args, kwargs = data + args, kwargs = unpack_args(args, kwargs) + assert not 'Transparent' in pypy_repr(protocol.objs[id]) + retval = getattr(protocol.objs[id], name)(args, kwargs) + send(("finished", wrap(retval))) + elif command == 'finished': + return unwrap(data) + else: + raise NotImplementedError("command %s" % command) + +class RemoteProtocol(AbstractProtocol): + #def __init__(self, gateway, remote_code): + # self.gateway = gateway + def __init__(self, send, receive, exported_names={}): + self.exported_names = exported_names + self.send = send + self.receive = receive + self.objs = [] + + def perform(self, id, name, *args, **kwargs): + args, kwargs = self.pack_args(args, kwargs) + self.send(('call', (id, name, args, kwargs))) + retval = remote_loop(self.send, self.receive, self) + return retval + + def get_remote(self, name): + self.send(("get", name)) + return self.unwrap(self.receive()) + class RemoteObject(object): def __init__(self, protocol, id): self.id = id @@ -134,6 +178,12 @@ def perform(self, name, *args, **kwargs): return self.protocol.perform(self.id, name, *args, **kwargs) +def bootstrap(gw): + import py + import sys + return gw.remote_exec(py.code.Source(sys.modules[__name__], "remote_loop(channel.send, channel.receive)")) + + ##class RemoteFunction(object): ## def __init__(self, channel, name): ## channel.send(protocol.get(name)) Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Wed Nov 15 15:46:40 2006 @@ -52,3 +52,19 @@ unwrap = protocol.unwrap item = unwrap(wrap(f)) assert item(3, 2) == 5 + + def test_remote_protocol_call(self): + def f(x, y): + return x + y + + import types + from distributed import RemoteProtocol, bootstrap + import sys + + data = [] + result = [] + protocol = RemoteProtocol(result.append, data.pop) + data += [("finished", protocol.wrap(5)), protocol.wrap(f)] + fun = protocol.get_remote("f") + assert isinstance(fun, types.FunctionType) + assert fun(2, 3) == 5 From pedronis at codespeak.net Wed Nov 15 16:46:39 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Nov 2006 16:46:39 +0100 (CET) Subject: [pypy-svn] r34633 - in pypy/dist/pypy: config rpython rpython/lltypesystem translator/c translator/c/src translator/c/test Message-ID: <20061115154639.C422F10077@code0.codespeak.net> Author: pedronis Date: Wed Nov 15 16:46:35 2006 New Revision: 34633 Modified: pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/lltypesystem/lloperation.py pypy/dist/pypy/translator/c/database.py pypy/dist/pypy/translator/c/funcgen.py pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/c/src/g_include.h pypy/dist/pypy/translator/c/src/main.h pypy/dist/pypy/translator/c/test/test_standalone.py Log: some support for persistent instrumentation counters (for unix, standalone for now). with a test. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Wed Nov 15 16:46:35 2006 @@ -159,6 +159,9 @@ BoolOption("debug_transform", "Perform the debug transformation", default=False, cmdline="--debug-transform", negation=False), + BoolOption("instrument", "internal: turn instrumentation on", + default=False, cmdline=None), + # portability options BoolOption("vanilla", "Try to be as portable as possible, which is not much", Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Wed Nov 15 16:46:35 2006 @@ -460,6 +460,9 @@ ll_exc_type = lltype.cast_pointer(rclass.OBJECTPTR, ll_exc).typeptr raise LLFatalError(msg, LLException(ll_exc_type, ll_exc)) + def op_instrument_count(self, ll_tag, ll_label): + pass # xxx for now + def op_keepalive(self, value): pass Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py Wed Nov 15 16:46:35 2006 @@ -402,6 +402,9 @@ 'debug_log_exc': LLOp(), 'debug_assert': LLOp(canfold=True), 'debug_fatalerror': LLOp(), + + # __________ instrumentation _________ + 'instrument_count': LLOp(), } # __________ operations on PyObjects __________ Modified: pypy/dist/pypy/translator/c/database.py ============================================================================== --- pypy/dist/pypy/translator/c/database.py (original) +++ pypy/dist/pypy/translator/c/database.py Wed Nov 15 16:46:35 2006 @@ -62,6 +62,8 @@ self.gctransformer = self.gcpolicy.transformerclass(translator) self.completed = False + self.instrument_ncounter = 0 + def gettypedefnode(self, T, varlength=1): if varlength <= 1: varlength = 1 # it's C after all Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Wed Nov 15 16:46:35 2006 @@ -736,6 +736,13 @@ msg = 'RPyString_AsString(%s)' % self.expr(msg) return 'fprintf(stderr, "%%s\\n", %s); abort();' % msg + + def OP_INSTRUMENT_COUNT(self, op): + counter_label = op.args[1].value + self.db.instrument_ncounter = max(self.db.instrument_ncounter, + counter_label+1) + counter_label = self.expr(op.args[1]) + return 'INSTRUMENT_COUNT(%s);' % counter_label assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator) Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Wed Nov 15 16:46:35 2006 @@ -132,6 +132,7 @@ if CBuilder.have___thread is None: CBuilder.have___thread = check_under_under_thread() if not self.standalone: + assert not self.config.translation.instrument from pypy.translator.c.symboltable import SymbolTable # XXX fix symboltable #self.symboltable = SymbolTable() @@ -140,6 +141,8 @@ exports = self.exports, symboltable = self.symboltable) else: + if self.config.translation.instrument: + defines['INSTRUMENT'] = 1 if CBuilder.have___thread: if not self.config.translation.no__thread: defines['USE___THREAD'] = 1 @@ -641,6 +644,13 @@ gen_startupcode(f, database) f.close() + + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + return filename, sg.getextrafiles() Modified: pypy/dist/pypy/translator/c/src/g_include.h ============================================================================== --- pypy/dist/pypy/translator/c/src/g_include.h (original) +++ pypy/dist/pypy/translator/c/src/g_include.h Wed Nov 15 16:46:35 2006 @@ -30,6 +30,8 @@ #include "src/float.h" #include "src/address.h" +#include "src/instrument.h" + /* optional assembler bits */ #if defined(__GNUC__) && defined(__i386__) # include "src/asm_gcc_x86.h" Modified: pypy/dist/pypy/translator/c/src/main.h ============================================================================== --- pypy/dist/pypy/translator/c/src/main.h (original) +++ pypy/dist/pypy/translator/c/src/main.h Wed Nov 15 16:46:35 2006 @@ -20,6 +20,9 @@ char *errmsg; int i, exitcode; RPyListOfString *list; + + instrument_setup(); + errmsg = RPython_StartupCode(); if (errmsg) goto error; Modified: pypy/dist/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_standalone.py (original) +++ pypy/dist/pypy/translator/c/test/test_standalone.py Wed Nov 15 16:46:35 2006 @@ -1,7 +1,10 @@ +import py +import sys, os + from pypy.translator.translator import TranslationContext from pypy.translator.c.genc import CStandaloneBuilder from pypy.annotation.listdef import s_list_of_strings -import os +from pypy.tool.udir import udir def test_hello_world(): @@ -47,3 +50,40 @@ '''argument lengths: [2, 5]\n''') # NB. RPython has only str, not repr, so str() on a list of strings # gives the strings unquoted in the list + +def test_counters(): + if sys.platform != 'linux2': + py.test.skip("instrument counters support is unix only for now") + from pypy.rpython.lltypesystem import lltype + from pypy.rpython.lltypesystem.lloperation import llop + def entry_point(argv): + llop.instrument_count(lltype.Void, 'test', 2) + llop.instrument_count(lltype.Void, 'test', 1) + llop.instrument_count(lltype.Void, 'test', 1) + llop.instrument_count(lltype.Void, 'test', 2) + llop.instrument_count(lltype.Void, 'test', 1) + return 0 + t = TranslationContext() + t.config.translation.instrument = True + t.buildannotator().build_types(entry_point, [s_list_of_strings]) + t.buildrtyper().specialize() + + cbuilder = CStandaloneBuilder(t, entry_point, config=t.config) # xxx + cbuilder.generate_source() + cbuilder.compile() + + counters_fname = udir.join("_counters_") + os.putenv('_INSTRUMENT_COUNTERS', str(counters_fname)) + try: + data = cbuilder.cmdexec() + finally: + os.unsetenv('_INSTRUMENT_COUNTERS') + + f = counters_fname.open('rb') + counters_data = f.read() + f.close() + + import struct + counters = struct.unpack("LLL", counters_data) + + assert counters == (0,3,2) From pedronis at codespeak.net Wed Nov 15 16:50:10 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Nov 2006 16:50:10 +0100 (CET) Subject: [pypy-svn] r34634 - pypy/dist/pypy/translator/c/src Message-ID: <20061115155010.00F491008F@code0.codespeak.net> Author: pedronis Date: Wed Nov 15 16:50:09 2006 New Revision: 34634 Added: pypy/dist/pypy/translator/c/src/instrument.h (contents, props changed) Log: oops, forgot to add this one Added: pypy/dist/pypy/translator/c/src/instrument.h ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/c/src/instrument.h Wed Nov 15 16:50:09 2006 @@ -0,0 +1,59 @@ + +void instrument_setup(); + +#ifdef INSTRUMENT + +void instrument_count(long); + +#ifndef PYPY_NOT_MAIN_FILE +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned long instrument_count_t; + +instrument_count_t *_instrument_counters; + +void instrument_setup() { + char *fname = getenv("_INSTRUMENT_COUNTERS"); + if (fname) { + int fd; + void *buf; + size_t sz = sizeof(instrument_count_t)*INSTRUMENT_NCOUNTER; + fd = open(fname, O_CREAT|O_TRUNC|O_RDWR, 0744); + lseek(fd, sz-1, SEEK_SET); + write(fd, "", 1); + buf = mmap(NULL, sz, PROT_WRITE|PROT_READ, MAP_SHARED, + fd, 0); + if (buf == MAP_FAILED) { + fprintf(stderr, "mapping instrument counters file failed\n"); + abort(); + } + _instrument_counters = (instrument_count_t *)buf; + } +} + +void instrument_count(long label) { + if(_instrument_counters) { + _instrument_counters[label]++; + } +} +#endif + + +#define INSTRUMENT_COUNT(label) instrument_count(label) + +#else + +#ifndef PYPY_NOT_MAIN_FILE +void instrument_setup() { +} +#endif + +#define INSTRUMENT_COUNT + +#endif From fijal at codespeak.net Wed Nov 15 17:44:54 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Nov 2006 17:44:54 +0100 (CET) Subject: [pypy-svn] r34635 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061115164454.49A8B1009A@code0.codespeak.net> Author: fijal Date: Wed Nov 15 17:44:51 2006 New Revision: 34635 Modified: pypy/dist/pypy/lib/distributed.py pypy/dist/pypy/lib/test2/test_distributed.py Log: First real tests using stackless Modified: pypy/dist/pypy/lib/distributed.py ============================================================================== --- pypy/dist/pypy/lib/distributed.py (original) +++ pypy/dist/pypy/lib/distributed.py Wed Nov 15 17:44:51 2006 @@ -128,10 +128,10 @@ args, kwargs = self.unpack_args(args, kwargs) return getattr(obj, name)(*args, **kwargs) -def remote_loop(send, receive, protocol=None): +def remote_loop(send, receive, exported_names, protocol=None): # the simplest version possible, without any concurrency and such if protocol is None: - protocol = RemoteProtocol(send, receive, {}) + protocol = RemoteProtocol(send, receive, exported_names) wrap = protocol.wrap unwrap = protocol.unwrap # we need this for wrap/unwrap @@ -142,9 +142,8 @@ send(wrap(protocol.exported_names[data])) elif command == 'call': id, name, args, kwargs = data - args, kwargs = unpack_args(args, kwargs) - assert not 'Transparent' in pypy_repr(protocol.objs[id]) - retval = getattr(protocol.objs[id], name)(args, kwargs) + args, kwargs = protocol.unpack_args(args, kwargs) + retval = getattr(protocol.objs[id], name)(*args, **kwargs) send(("finished", wrap(retval))) elif command == 'finished': return unwrap(data) @@ -178,19 +177,13 @@ def perform(self, name, *args, **kwargs): return self.protocol.perform(self.id, name, *args, **kwargs) -def bootstrap(gw): - import py - import sys - return gw.remote_exec(py.code.Source(sys.modules[__name__], "remote_loop(channel.send, channel.receive)")) - - -##class RemoteFunction(object): -## def __init__(self, channel, name): -## channel.send(protocol.get(name)) -## self.channel = channel -## self.id = protocol.id(channel.receive()) -## self.fun = proxy(types.FunctionType, self.perform) -## -## def perform(self, name, *args, **kwargs): -## self.channel.send(protocol.pack_call(self.id, name, args, kwargs)) -## return protocol.unpack(self.channel.receive()) +def test_env(exported_names): + from stackless import channel, tasklet, run + inp, out = channel(), channel() + tasklet(remote_loop)(inp.send, out.receive, exported_names) + return RemoteProtocol(out.send, inp.receive) + +#def bootstrap(gw): +# import py +# import sys +# return gw.remote_exec(py.code.Source(sys.modules[__name__], "remote_loop(channel.send, channel.receive)")) Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Wed Nov 15 17:44:51 2006 @@ -11,7 +11,8 @@ class AppTestDistributed(object): def setup_class(cls): - cls.space = gettestobjspace(**{"objspace.std.withtproxy": True}) + cls.space = gettestobjspace(**{"objspace.std.withtproxy": True, + "usemodules":("_stackless",)}) def test_init(self): import distributed @@ -53,12 +54,12 @@ item = unwrap(wrap(f)) assert item(3, 2) == 5 - def test_remote_protocol_call(self): + def test_simulation_call(self): def f(x, y): return x + y import types - from distributed import RemoteProtocol, bootstrap + from distributed import RemoteProtocol import sys data = [] @@ -68,3 +69,12 @@ fun = protocol.get_remote("f") assert isinstance(fun, types.FunctionType) assert fun(2, 3) == 5 + + def test_remote_protocol_call(self): + def f(x, y): + return x + y + + from distributed import test_env + protocol = test_env({"f": f}) + fun = protocol.get_remote("f") + assert fun(2, 3) == 5 From fijal at codespeak.net Wed Nov 15 18:10:13 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Nov 2006 18:10:13 +0100 (CET) Subject: [pypy-svn] r34636 - pypy/dist/pypy/lib Message-ID: <20061115171013.7495710092@code0.codespeak.net> Author: fijal Date: Wed Nov 15 18:10:12 2006 New Revision: 34636 Modified: pypy/dist/pypy/lib/stackless.py Log: Restore a stack Modified: pypy/dist/pypy/lib/stackless.py ============================================================================== --- pypy/dist/pypy/lib/stackless.py (original) +++ pypy/dist/pypy/lib/stackless.py Wed Nov 15 18:10:12 2006 @@ -57,7 +57,8 @@ def restore_exception(etype, value, stack): """until I find out how to restore an exception on python level""" #sys.excepthook(etype, value, stack) - raise etype(value) + raise etype, value, stack + #raise etype(value) class TaskletProxy(object): """TaskletProxy is needed to give the main_coroutine tasklet behaviour""" From fijal at codespeak.net Wed Nov 15 18:12:33 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Nov 2006 18:12:33 +0100 (CET) Subject: [pypy-svn] r34637 - pypy/dist/pypy/lib/test2 Message-ID: <20061115171233.41C0810092@code0.codespeak.net> Author: fijal Date: Wed Nov 15 18:12:32 2006 New Revision: 34637 Modified: pypy/dist/pypy/lib/test2/test_distributed.py Log: Added a cool test. Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Wed Nov 15 18:12:32 2006 @@ -78,3 +78,15 @@ protocol = test_env({"f": f}) fun = protocol.get_remote("f") assert fun(2, 3) == 5 + + def test_callback(self): + def g(): + return 8 + + def f(x): + return x + g() + + from distributed import test_env + protocol = test_env({"f":f}) + fun = protocol.get_remote("f") + assert fun(8) == 16 From fijal at codespeak.net Wed Nov 15 18:44:17 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Nov 2006 18:44:17 +0100 (CET) Subject: [pypy-svn] r34639 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061115174417.397B9100A6@code0.codespeak.net> Author: fijal Date: Wed Nov 15 18:44:15 2006 New Revision: 34639 Modified: pypy/dist/pypy/lib/distributed.py pypy/dist/pypy/lib/test2/test_distributed.py Log: Another improvement and a test. Modified: pypy/dist/pypy/lib/distributed.py ============================================================================== --- pypy/dist/pypy/lib/distributed.py (original) +++ pypy/dist/pypy/lib/distributed.py Wed Nov 15 18:44:15 2006 @@ -58,7 +58,8 @@ 'l' : long, 's' : str, 'lst' : list, - 'fun' : types.FunctionType + 'fun' : types.FunctionType, + 'cus' : object, } type_letters = dict([(value, key) for key, value in letter_types.items()]) assert len(type_letters) == len(letter_types) @@ -85,8 +86,9 @@ id = self.register_obj(obj) return (self.type_letters[tp], id) else: - raise NotImplementedError("Cannot wrap %s: unsupported type %s" % - (obj, tp)) + type_id = self.register_type(tp) + id = self.register_obj(obj) + return ("cus", (type_id, id)) def unwrap(self, data): """ Unwrap an object @@ -99,6 +101,11 @@ return tuple([self.unwrap(i) for i in obj_data]) elif tp in (list, dict, types.FunctionType): return proxy(tp, RemoteObject(self, obj_data).perform) + elif tp is object: + # we need to create a proper type + type_id, id = obj_data + real_tp = self.get_type(type_id) + return proxy(real_tp, RemoteObject(self, id).perform) else: raise NotImplementedError("Cannot unwrap %s" % (data,)) @@ -119,6 +126,10 @@ class LocalProtocol(AbstractProtocol): """ This is stupid protocol for testing purposes only """ + def __init__(self): + super(LocalProtocol, self).__init__() + self.types = [] + def perform(self, id, name, *args, **kwargs): obj = self.objs[id] # we pack and than unpack, for tests @@ -127,6 +138,13 @@ dumps((args, kwargs)) args, kwargs = self.unpack_args(args, kwargs) return getattr(obj, name)(*args, **kwargs) + + def register_type(self, tp): + self.types.append(tp) + return len(self.types) - 1 + + def get_type(self, id): + return self.types[id] def remote_loop(send, receive, exported_names, protocol=None): # the simplest version possible, without any concurrency and such @@ -154,10 +172,10 @@ #def __init__(self, gateway, remote_code): # self.gateway = gateway def __init__(self, send, receive, exported_names={}): + super(RemoteProtocol, self).__init__() self.exported_names = exported_names self.send = send self.receive = receive - self.objs = [] def perform(self, id, name, *args, **kwargs): args, kwargs = self.pack_args(args, kwargs) Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Wed Nov 15 18:44:15 2006 @@ -90,3 +90,19 @@ protocol = test_env({"f":f}) fun = protocol.get_remote("f") assert fun(8) == 16 + + def test_local_obj(self): + class A: + def __init__(self, x): + self.x = x + + def __len__(self): + return self.x + 8 + + from distributed import LocalProtocol + protocol = LocalProtocol() + wrap = protocol.wrap + unwrap = protocol.unwrap + item = unwrap(wrap(A(3))) + assert item.x == 3 + assert len(item) == 11 From pedronis at codespeak.net Wed Nov 15 19:06:29 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Nov 2006 19:06:29 +0100 (CET) Subject: [pypy-svn] r34640 - in pypy/dist/pypy: config translator/c translator/tool Message-ID: <20061115180629.55F06100AA@code0.codespeak.net> Author: pedronis Date: Wed Nov 15 19:06:26 2006 New Revision: 34640 Modified: pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/tool/cbuild.py Log: intermediate checkin: generalize the genc code for profopt translation for use with our own instrumentation. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Wed Nov 15 19:06:26 2006 @@ -1,6 +1,6 @@ import autopath import py, os -from pypy.config.config import OptionDescription, BoolOption, IntOption +from pypy.config.config import OptionDescription, BoolOption, IntOption, ArbitraryOption from pypy.config.config import ChoiceOption, StrOption, to_optparse, Config modulepath = py.magic.autopath().dirpath().dirpath().join("module") @@ -162,6 +162,9 @@ BoolOption("instrument", "internal: turn instrumentation on", default=False, cmdline=None), + ArbitraryOption("instrumentctl", "internal", + default=None), + # portability options BoolOption("vanilla", "Try to be as portable as possible, which is not much", Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Wed Nov 15 19:06:26 2006 @@ -5,7 +5,7 @@ from pypy.translator.c.extfunc import pre_include_code_lines from pypy.translator.gensupp import uniquemodulename, NameManager from pypy.translator.tool.cbuild import compile_c_module -from pypy.translator.tool.cbuild import build_executable, CCompiler +from pypy.translator.tool.cbuild import build_executable, CCompiler, ProfOpt 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 @@ -227,12 +227,19 @@ from distutils import sysconfig python_inc = sysconfig.get_python_inc() cc = self.config.translation.cc - profopt = self.config.translation.profopt + profbased = None + if self.config.translation.instrumentctl is not None: + profbased = self.config.translation.instrumentctl + else: + profopt = self.config.translation.profopt + if profopt is not None: + profbased = (ProfOpt, profopt) + return CCompiler( [self.c_source_filename] + self.extrafiles, include_dirs = [autopath.this_dir, python_inc] + extra_includes, libraries = self.libraries, - compiler_exe = cc, profopt = profopt) + compiler_exe = cc, profbased = profbased) def compile(self): assert self.c_source_filename Modified: pypy/dist/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/dist/pypy/translator/tool/cbuild.py (original) +++ pypy/dist/pypy/translator/tool/cbuild.py Wed Nov 15 19:06:26 2006 @@ -259,11 +259,57 @@ return spawn_and_log +class ProfOpt(object): + #XXX assuming gcc style flags for now + name = "profopt" + + def __init__(self, compiler): + self.compiler = compiler + + def first(self): + self.build('-fprofile-generate') + + def probe(self, exe, args): + from py.compat import subprocess + subprocess.call([exe, args]) + + def after(self): + self.build('-fprofile-use') + + def build(self, option): + compiler = self.compiler + compiler.compile_extra.append(option) + compiler.link_extra.append(option) + try: + compiler._build() + finally: + compiler.compile_extra.pop() + compiler.link_extra.pop() + +class ProfInstrument(object): + name = "profinstrument" + + def __init__(self, compiler): + self.compiler = compiler + + def first(self): + self.compiler._build() + + def probe(self, exe, args): + from pypy.tool.udir import udir + from py.compat import subprocess + env = os.environ.copy() + env['_INSTRUMENT_COUNTERS'] = str(udir.join('_instrument_counters')) + subprocess.call([exe, args], env=env) + + def after(self): + pass + class CCompiler: def __init__(self, cfilenames, outputfilename=None, include_dirs=[], libraries=[], library_dirs=[], compiler_exe=None, - profopt=None): + profbased=None): self.cfilenames = cfilenames ext = '' self.compile_extra = [] @@ -272,7 +318,7 @@ self.include_dirs = list(include_dirs) self.library_dirs = list(library_dirs) self.compiler_exe = compiler_exe - self.profopt = profopt + self.profbased = profbased if not sys.platform in ('win32', 'darwin'): # xxx if 'm' not in self.libraries: self.libraries.append('m') @@ -303,26 +349,18 @@ try: try: c = stdoutcapture.Capture(mixed_out_err = True) - log.profopt(str(self.profopt)) - if self.profopt is None: - self._build() - else: #XXX assuming gcc style flags for now - self.compile_extra.append('-fprofile-generate') - self.link_extra.append('-fprofile-generate') - self._build() - self.compile_extra.pop() - self.link_extra.pop() - - log.profopt('Gathering profile data from: %s %s' % ( - str(self.outputfilename), self.profopt)) - import subprocess - subprocess.call([str(self.outputfilename), self.profopt]) - - self.compile_extra.append('-fprofile-use') - self.link_extra.append('-fprofile-use') + if self.profbased is None: self._build() - self.compile_extra.pop() - self.link_extra.pop() + else: + ProfDriver, args = self.profbased + profdrv = ProfDriver(self) + dolog = getattr(log, ProfDriver.name) + dolog(args) + profdrv.first() + dolog('Gathering profile data from: %s %s' % ( + str(self.outputfilename), args)) + profdrv.probe(str(self.outputfilename),args) + profdrv.after() finally: foutput, foutput = c.done() data = foutput.read() From pedronis at codespeak.net Wed Nov 15 20:52:08 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 15 Nov 2006 20:52:08 +0100 (CET) Subject: [pypy-svn] r34641 - pypy/dist/pypy/translator/c/test Message-ID: <20061115195208.9A008100A5@code0.codespeak.net> Author: pedronis Date: Wed Nov 15 20:52:05 2006 New Revision: 34641 Modified: pypy/dist/pypy/translator/c/test/test_standalone.py Log: tested on Darwin too. Modified: pypy/dist/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_standalone.py (original) +++ pypy/dist/pypy/translator/c/test/test_standalone.py Wed Nov 15 20:52:05 2006 @@ -52,7 +52,7 @@ # gives the strings unquoted in the list def test_counters(): - if sys.platform != 'linux2': + if sys.platform == 'win32': py.test.skip("instrument counters support is unix only for now") from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem.lloperation import llop From fijal at codespeak.net Wed Nov 15 22:21:06 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Nov 2006 22:21:06 +0100 (CET) Subject: [pypy-svn] r34642 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20061115212106.5F6AA100A4@code0.codespeak.net> Author: fijal Date: Wed Nov 15 22:21:03 2006 New Revision: 34642 Modified: pypy/dist/pypy/objspace/std/objspace.py pypy/dist/pypy/objspace/std/proxyobject.py pypy/dist/pypy/objspace/std/test/test_proxy_internals.py pypy/dist/pypy/objspace/std/transparent.py Log: Added check for controller (in pypymagic). I did not find a good name, please replace it if you feel like finding better. Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Wed Nov 15 22:21:03 2006 @@ -135,10 +135,12 @@ # Adding transparent proxy call if self.config.objspace.std.withtproxy: w_pypymagic = self.getbuiltinmodule("pypymagic") - from pypy.objspace.std.transparent import app_proxy + from pypy.objspace.std.transparent import app_proxy, app_proxy_controller self.setattr(w_pypymagic, self.wrap('transparent_proxy'), self.wrap(app_proxy)) + self.setattr(w_pypymagic, self.wrap('get_transparent_controller'), + self.wrap(app_proxy_controller)) def enable_old_style_classes_as_default_metaclass(self): self.setitem(self.builtin.w_dict, self.wrap('__metaclass__'), self.w_classobj) Modified: pypy/dist/pypy/objspace/std/proxyobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/proxyobject.py (original) +++ pypy/dist/pypy/objspace/std/proxyobject.py Wed Nov 15 22:21:03 2006 @@ -68,7 +68,7 @@ def setdict(self, space, w_dict): if not self.setdictvalue(space, space.wrap('__dict__'), w_dict): baseobjspace.W_Root.setdict(self, space, w_dict) - + W_Transparent.__name__ = name return W_Transparent Modified: pypy/dist/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/dist/pypy/objspace/std/test/test_proxy_internals.py Wed Nov 15 22:21:03 2006 @@ -101,6 +101,14 @@ e = sys.exc_info() assert traceback.format_tb(last_tb) == traceback.format_tb(e[2]) + + def test_proxy_get(self): + from pypymagic import transparent_proxy, get_transparent_controller + l = [1,2,3] + def f(name, *args, **kwargs): + return getattr(l, name)(*args, **kwargs) + lst = transparent_proxy(list, f) + assert get_transparent_controller(lst) is f class DONTAppTestProxyType(AppProxy): def test_filetype(self): Modified: pypy/dist/pypy/objspace/std/transparent.py ============================================================================== --- pypy/dist/pypy/objspace/std/transparent.py (original) +++ pypy/dist/pypy/objspace/std/transparent.py Wed Nov 15 22:21:03 2006 @@ -35,5 +35,12 @@ raise OperationError(space.w_TypeError, space.wrap("Object type %s could not "\ "be wrapped (YET)" % w_type.getname(space, "?"))) +def proxy_controller(space, w_object): + if (not isinstance(w_object, W_Transparent)) and \ + (not isinstance(w_object, W_TransparentObject)): + return None + return w_object.w_controller + app_proxy = gateway.interp2app(proxy, unwrap_spec=[gateway.ObjSpace, gateway.W_Root, \ gateway.W_Root]) +app_proxy_controller = gateway.interp2app(proxy_controller, unwrap_spec=[gateway.ObjSpace, gateway.W_Root]) From fijal at codespeak.net Wed Nov 15 22:32:28 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Nov 2006 22:32:28 +0100 (CET) Subject: [pypy-svn] r34643 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061115213228.65AAD100AA@code0.codespeak.net> Author: fijal Date: Wed Nov 15 22:32:26 2006 New Revision: 34643 Modified: pypy/dist/pypy/lib/distributed.py pypy/dist/pypy/lib/test2/test_distributed.py Log: First test of distributed obj passes. This is quite a lot of cheating, but cool anyway :-] Modified: pypy/dist/pypy/lib/distributed.py ============================================================================== --- pypy/dist/pypy/lib/distributed.py (original) +++ pypy/dist/pypy/lib/distributed.py Wed Nov 15 22:32:26 2006 @@ -37,6 +37,7 @@ try: from pypymagic import transparent_proxy as proxy + from pypymagic import get_transparent_controller except ImportError: raise ImportError("Cannot work without transparent proxy functional") @@ -47,6 +48,26 @@ import types from marshal import dumps +def get_bound(im_class, im_self, im_func): + return FakeMethod(im_class, im_self, im_func) + +class FakeMethod(object): + def __init__(self, im_class, im_self, im_func): + self.im_self = im_self + self.im_func = im_func + self.im_class = im_class + + def __call__(self, *args, **kwargs): + return self.im_func(self.im_self, *args, **kwargs) + + def __get__(self, instance, owner=None): + if self.im_self is not None: + return self + if not owner is None and not issubclass(owner, self.im_class): + return self + else: + return get_bound(self.im_class, instance, self.im_func) + class AbstractProtocol(object): letter_types = { 'l' : list, @@ -57,14 +78,18 @@ 'u' : unicode, 'l' : long, 's' : str, + 'n' : types.NoneType, 'lst' : list, 'fun' : types.FunctionType, 'cus' : object, + 'meth' : types.MethodType, + 'tp' : None, } type_letters = dict([(value, key) for key, value in letter_types.items()]) assert len(type_letters) == len(letter_types) def __init__(self): + self.remote_objects = {} self.objs = [] # we just store everything, maybe later # we'll need some kind of garbage collection @@ -76,7 +101,12 @@ """ Wrap an object as sth prepared for sending """ tp = type(obj) - if tp in (str, int, float, long, unicode): + ctrl = get_transparent_controller(obj) + if ctrl: + return "tp", self.remote_objects[ctrl] + elif obj is None: + return self.type_letters[tp] + elif tp in (str, int, float, long, unicode): # simple, immutable object, just copy return (self.type_letters[tp], obj) elif tp is tuple: @@ -85,6 +115,11 @@ elif tp in (list, dict, types.FunctionType): id = self.register_obj(obj) return (self.type_letters[tp], id) + elif tp is types.MethodType: + type_id = self.register_type(obj.im_class) + self_ = self.wrap(obj.im_self) + func_ = self.wrap(obj.im_func) + return (self.type_letters[tp], (type_id, self_, func_)) else: type_id = self.register_type(tp) id = self.register_obj(obj) @@ -93,19 +128,32 @@ def unwrap(self, data): """ Unwrap an object """ + if data == 'n': + return None tp_letter, obj_data = data tp = self.letter_types[tp_letter] - if tp in (str, int, float, long, unicode): + if tp is None: + return self.objs[obj_data] + elif tp in (str, int, float, long, unicode): return obj_data # this is the object elif tp is tuple: return tuple([self.unwrap(i) for i in obj_data]) elif tp in (list, dict, types.FunctionType): - return proxy(tp, RemoteObject(self, obj_data).perform) + id = obj_data + ro = RemoteObject(self, id) + self.remote_objects[ro.perform] = id + return proxy(tp, ro.perform) + elif tp is types.MethodType: + type_id, w_self, w_func = obj_data + tp = self.get_type(type_id) + return FakeMethod(tp, self.unwrap(w_self), self.unwrap(w_func)) elif tp is object: # we need to create a proper type type_id, id = obj_data real_tp = self.get_type(type_id) - return proxy(real_tp, RemoteObject(self, id).perform) + ro = RemoteObject(self, id) + self.remote_objects[ro.perform] = id + return proxy(real_tp, ro.perform) else: raise NotImplementedError("Cannot unwrap %s" % (data,)) @@ -122,6 +170,9 @@ args = [self.unwrap(i) for i in args] kwargs = dict([(self.unwrap(key), self.unwrap(val)) for key, val in kwargs.items()]) return args, kwargs + + def fake_deferred(self): + pass class LocalProtocol(AbstractProtocol): """ This is stupid protocol for testing purposes only @@ -157,14 +208,18 @@ command, data = receive() if command == 'get': # XXX: Error recovery anyone??? - send(wrap(protocol.exported_names[data])) + send(("finished", wrap(protocol.exported_names[data]))) elif command == 'call': id, name, args, kwargs = data args, kwargs = protocol.unpack_args(args, kwargs) retval = getattr(protocol.objs[id], name)(*args, **kwargs) send(("finished", wrap(retval))) elif command == 'finished': + #protocol.fake_deferred() return unwrap(data) + elif command == 'type_reg': + type_id, name, _dict = data + protocol.register_fake_type(type_id, name, _dict) else: raise NotImplementedError("command %s" % command) @@ -176,6 +231,10 @@ self.exported_names = exported_names self.send = send self.receive = receive + self.type_cache = {} + self.type_id = 0 + self.remote_types = {} + #self.deferred_attr_set = [] def perform(self, id, name, *args, **kwargs): args, kwargs = self.pack_args(args, kwargs) @@ -185,7 +244,48 @@ def get_remote(self, name): self.send(("get", name)) - return self.unwrap(self.receive()) + retval = remote_loop(self.send, self.receive, self) + return retval + + def register_type(self, tp): + try: + return self.type_cache[tp] + except KeyError: + print "Registering type %s as %s" % (tp, self.type_id) + self.type_cache[tp] = self.type_id + tp_id = self.type_id + self.type_id += 1 + + # XXX: We don't support inheritance here, nor recursive types + # shall we??? + _dict = dict([(key, self.wrap(getattr(tp, key))) for key in dir(tp) + if key not in ('__dict__', '__weakref__', '__class__', '__new__', + '__doc__')]) + self.send(("type_reg", (tp_id, + tp.__name__, _dict))) + return tp_id + + #def fake_deferred(self): + # for tp, _dict in self.deferred_attr_set: + # for key, value in _dict.items(): + # setattr(tp, key, self.unwrap(value)) + # self.deferred_attr_set = [] + + def register_fake_type(self, type_id, _name, _dict): + print "Faking type %s as %s" % (_name, type_id) + # create and register new type + d = dict([(key, None) for key in _dict]) + tp = type(_name, (object,), d) + self.remote_types[type_id] = tp + for key, value in _dict.items(): + setattr(tp, key, self.unwrap(value)) + + def get_type(self, id): + try: + return self.remote_types[id] + except KeyError: + print "Warning!!! Type %d is not present by now" % id + return object class RemoteObject(object): def __init__(self, protocol, id): @@ -197,8 +297,10 @@ def test_env(exported_names): from stackless import channel, tasklet, run + # XXX: This is a hack, proper support for recursive type is needed inp, out = channel(), channel() - tasklet(remote_loop)(inp.send, out.receive, exported_names) + remote_protocol = RemoteProtocol(inp.send, out.receive, exported_names) + t = tasklet(remote_loop)(inp.send, out.receive, exported_names, remote_protocol) return RemoteProtocol(out.send, inp.receive) #def bootstrap(gw): Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Wed Nov 15 22:32:26 2006 @@ -65,7 +65,7 @@ data = [] result = [] protocol = RemoteProtocol(result.append, data.pop) - data += [("finished", protocol.wrap(5)), protocol.wrap(f)] + data += [("finished", protocol.wrap(5)), ("finished", protocol.wrap(f))] fun = protocol.get_remote("f") assert isinstance(fun, types.FunctionType) assert fun(2, 3) == 5 @@ -106,3 +106,19 @@ item = unwrap(wrap(A(3))) assert item.x == 3 assert len(item) == 11 + + def test_remote_obj(self): + class A: + def __init__(self, x): + self.x = x + + def __len__(self): + return self.x + 8 + a = A(3) + + from distributed import test_env + protocol = test_env({'a':a}) + xa = protocol.get_remote("a") + assert xa.x == 3 + assert len(xa) == 11 + From fijal at codespeak.net Wed Nov 15 22:34:25 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Nov 2006 22:34:25 +0100 (CET) Subject: [pypy-svn] r34644 - pypy/dist/pypy/lib Message-ID: <20061115213425.99C4D100AA@code0.codespeak.net> Author: fijal Date: Wed Nov 15 22:34:24 2006 New Revision: 34644 Modified: pypy/dist/pypy/lib/distributed.py Log: A small heuristic to copy __doc__ as well. Modified: pypy/dist/pypy/lib/distributed.py ============================================================================== --- pypy/dist/pypy/lib/distributed.py (original) +++ pypy/dist/pypy/lib/distributed.py Wed Nov 15 22:34:24 2006 @@ -259,8 +259,7 @@ # XXX: We don't support inheritance here, nor recursive types # shall we??? _dict = dict([(key, self.wrap(getattr(tp, key))) for key in dir(tp) - if key not in ('__dict__', '__weakref__', '__class__', '__new__', - '__doc__')]) + if key not in ('__dict__', '__weakref__', '__class__', '__new__')]) self.send(("type_reg", (tp_id, tp.__name__, _dict))) return tp_id @@ -275,10 +274,13 @@ print "Faking type %s as %s" % (_name, type_id) # create and register new type d = dict([(key, None) for key in _dict]) + if '__doc__' in _dict: + d['__doc__'] = self.unwrap(_dict['__doc__']) tp = type(_name, (object,), d) self.remote_types[type_id] = tp for key, value in _dict.items(): - setattr(tp, key, self.unwrap(value)) + if key != '__doc__': + setattr(tp, key, self.unwrap(value)) def get_type(self, id): try: From fijal at codespeak.net Thu Nov 16 00:19:16 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 16 Nov 2006 00:19:16 +0100 (CET) Subject: [pypy-svn] r34645 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061115231916.BBE311009C@code0.codespeak.net> Author: fijal Date: Thu Nov 16 00:19:14 2006 New Revision: 34645 Modified: pypy/dist/pypy/lib/distributed.py pypy/dist/pypy/lib/test2/test_distributed.py Log: (pedronis, fijal) - Basic demo of methods now works. Now we need to perform some refactoring, cause code grows a bit too much, as well as some stackless module inspection. Modified: pypy/dist/pypy/lib/distributed.py ============================================================================== --- pypy/dist/pypy/lib/distributed.py (original) +++ pypy/dist/pypy/lib/distributed.py Thu Nov 16 00:19:14 2006 @@ -43,37 +43,27 @@ # XXX We do not make any garbage collection. We'll need it at some point +""" +TODO list: + +1. Move it to more than one file +2. Refactor it a bit (split class into logical/bookkeeper one) +3. Add some garbage collection +4. Add caching of objects that are presented (even on name level) +""" + from pypymagic import pypy_repr import types from marshal import dumps -def get_bound(im_class, im_self, im_func): - return FakeMethod(im_class, im_self, im_func) - -class FakeMethod(object): - def __init__(self, im_class, im_self, im_func): - self.im_self = im_self - self.im_func = im_func - self.im_class = im_class - - def __call__(self, *args, **kwargs): - return self.im_func(self.im_self, *args, **kwargs) - - def __get__(self, instance, owner=None): - if self.im_self is not None: - return self - if not owner is None and not issubclass(owner, self.im_class): - return self - else: - return get_bound(self.im_class, instance, self.im_func) - class AbstractProtocol(object): letter_types = { 'l' : list, 'd' : dict, 't' : tuple, 'i' : int, + 'b' : bool, 'f' : float, 'u' : unicode, 'l' : long, @@ -83,13 +73,14 @@ 'fun' : types.FunctionType, 'cus' : object, 'meth' : types.MethodType, + 'type' : type, 'tp' : None, } type_letters = dict([(value, key) for key, value in letter_types.items()]) assert len(type_letters) == len(letter_types) def __init__(self): - self.remote_objects = {} + self.remote_objects = {} # a dictionary controller --> id self.objs = [] # we just store everything, maybe later # we'll need some kind of garbage collection @@ -106,7 +97,7 @@ return "tp", self.remote_objects[ctrl] elif obj is None: return self.type_letters[tp] - elif tp in (str, int, float, long, unicode): + elif tp in (str, int, float, long, unicode, bool): # simple, immutable object, just copy return (self.type_letters[tp], obj) elif tp is tuple: @@ -115,14 +106,18 @@ elif tp in (list, dict, types.FunctionType): id = self.register_obj(obj) return (self.type_letters[tp], id) + elif tp is type: + id = self.register_type(obj) + return (self.type_letters[tp], id) elif tp is types.MethodType: type_id = self.register_type(obj.im_class) - self_ = self.wrap(obj.im_self) - func_ = self.wrap(obj.im_func) - return (self.type_letters[tp], (type_id, self_, func_)) + w_func = self.wrap(obj.im_func) + w_self = self.wrap(obj.im_self) + return (self.type_letters[tp], (type_id, \ + self.wrap(obj.im_func.func_name), w_func, w_self)) else: - type_id = self.register_type(tp) id = self.register_obj(obj) + type_id = self.register_type(tp) return ("cus", (type_id, id)) def unwrap(self, data): @@ -134,7 +129,7 @@ tp = self.letter_types[tp_letter] if tp is None: return self.objs[obj_data] - elif tp in (str, int, float, long, unicode): + elif tp in (str, int, float, long, unicode, bool): return obj_data # this is the object elif tp is tuple: return tuple([self.unwrap(i) for i in obj_data]) @@ -144,9 +139,19 @@ self.remote_objects[ro.perform] = id return proxy(tp, ro.perform) elif tp is types.MethodType: - type_id, w_self, w_func = obj_data + type_id, w_name, w_func, w_self = obj_data tp = self.get_type(type_id) - return FakeMethod(tp, self.unwrap(w_self), self.unwrap(w_func)) + name = self.unwrap(w_name) + self_ = self.unwrap(w_self) + if self_: + return getattr(tp, name).__get__(self_, tp) + func = self.unwrap(w_func) + setattr(tp, name, func) + return getattr(tp, name) + elif tp is type: + id = obj_data + elem = self.get_type(obj_data) + return elem elif tp is object: # we need to create a proper type type_id, id = obj_data @@ -171,9 +176,6 @@ kwargs = dict([(self.unwrap(key), self.unwrap(val)) for key, val in kwargs.items()]) return args, kwargs - def fake_deferred(self): - pass - class LocalProtocol(AbstractProtocol): """ This is stupid protocol for testing purposes only """ @@ -197,12 +199,12 @@ def get_type(self, id): return self.types[id] -def remote_loop(send, receive, exported_names, protocol=None): +def remote_loop(protocol): # the simplest version possible, without any concurrency and such - if protocol is None: - protocol = RemoteProtocol(send, receive, exported_names) wrap = protocol.wrap unwrap = protocol.unwrap + send = protocol.send + receive = protocol.receive # we need this for wrap/unwrap while 1: command, data = receive() @@ -215,7 +217,6 @@ retval = getattr(protocol.objs[id], name)(*args, **kwargs) send(("finished", wrap(retval))) elif command == 'finished': - #protocol.fake_deferred() return unwrap(data) elif command == 'type_reg': type_id, name, _dict = data @@ -234,17 +235,16 @@ self.type_cache = {} self.type_id = 0 self.remote_types = {} - #self.deferred_attr_set = [] def perform(self, id, name, *args, **kwargs): args, kwargs = self.pack_args(args, kwargs) self.send(('call', (id, name, args, kwargs))) - retval = remote_loop(self.send, self.receive, self) + retval = remote_loop(self) return retval def get_remote(self, name): self.send(("get", name)) - retval = remote_loop(self.send, self.receive, self) + retval = remote_loop(self) return retval def register_type(self, tp): @@ -259,17 +259,12 @@ # XXX: We don't support inheritance here, nor recursive types # shall we??? _dict = dict([(key, self.wrap(getattr(tp, key))) for key in dir(tp) - if key not in ('__dict__', '__weakref__', '__class__', '__new__')]) + if key not in ('__dict__', '__weakref__', '__class__', '__new__', + '__base__', '__flags__', '__mro__', '__bases__')]) self.send(("type_reg", (tp_id, tp.__name__, _dict))) return tp_id - #def fake_deferred(self): - # for tp, _dict in self.deferred_attr_set: - # for key, value in _dict.items(): - # setattr(tp, key, self.unwrap(value)) - # self.deferred_attr_set = [] - def register_fake_type(self, type_id, _name, _dict): print "Faking type %s as %s" % (_name, type_id) # create and register new type @@ -280,7 +275,10 @@ self.remote_types[type_id] = tp for key, value in _dict.items(): if key != '__doc__': - setattr(tp, key, self.unwrap(value)) + try: + setattr(tp, key, self.unwrap(value)) + except TypeError: + import pdb;pdb.set_trace() def get_type(self, id): try: @@ -302,7 +300,7 @@ # XXX: This is a hack, proper support for recursive type is needed inp, out = channel(), channel() remote_protocol = RemoteProtocol(inp.send, out.receive, exported_names) - t = tasklet(remote_loop)(inp.send, out.receive, exported_names, remote_protocol) + t = tasklet(remote_loop)(remote_protocol) return RemoteProtocol(out.send, inp.receive) #def bootstrap(gw): Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Thu Nov 16 00:19:14 2006 @@ -122,3 +122,22 @@ assert xa.x == 3 assert len(xa) == 11 + def test_remote_doc_and_callback(self): + class A: + """xxx""" + def __init__(self): + pass + + def meth(self, x): + return x() + 3 + + def x(): + return 1 + + a = A() + + from distributed import test_env + protocol = test_env({'a':a}) + xa = protocol.get_remote('a') + assert xa.__class__.__doc__ == 'xxx' + assert xa.meth(x) == 4 From fijal at codespeak.net Thu Nov 16 00:25:23 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 16 Nov 2006 00:25:23 +0100 (CET) Subject: [pypy-svn] r34646 - in pypy/dist/pypy/lib: . test2 Message-ID: <20061115232523.B6C90100A6@code0.codespeak.net> Author: fijal Date: Thu Nov 16 00:25:22 2006 New Revision: 34646 Modified: pypy/dist/pypy/lib/distributed.py pypy/dist/pypy/lib/test2/test_distributed.py Log: Added simple fix and a fancy test. Modified: pypy/dist/pypy/lib/distributed.py ============================================================================== --- pypy/dist/pypy/lib/distributed.py (original) +++ pypy/dist/pypy/lib/distributed.py Thu Nov 16 00:25:22 2006 @@ -50,6 +50,7 @@ 2. Refactor it a bit (split class into logical/bookkeeper one) 3. Add some garbage collection 4. Add caching of objects that are presented (even on name level) +5. Add exceptions, frames and error handling """ from pypymagic import pypy_repr @@ -58,6 +59,8 @@ from marshal import dumps class AbstractProtocol(object): + immutable_primitives = (str, int, float, long, unicode, bool, types.NotImplementedType) + letter_types = { 'l' : list, 'd' : dict, @@ -68,6 +71,7 @@ 'u' : unicode, 'l' : long, 's' : str, + 'ni' : types.NotImplementedType, 'n' : types.NoneType, 'lst' : list, 'fun' : types.FunctionType, @@ -97,7 +101,7 @@ return "tp", self.remote_objects[ctrl] elif obj is None: return self.type_letters[tp] - elif tp in (str, int, float, long, unicode, bool): + elif tp in self.immutable_primitives: # simple, immutable object, just copy return (self.type_letters[tp], obj) elif tp is tuple: @@ -129,7 +133,7 @@ tp = self.letter_types[tp_letter] if tp is None: return self.objs[obj_data] - elif tp in (str, int, float, long, unicode, bool): + elif tp in self.immutable_primitives: return obj_data # this is the object elif tp is tuple: return tuple([self.unwrap(i) for i in obj_data]) Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Thu Nov 16 00:25:22 2006 @@ -141,3 +141,22 @@ xa = protocol.get_remote('a') assert xa.__class__.__doc__ == 'xxx' assert xa.meth(x) == 4 + + def test_double_reference(self): + class A: + def meth(self, one): + self.one = one + + def perform(self): + return 1 + len(self.one()) + + class B: + def __call__(self): + return [1,2,3] + + from distributed import test_env + a = A() + protocol = test_env({'a': a}) + xa = protocol.get_remote('a') + xa.meth(B()) + assert xa.perform() == 4 From pedronis at codespeak.net Thu Nov 16 00:25:39 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 16 Nov 2006 00:25:39 +0100 (CET) Subject: [pypy-svn] r34647 - in pypy/dist/pypy/translator: . test Message-ID: <20061115232539.DC55A100AB@code0.codespeak.net> Author: pedronis Date: Thu Nov 16 00:25:37 2006 New Revision: 34647 Modified: pypy/dist/pypy/translator/interactive.py pypy/dist/pypy/translator/test/test_interactive.py Log: fix for config out of sync with test. Modified: pypy/dist/pypy/translator/interactive.py ============================================================================== --- pypy/dist/pypy/translator/interactive.py (original) +++ pypy/dist/pypy/translator/interactive.py Thu Nov 16 00:25:37 2006 @@ -14,15 +14,15 @@ class Translation(object): def __init__(self, entry_point, argtypes=None, **kwds): + self.driver = driver.TranslationDriver(overrides=DEFAULTS) + self.config = self.driver.config + self.entry_point = entry_point - self.context = TranslationContext() + self.context = TranslationContext(config=self.config) # for t.view() to work just after construction graph = self.context.buildflowgraph(entry_point) self.context._prebuilt_graphs[entry_point] = graph - self.driver = driver.TranslationDriver(overrides=DEFAULTS) - self.config = self.driver.config - # hook into driver events driver_own_event = self.driver._event def _event(kind, goal, func): @@ -53,7 +53,8 @@ else: if argtypes is None: argtypes = [] - self.driver.setup(self.entry_point, argtypes, policy, empty_translator=self.context) + self.driver.setup(self.entry_point, argtypes, policy, + empty_translator=self.context) self.ann_argtypes = argtypes self.ann_policy = policy self.driver_setup = True Modified: pypy/dist/pypy/translator/test/test_interactive.py ============================================================================== --- pypy/dist/pypy/translator/test/test_interactive.py (original) +++ pypy/dist/pypy/translator/test/test_interactive.py Thu Nov 16 00:25:37 2006 @@ -8,6 +8,7 @@ t = Translation(f, [int, int]) assert t.context is t.driver.translator + assert t.config is t.driver.config is t.context.config s = t.annotate([int, int]) assert s.knowntype == int From pedronis at codespeak.net Thu Nov 16 02:05:36 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 16 Nov 2006 02:05:36 +0100 (CET) Subject: [pypy-svn] r34648 - pypy/dist/pypy/translator/tool Message-ID: <20061116010536.70115100A7@code0.codespeak.net> Author: pedronis Date: Thu Nov 16 02:05:34 2006 New Revision: 34648 Modified: pypy/dist/pypy/translator/tool/cbuild.py Log: this class was not used so far, is moved in the next check-in Modified: pypy/dist/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/dist/pypy/translator/tool/cbuild.py (original) +++ pypy/dist/pypy/translator/tool/cbuild.py Thu Nov 16 02:05:34 2006 @@ -285,25 +285,6 @@ finally: compiler.compile_extra.pop() compiler.link_extra.pop() - -class ProfInstrument(object): - name = "profinstrument" - - def __init__(self, compiler): - self.compiler = compiler - - def first(self): - self.compiler._build() - - def probe(self, exe, args): - from pypy.tool.udir import udir - from py.compat import subprocess - env = os.environ.copy() - env['_INSTRUMENT_COUNTERS'] = str(udir.join('_instrument_counters')) - subprocess.call([exe, args], env=env) - - def after(self): - pass class CCompiler: @@ -354,7 +335,7 @@ else: ProfDriver, args = self.profbased profdrv = ProfDriver(self) - dolog = getattr(log, ProfDriver.name) + dolog = getattr(log, profdrv.name) dolog(args) profdrv.first() dolog('Gathering profile data from: %s %s' % ( From pedronis at codespeak.net Thu Nov 16 02:19:26 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 16 Nov 2006 02:19:26 +0100 (CET) Subject: [pypy-svn] r34649 - in pypy/dist/pypy: config translator translator/backendopt translator/backendopt/test translator/c/test Message-ID: <20061116011926.17B68100AB@code0.codespeak.net> Author: pedronis Date: Thu Nov 16 02:18:59 2006 New Revision: 34649 Modified: pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/translator/backendopt/all.py pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/backendopt/test/test_inline.py pypy/dist/pypy/translator/c/test/test_standalone.py pypy/dist/pypy/translator/driver.py Log: profile based (call counts) inlining: --prof-based-inline= There's even a test. A first stab. Based on forking... I managed to get an -O3 executable for PyPy that's is slightly smaller but not slower. No such luck with -O2. Still kind of good considering our failures so far to reduce the inlining amount without killing the performance. Didn't spend time on tuning or playing with the parameters at all. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Thu Nov 16 02:18:59 2006 @@ -209,6 +209,10 @@ "optimizer remove the asserts", default=False), IntOption("inline_threshold", "Threshold when to inline functions", default=1, cmdline=None), + StrOption("profile_based_inline", + "Use call count profiling to drive inlining" + ", specify arguments", + default=None, cmdline="--prof-based-inline"), ]), OptionDescription("cli", "GenCLI options", [ Modified: pypy/dist/pypy/translator/backendopt/all.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/all.py (original) +++ pypy/dist/pypy/translator/backendopt/all.py Thu Nov 16 02:18:59 2006 @@ -43,35 +43,27 @@ print_statistics(translator.graphs[0], translator) if not config.clever_malloc_removal: - # inline functions in each other - if config.inline_threshold: - callgraph = inline.inlinable_static_callers(graphs) - inline.auto_inlining(translator, config.inline_threshold, - callgraph=callgraph) - for graph in graphs: - removenoops.remove_superfluous_keep_alive(graph) - removenoops.remove_duplicate_casts(graph, translator) - - if config.print_statistics: - print "after inlining:" - print_statistics(translator.graphs[0], translator) - - # vaporize mallocs - if config.mallocs: - tot = 0 - for graph in graphs: - count = remove_simple_mallocs(graph) - if count: - # remove typical leftovers from malloc removal - removenoops.remove_same_as(graph) - simplify.eliminate_empty_blocks(graph) - simplify.transform_dead_op_vars(graph, translator) - tot += count - log.malloc("removed %d simple mallocs in total" % tot) - - if config.print_statistics: - print "after malloc removal:" - print_statistics(translator.graphs[0], translator) + if config.profile_based_inline: + inline_malloc_removal_phase(config, translator, graphs, + config.inline_threshold*.5) # xxx tune! + inline.instrument_inline_candidates(graphs, config.inline_threshold) + data = translator.driver_instrument_result( + config.profile_based_inline) + import array, struct + n = data.size()//struct.calcsize('L') + data = data.open('rb') + counters = array.array('L') + counters.fromfile(data, n) + data.close() + def call_count_pred(label): + if label >= n: + return False + return counters[label] > 250 # xxx tune! + else: + call_count_pred = None + inline_malloc_removal_phase(config, translator, graphs, + config.inline_threshold, + call_count_pred=call_count_pred) else: assert graphs is translator.graphs # XXX for now clever_inlining_and_malloc_removal(translator) @@ -101,3 +93,39 @@ for graph in graphs: checkgraph(graph) + +def inline_malloc_removal_phase(config, translator, graphs, inline_threshold, + call_count_pred=None): + + log.inlining("phase with threshold factor: %s" % inline_threshold) + + # inline functions in each other + if inline_threshold: + callgraph = inline.inlinable_static_callers(graphs) + inline.auto_inlining(translator, inline_threshold, + callgraph=callgraph, + call_count_pred=call_count_pred) + for graph in graphs: + removenoops.remove_superfluous_keep_alive(graph) + removenoops.remove_duplicate_casts(graph, translator) + + if config.print_statistics: + print "after inlining:" + print_statistics(translator.graphs[0], translator) + + # vaporize mallocs + if config.mallocs: + tot = 0 + for graph in graphs: + count = remove_simple_mallocs(graph) + if count: + # remove typical leftovers from malloc removal + removenoops.remove_same_as(graph) + simplify.eliminate_empty_blocks(graph) + simplify.transform_dead_op_vars(graph, translator) + tot += count + log.malloc("removed %d simple mallocs in total" % tot) + + if config.print_statistics: + print "after malloc removal:" + print_statistics(translator.graphs[0], translator) Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Thu Nov 16 02:18:59 2006 @@ -7,7 +7,7 @@ from pypy.objspace.flow.model import FunctionGraph from pypy.objspace.flow.model import traverse, mkentrymap, checkgraph from pypy.annotation import model as annmodel -from pypy.rpython.lltypesystem.lltype import Bool, typeOf, Void, Ptr +from pypy.rpython.lltypesystem.lltype import Bool, Signed, typeOf, Void, Ptr from pypy.rpython.lltypesystem.lltype import normalizeptr from pypy.rpython import rmodel from pypy.tool.algo import sparsemat @@ -72,9 +72,10 @@ return False def inline_function(translator, inline_func, graph, lltype_to_classdef, - raise_analyzer): + raise_analyzer, call_count_pred=None): inliner = Inliner(translator, graph, inline_func, lltype_to_classdef, - raise_analyzer = raise_analyzer) + raise_analyzer = raise_analyzer, + call_count_pred=call_count_pred) return inliner.inline_all() def simple_inline_function(translator, inline_func, graph): @@ -128,7 +129,9 @@ class BaseInliner(object): def __init__(self, translator, graph, lltype_to_classdef, inline_guarded_calls=False, - inline_guarded_calls_no_matter_what=False, raise_analyzer=None): + inline_guarded_calls_no_matter_what=False, + raise_analyzer=None, + call_count_pred=None): self.translator = translator self.graph = graph self.inline_guarded_calls = inline_guarded_calls @@ -138,10 +141,12 @@ assert raise_analyzer is not None self.raise_analyzer = raise_analyzer self.lltype_to_classdef = lltype_to_classdef + self.call_count_pred = call_count_pred def inline_all(self): count = 0 non_recursive = {} + call_count_pred = self.call_count_pred while self.block_to_index: block, d = self.block_to_index.popitem() index_operation, subgraph = d.popitem() @@ -151,6 +156,13 @@ raise CannotInline("inlining a recursive function") else: non_recursive[subgraph] = True + if call_count_pred: + countop = block.operations[index_operation-1] + assert countop.opname == 'instrument_count' + assert countop.args[0].value == 'inline' + label = countop.args[1].value + if not call_count_pred(label): + continue operation = block.operations[index_operation] self.inline_once(block, index_operation) count += 1 @@ -417,12 +429,16 @@ class Inliner(BaseInliner): - def __init__(self, translator, graph, inline_func, lltype_to_classdef, inline_guarded_calls=False, - inline_guarded_calls_no_matter_what=False, raise_analyzer=None): + def __init__(self, translator, graph, inline_func, lltype_to_classdef, + inline_guarded_calls=False, + inline_guarded_calls_no_matter_what=False, + raise_analyzer=None, + call_count_pred=None): BaseInliner.__init__(self, translator, graph, lltype_to_classdef, inline_guarded_calls, inline_guarded_calls_no_matter_what, - raise_analyzer) + raise_analyzer, + call_count_pred) self.inline_func = inline_func # to simplify exception matching join_blocks(graph) @@ -447,6 +463,7 @@ 'malloc': 2, 'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme 'resume_point': sys.maxint, # XXX bit extreme + 'instrument_count': 0, } def block_weight(block, weights=OP_WEIGHTS): @@ -535,8 +552,48 @@ return result +def instrument_inline_candidates(graphs, multiplier): + threshold = BASE_INLINE_THRESHOLD * multiplier + cache = {None: False} + def candidate(graph): + try: + return cache[graph] + except KeyError: + res = static_instruction_count(graph) <= threshold + cache[graph] = res + return res + n = 0 + for parentgraph in graphs: + for block in parentgraph.iterblocks(): + ops = block.operations + i = len(ops)-1 + while i >= 0: + op = ops[i] + i -= 1 + if op.opname == "direct_call": + funcobj = op.args[0].value._obj + graph = getattr(funcobj, 'graph', None) + if graph is not None: + if getattr(getattr(funcobj, '_callable', None), + 'suggested_primitive', False): + continue + if getattr(getattr(funcobj, '_callable', None), + 'dont_inline', False): + continue + if candidate(graph): + tag = Constant('inline', Void) + label = Constant(n, Signed) + dummy = Variable() + dummy.concretetype = Void + count = SpaceOperation('instrument_count', + [tag, label], dummy) + ops.insert(i+1, count) + n += 1 + log.inlining("%d call sites instrumented" % n) + def auto_inlining(translator, multiplier=1, callgraph=None, - threshold=BASE_INLINE_THRESHOLD): + threshold=BASE_INLINE_THRESHOLD, + call_count_pred=None): from heapq import heappush, heappop, heapreplace, heapify threshold = threshold * multiplier callers = {} # {graph: {graphs-that-call-it}} @@ -587,7 +644,8 @@ continue try: res = bool(inline_function(translator, graph, parentgraph, - lltype_to_classdef, raise_analyzer)) + lltype_to_classdef, raise_analyzer, + call_count_pred)) except CannotInline: couldnt_inline[graph] = True res = CannotInline 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 Nov 16 02:18:59 2006 @@ -8,6 +8,7 @@ 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.backendopt.inline import instrument_inline_candidates from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.llinterp import LLInterpreter from pypy.rlib.rarithmetic import ovfcheck @@ -66,16 +67,25 @@ return interp.eval_graph(graphof(t, entry), args) return eval_func -def check_auto_inlining(func, sig, multiplier=None): +def check_auto_inlining(func, sig, multiplier=None, call_count_check=False): t = translate(func, sig) if option.view: t.view() # inline! sanity_check(t) # also check before inlining (so we don't blame it) - if multiplier is None: - auto_inlining(t) + + if multiplier is not None: + multiplier = {'multiplier': multiplier} else: - auto_inlining(t, multiplier=multiplier) + multiplier = {} + + call_count_pred = None + if call_count_check: + call_count_pred = lambda lbl: True + instrument_inline_candidates(t.graphs, **multiplier) + + auto_inlining(t, call_count_pred=call_count_pred, **multiplier) + sanity_check(t) if option.view: t.view() @@ -364,6 +374,33 @@ result = eval_func([15]) assert result == -1 +def test_auto_inlining_small_call_big_call_count(): + def leaf(n): + total = 0 + i = 0 + while i < n: + total += i + if total > 100: + raise OverflowError + i += 1 + return total + def g(n): + return leaf(n) + def f(n): + try: + return g(n) + except OverflowError: + return -1 + eval_func, t = check_auto_inlining(f, [int], multiplier=10, + call_count_check=True) + f_graph = graphof(t, f) + assert len(collect_called_graphs(f_graph, t)) == 0 + + result = eval_func([10]) + assert result == 45 + result = eval_func([15]) + assert result == -1 + def test_inline_exception_catching(): def f3(): raise CustomError1 Modified: pypy/dist/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/dist/pypy/translator/c/test/test_standalone.py (original) +++ pypy/dist/pypy/translator/c/test/test_standalone.py Thu Nov 16 02:18:59 2006 @@ -87,3 +87,24 @@ counters = struct.unpack("LLL", counters_data) assert counters == (0,3,2) + +def test_prof_inline(): + if sys.platform == 'win32': + py.test.skip("instrumentation support is unix only for now") + def add(a,b): + return a + b - b + b - b + b - b + b - b + b - b + b - b + b + def entry_point(argv): + tot = 0 + x = int(argv[1]) + while x > 0: + tot = add(tot, x) + x -= 1 + os.write(1, str(tot)) + return 0 + from pypy.translator.interactive import Translation + t = Translation(entry_point, backend='c', standalone=True) + t.backendopt(profile_based_inline="500") + exe = t.compile() + out = py.process.cmdexec("%s 500" % exe) + assert int(out) == 500*501/2 + Modified: pypy/dist/pypy/translator/driver.py ============================================================================== --- pypy/dist/pypy/translator/driver.py (original) +++ pypy/dist/pypy/translator/driver.py Thu Nov 16 02:18:59 2006 @@ -51,6 +51,31 @@ def backend_to_typesystem(backend): return _BACKEND_TO_TYPESYSTEM.get(backend, 'ootype') + +class Instrument(Exception): + pass + + +class ProfInstrument(object): + name = "profinstrument" + def __init__(self, datafile, compiler): + self.datafile = datafile + self.compiler = compiler + + def first(self): + self.compiler._build() + + def probe(self, exe, args): + from py.compat import subprocess + env = os.environ.copy() + env['_INSTRUMENT_COUNTERS'] = str(self.datafile) + subprocess.call([exe, args], env=env) + + def after(self): + # xxx + os._exit(0) + + class TranslationDriver(SimpleTaskEngine): def __init__(self, setopts=None, default_goal=None, disable=[], @@ -183,6 +208,34 @@ self.entry_point = entry_point self.translator = translator + self.translator.driver_instrument_result = self.instrument_result + + def instrument_result(self, args): + backend, ts = self.get_backend_and_type_system() + if backend != 'c' or sys.platform == 'win32': + raise Exception("instrumentation requires the c backend" + " and unix for now") + from pypy.tool.udir import udir + + datafile = udir.join('_instrument_counters') + makeProfInstrument = lambda compiler: ProfInstrument(datafile, compiler) + + pid = os.fork() + if pid == 0: + # child compiling and running with instrumentation + self.config.translation.instrument = True + self.config.translation.instrumentctl = (makeProfInstrument, + args) + raise Instrument + else: + pid, status = os.waitpid(pid, 0) + if os.WIFEXITED(status): + status = os.WEXITSTATUS(status) + if status != 0: + raise Exception, "instrumentation child failed: %d" % status + else: + raise Exception, "instrumentation child aborted" + return datafile def info(self, msg): log.info(msg) @@ -194,9 +247,16 @@ return else: self.log.info("%s..." % title) - res = func() + instrument = False + try: + res = func() + except Instrument: + instrument = True if not func.task_idempotent: self.done[goal] = True + if instrument: + self.proceed('compile') + assert False, 'we should not get here' return res def task_annotate(self): From cfbolz at codespeak.net Thu Nov 16 10:55:44 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Nov 2006 10:55:44 +0100 (CET) Subject: [pypy-svn] r34654 - pypy/dist/pypy/objspace/std/test Message-ID: <20061116095544.32EE3100B6@code0.codespeak.net> Author: cfbolz Date: Thu Nov 16 10:55:41 2006 New Revision: 34654 Modified: pypy/dist/pypy/objspace/std/test/test_strjoinobject.py Log: this was fixed, un-skipping test Modified: pypy/dist/pypy/objspace/std/test/test_strjoinobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_strjoinobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_strjoinobject.py Thu Nov 16 10:55:41 2006 @@ -15,7 +15,6 @@ assert 'W_StringJoinObject' in pypymagic.pypy_repr(s) def test_add_twice(self): - skip("minimal failing test") x = "a" + "" y = x + "b" c = x + "b" From arigo at codespeak.net Thu Nov 16 11:36:57 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Nov 2006 11:36:57 +0100 (CET) Subject: [pypy-svn] r34655 - pypy/dist/demo Message-ID: <20061116103657.1C264100B4@code0.codespeak.net> Author: arigo Date: Thu Nov 16 11:36:56 2006 New Revision: 34655 Added: pypy/dist/demo/pickle_coroutine.py Log: A stackless coroutine pickling demo. Added: pypy/dist/demo/pickle_coroutine.py ============================================================================== --- (empty file) +++ pypy/dist/demo/pickle_coroutine.py Thu Nov 16 11:36:56 2006 @@ -0,0 +1,84 @@ +""" +Stackless demo. + +This example only works on top of a pypy-c compiled with stackless features +and the signal module: + + translate.py --stackless targetpypystandalone --withmod-signal + +Usage: + + pypy-c pickle_coroutine.py --start demo.pickle + + Start the computation. You can interrupt it at any time by + pressing Ctrl-C; at this point, the state of the computing + coroutine is saved in demo.pickle. + + pypy-c pickle_coroutine.py --resume demo.pickle + + Reload the coroutine from demo.pickle and continue running it. + (It can be interrupted again with Ctrl-C.) +""" + +try: + import sys, pickle, signal + from stackless import coroutine +except ImportError: + print __doc__ + sys.exit(2) + + +def ackermann(x, y): + check() + if x == 0: + return y + 1 + if y == 0: + return ackermann(x - 1, 1) + return ackermann(x - 1, ackermann(x, y - 1)) + +# ____________________________________________________________ + +main = coroutine.getcurrent() +sys.setrecursionlimit(100000) + +interrupt_flag = False + +def interrupt_handler(*args): + global interrupt_flag + interrupt_flag = True + +def check(): + if interrupt_flag: + main.switch() + + +def execute(coro): + signal.signal(signal.SIGINT, interrupt_handler) + res = coro.switch() + if res is None and coro.is_alive: # interrupted! + print "interrupted! writing %s..." % (filename,) + f = open(filename, 'w') + pickle.dump(coro, f) + f.close() + print "done" + else: + print "result:", res + +try: + operation, filename = sys.argv[1:] +except ValueError: + print __doc__ + sys.exit(2) + +if operation == '--start': + coro = coroutine() + coro.bind(ackermann, 3, 7) + print "running from the start..." + execute(coro) +elif operation == '--resume': + print "reloading %s..." % (filename,) + f = open(filename) + coro = pickle.load(f) + f.close() + print "done, running now..." + execute(coro) From ac at codespeak.net Thu Nov 16 11:48:57 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Nov 2006 11:48:57 +0100 (CET) Subject: [pypy-svn] r34656 - pypy/dist/pypy/jit/timeshifter/test Message-ID: <20061116104857.8111B100B7@code0.codespeak.net> Author: ac Date: Thu Nov 16 11:48:56 2006 New Revision: 34656 Modified: pypy/dist/pypy/jit/timeshifter/test/test_tlc.py Log: This test passes so enable it. Modified: pypy/dist/pypy/jit/timeshifter/test/test_tlc.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_tlc.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_tlc.py Thu Nov 16 11:48:56 2006 @@ -36,7 +36,6 @@ assert res == expected def test_nth_item(self): - py.test.skip("in-progress") # get the nth item of a chained list code = tlc.compile(""" NIL @@ -50,6 +49,8 @@ DIV """) bytecode = ','.join([str(ord(c)) for c in code]) - res = self.timeshift(tlc_interp_without_call, [bytecode, 0, 1], - [0, 1], policy=P_OOPSPEC)#, backendoptimize=True) + res = self.timeshift_from_portal(tlc_interp_without_call, + tlc_interp_eval_without_call, + [bytecode, 0, 1], + policy=P_OOPSPEC)#, backendoptimize=True) assert res == 20 From arigo at codespeak.net Thu Nov 16 12:29:43 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Nov 2006 12:29:43 +0100 (CET) Subject: [pypy-svn] r34658 - pypy/dist/pypy/doc Message-ID: <20061116112943.38C59100BB@code0.codespeak.net> Author: arigo Date: Thu Nov 16 12:29:41 2006 New Revision: 34658 Modified: pypy/dist/pypy/doc/_ref.txt pypy/dist/pypy/doc/stackless.txt Log: Small fixes, and "example" and "limitations" sections for coroutine pickling. Modified: pypy/dist/pypy/doc/_ref.txt ============================================================================== --- pypy/dist/pypy/doc/_ref.txt (original) +++ pypy/dist/pypy/doc/_ref.txt Thu Nov 16 12:29:41 2006 @@ -1,4 +1,5 @@ .. _`demo/`: ../../demo +.. _`demo/pickle_coroutine.py`: ../../demo/pickle_coroutine.py .. _`lib-python/`: ../../lib-python .. _`lib-python/2.4.1/dis.py`: ../../lib-python/2.4.1/dis.py .. _`annotation/`: @@ -48,7 +49,10 @@ .. _`objspace/thunk.py`: ../../pypy/objspace/thunk.py .. _`objspace/trace.py`: .. _`pypy/objspace/trace.py`: ../../pypy/objspace/trace.py +.. _`pypy/rlib`: ../../pypy/rlib .. _`pypy/rlib/objectmodel.py`: ../../pypy/rlib/objectmodel.py +.. _`pypy/rlib/rarithmetic.py`: ../../pypy/rlib/rarithmetic.py +.. _`pypy/rlib/test`: ../../pypy/rlib/test .. _`pypy/rpython`: .. _`pypy/rpython/`: .. _`rpython/`: ../../pypy/rpython Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Thu Nov 16 12:29:41 2006 @@ -135,7 +135,7 @@ as possible. This makes the code somewhat unpythonic. Bird's eye view of tasklets and channels ----------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tasklets are a bit like threads: they encapsulate a function in such a way that they can be suspended/restarted any time. Unlike threads, they won't @@ -169,8 +169,14 @@ precise tree, which fully determines their order of execution. For usage reference, see the documentation of the `Py lib greenlets`_. -The PyPy interface is identical, except that the ``greenlet`` class is -in the ``stackless`` module instead of in the ``py.magic`` module. +The PyPy interface is identical. You should use ``py.magic.greenlet`` +instead of ``stackless.greenlet`` directly, because the Py lib can now +give you the latter when you ask for the former on top of PyPy. + +PyPy's greenlets do not suffer from the cyclic GC limitation that the +CPython greenlets have: greenlets referencing each other via local +variables tend to leak on top of CPython (where it is mostly impossible +to do the right thing). It works correctly on top of PyPy. Coroutine Pickling @@ -222,7 +228,99 @@ interface that allows an RPython program to artifically rebuild a chain of calls in a reflective way, completely from scratch, and jump to it. -XXX examples, limitations? +Example +~~~~~~~ + +(See `demo/pickle_coroutine.py`_ for the complete source of this demo.) + +Consider a program which contains a part performing a long-running +computation:: + + def ackermann(x, y): + if x == 0: + return y + 1 + if y == 0: + return ackermann(x - 1, 1) + return ackermann(x - 1, ackermann(x, y - 1)) + +By using pickling, we can save the state of the computation while it is +running, for the purpose of restoring it later and continuing the +computation at another time or on a different machine. However, +pickling does not produce a whole-program dump: it can only pickle +individual coroutines. This means that the computation should be +started in its own coroutine:: + + # Make a coroutine that will run 'ackermann(3, 8)' + coro = coroutine() + coro.bind(ackermann, 3, 8) + + # Now start running the coroutine + result = coro.switch() + +The coroutine itself must switch back to the main program when it needs +to be interrupted (we can only pickle suspended coroutines). Due to +current limitations this requires an explicit check in the +``ackermann()`` function:: + + def ackermann(x, y): + if interrupt_flag: # test a global flag + main.switch() # and switch back to 'main' if it is set + if x == 0: + return y + 1 + if y == 0: + return ackermann(x - 1, 1) + return ackermann(x - 1, ackermann(x, y - 1)) + +The global ``interrupt_flag`` would be set for example by a timeout, or +by a signal handler reacting to Ctrl-C, etc. It causes the coroutine to +transfer control back to the main program. The execution comes back +just after the line ``coro.switch()``, where we can pickle the coroutine +if necessary:: + + if not coro.is_alive: + print "finished; the result is:", result + else: + # save the state of the suspended coroutine + f = open('demo.pickle', 'w') + pickle.dump(coro, f) + f.close() + +The process can then stop. At any later time, or on another machine, +we can reload the file and restart the coroutine with:: + + f = open('demo.pickle', 'r') + coro = pickle.load(f) + f.close() + result = coro.switch() + +Limitations +~~~~~~~~~~~ + +Coroutine pickling is subject to some limitations. First of all, it is +not a whole-program "memory dump". It means that only the "local" state +of a coroutine is saved. The local state is defined to include the +chain of calls and the local variables, but not for example the value of +any global variable. + +As in normal Python, the pickle will not include any function object's +code, any class definition, etc., but only references to functions and +classes. Unlike normal Python, the pickle contains frames. A pickled +frame stores a bytecode index, representing the current execution +position. This means that the user program cannot be modified *at all* +between pickling and unpickling! + +On the other hand, the pickled data is fairly independent from the +platform and from the PyPy version. + +Pickling/unpickling fails if the coroutine is suspended in a state that +involves Python frames which were *indirectly* called. To define this +more precisely, a Python function can issue a regular function or method +call to invoke another Python function - this is a *direct* call and can +be pickled and unpickled. But there are many ways to invoke a Python +function indirectly. For example, most operators can invoke a special +method ``__xyz__()`` on a class, various built-in functions can call +back Python functions, signals can invoke signal handlers, and so on. +These cases are not supported yet. Coroutine Cloning From arigo at codespeak.net Thu Nov 16 12:47:00 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Nov 2006 12:47:00 +0100 (CET) Subject: [pypy-svn] r34660 - pypy/dist/pypy/doc Message-ID: <20061116114700.EDECC100C3@code0.codespeak.net> Author: arigo Date: Thu Nov 16 12:46:59 2006 New Revision: 34660 Modified: pypy/dist/pypy/doc/stackless.txt Log: A basic coroutine example. Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Thu Nov 16 12:46:59 2006 @@ -112,6 +112,42 @@ catch it, and that ``try: finally:`` clauses are not honored. This will be fixed in the future.) +Example +~~~~~~~ + +Here is a classical producer/consumer example: an algorithm computes a +sequence of values, while another consumes them. For our purposes we +assume that the producer can generate several values at once, and the +consumer can process up to 3 values in a batch - it can also process +batches with less than 3 values without waiting for the producer (which +would be messy to express with a classical Python generator). :: + + def producer(lst): + while True: + ...compute some more values... + lst.extend(new_values) + coro_consumer.switch() + + def consumer(lst): + while True: + # First ask the producer for more values if needed + while len(lst) == 0: + coro_producer.switch() + # Process the available values in a batch, but at most 3 + batch = lst[:3] + del lst[:3] + ... process batch ... + + # Initialize two coroutines with a shared list as argument + exchangelst = [] + coro_producer = coroutine() + coro_producer.bind(producer, exchangelst) + coro_consumer = coroutine() + coro_consumer.bind(consumer, exchangelst) + + # Start running the consumer coroutine + coro_consumer.switch() + Tasklets and channels +++++++++++++++++++++ From cfbolz at codespeak.net Thu Nov 16 12:48:02 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Nov 2006 12:48:02 +0100 (CET) Subject: [pypy-svn] r34661 - in pypy/dist/pypy: lib lib/test2 module/__builtin__ Message-ID: <20061116114802.8DBFF100CE@code0.codespeak.net> Author: cfbolz Date: Thu Nov 16 12:48:00 2006 New Revision: 34661 Removed: pypy/dist/pypy/lib/_osfilewrapper.py pypy/dist/pypy/lib/test2/test_osfilewrapper.py Modified: pypy/dist/pypy/module/__builtin__/importing.py Log: remove _osfilewrapper and use streamio instead Modified: pypy/dist/pypy/module/__builtin__/importing.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/importing.py (original) +++ pypy/dist/pypy/module/__builtin__/importing.py Thu Nov 16 12:48:00 2006 @@ -9,31 +9,16 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace from pypy.interpreter.eval import Code -from pypy.lib._osfilewrapper import OsFileWrapper +from pypy.rlib import streamio from pypy.rlib.rarithmetic import intmask -# XXX this uses the os.path module at interp-level, which means -# XXX that translate_pypy will produce a translated version of -# XXX PyPy that will only run on the same platform, as it contains -# XXX a frozen version of some routines of only one of the -# XXX posixpath/ntpath/macpath modules. - -try: - BIN_READMASK = os.O_BINARY | os.O_RDONLY - BIN_WRITEMASK = os.O_BINARY | os.O_RDWR | os.O_CREAT -except AttributeError: - BIN_READMASK = os.O_RDONLY - BIN_WRITEMASK = os.O_RDWR | os.O_CREAT - NOFILE = 0 PYFILE = 1 PYCFILE = 2 -import stat - PYC_ONOFF = True -def info_modtype(space ,filepart): +def info_modtype(space, filepart): """ calculate whether the .py file exists, the .pyc file exists and whether the .pyc file has the correct mtime entry. @@ -99,11 +84,11 @@ e = None if modtype == PYFILE: filename = filepart + ".py" - fd = os.open(filename, os.O_RDONLY, 0666) + stream = streamio.open_file_as_stream(filename, "r") else: assert modtype == PYCFILE filename = filepart + ".pyc" - fd = os.open(filename, BIN_READMASK, 0666) + stream = streamio.open_file_as_stream(filename, "rb") space.sys.setmodule(w_mod) space.setattr(w_mod, w('__file__'), space.wrap(filename)) @@ -112,14 +97,13 @@ space.setattr(w_mod, w('__path__'), space.newlist([w(pkgdir)])) try: - osfile = OsFileWrapper(fd) try: if modtype == PYFILE: - load_source_module(space, w_modulename, w_mod, filename, osfile) + load_source_module(space, w_modulename, w_mod, filename, stream) else: - load_compiled_module(space, w_modulename, w_mod, filename, osfile) + load_compiled_module(space, w_modulename, w_mod, filename, stream) finally: - osfile.close() + stream.close() except OperationError, e: w_mods = space.sys.get('modules') @@ -130,7 +114,7 @@ if w_mod is not None and w_parent is not None: space.setattr(w_parent, w_name, w_mod) if e: - raise e + raise e return w_mod def try_getattr(space, w_obj, w_name): @@ -349,34 +333,33 @@ pyc_magic = MAGIC -def parse_source_module(space, pathname, osfile): +def parse_source_module(space, pathname, stream): """ Parse a source file and return the corresponding code object """ w = space.wrap - size = os.fstat(osfile.fd)[stat.ST_SIZE] - source = osfile.read(size) + source = stream.readall() w_source = w(source) w_mode = w("exec") w_pathname = w(pathname) - w_code = space.builtin.call('compile', w_source, w_pathname, w_mode) + w_code = space.builtin.call('compile', w_source, w_pathname, w_mode) pycode = space.interp_w(Code, w_code) return pycode -def load_source_module(space, w_modulename, w_mod, pathname, osfile): +def load_source_module(space, w_modulename, w_mod, pathname, stream): """ Load a source module from a given file and return its module object. """ w = space.wrap - pycode = parse_source_module(space, pathname, osfile) + pycode = parse_source_module(space, pathname, stream) w_dict = space.getattr(w_mod, w('__dict__')) - space.call_method(w_dict, 'setdefault', - w('__builtins__'), + space.call_method(w_dict, 'setdefault', + w('__builtins__'), w(space.builtin)) - pycode.exec_code(space, w_dict, w_dict) + pycode.exec_code(space, w_dict, w_dict) if PYC_ONOFF: - mtime = os.fstat(osfile.fd)[stat.ST_MTIME] + mtime = os.stat(pathname)[stat.ST_MTIME] cpathname = pathname + 'c' write_compiled_module(space, pycode, cpathname, mtime) @@ -385,8 +368,8 @@ # helper, to avoid exposing internals of marshal and the # difficulties of using it though applevel. _r_correction = intmask(1L<<32) # == 0 on 32-bit machines -def _r_long(osfile): - s = osfile.read(4) +def _r_long(stream): + s = stream.read(4) # XXX XXX could return smaller string if len(s) < 4: return -1 # good enough for our purposes a = ord(s[0]) @@ -398,7 +381,7 @@ x -= _r_correction return int(x) -def _w_long(osfile, x): +def _w_long(stream, x): a = x & 0xff x >>= 8 b = x & 0xff @@ -406,7 +389,7 @@ c = x & 0xff x >>= 8 d = x & 0xff - osfile.write(chr(a) + chr(b) + chr(c) + chr(d)) + stream.write(chr(a) + chr(b) + chr(c) + chr(d)) def check_compiled_module(space, pathname, mtime, cpathname): """ @@ -423,31 +406,28 @@ #XXX debug #print "skipped checking of", cpathname return -1 - fd = os.open(cpathname, BIN_READMASK, 0666) # using no defaults - osfile = OsFileWrapper(fd) - magic = _r_long(osfile) + stream = streamio.open_file_as_stream(cpathname, "rb") + magic = _r_long(stream) try: if magic != pyc_magic: # XXX what to do about Py_VerboseFlag ? # PySys_WriteStderr("# %s has bad magic\n", cpathname); return -1 - pyc_mtime = _r_long(osfile) + pyc_mtime = _r_long(stream) if pyc_mtime != mtime: # PySys_WriteStderr("# %s has bad mtime\n", cpathname); return 0 # if (Py_VerboseFlag) # PySys_WriteStderr("# %s matches %s\n", cpathname, pathname); finally: - os.close(fd) + stream.close() return 1 -def read_compiled_module(space, cpathname, osfile): +def read_compiled_module(space, cpathname, stream): """ Read a code object from a file and check it for validity """ w_marshal = space.getbuiltinmodule('marshal') - fd = osfile.fd - size = os.fstat(fd)[stat.ST_SIZE] - os.lseek(fd, 0, 1) - strbuf = osfile.read(size) + strbuf = stream.readall() w_code = space.call_method(w_marshal, 'loads', space.wrap(strbuf)) pycode = space.interpclass_w(w_code) if pycode is None or not isinstance(pycode, Code): @@ -455,19 +435,19 @@ "Non-code object in %s" % cpathname)) return pycode -def load_compiled_module(space, w_modulename, w_mod, cpathname, osfile): +def load_compiled_module(space, w_modulename, w_mod, cpathname, stream): """ Load a module from a compiled file, execute it, and return its module object. """ w = space.wrap - magic = _r_long(osfile) + magic = _r_long(stream) if magic != pyc_magic: raise OperationError(space.w_ImportError, w( "Bad magic number in %s" % cpathname)) - _r_long(osfile) # skip time stamp + _r_long(stream) # skip time stamp #print "loading pyc file:", cpathname - code_w = read_compiled_module(space, cpathname, osfile) + code_w = read_compiled_module(space, cpathname, stream) #if (Py_VerboseFlag) # PySys_WriteStderr("import %s # precompiled from %s\n", # name, cpathname); @@ -509,24 +489,23 @@ # too much like a valid pyc file but really isn't one. # try: - fd = os.open(cpathname, BIN_WRITEMASK, 0666) + stream = streamio.open_file_as_stream(cpathname, "wb") except OSError: return # cannot create file try: - osfile = OsFileWrapper(fd) try: # will patch the header later; write zeroes until we are sure that # the rest of the file is valid - _w_long(osfile, 0) # pyc_magic - _w_long(osfile, 0) # mtime - osfile.write(strbuf) + _w_long(stream, 0) # pyc_magic + _w_long(stream, 0) # mtime + stream.write(strbuf) # should be ok (XXX or should call os.fsync() to be sure?) - osfile.seek(0) - _w_long(osfile, pyc_magic) - _w_long(osfile, mtime) + stream.seek(0, 0) + _w_long(stream, pyc_magic) + _w_long(stream, mtime) finally: - osfile.close() + stream.close() except OSError: try: os.unlink(cpathname) From cfbolz at codespeak.net Thu Nov 16 14:02:18 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Nov 2006 14:02:18 +0100 (CET) Subject: [pypy-svn] r34665 - in pypy/dist/pypy: config module/__builtin__ Message-ID: <20061116130218.7018D100BD@code0.codespeak.net> Author: cfbolz Date: Thu Nov 16 14:02:16 2006 New Revision: 34665 Modified: pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/module/__builtin__/importing.py Log: add a config option to make it possible to completely disable pyc files Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Thu Nov 16 14:02:16 2006 @@ -58,6 +58,9 @@ BoolOption("logbytecodes", "keep track of bytecode usage", default=False), + + BoolOption("usepycfiles", "Write and read pyc files when importing", + default=True), OptionDescription("std", "Standard Object Space Options", [ BoolOption("withtproxy", "support transparent proxies", Modified: pypy/dist/pypy/module/__builtin__/importing.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/importing.py (original) +++ pypy/dist/pypy/module/__builtin__/importing.py Thu Nov 16 14:02:16 2006 @@ -16,8 +16,6 @@ PYFILE = 1 PYCFILE = 2 -PYC_ONOFF = True - def info_modtype(space, filepart): """ calculate whether the .py file exists, the .pyc file exists @@ -36,7 +34,7 @@ pyfile_exist = False pycfile = filepart + ".pyc" - if PYC_ONOFF and os.path.exists(pycfile): + if space.config.objspace.usepycfiles and os.path.exists(pycfile): pyc_state = check_compiled_module(space, pyfile, pyfile_ts, pycfile) pycfile_exists = pyc_state >= 0 pycfile_ts_valid = pyc_state > 0 or (pyc_state == 0 and not pyfile_exist) @@ -358,7 +356,7 @@ w(space.builtin)) pycode.exec_code(space, w_dict, w_dict) - if PYC_ONOFF: + if space.config.objspace.usepycfiles: mtime = os.stat(pathname)[stat.ST_MTIME] cpathname = pathname + 'c' write_compiled_module(space, pycode, cpathname, mtime) From esmljaos at codespeak.net Thu Nov 16 15:15:03 2006 From: esmljaos at codespeak.net (esmljaos at codespeak.net) Date: Thu, 16 Nov 2006 15:15:03 +0100 (CET) Subject: [pypy-svn] r34670 - pypy/dist/pypy/rpython Message-ID: <20061116141503.76C6E100D2@code0.codespeak.net> Author: esmljaos Date: Thu Nov 16 15:15:02 2006 New Revision: 34670 Modified: pypy/dist/pypy/rpython/callparse.py Log: (arre, iko, oscar, pedronis) fix this code to work both for oo/ll type systems, it seems is not really used by PyPy tough. Modified: pypy/dist/pypy/rpython/callparse.py ============================================================================== --- pypy/dist/pypy/rpython/callparse.py (original) +++ pypy/dist/pypy/rpython/callparse.py Thu Nov 16 15:15:02 2006 @@ -1,6 +1,6 @@ from pypy.interpreter.argument import Arguments, ArgErr from pypy.annotation import model as annmodel -from pypy.rpython.lltypesystem import rtuple # XXX not independent of type system! +from pypy.rpython import rtuple from pypy.rpython.error import TyperError from pypy.rpython.lltypesystem import lltype @@ -137,12 +137,12 @@ return self.holders def _emit(self, repr, hop): - assert isinstance(repr, rtuple.TupleRepr) + assert isinstance(repr, rtuple.AbstractTupleRepr) tupleitems_v = [] for h in self.holders: v = h.emit(repr.items_r[len(tupleitems_v)], hop) tupleitems_v.append(v) - vtuple = rtuple.newtuple(hop.llops, repr, tupleitems_v) + vtuple = repr.newtuple(hop.llops, repr, tupleitems_v) return vtuple From arigo at codespeak.net Thu Nov 16 15:39:15 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Nov 2006 15:39:15 +0100 (CET) Subject: [pypy-svn] r34672 - pypy/dist/pypy/objspace/std/test Message-ID: <20061116143915.ADEDC100D9@code0.codespeak.net> Author: arigo Date: Thu Nov 16 15:39:14 2006 New Revision: 34672 Modified: pypy/dist/pypy/objspace/std/test/test_multimethod.py Log: - reorganize the test to check both multimethod installer versions - add a systematic test Modified: pypy/dist/pypy/objspace/std/test/test_multimethod.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_multimethod.py (original) +++ pypy/dist/pypy/objspace/std/test/test_multimethod.py Thu Nov 16 15:39:14 2006 @@ -1,7 +1,8 @@ import autopath from py.test import raises -from pypy.objspace.std.multimethod import * +from pypy.objspace.std import multimethod +from pypy.objspace.std.multimethod import FailedToImplement class W_Root(object): @@ -20,90 +21,169 @@ assert isinstance(w_x, W_BoolObject) return W_IntObject() -add = MultiMethodTable(2, root_class=W_Root, argnames_before=['space']) - def add__Int_Int(space, w_x, w_y): assert space == 'space' assert isinstance(w_x, W_IntObject) assert isinstance(w_y, W_IntObject) return 'fine' -add.register(add__Int_Int, W_IntObject, W_IntObject) + +class TestMultiMethod1: + Installer = multimethod.InstallerVersion1 + + def setup_class(cls): + cls.prev_installer = multimethod.Installer + multimethod.Installer = cls.Installer + add = multimethod.MultiMethodTable(2, root_class=W_Root, + argnames_before=['space']) + add.register(add__Int_Int, W_IntObject, W_IntObject) + typeorder = { + W_IntObject: [(W_IntObject, None), (W_Root, None)], + W_BoolObject: [(W_BoolObject, None), (W_IntObject, delegate_b2i), + (W_Root, None)], + W_StringObject: [(W_StringObject, None), (W_Root, None)], + } + cls.typeorder = typeorder + cls.add = add + cls.add1 = staticmethod(add.install('__add', [typeorder, typeorder])) + + def teardown_class(cls): + multimethod.Installer = cls.prev_installer + + def test_simple(self): + space = 'space' + w_x = W_IntObject() + w_y = W_IntObject() + assert self.add1(space, w_x, w_y) == 'fine' + + def test_failtoimplement(self): + space = 'space' + w_x = W_IntObject() + w_s = W_StringObject() + raises(FailedToImplement, "self.add1(space, w_x, w_s)") + raises(FailedToImplement, "self.add1(space, w_s, w_x)") + + def test_delegate(self): + space = 'space' + w_x = W_IntObject() + w_s = W_StringObject() + w_b = W_BoolObject() + assert self.add1(space, w_x, w_b) == 'fine' + assert self.add1(space, w_b, w_x) == 'fine' + assert self.add1(space, w_b, w_b) == 'fine' + raises(FailedToImplement, "self.add1(space, w_b, w_s)") + raises(FailedToImplement, "self.add1(space, w_s, w_b)") + + def test_not_baked(self): + typeorder = self.typeorder + add2 = self.add.install('__add2', [typeorder, typeorder], + baked_perform_call=False) + assert add2[0] == ['space', 'arg0', 'arg1'] + if multimethod.Installer is multimethod.InstallerVersion1: + assert add2[1] == 'arg0.__add2(space, arg1)' + assert isinstance(add2[2], dict) + assert not add2[3] + + def test_empty(self): + add3_installer = multimethod.Installer(self.add, '__add3', [{},{}]) + assert add3_installer.is_empty() + if multimethod.Installer is multimethod.InstallerVersion1: + assert len(add3_installer.to_install) == 1 + assert add3_installer.to_install[0][0] is None + + def test_empty_direct(self): + assert not self.add.install_if_not_empty('__add4', [{},{}]) + + def test_empty_not_baked(self): + add5_installer = multimethod.Installer(self.add, '__add5', [{},{}], + baked_perform_call=False) + assert add5_installer.is_empty() + if multimethod.Installer is multimethod.InstallerVersion1: + assert len(add5_installer.to_install) == 0 + add5 = add5_installer.install() + assert add5[0] == ['space', 'arg0', 'arg1'] + assert add5[1] == 'raiseFailedToImplement()' + assert isinstance(add5[2], dict) + assert add5[3] + + def test_mmdispatcher(self): + typeorder = self.typeorder + add2 = multimethod.MMDispatcher(self.add, [typeorder, typeorder]) + space = 'space' + w_x = W_IntObject() + w_s = W_StringObject() + w_b1 = W_BoolObject() + w_b2 = W_BoolObject() + assert add2(space, w_x, w_b1) == 'fine' + assert add2(space, w_b2, w_x) == 'fine' + assert add2(space, w_b1, w_b2) == 'fine' + raises(FailedToImplement, "add2(space, w_b2, w_s)") + raises(FailedToImplement, "add2(space, w_s, w_b1)") + + def test_all_cases(self): + import random + space = 'space' + w_x = W_IntObject() + w_x.expected = [W_IntObject, W_Root] + w_s = W_StringObject() + w_s.expected = [W_StringObject, W_Root] + w_b = W_BoolObject() + w_b.expected = [W_BoolObject, W_IntObject, W_Root] + + def test(indices): + sub = multimethod.MultiMethodTable(2, root_class=W_Root, + argnames_before=['space']) + def addimpl(cls1, cls2): + token = random.random() + def sub__cls1_cls2(space, w_x, w_y): + assert space == 'space' + assert isinstance(w_x, cls1) + assert isinstance(w_y, cls2) + return token + sub.register(sub__cls1_cls2, cls1, cls2) + return token + + def check(w1, w2): + try: + res = sub1(space, w1, w2) + except FailedToImplement: + res = FailedToImplement + for cls1 in w1.expected: + for cls2 in w2.expected: + if (cls1, cls2) in expected: + assert res == expected[cls1, cls2] + return + else: + assert res is FailedToImplement + + random.shuffle(indices) + expected = {} + for index in indices: + cls1, cls2 = choices[index] + token = addimpl(cls1, cls2) + expected[cls1, cls2] = token + + typeorder = self.typeorder + sub1 = sub.install('__sub', [typeorder, typeorder]) + for w1 in [w_x, w_s, w_b]: + for w2 in [w_x, w_s, w_b]: + check(w1, w2) + + classes = [W_Root, W_StringObject, W_IntObject, W_BoolObject] + choices = [(cls1, cls2) for cls1 in classes + for cls2 in classes] + # each choice is a pair of classes which can be implemented or + # not by the multimethod 'sub'. Test all combinations that + # involve at most three implemented choices. + for i in range(len(choices)): + test([i]) + for j in range(i+1, len(choices)): + test([i, j]) + for k in range(j+1, len(choices)): + test([i, j, k]) + #for l in range(k+1, len(choices)): -- for a 4th choice + # test([i, j, k, l]) -- (takes a while) -def setup_module(mod): - typeorder = { - W_IntObject: [(W_IntObject, None)], - W_BoolObject: [(W_BoolObject, None), (W_IntObject, delegate_b2i)], - W_StringObject: [(W_StringObject, None)], - } - mod.typeorder = typeorder - mod.add1 = add.install('__add', [typeorder, typeorder]) - - -def test_simple(): - space = 'space' - w_x = W_IntObject() - w_y = W_IntObject() - assert add1(space, w_x, w_y) == 'fine' - -def test_failtoimplement(): - space = 'space' - w_x = W_IntObject() - w_s = W_StringObject() - raises(FailedToImplement, "add1(space, w_x, w_s)") - raises(FailedToImplement, "add1(space, w_s, w_x)") - -def test_delegate(): - space = 'space' - w_x = W_IntObject() - w_s = W_StringObject() - w_b = W_BoolObject() - assert add1(space, w_x, w_b) == 'fine' - assert add1(space, w_b, w_x) == 'fine' - assert add1(space, w_b, w_b) == 'fine' - raises(FailedToImplement, "add1(space, w_b, w_s)") - raises(FailedToImplement, "add1(space, w_s, w_b)") - -def test_not_baked(): - add2 = add.install('__add2', [typeorder, typeorder],baked_perform_call=False) - assert add2[0] == ['space', 'arg0', 'arg1'] - if Installer is InstallerVersion1: - assert add2[1] == 'arg0.__add2(space, arg1)' - assert isinstance(add2[2], dict) - assert not add2[3] - -def test_empty(): - add3_installer = Installer(add, '__add3', [{},{}]) - assert add3_installer.is_empty() - if Installer is InstallerVersion1: - assert len(add3_installer.to_install) == 1 - assert add3_installer.to_install[0][0] is None - -def test_empty_direct(): - assert not add.install_if_not_empty('__add4', [{},{}]) - - -def test_empty_not_baked(): - add5_installer = Installer(add, '__add5', [{},{}], baked_perform_call=False) - assert add5_installer.is_empty() - if Installer is InstallerVersion1: - assert len(add5_installer.to_install) == 0 - add5 = add5_installer.install() - assert add5[0] == ['space', 'arg0', 'arg1'] - assert add5[1] == 'raiseFailedToImplement()' - assert isinstance(add5[2], dict) - assert add5[3] - -def test_mmdispatcher(): - add2 = MMDispatcher(add, [typeorder, typeorder]) - space = 'space' - w_x = W_IntObject() - w_s = W_StringObject() - w_b1 = W_BoolObject() - w_b2 = W_BoolObject() - assert add2(space, w_x, w_b1) == 'fine' - assert add2(space, w_b2, w_x) == 'fine' - assert add2(space, w_b1, w_b2) == 'fine' - raises(FailedToImplement, "add2(space, w_b2, w_s)") - raises(FailedToImplement, "add2(space, w_s, w_b1)") +class TestMultiMethod2(TestMultiMethod1): + Installer = multimethod.InstallerVersion2 From auc at codespeak.net Thu Nov 16 15:48:16 2006 From: auc at codespeak.net (auc at codespeak.net) Date: Thu, 16 Nov 2006 15:48:16 +0100 (CET) Subject: [pypy-svn] r34673 - pypy/dist/pypy/objspace Message-ID: <20061116144816.34CD0100DA@code0.codespeak.net> Author: auc Date: Thu Nov 16 15:48:14 2006 New Revision: 34673 Modified: pypy/dist/pypy/objspace/logic.py Log: fix typeorders Modified: pypy/dist/pypy/objspace/logic.py ============================================================================== --- pypy/dist/pypy/objspace/logic.py (original) +++ pypy/dist/pypy/objspace/logic.py Thu Nov 16 15:48:14 2006 @@ -187,13 +187,10 @@ # multimethods hack space.model.typeorder[W_Var] = [(W_Var, None), (W_Root, None)] # None means no conversion - space.model.typeorder[W_Future] = [(W_Future, None), (W_Var, None)] - space.model.typeorder[W_CVar] = [(W_CVar, None), (W_Var, None)] - space.model.typeorder[W_CSpace] = [(W_CSpace, None), (baseobjspace.Wrappable, None)] - space.model.typeorder[W_ThreadGroupScheduler] = [(W_ThreadGroupScheduler, None), (W_CSpace, None)] + space.model.typeorder[W_Future] = [(W_Future, None), (W_Var, None), (W_Root, None)] + space.model.typeorder[W_CVar] = [(W_CVar, None), (W_Var, None), (W_Root, None)] space.model.typeorder[W_FiniteDomain] = [(W_FiniteDomain, None), (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)) From arigo at codespeak.net Thu Nov 16 15:58:16 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Nov 2006 15:58:16 +0100 (CET) Subject: [pypy-svn] r34674 - pypy/dist/pypy/doc Message-ID: <20061116145816.0159B100E3@code0.codespeak.net> Author: arigo Date: Thu Nov 16 15:58:13 2006 New Revision: 34674 Modified: pypy/dist/pypy/doc/stackless.txt Log: Tasklet example. Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Thu Nov 16 15:58:13 2006 @@ -194,6 +194,44 @@ is removed from the scheduling queue and will be reinserted when it becomes unblocked. +Example +~~~~~~~ + +Here is a many-producers many-consumers example, where any consumer can +process the result of any producer. For this situation we set up a +single channel where all producer send, and on which all consumers +wait:: + + def producer(chan): + while True: + chan.send(...next value...) + + def consumer(chan): + while True: + x = chan.receive() + ...do something with x... + + # Set up the N producer and M consumer tasklets + common_channel = stackless.channel() + for i in range(N): + stackless.tasklet(producer, common_channel)() + for i in range(M): + stackless.tasklet(consumer, common_channel)() + + # Run it all + stackless.run() + +Each item sent over the channel is received by one of the waiting +consumers; which one is not specified. The producers block until their +item is consumed: the channel is not a queue, but rather a meeting point +which causes tasklets to block until both a consumer and a producer are +ready. In practice, the reason for having several consumers receiving +on a single channel is that some of the consumers can be busy in other +ways part of the time. For example, each consumer might receive a +database request, process it, and send the result to a further channel +before it asks for the next request. In this situation, further +requests can still be received by other consumers. + Greenlets +++++++++ From ac at codespeak.net Thu Nov 16 16:30:55 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Nov 2006 16:30:55 +0100 (CET) Subject: [pypy-svn] r34675 - pypy/dist/pypy/translator/js/modules Message-ID: <20061116153055.CD817100DE@code0.codespeak.net> Author: ac Date: Thu Nov 16 16:30:51 2006 New Revision: 34675 Modified: pypy/dist/pypy/translator/js/modules/dom.py Log: (pedronis, arre) Make the pythonconsole demo work again. Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Thu Nov 16 16:30:51 2006 @@ -394,6 +394,8 @@ # HTML specific 'style' : Style(), 'tabIndex' : 12, + # XXX: From HTMLInputElement to make pythonconsole work. + 'value': 'aa', }) Element._methods = Node._methods.copy() From pedronis at codespeak.net Thu Nov 16 16:34:20 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 16 Nov 2006 16:34:20 +0100 (CET) Subject: [pypy-svn] r34676 - pypy/dist/pypy/translator/js/demo/jsdemo Message-ID: <20061116153420.6B3C8100ED@code0.codespeak.net> Author: pedronis Date: Thu Nov 16 16:34:16 2006 New Revision: 34676 Added: pypy/dist/pypy/translator/js/demo/jsdemo/support.py (contents, props changed) Modified: pypy/dist/pypy/translator/js/demo/jsdemo/example.py pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Log: use the js_source style (moved the helper to the support file) for both basic demos. Modified: pypy/dist/pypy/translator/js/demo/jsdemo/example.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/example.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/example.py Thu Nov 16 16:34:16 2006 @@ -4,7 +4,8 @@ import autopath -from pypy.translator.js.test.runtest import compile_function +from pypy.translator.js.demo.jsdemo import support + from pypy.translator.js.modules.dom import setTimeout, get_document from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy @@ -81,10 +82,8 @@ if self.server.source: source = self.server.source else: - fn = compile_function(runjs, []) - source = fn.source() + source = support.js_source([runjs]) self.server.source = source - self.serve_data("text/javascript", source) def serve_data(self, content_type, data): Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Thu Nov 16 16:34:16 2006 @@ -10,36 +10,20 @@ import autopath -import new, sys, os, cStringIO +import sys, os, cStringIO from cgi import parse_qs from pypy.translator.js.modules.dom import setTimeout, get_document -from pypy.translator.js.main import rpython2javascript from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy from pypy.translator.js.modules.mochikit import escapeHTML +from pypy.translator.js.demo.jsdemo import support + commproxy.USE_MOCHIKIT = True from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler #from SimpleHTTPServer import SimpleHTTPRequestHandler -def js_source(functions): - mod = new.module('_js_src') - function_names = [] - for func in functions: - name = func.__name__ - if hasattr(mod, name): - raise ValueError("exported function name %r is duplicated" - % (name,)) - mod.__dict__[name] = func - function_names.append(name) - sys.modules['_js_src'] = mod - try: - return rpython2javascript(mod, function_names) - finally: - del sys.modules['_js_src'] - -# ____________________________________________________________ HTML_PAGE = """ @@ -181,7 +165,7 @@ if self.server.source: source = self.server.source else: - source = js_source([setup_page]) + source = support.js_source([setup_page]) self.server.source = source self.serve_data("text/javascript", source) Added: pypy/dist/pypy/translator/js/demo/jsdemo/support.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/js/demo/jsdemo/support.py Thu Nov 16 16:34:16 2006 @@ -0,0 +1,20 @@ + +import sys, new +from pypy.translator.js.main import rpython2javascript + +def js_source(functions): + mod = new.module('_js_src') + function_names = [] + for func in functions: + name = func.__name__ + if hasattr(mod, name): + raise ValueError("exported function name %r is duplicated" + % (name,)) + mod.__dict__[name] = func + function_names.append(name) + sys.modules['_js_src'] = mod + try: + return rpython2javascript(mod, function_names) + finally: + del sys.modules['_js_src'] + From arigo at codespeak.net Thu Nov 16 16:48:39 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Nov 2006 16:48:39 +0100 (CET) Subject: [pypy-svn] r34677 - pypy/dist/pypy/objspace/std Message-ID: <20061116154839.0D18A100ED@code0.codespeak.net> Author: arigo Date: Thu Nov 16 16:48:38 2006 New Revision: 34677 Modified: pypy/dist/pypy/objspace/std/multimethod.py Log: A comment, and an attempt to reduce the amount of isinstance() checks in the last step of multimethod dispatch. The result appears to work and makes pypy-c smaller by some 175kb. Modified: pypy/dist/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/dist/pypy/objspace/std/multimethod.py (original) +++ pypy/dist/pypy/objspace/std/multimethod.py Thu Nov 16 16:48:38 2006 @@ -459,6 +459,13 @@ for t1, num in self.typenum.items(): setattr(t1, self.attrname, num) self.indexarray = CompressedArray(0) + self.strict_subclasses = {} + for cls1 in list_of_types: + lst = [] + for cls2 in list_of_types: + if cls1 is not cls2 and issubclass(cls2, cls1): + lst.append(cls2) + self.strict_subclasses[cls1] = lst def normalize_length(self, next_array): # make sure that the indexarray is not smaller than any funcarray @@ -504,8 +511,9 @@ checklines.append(self.body) body = '\n '.join(checklines) source = 'def %s(%s):\n %s\n' % (name, ', '.join(fnargs), body) - #print '_' * 60 - #print source + #f = open('/tmp/mm-source/%s' % name, 'a') + #print >> f, source + #f.close() exec compile2(source) in self.miniglobals self._function = self.miniglobals[name] return self._function @@ -534,6 +542,27 @@ fulls += 1 if fulls == types_total: return 1 + + # a word about subclasses: we are using isinstance() to do + # the checks in generate_typechecks(), which is a + # compromize. In theory we should check the type ids + # instead. But using isinstance() is better because the + # annotator can deduce information from that. It is still + # correct to use isinstance() instead of type ids in + # "reasonable" cases, though -- where "reasonable" means + # that classes always have a delegate to their superclasses, + # e.g. W_IntObject delegates to W_Root. If this is true + # then both kind of checks are good enough to spot + # mismatches caused by the compression table. + + # Based on this reasoning, we can compress the typechecks a + # bit more - if we accept W_Root, for example, then we + # don't have to specifically accept W_IntObject too. + for cls, subnode in node.items(): + for cls2 in mrdtable.strict_subclasses[cls]: + if cls2 in node and node[cls2] == subnode: + del node[cls2] + return 0 types_total = len(mrdtable.list_of_types) From ac at codespeak.net Thu Nov 16 16:56:45 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Nov 2006 16:56:45 +0100 (CET) Subject: [pypy-svn] r34678 - in pypy/dist/pypy/translator/js/demo/jsdemo: . test Message-ID: <20061116155645.39E47100E5@code0.codespeak.net> Author: ac Date: Thu Nov 16 16:56:44 2006 New Revision: 34678 Added: pypy/dist/pypy/translator/js/demo/jsdemo/test/ (props changed) pypy/dist/pypy/translator/js/demo/jsdemo/test/__init__.py (contents, props changed) pypy/dist/pypy/translator/js/demo/jsdemo/test/test_demo.py (contents, props changed) Modified: pypy/dist/pypy/translator/js/demo/jsdemo/example.py pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Log: (pedronis, arre) Test that the code in the demos are translatable. Modified: pypy/dist/pypy/translator/js/demo/jsdemo/example.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/example.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/example.py Thu Nov 16 16:56:44 2006 @@ -93,12 +93,13 @@ self.end_headers() self.wfile.write(data) -def _main(server_class=Server, - handler_class=RequestHandler): +def build_http_server(server_address=('', 8000)): global httpd + httpd = Server(server_address, RequestHandler) - server_address = ('', 8000) - httpd = server_class(server_address, handler_class) +def _main(server_class=Server, + handler_class=RequestHandler): + build_http_server() httpd.serve_forever() if __name__ == '__main__': Modified: pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/pythonconsole.py Thu Nov 16 16:56:44 2006 @@ -176,13 +176,14 @@ self.end_headers() self.wfile.write(data) -def _main(server_class=Server, - handler_class=RequestHandler): - global httpd - server_address = ('127.0.0.1', 8000) - httpd = server_class(server_address, handler_class) +def build_http_server(server_address=('', 8000)): + global httpd + httpd = Server(server_address, RequestHandler) print 'http://127.0.0.1:%d' % (server_address[1],) + +def _main(): + build_http_server() httpd.serve_forever() if __name__ == '__main__': Added: pypy/dist/pypy/translator/js/demo/jsdemo/test/__init__.py ============================================================================== Added: pypy/dist/pypy/translator/js/demo/jsdemo/test/test_demo.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/js/demo/jsdemo/test/test_demo.py Thu Nov 16 16:56:44 2006 @@ -0,0 +1,18 @@ +from pypy.translator.js.demo.jsdemo import example, pythonconsole +from pypy.translator.js.demo.jsdemo.support import js_source + +def test_example(): + example.build_http_server() + try: + source = js_source([example.runjs]) + assert 'function runjs ()' in source + finally: + example.httpd = None + +def test_pythonconsole(): + pythonconsole.build_http_server() + try: + source = js_source([pythonconsole.setup_page]) + assert 'function setup_page ()' in source + finally: + pythonconsole.httpd = None From ac at codespeak.net Thu Nov 16 17:02:18 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Nov 2006 17:02:18 +0100 (CET) Subject: [pypy-svn] r34679 - pypy/dist/pypy/translator/js/demo/jsdemo Message-ID: <20061116160218.2887C100F1@code0.codespeak.net> Author: ac Date: Thu Nov 16 17:02:17 2006 New Revision: 34679 Modified: pypy/dist/pypy/translator/js/demo/jsdemo/support.py Log: Oops, have rpython2javascript not invoke pdb. Modified: pypy/dist/pypy/translator/js/demo/jsdemo/support.py ============================================================================== --- pypy/dist/pypy/translator/js/demo/jsdemo/support.py (original) +++ pypy/dist/pypy/translator/js/demo/jsdemo/support.py Thu Nov 16 17:02:17 2006 @@ -2,7 +2,7 @@ import sys, new from pypy.translator.js.main import rpython2javascript -def js_source(functions): +def js_source(functions, use_pdb=False): mod = new.module('_js_src') function_names = [] for func in functions: @@ -14,7 +14,7 @@ function_names.append(name) sys.modules['_js_src'] = mod try: - return rpython2javascript(mod, function_names) + return rpython2javascript(mod, function_names, use_pdb=use_pdb) finally: del sys.modules['_js_src'] From cfbolz at codespeak.net Thu Nov 16 17:07:31 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Nov 2006 17:07:31 +0100 (CET) Subject: [pypy-svn] r34680 - in pypy/dist/pypy/module: __builtin__ __builtin__/test pypymagic pypymagic/test Message-ID: <20061116160731.23259100F5@code0.codespeak.net> Author: cfbolz Date: Thu Nov 16 17:07:30 2006 New Revision: 34680 Added: pypy/dist/pypy/module/pypymagic/test/test_special.py - copied, changed from r34533, pypy/dist/pypy/module/__builtin__/test/test_special.py Removed: pypy/dist/pypy/module/__builtin__/test/test_special.py Modified: pypy/dist/pypy/module/__builtin__/__init__.py pypy/dist/pypy/module/__builtin__/special.py pypy/dist/pypy/module/pypymagic/__init__.py pypy/dist/pypy/module/pypymagic/interp_magic.py Log: move two somewhat obscure builtins to pypymagic. remove the double entry for hash. Modified: pypy/dist/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/__init__.py (original) +++ pypy/dist/pypy/module/__builtin__/__init__.py Thu Nov 16 17:07:30 2006 @@ -80,8 +80,6 @@ '_instance' : 'space.w_instance', # default __metaclass__ '__metaclass__' : '(space.w_type)', - '_isfake' : 'special._isfake', - '_pdb' : 'special._pdb', # interp-level function definitions 'abs' : 'operation.abs', @@ -103,7 +101,6 @@ 'setattr' : 'operation.setattr', 'delattr' : 'operation.delattr', 'iter' : 'operation.iter', - 'hash' : 'operation.hash', 'id' : 'operation.id', '_seqiter' : 'operation._seqiter', 'intern' : 'operation.intern', Modified: pypy/dist/pypy/module/__builtin__/special.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/special.py (original) +++ pypy/dist/pypy/module/__builtin__/special.py Thu Nov 16 17:07:30 2006 @@ -2,11 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.rlib import rarithmetic -def _isfake(space, w_obj): - return space.wrap(bool(w_obj.typedef.fakedcpytype)) - #return space.wrap(bool(getattr(w_obj.typedef, 'fakedcpytype', None))) - - def _formatd(space, alt, prec, kind, x): formatd_max_length = rarithmetic.formatd_max_length if ((kind == 'g' and formatd_max_length <= 10+prec) or @@ -23,14 +18,4 @@ return space.wrap(rarithmetic.formatd(fmt, x)) _formatd.unwrap_spec = [gateway.ObjSpace, int, int, str, float] -def _pdb(space): - """Run an interp-level pdb. - This is not available in translated versions of PyPy.""" - from pypy.rlib.objectmodel import we_are_translated - if we_are_translated(): - raise OperationError(space.w_NotImplementedError, - space.wrap("Cannot use interp-level pdb in translated pypy")) - else: - import pdb - pdb.set_trace() Modified: pypy/dist/pypy/module/pypymagic/__init__.py ============================================================================== --- pypy/dist/pypy/module/pypymagic/__init__.py (original) +++ pypy/dist/pypy/module/pypymagic/__init__.py Thu Nov 16 17:07:30 2006 @@ -8,4 +8,6 @@ interpleveldefs = { 'pypy_repr' : 'interp_magic.pypy_repr', + 'isfake' : 'interp_magic.isfake', + 'interp_pdb' : 'interp_magic.interp_pdb', } Modified: pypy/dist/pypy/module/pypymagic/interp_magic.py ============================================================================== --- pypy/dist/pypy/module/pypymagic/interp_magic.py (original) +++ pypy/dist/pypy/module/pypymagic/interp_magic.py Thu Nov 16 17:07:30 2006 @@ -1,3 +1,21 @@ +from pypy.interpreter.error import OperationError +from pypy.rlib.objectmodel import we_are_translated def pypy_repr(space, w_object): return space.wrap('%r' % (w_object,)) + +def isfake(space, w_obj): + if we_are_translated(): + return space.w_False + return space.wrap(bool(w_obj.typedef.fakedcpytype)) + #return space.wrap(bool(getattr(w_obj.typedef, 'fakedcpytype', None))) + +def interp_pdb(space): + """Run an interp-level pdb. + This is not available in translated versions of PyPy.""" + if we_are_translated(): + raise OperationError(space.w_NotImplementedError, + space.wrap("Cannot use interp-level pdb in translated pypy")) + else: + import pdb + pdb.set_trace() From arigo at codespeak.net Thu Nov 16 17:23:56 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Nov 2006 17:23:56 +0100 (CET) Subject: [pypy-svn] r34681 - pypy/dist/pypy/doc Message-ID: <20061116162356.34C54100EE@code0.codespeak.net> Author: arigo Date: Thu Nov 16 17:23:55 2006 New Revision: 34681 Modified: pypy/dist/pypy/doc/stackless.txt Log: Finish the Composability section. Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Thu Nov 16 17:23:55 2006 @@ -136,7 +136,7 @@ # Process the available values in a batch, but at most 3 batch = lst[:3] del lst[:3] - ... process batch ... + ...process batch... # Initialize two coroutines with a shared list as argument exchangelst = [] @@ -585,9 +585,34 @@ ...generators_view.getcurrent()... -Then the composition ``grab_values()`` works as expected. - -XXX a few words about how +Then the composition ``grab_values()`` works as expected, because the +two views are independent. The coroutine captured as ``self.caller`` in +the ``generator_iterator.next()`` method is the main coroutine of the +``generators_view``. It is no longer the same object as the main +coroutine of the ``producer_view``, so when ``data_producer()`` issues +the following command:: + + main_coro.switch() + +the control flow cannot accidentally jump back to +``generator_iterator.next()``. In other words, from the point of view +of ``producer_view``, the function ``grab_next_value()`` always runs in +its main coroutine ``main_coro`` and the function ``data_producer`` in +its coroutine ``producer_coro``. This is the case independently of +which ``generators_view``-based coroutine is the current one when +``grab_next_value()`` is called. + +Only code that has explicit access to the ``producer_view`` or its +coroutine objects can perform switches that are relevant for the +generator code. If the view object and the coroutine objects that share +this view are all properly encapsulated inside the generator logic, no +external code can accidentally temper with the expected control flow any +longer. + +In conclusion: we will probably change the app-level interface of PyPy's +stackless module in the future to not expose coroutines and greenlets at +all, but only views. They are not much more difficult to use, and they +scale automatically to larger programs. .. _`Stackless Python`: http://www.stackless.com From cfbolz at codespeak.net Thu Nov 16 17:34:37 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 16 Nov 2006 17:34:37 +0100 (CET) Subject: [pypy-svn] r34682 - pypy/dist/demo Message-ID: <20061116163437.3F116100F6@code0.codespeak.net> Author: cfbolz Date: Thu Nov 16 17:34:37 2006 New Revision: 34682 Removed: pypy/dist/demo/rrandom.py Modified: pypy/dist/demo/bpnn.py Log: get rid of the rrandom.py module in demo and use rlib/rrandom.py in bpnn Modified: pypy/dist/demo/bpnn.py ============================================================================== --- pypy/dist/demo/bpnn.py (original) +++ pypy/dist/demo/bpnn.py Thu Nov 16 17:34:37 2006 @@ -23,12 +23,12 @@ import math import time -# RPython version of random: rrandom -import autopath; import rrandom as random +import autopath +from pypy.rlib import rrandom PRINT_IT = False -random.seed(0) +random = rrandom.Random(1) # calculate a random number where: a <= rand < b def rand(a, b): From ac at codespeak.net Thu Nov 16 18:18:02 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 16 Nov 2006 18:18:02 +0100 (CET) Subject: [pypy-svn] r34684 - in pypy/dist/pypy/translator: . backendopt Message-ID: <20061116171802.A5011100F0@code0.codespeak.net> Author: ac Date: Thu Nov 16 18:18:01 2006 New Revision: 34684 Modified: pypy/dist/pypy/translator/backendopt/all.py pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/driver.py Log: (pedronis, arre) Tweak the inlining. Modified: pypy/dist/pypy/translator/backendopt/all.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/all.py (original) +++ pypy/dist/pypy/translator/backendopt/all.py Thu Nov 16 18:18:01 2006 @@ -47,14 +47,9 @@ inline_malloc_removal_phase(config, translator, graphs, config.inline_threshold*.5) # xxx tune! inline.instrument_inline_candidates(graphs, config.inline_threshold) - data = translator.driver_instrument_result( + counters = translator.driver_instrument_result( config.profile_based_inline) - import array, struct - n = data.size()//struct.calcsize('L') - data = data.open('rb') - counters = array.array('L') - counters.fromfile(data, n) - data.close() + n = len(counters) def call_count_pred(label): if label >= n: return False @@ -102,9 +97,10 @@ # inline functions in each other if inline_threshold: callgraph = inline.inlinable_static_callers(graphs) - inline.auto_inlining(translator, inline_threshold, - callgraph=callgraph, - call_count_pred=call_count_pred) + count = inline.auto_inlining(translator, inline_threshold, + callgraph=callgraph, + call_count_pred=call_count_pred) + log.inlining('inlined %d callsites.'% (count,)) for graph in graphs: removenoops.remove_superfluous_keep_alive(graph) removenoops.remove_duplicate_casts(graph, translator) @@ -129,3 +125,8 @@ if config.print_statistics: print "after malloc removal:" print_statistics(translator.graphs[0], translator) + + if config.constfold: + for graph in graphs: + constant_fold_graph(graph) + Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Thu Nov 16 18:18:01 2006 @@ -642,15 +642,17 @@ for parentgraph in callers[graph]: if parentgraph == graph: continue + subcount = 0 try: - res = bool(inline_function(translator, graph, parentgraph, + subcount = inline_function(translator, graph, parentgraph, lltype_to_classdef, raise_analyzer, - call_count_pred)) + call_count_pred) + res = bool(subcount) except CannotInline: couldnt_inline[graph] = True res = CannotInline if res is True: - count += 1 + count += subcount # the parentgraph should now contain all calls that were # done by 'graph' for graph2 in callees.get(graph, {}): Modified: pypy/dist/pypy/translator/driver.py ============================================================================== --- pypy/dist/pypy/translator/driver.py (original) +++ pypy/dist/pypy/translator/driver.py Thu Nov 16 18:18:01 2006 @@ -235,7 +235,13 @@ raise Exception, "instrumentation child failed: %d" % status else: raise Exception, "instrumentation child aborted" - return datafile + import array, struct + n = datafile.size()//struct.calcsize('L') + datafile = datafile.open('rb') + counters = array.array('L') + counters.fromfile(datafile, n) + datafile.close() + return counters def info(self, msg): log.info(msg) From arigo at codespeak.net Thu Nov 16 19:07:43 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 16 Nov 2006 19:07:43 +0100 (CET) Subject: [pypy-svn] r34685 - in pypy/dist/pypy: module/_stackless objspace/cclp Message-ID: <20061116180743.59339100EE@code0.codespeak.net> Author: arigo Date: Thu Nov 16 19:07:42 2006 New Revision: 34685 Removed: pypy/dist/pypy/module/_stackless/clonable.py Modified: pypy/dist/pypy/module/_stackless/__init__.py pypy/dist/pypy/objspace/cclp/misc.py Log: Remove the no-longer-used app-level interface to clonable coroutines, before we start a different approach. Modified: pypy/dist/pypy/module/_stackless/__init__.py ============================================================================== --- pypy/dist/pypy/module/_stackless/__init__.py (original) +++ pypy/dist/pypy/module/_stackless/__init__.py Thu Nov 16 19:07:42 2006 @@ -14,7 +14,7 @@ interpleveldefs = { 'tasklet' : 'interp_stackless.tasklet', 'coroutine' : 'coroutine.AppCoroutine', - 'clonable' : 'clonable.ClonableCoroutine', + #'clonable' : 'clonable.ClonableCoroutine', 'greenlet' : 'interp_greenlet.AppGreenlet', 'usercostate': 'composable_coroutine.W_UserCoState', } Modified: pypy/dist/pypy/objspace/cclp/misc.py ============================================================================== --- pypy/dist/pypy/objspace/cclp/misc.py (original) +++ pypy/dist/pypy/objspace/cclp/misc.py Thu Nov 16 19:07:42 2006 @@ -2,7 +2,6 @@ from pypy.rlib.objectmodel import we_are_translated # commonly imported there, used from types, variable, thread -from pypy.module._stackless.clonable import ClonableCoroutine from pypy.module._stackless.coroutine import AppCoroutine import os From fijal at codespeak.net Thu Nov 16 21:25:34 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 16 Nov 2006 21:25:34 +0100 (CET) Subject: [pypy-svn] r34691 - pypy/dist/pypy/module/_stackless Message-ID: <20061116202534.EFDCC100F0@code0.codespeak.net> Author: fijal Date: Thu Nov 16 21:25:32 2006 New Revision: 34691 Modified: pypy/dist/pypy/module/_stackless/__init__.py Log: Removed non-existing import Modified: pypy/dist/pypy/module/_stackless/__init__.py ============================================================================== --- pypy/dist/pypy/module/_stackless/__init__.py (original) +++ pypy/dist/pypy/module/_stackless/__init__.py Thu Nov 16 21:25:32 2006 @@ -24,8 +24,8 @@ # are not yet directly supported from pypy.module._stackless.coroutine import post_install as post_install_coro post_install_coro(self) - from pypy.module._stackless.clonable import post_install as post_install_clonable - post_install_clonable(self) + #from pypy.module._stackless.clonable import post_install as post_install_clonable + #post_install_clonable(self) from pypy.module._stackless.interp_greenlet import post_install as post_install_greenlet post_install_greenlet(self) From fijal at codespeak.net Thu Nov 16 21:37:10 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 16 Nov 2006 21:37:10 +0100 (CET) Subject: [pypy-svn] r34693 - pypy/dist/pypy/objspace/std/test Message-ID: <20061116203710.9A2E6100F6@code0.codespeak.net> Author: fijal Date: Thu Nov 16 21:37:08 2006 New Revision: 34693 Modified: pypy/dist/pypy/objspace/std/test/test_proxy.py pypy/dist/pypy/objspace/std/test/test_proxy_function.py Log: Added some tests, which passes out of the box. Modified: pypy/dist/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/dist/pypy/objspace/std/test/test_proxy.py Thu Nov 16 21:37:08 2006 @@ -88,6 +88,12 @@ lst = self.proxy(list, c.perform) lst += [1,2,3] assert len(lst) == 6 + + def test_list_reverse_add(self): + c = self.Controller([1,2,3]) + lst = self.proxy(list, c.perform) + l = [1] + lst + assert l == [1,1,2,3] class AppTestDictProxy(AppProxyBasic): def test_dict(self): Modified: pypy/dist/pypy/objspace/std/test/test_proxy_function.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_proxy_function.py (original) +++ pypy/dist/pypy/objspace/std/test/test_proxy_function.py Thu Nov 16 21:37:08 2006 @@ -80,3 +80,25 @@ del fun.__doc__ assert f.__doc__ is None + def test_proxy_bind_method(self): + class A: + pass + + def f(self): + return 3 + + class AA: + pass + + from pypymagic import transparent_proxy as proxy + a = A() + class X: + def __init__(self, x): + self.x = x + def f(self, name, *args, **kwargs): + return getattr(self.x, name)(*args, **kwargs) + + y = proxy(type(f), X(f).f) + x = proxy(AA, X(a).f) + AA.f = y + assert x.f() == 3 From fijal at codespeak.net Thu Nov 16 21:37:35 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 16 Nov 2006 21:37:35 +0100 (CET) Subject: [pypy-svn] r34694 - pypy/dist/pypy/objspace/std Message-ID: <20061116203735.08CEF100F9@code0.codespeak.net> Author: fijal Date: Thu Nov 16 21:37:30 2006 New Revision: 34694 Modified: pypy/dist/pypy/objspace/std/transparent.py Log: Trying to make annotator happy. Modified: pypy/dist/pypy/objspace/std/transparent.py ============================================================================== --- pypy/dist/pypy/objspace/std/transparent.py (original) +++ pypy/dist/pypy/objspace/std/transparent.py Thu Nov 16 21:37:30 2006 @@ -36,10 +36,11 @@ "be wrapped (YET)" % w_type.getname(space, "?"))) def proxy_controller(space, w_object): - if (not isinstance(w_object, W_Transparent)) and \ - (not isinstance(w_object, W_TransparentObject)): - return None - return w_object.w_controller + if isinstance(w_object, W_Transparent): + return w_object.w_controller + if isinstance(w_object, W_TransparentObject): + return w_object.w_controller + return None app_proxy = gateway.interp2app(proxy, unwrap_spec=[gateway.ObjSpace, gateway.W_Root, \ gateway.W_Root]) From antocuni at codespeak.net Fri Nov 17 13:48:11 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 17 Nov 2006 13:48:11 +0100 (CET) Subject: [pypy-svn] r34706 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20061117124811.631BE100A5@code0.codespeak.net> Author: antocuni Date: Fri Nov 17 13:48:04 2006 New Revision: 34706 Modified: pypy/dist/pypy/translator/cli/dotnet.py pypy/dist/pypy/translator/cli/test/test_dotnet.py Log: - Support for creating native arrays of a known length. - Support for setting items on arrays. Modified: pypy/dist/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/dotnet.py (original) +++ pypy/dist/pypy/translator/cli/dotnet.py Fri Nov 17 13:48:04 2006 @@ -50,7 +50,15 @@ if ooinst.ootype._isArray: return SomeOOInstance(ooinst.ootype._ELEMENT) return s_ImpossibleValue - + + def setitem((ooinst, index), s_value): + if ooinst.ootype._isArray: + ELEMENT = ooinst.ootype._ELEMENT + VALUE = s_value.ootype + assert ootype.isSubclass(VALUE, ELEMENT) + return s_None + return s_ImpossibleValue + ## Rtyper model @@ -100,6 +108,13 @@ hop.exception_is_here() return hop.genop('cli_getelem', [v_array, v_index], hop.r_result.lowleveltype) + def rtype_setitem((r_inst, r_int), hop): + if not r_inst.lowleveltype._isArray: + raise TyperError("setitem() on a non-array instance") + vlist = hop.inputargs(*hop.args_r) + hop.exception_is_here() + return hop.genop('cli_setelem', vlist, hop.r_result.lowleveltype) + ## OOType model @@ -344,12 +359,32 @@ v_obj, = hop.inputargs(*hop.args_r) return hop.genop('same_as', [v_obj], hop.r_result.lowleveltype) +def new_array(type, length): + return [None] * length def init_array(type, *args): # PythonNet doesn't provide a straightforward way to create arrays... fake it with a list return args class Entry(ExtRegistryEntry): + _about_ = new_array + + def compute_result_annotation(self, type_s, length_s): + from pypy.translator.cli.query import load_class_maybe + assert type_s.is_constant() + assert isinstance(length_s, SomeInteger) + TYPE = type_s.const._INSTANCE + fullname = '%s.%s[]' % (TYPE._namespace, TYPE._classname) + cliArray = load_class_maybe(fullname) + return SomeOOInstance(cliArray._INSTANCE) + + def specialize_call(self, hop): + c_type, v_length = hop.inputargs(*hop.args_r) + hop.exception_cannot_occur() + return hop.genop('cli_newarray', [c_type, v_length], hop.r_result.lowleveltype) + + +class Entry(ExtRegistryEntry): _about_ = init_array def compute_result_annotation(self, type_s, *args_s): Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Fri Nov 17 13:48:04 2006 @@ -7,7 +7,7 @@ from pypy.translator.cli.test.runtest import CliTest from pypy.translator.cli.dotnet import SomeCliClass, SomeCliStaticMethod,\ NativeInstance, CLR, box, unbox, OverloadingResolver, NativeException,\ - native_exc, init_array + native_exc, new_array, init_array System = CLR.System Math = CLR.System.Math @@ -111,7 +111,7 @@ a = RPythonAnnotator() s = a.build_types(fn, []) assert isinstance(s, annmodel.SomeOOInstance) - assert s.ootype._name == '[mscorlib]System.Object' + assert s.ootype._name == '[mscorlib]System.Object' class TestDotnetRtyping(CliTest): def _skip_pythonnet(self, msg): @@ -188,10 +188,18 @@ return unbox(array[0], ootype.Signed) assert self.interpret(fn, []) == 42 + def test_new_array(self): + def fn(): + x = new_array(System.Object, 2) + x[0] = box(42) + x[1] = box(43) + return unbox(x[0], ootype.Signed) + unbox(x[1], ootype.Signed) + assert self.interpret(fn, []) == 42+43 + def test_init_array(self): def fn(): - array = init_array(System.Object, box(42), box(43)) - return unbox(array[0], ootype.Signed) + unbox(array[1], ootype.Signed) + x = init_array([box(42), box(43)]) + return unbox(x[0], ootype.Signed) + unbox(x[1], ootype.Signed) assert self.interpret(fn, []) == 42+43 def test_null(self): @@ -241,7 +249,6 @@ res = self.ll_to_string(self.interpret(fn, [])) assert res.startswith("Index is less than 0") - class TestPythonnet(TestDotnetRtyping): # don't interpreter functions but execute them directly through pythonnet def interpret(self, f, args): From ericvrp at codespeak.net Fri Nov 17 15:46:20 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Fri, 17 Nov 2006 15:46:20 +0100 (CET) Subject: [pypy-svn] r34708 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061117144620.5B463100A5@code0.codespeak.net> Author: ericvrp Date: Fri Nov 17 15:46:17 2006 New Revision: 34708 Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: pushed the llvm jit codegenerator a little... * made call across sources testcase work (by having execution context use a single module) * removed some helper that would not translate Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Fri Nov 17 15:46:17 2006 @@ -20,59 +20,45 @@ using namespace llvm; -ExecutionEngine* g_execution_engine; +Module* gp_module = new Module("llvmjit"); +ExecutionEngine* gp_execution_engine = ExecutionEngine::create( + new ExistingModuleProvider(gp_module), false); void restart() { - delete g_execution_engine; //XXX test if this correctly cleans up including generated code - g_execution_engine = NULL; + delete gp_execution_engine; //XXX test if this correctly cleans up including generated code + + gp_module = new Module("llvmjit"); + gp_execution_engine = ExecutionEngine::create(new ExistingModuleProvider(gp_module), false); } int compile(const char* llsource) { - Module* module = ParseAssemblyString(llsource, new Module("llvmjit")); + Module* module = ParseAssemblyString(llsource, gp_module); if (!module) { - std::cerr << "Error: can not parse " << llsource << "\n" << std::flush; + std::cerr << "Can not parse:\n" << llsource << "\n" << std::flush; return false; } - //std::ostream *Out = new std::ofstream("temp-libllvmjit.bc", - // std::ios::out | std::ios::trunc | std::ios::binary); - //WriteBytecodeToFile(module, *Out); //XXX what to do with the 3rd param (NoCompress)? - - ModuleProvider* module_provider = new ExistingModuleProvider(module); - if (!g_execution_engine) { - g_execution_engine = ExecutionEngine::create(module_provider, false); - } else { - g_execution_engine->addModuleProvider(module_provider); - } - return true; } void* find_function(const char* name) { - if (!g_execution_engine) return NULL; //note: decided not to be treated as an error - - return g_execution_engine->FindFunctionNamed(name); //note: can be NULL + return gp_execution_engine->FindFunctionNamed(name); //note: can be NULL } int execute(const void* function, int param) { //XXX allow different function signatures - if (!g_execution_engine) { - std::cerr << "Error: no llvm code compiled yet!\n" << std::flush; - return -1; - } - if (!function) { - std::cerr << "Error: no function supplied to libllvmjit.execute(...)\n" << std::flush; + std::cerr << "No function supplied to libllvmjit.execute(...)\n" << std::flush; return -1; } std::vector args; args.push_back((void*)param); - GenericValue gv = g_execution_engine->runFunction((Function*)function, args); + GenericValue gv = gp_execution_engine->runFunction((Function*)function, args); return gv.IntVal; } Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Fri Nov 17 15:46:17 2006 @@ -56,11 +56,3 @@ execute.restype = c_int execute.argtypes = [c_void_p, c_int] -#helpers... -class FindFunction(object): - def __init__(self, function_name): - self.function = find_function(function_name) - - def __call__(self, param): #XXX this does not seem to translate, how to do it instead? - return execute(self.function, param) - Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Fri Nov 17 15:46:17 2006 @@ -27,7 +27,9 @@ ret int %n2 }''' -llacross1 = '''declare int %across2(int %n2) +llacross1 = '''declare int %across2(int) + +implementation int %across1(int %n) { block0: @@ -42,7 +44,9 @@ ret int %n3 }''' -llacross2 = '''declare int %across1(int %n2) +llacross2 = '''declare int %across1(int %dsf) + +implementation int %across2(int %n) { block0: @@ -60,10 +64,9 @@ #helpers def execute(llsource, function_name, param): assert llvmjit.compile(llsource) - f = llvmjit.FindFunction(function_name) - assert f.function - return llvmjit.execute(f.function, param) - #return function(param) #XXX this does not seem to translate, how to do it instead? + function = llvmjit.find_function(function_name) + assert function + return llvmjit.execute(function, param) #tests... def test_restart(): @@ -90,6 +93,10 @@ llvmjit.restart() assert execute(llsquare, 'square', 4) == 4 * 4 +def test_execute_nothing(): + llvmjit.restart() + assert llvmjit.execute(None, 4) == -1 #-1 == no function supplied + def test_execute_multiple(): llvmjit.restart() llvmjit.compile(llsquare) @@ -104,13 +111,13 @@ llvmjit.restart() llvmjit.compile(llsquare) llvmjit.compile(llmul2) - square = llvmjit.FindFunction('square') - mul2 = llvmjit.FindFunction('mul2') + square = llvmjit.find_function('square') + mul2 = llvmjit.find_function('mul2') for i in range(5): - assert square(i) == i * i - assert mul2(i) == i * 2 + assert llvmjit.execute(square, i) == i * i + assert llvmjit.execute(mul2 , i) == i * 2 -def DONTtest_execute_across_module(): +def test_execute_across_module(): def my_across1(n): return n * 3 @@ -126,11 +133,11 @@ llvmjit.restart() llvmjit.compile(llacross1) llvmjit.compile(llacross2) - across1to2 = llvmjit.FindFunction('across1to2') - across2to1 = llvmjit.FindFunction('across2to1') + across1to2 = llvmjit.find_function('across1to2') + across2to1 = llvmjit.find_function('across2to1') for i in range(5): - assert across1to2(i) == my_across1to2(i) - assert across2to1(i) == my_across2to1(i) + assert llvmjit.execute(across1to2, i) == my_across1to2(i) + assert llvmjit.execute(across2to1, i) == my_across2to1(i) def DONTtest_modify_global_data(): From fijal at codespeak.net Fri Nov 17 17:26:14 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 17 Nov 2006 17:26:14 +0100 (CET) Subject: [pypy-svn] r34714 - pypy/extradoc/planning Message-ID: <20061117162614.2DDDD100A5@code0.codespeak.net> Author: fijal Date: Fri Nov 17 17:26:02 2006 New Revision: 34714 Modified: pypy/extradoc/planning/sprint-planning.txt Log: Moved location. Modified: pypy/extradoc/planning/sprint-planning.txt ============================================================================== --- pypy/extradoc/planning/sprint-planning.txt (original) +++ pypy/extradoc/planning/sprint-planning.txt Fri Nov 17 17:26:02 2006 @@ -92,7 +92,7 @@ Late autumn sprint dates and possible locations (TBD): -------------------------------------------------------- -8th-14th January 2007, Poland (fijal checks) or GBorg +8th-14th January 2007, probably Leysin 26th feb-4th March 2006, Hildesheim / Trillke (offered, or somewhere else) From antocuni at codespeak.net Fri Nov 17 20:38:05 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 17 Nov 2006 20:38:05 +0100 (CET) Subject: [pypy-svn] r34718 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20061117193805.5F86D100B0@code0.codespeak.net> Author: antocuni Date: Fri Nov 17 20:38:04 2006 New Revision: 34718 Modified: pypy/dist/pypy/translator/cli/database.py pypy/dist/pypy/translator/cli/test/test_dotnet.py Log: A failing test and the relative bug fix. Modified: pypy/dist/pypy/translator/cli/database.py ============================================================================== --- pypy/dist/pypy/translator/cli/database.py (original) +++ pypy/dist/pypy/translator/cli/database.py Fri Nov 17 20:38:04 2006 @@ -127,7 +127,11 @@ return name def class_name(self, INSTANCE): - return self.classes[INSTANCE] + try: + NATIVE_INSTANCE = INSTANCE._hints['NATIVE_INSTANCE'] + return NATIVE_INSTANCE._name + except KeyError: + return self.classes[INSTANCE] def get_record_name(self, RECORD): try: Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Fri Nov 17 20:38:04 2006 @@ -249,6 +249,23 @@ res = self.ll_to_string(self.interpret(fn, [])) assert res.startswith("Index is less than 0") + def test_native_exception_invoke(self): + TargetInvocationException = NativeException(CLR.System.Reflection.TargetInvocationException) + def fn(): + x = ArrayList() + t = x.GetType() + meth = t.GetMethod('get_Item') + args = init_array(System.Object, box(0)) + try: + meth.Invoke(x, args) + return "Impossible!" + except TargetInvocationException, e: + inner = native_exc(e).get_InnerException() + message = str(inner.get_Message()) + return message + res = self.ll_to_string(self.interpret(fn, [])) + assert res.startswith("Index is less than 0") + class TestPythonnet(TestDotnetRtyping): # don't interpreter functions but execute them directly through pythonnet def interpret(self, f, args): From antocuni at codespeak.net Fri Nov 17 20:39:38 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 17 Nov 2006 20:39:38 +0100 (CET) Subject: [pypy-svn] r34719 - in pypy/dist/pypy/translator: cli cli/test oosupport Message-ID: <20061117193938.A7A6B100AA@code0.codespeak.net> Author: antocuni Date: Fri Nov 17 20:39:37 2006 New Revision: 34719 Modified: pypy/dist/pypy/translator/cli/constant.py pypy/dist/pypy/translator/cli/ilgenerator.py pypy/dist/pypy/translator/cli/test/test_constant.py pypy/dist/pypy/translator/oosupport/constant.py Log: Fix a bug in oosupport that produced wrong code when splitting constant initialization into multiple steps, and the relative test. Modified: pypy/dist/pypy/translator/cli/constant.py ============================================================================== --- pypy/dist/pypy/translator/cli/constant.py (original) +++ pypy/dist/pypy/translator/cli/constant.py Fri Nov 17 20:39:37 2006 @@ -41,7 +41,6 @@ DEBUG_CONST_INIT = False DEBUG_CONST_INIT_VERBOSE = False -MAX_CONST_PER_STEP = 100 SERIALIZE = False # ______________________________________________________________________ Modified: pypy/dist/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/dist/pypy/translator/cli/ilgenerator.py (original) +++ pypy/dist/pypy/translator/cli/ilgenerator.py Fri Nov 17 20:39:37 2006 @@ -252,7 +252,7 @@ self.call_method('void class [mscorlib]System.IO.TextWriter::WriteLine(string)', virtual=True) def add_comment(self, text): - self.out.write('// %s\n' % text) + self.code.writeline('// %s' % text) def flush(self): pass Modified: pypy/dist/pypy/translator/cli/test/test_constant.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_constant.py (original) +++ pypy/dist/pypy/translator/cli/test/test_constant.py Fri Nov 17 20:39:37 2006 @@ -119,3 +119,12 @@ s = A('bar') return a.dict[s] assert self.interpret(fn, [True]) == 42 + + def test_multiple_step(self): + from pypy.translator.oosupport import constant + constant.MAX_CONST_PER_STEP = 2 + c1 = [1] + c2 = [2] + def fn(x, y): + return c1[x] + c2[y] + assert self.interpret(fn, [0, 0]) == 3 Modified: pypy/dist/pypy/translator/oosupport/constant.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/constant.py (original) +++ pypy/dist/pypy/translator/oosupport/constant.py Fri Nov 17 20:39:37 2006 @@ -29,6 +29,8 @@ from pypy.rpython.ootypesystem import ootype import operator +MAX_CONST_PER_STEP = 100 + PRIMITIVE_TYPES = set([ootype.Void, ootype.Bool, ootype.Char, ootype.UniChar, ootype.Float, ootype.Signed, ootype.Unsigned, ootype.String, ootype.SignedLongLong, @@ -255,9 +257,9 @@ """ Iterates through each constant, initializing its data. """ gen.add_section("Initialize Data Phase") for const in all_constants: + self._consider_step(gen) gen.add_comment("Constant: %s" % const.name) self._push_constant_during_init(gen, const) - self._consider_step(gen) if not const.initialize_data(gen): gen.pop(const.OOTYPE()) @@ -266,7 +268,7 @@ start a new step every so often to ensure the initialization functions don't get too large and upset mono or the JVM or what have you. """ - if (self._all_counter % 100) == 0: + if (self._all_counter % MAX_CONST_PER_STEP) == 0: self._end_step(gen) self._declare_step(gen, self._step_counter) # open the next step self._all_counter += 1 From arigo at codespeak.net Fri Nov 17 20:49:10 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 17 Nov 2006 20:49:10 +0100 (CET) Subject: [pypy-svn] r34720 - pypy/dist/pypy/module/pypymagic/test Message-ID: <20061117194910.58EB2100AF@code0.codespeak.net> Author: arigo Date: Fri Nov 17 20:49:08 2006 New Revision: 34720 Modified: pypy/dist/pypy/module/pypymagic/test/test_special.py Log: A test file... that is not tested? Obscure. Modified: pypy/dist/pypy/module/pypymagic/test/test_special.py ============================================================================== --- pypy/dist/pypy/module/pypymagic/test/test_special.py (original) +++ pypy/dist/pypy/module/pypymagic/test/test_special.py Fri Nov 17 20:49:08 2006 @@ -1,9 +1,9 @@ import py -from pypy.conftest import gettestobjspace, runappdirect +from pypy.conftest import gettestobjspace, option class AppTest(object): def setup_class(cls): - if runappdirect: + if option.runappdirect: py.test.skip("does not make sense on pypy-c") cls.space = gettestobjspace(**{"objspace.usemodules.select": False}) From antocuni at codespeak.net Fri Nov 17 21:11:39 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Fri, 17 Nov 2006 21:11:39 +0100 (CET) Subject: [pypy-svn] r34721 - pypy/dist/pypy/translator/cli Message-ID: <20061117201139.BE42E100AF@code0.codespeak.net> Author: antocuni Date: Fri Nov 17 21:11:38 2006 New Revision: 34721 Modified: pypy/dist/pypy/translator/cli/function.py Log: bugfix needed for compiling pypy on windows. Modified: pypy/dist/pypy/translator/cli/function.py ============================================================================== --- pypy/dist/pypy/translator/cli/function.py (original) +++ pypy/dist/pypy/translator/cli/function.py Fri Nov 17 21:11:38 2006 @@ -60,7 +60,7 @@ if isinstance(link.last_exception, flowmodel.Variable): self.ilasm.opcode('dup') self.store(link.last_exc_value) - self.ilasm.get_field(('Object_meta', 'Object', 'meta')) + self.ilasm.get_field(('class Object_meta', 'Object', 'meta')) self.store(link.last_exception) else: self.store(link.last_exc_value) From pedronis at codespeak.net Sat Nov 18 00:26:34 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 18 Nov 2006 00:26:34 +0100 (CET) Subject: [pypy-svn] r34725 - in pypy/dist/pypy: rpython translator/backendopt Message-ID: <20061117232634.9F0B2100AF@code0.codespeak.net> Author: pedronis Date: Sat Nov 18 00:26:32 2006 New Revision: 34725 Modified: pypy/dist/pypy/rpython/annlowlevel.py pypy/dist/pypy/translator/backendopt/all.py Log: make --prof-based-inline and --gc=framework compatible Modified: pypy/dist/pypy/rpython/annlowlevel.py ============================================================================== --- pypy/dist/pypy/rpython/annlowlevel.py (original) +++ pypy/dist/pypy/rpython/annlowlevel.py Sat Nov 18 00:26:32 2006 @@ -290,7 +290,7 @@ translator = self.rtyper.annotator.translator newgraphs = translator.graphs[self.original_graph_count:] self.original_graph_count = len(translator.graphs) - backend_optimizations(translator, newgraphs, **flags) + backend_optimizations(translator, newgraphs, secondary=True, **flags) # ____________________________________________________________ Modified: pypy/dist/pypy/translator/backendopt/all.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/all.py (original) +++ pypy/dist/pypy/translator/backendopt/all.py Sat Nov 18 00:26:32 2006 @@ -12,7 +12,7 @@ from pypy.translator.backendopt.support import log from pypy.objspace.flow.model import checkgraph -def backend_optimizations(translator, graphs=None, **kwds): +def backend_optimizations(translator, graphs=None, secondary=False, **kwds): # sensible keywords are # raisingop2direct_call, inline_threshold, mallocs # merge_if_blocks, constfold, heap2stack @@ -43,7 +43,7 @@ print_statistics(translator.graphs[0], translator) if not config.clever_malloc_removal: - if config.profile_based_inline: + if config.profile_based_inline and not secondary: inline_malloc_removal_phase(config, translator, graphs, config.inline_threshold*.5) # xxx tune! inline.instrument_inline_candidates(graphs, config.inline_threshold) From arigo at codespeak.net Sat Nov 18 12:52:09 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 12:52:09 +0100 (CET) Subject: [pypy-svn] r34731 - pypy/dist/pypy/module/rctime/test Message-ID: <20061118115209.509F9100B5@code0.codespeak.net> Author: arigo Date: Sat Nov 18 12:52:07 2006 New Revision: 34731 Modified: pypy/dist/pypy/module/rctime/test/test_rctime.py Log: In case the gmtime() function returns an integer, it sometimes jumps as much as 1.0 between two quick consecutive calls. Modified: pypy/dist/pypy/module/rctime/test/test_rctime.py ============================================================================== --- pypy/dist/pypy/module/rctime/test/test_rctime.py (original) +++ pypy/dist/pypy/module/rctime/test/test_rctime.py Sat Nov 18 12:52:07 2006 @@ -55,7 +55,7 @@ assert res[-1] == 0 # DST is always zero in gmtime() t0 = rctime.mktime(rctime.gmtime()) t1 = rctime.mktime(rctime.gmtime(None)) - assert 0 <= (t1 - t0) < 0.2 + assert 0 <= (t1 - t0) < 1.2 t = rctime.time() assert rctime.gmtime(t) == rctime.gmtime(t) @@ -69,7 +69,7 @@ assert isinstance(res, rctime.struct_time) t0 = rctime.mktime(rctime.localtime()) t1 = rctime.mktime(rctime.localtime(None)) - assert 0 <= (t1 - t0) < 0.2 + assert 0 <= (t1 - t0) < 1.2 t = rctime.time() assert rctime.localtime(t) == rctime.localtime(t) From arigo at codespeak.net Sat Nov 18 16:42:42 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 16:42:42 +0100 (CET) Subject: [pypy-svn] r34734 - in pypy/dist/pypy: annotation/test rpython Message-ID: <20061118154242.6CD76100BE@code0.codespeak.net> Author: arigo Date: Sat Nov 18 16:42:39 2006 New Revision: 34734 Added: pypy/dist/pypy/rpython/controllerentry.py (contents, props changed) Modified: pypy/dist/pypy/annotation/test/test_annrpython.py Log: (pedronis, arigo) Experimentation. See some later check-in message. Modified: pypy/dist/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_annrpython.py (original) +++ pypy/dist/pypy/annotation/test/test_annrpython.py Sat Nov 18 16:42:39 2006 @@ -1,9 +1,11 @@ import autopath import py.test +from pypy import conftest from pypy.tool.udir import udir -from pypy.annotation.annrpython import annmodel +from pypy.annotation import model as annmodel +from pypy.annotation.annrpython import RPythonAnnotator as _RPythonAnnotator from pypy.translator.translator import graphof as tgraphof from pypy.annotation import policy from pypy.annotation import specialize @@ -42,7 +44,12 @@ def setup_class(cls): cls.space = FlowObjSpace() - from pypy.annotation.annrpython import RPythonAnnotator + class RPythonAnnotator(_RPythonAnnotator): + def build_types(self, *args): + s = _RPythonAnnotator.build_types(self, *args) + if conftest.option.view: + self.translator.view() + return s def make_fun(self, func): import inspect @@ -55,11 +62,6 @@ funcgraph.source = inspect.getsource(func) return funcgraph - def show(self, a): - from pypy import conftest - if conftest.option.view: - a.translator.view() - def test_simple_func(self): """ one test source: @@ -2293,7 +2295,6 @@ a = self.RPythonAnnotator() a.build_types(f, []) - self.show(a) v1, v2 = graphof(a, readout).getargs() assert not a.bindings[v1].is_constant() assert not a.bindings[v2].is_constant() @@ -2323,7 +2324,6 @@ a = self.RPythonAnnotator() s = a.build_types(fun, [int]) - self.show(a) assert isinstance(s, annmodel.SomeChar) def test_range_nonneg(self): @@ -2334,7 +2334,6 @@ return 0 a = self.RPythonAnnotator() s = a.build_types(fun, [int, int]) - self.show(a) assert isinstance(s, annmodel.SomeInteger) assert s.nonneg @@ -2346,7 +2345,6 @@ return 0 a = self.RPythonAnnotator() s = a.build_types(fun, [int, int]) - self.show(a) assert isinstance(s, annmodel.SomeInteger) assert s.nonneg @@ -2403,6 +2401,30 @@ from pypy.annotation.classdef import NoSuchSlotError py.test.raises(NoSuchSlotError, a.build_types, fun, [int]) + + def test_simple_controllerentry(self): + from pypy.rpython.controllerentry import ControllerEntry + + class C: + "Imagine some magic here to have a foo attribute on instances" + + def fun(): + c = C() + return c.foo + + class MyC: + def get_foo(self): + return 42 + + class Entry(ControllerEntry): + _about_ = C + _implementation_ = MyC + + a = self.RPythonAnnotator() + s = a.build_types(fun, []) + assert isinstance(s, annmodel.SomeInteger) + + def g(n): return [0,1,2,n] Added: pypy/dist/pypy/rpython/controllerentry.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rpython/controllerentry.py Sat Nov 18 16:42:39 2006 @@ -0,0 +1,46 @@ +from pypy.annotation import model as annmodel +from pypy.annotation.bookkeeper import getbookkeeper +from pypy.rpython.extregistry import ExtRegistryEntry + + +class SomeControlledInstance(annmodel.SomeObject): + + def __init__(self, classdef, originaltype): + self.classdef = classdef + self.knowntype = originaltype + + def s_implself(self): + return annmodel.SomeInstance(self.classdef) + + def delegate(self, methodname, *args_s): + bk = getbookkeeper() + classdef = self.classdef + # emulate a getattr to make sure it's on the classdef + classdef.find_attribute(methodname) + origindesc = classdef.classdesc.lookup(methodname) + s_func = origindesc.s_read_attribute(methodname) + funcdesc, = s_func.descriptions + methdesc = bk.getmethoddesc( + funcdesc, + origindesc.getuniqueclassdef(), + classdef, + methodname) + s_meth = annmodel.SomePBC([methdesc]) + return bk.emulate_pbc_call(bk.position_key, s_meth, args_s, + callback = bk.position_key) + + +class __extend__(SomeControlledInstance): + + def getattr(s_cin, s_attr): + assert s_attr.is_constant() + assert isinstance(s_attr.const, str) + return s_cin.delegate('get_' + s_attr.const) + + +class ControllerEntry(ExtRegistryEntry): + + def compute_result_annotation(self): + cls = self.instance + classdef = self.bookkeeper.getuniqueclassdef(self._implementation_) + return SomeControlledInstance(classdef, cls) From arigo at codespeak.net Sat Nov 18 17:43:01 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 17:43:01 +0100 (CET) Subject: [pypy-svn] r34735 - in pypy/dist/pypy: annotation/test rpython Message-ID: <20061118164301.CB1F9100BE@code0.codespeak.net> Author: arigo Date: Sat Nov 18 17:42:59 2006 New Revision: 34735 Modified: pypy/dist/pypy/annotation/test/test_annrpython.py pypy/dist/pypy/rpython/controllerentry.py Log: (pedronis, arigo) More experimentation... Modified: pypy/dist/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_annrpython.py (original) +++ pypy/dist/pypy/annotation/test/test_annrpython.py Sat Nov 18 17:42:59 2006 @@ -2403,7 +2403,7 @@ def test_simple_controllerentry(self): - from pypy.rpython.controllerentry import ControllerEntry + from pypy.rpython.controllerentry import Controller, ControllerEntry class C: "Imagine some magic here to have a foo attribute on instances" @@ -2412,17 +2412,22 @@ c = C() return c.foo - class MyC: - def get_foo(self): - return 42 + class C_Controller(Controller): + knowntype = C + + def new(self): + return "4" + + def get_foo(self, obj): + return obj + "2" class Entry(ControllerEntry): _about_ = C - _implementation_ = MyC + _controller_ = C_Controller - a = self.RPythonAnnotator() + a = self.RPythonAnnotator(policy=policy.AnnotatorPolicy()) s = a.build_types(fun, []) - assert isinstance(s, annmodel.SomeInteger) + assert s.const == "42" def g(n): Modified: pypy/dist/pypy/rpython/controllerentry.py ============================================================================== --- pypy/dist/pypy/rpython/controllerentry.py (original) +++ pypy/dist/pypy/rpython/controllerentry.py Sat Nov 18 17:42:59 2006 @@ -1,46 +1,67 @@ from pypy.annotation import model as annmodel +from pypy.annotation.pairtype import pairtype from pypy.annotation.bookkeeper import getbookkeeper from pypy.rpython.extregistry import ExtRegistryEntry +from pypy.rpython.annlowlevel import cachedtype +class ControllerEntry(ExtRegistryEntry): + + def compute_result_annotation(self, *args_s): + cls = self.instance + controller = self.getcontroller(*args_s) + s_real_obj = controller.ctrl_new(*args_s) + return SomeControlledInstance(s_real_obj, controller) + + def getcontroller(self, *args_s): + return self._controller_() + + +class Controller(object): + __metaclass__ = cachedtype + + def _freeze_(self): + return True + + def ctrl_new(self, *args_s): + return delegate(self.new, *args_s) + + def ctrl_getattr(self, s_obj, s_attr): + return delegate(self.getattr, s_obj, s_attr) + + def getattr(self, obj, attr): + return getattr(self, 'get_' + attr)(obj) + getattr._annspecialcase_ = 'specialize:arg(2)' + + +def delegate(boundmethod, *args_s): + bk = getbookkeeper() + s_meth = bk.immutablevalue(boundmethod) + return bk.emulate_pbc_call(bk.position_key, s_meth, args_s, + callback = bk.position_key) + +# ____________________________________________________________ + class SomeControlledInstance(annmodel.SomeObject): - def __init__(self, classdef, originaltype): - self.classdef = classdef - self.knowntype = originaltype - - def s_implself(self): - return annmodel.SomeInstance(self.classdef) - - def delegate(self, methodname, *args_s): - bk = getbookkeeper() - classdef = self.classdef - # emulate a getattr to make sure it's on the classdef - classdef.find_attribute(methodname) - origindesc = classdef.classdesc.lookup(methodname) - s_func = origindesc.s_read_attribute(methodname) - funcdesc, = s_func.descriptions - methdesc = bk.getmethoddesc( - funcdesc, - origindesc.getuniqueclassdef(), - classdef, - methodname) - s_meth = annmodel.SomePBC([methdesc]) - return bk.emulate_pbc_call(bk.position_key, s_meth, args_s, - callback = bk.position_key) + def __init__(self, s_real_obj, controller): + self.s_real_obj = s_real_obj + self.controller = controller + self.knowntype = controller.knowntype class __extend__(SomeControlledInstance): def getattr(s_cin, s_attr): assert s_attr.is_constant() - assert isinstance(s_attr.const, str) - return s_cin.delegate('get_' + s_attr.const) + return s_cin.controller.ctrl_getattr(s_cin.s_real_obj, s_attr) -class ControllerEntry(ExtRegistryEntry): +class __extend__(pairtype(SomeControlledInstance, SomeControlledInstance)): - def compute_result_annotation(self): - cls = self.instance - classdef = self.bookkeeper.getuniqueclassdef(self._implementation_) - return SomeControlledInstance(classdef, cls) + def union((s_cin1, s_cin2)): + if s_cin1.controller is not s_cin2.controller: + raise annmodel.UnionError("different controller!") + return SomeControlledInstance(annmodel.unionof(s_cin1.s_real_obj, + s_cin2.s_real_obj), + s_cin1.controller) From arigo at codespeak.net Sat Nov 18 17:51:30 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 17:51:30 +0100 (CET) Subject: [pypy-svn] r34736 - in pypy/dist/pypy: annotation/test rpython Message-ID: <20061118165130.059A6100C1@code0.codespeak.net> Author: arigo Date: Sat Nov 18 17:51:29 2006 New Revision: 34736 Modified: pypy/dist/pypy/annotation/test/test_annrpython.py pypy/dist/pypy/rpython/controllerentry.py Log: (pedronis, arigo) setattr support too. (Check-in message will come one day if it proves to not be all non-sense...) Modified: pypy/dist/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_annrpython.py (original) +++ pypy/dist/pypy/annotation/test/test_annrpython.py Sat Nov 18 17:51:29 2006 @@ -2409,8 +2409,10 @@ "Imagine some magic here to have a foo attribute on instances" def fun(): + lst = [] c = C() - return c.foo + c.foo = lst # side-effect on lst! well, it's a test + return c.foo, lst[0] class C_Controller(Controller): knowntype = C @@ -2421,13 +2423,16 @@ def get_foo(self, obj): return obj + "2" + def set_foo(self, obj, value): + value.append(obj) + class Entry(ControllerEntry): _about_ = C _controller_ = C_Controller a = self.RPythonAnnotator(policy=policy.AnnotatorPolicy()) s = a.build_types(fun, []) - assert s.const == "42" + assert s.const == ("42", "4") def g(n): Modified: pypy/dist/pypy/rpython/controllerentry.py ============================================================================== --- pypy/dist/pypy/rpython/controllerentry.py (original) +++ pypy/dist/pypy/rpython/controllerentry.py Sat Nov 18 17:51:29 2006 @@ -33,6 +33,13 @@ return getattr(self, 'get_' + attr)(obj) getattr._annspecialcase_ = 'specialize:arg(2)' + def ctrl_setattr(self, s_obj, s_attr, s_value): + return delegate(self.setattr, s_obj, s_attr, s_value) + + def setattr(self, obj, attr, value): + return getattr(self, 'set_' + attr)(obj, value) + setattr._annspecialcase_ = 'specialize:arg(2)' + def delegate(boundmethod, *args_s): bk = getbookkeeper() @@ -56,6 +63,10 @@ assert s_attr.is_constant() return s_cin.controller.ctrl_getattr(s_cin.s_real_obj, s_attr) + def setattr(s_cin, s_attr, s_value): + assert s_attr.is_constant() + s_cin.controller.ctrl_setattr(s_cin.s_real_obj, s_attr, s_value) + class __extend__(pairtype(SomeControlledInstance, SomeControlledInstance)): From arigo at codespeak.net Sat Nov 18 18:05:14 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:05:14 +0100 (CET) Subject: [pypy-svn] r34737 - pypy/branch/malloc-cleanup Message-ID: <20061118170514.47F4F100BC@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:05:13 2006 New Revision: 34737 Removed: pypy/branch/malloc-cleanup/ Log: Kill unused branch. From arigo at codespeak.net Sat Nov 18 18:05:50 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:05:50 +0100 (CET) Subject: [pypy-svn] r34738 - pypy/branch/another-keepalive-experiment Message-ID: <20061118170550.E8899100BC@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:05:50 2006 New Revision: 34738 Removed: pypy/branch/another-keepalive-experiment/ Log: (pedronis) kill. From arigo at codespeak.net Sat Nov 18 18:06:48 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:06:48 +0100 (CET) Subject: [pypy-svn] r34739 - pypy/branch/pypy-translation-snapshot Message-ID: <20061118170648.5E572100BC@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:06:46 2006 New Revision: 34739 Removed: pypy/branch/pypy-translation-snapshot/ Log: Ha ha! This one is still around :-) From arigo at codespeak.net Sat Nov 18 18:10:53 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:10:53 +0100 (CET) Subject: [pypy-svn] r34740 - pypy/branch/condexpr Message-ID: <20061118171053.A9BE9100C1@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:10:51 2006 New Revision: 34740 Removed: pypy/branch/condexpr/ Log: I think this branch has been merged. From arigo at codespeak.net Sat Nov 18 18:12:48 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:12:48 +0100 (CET) Subject: [pypy-svn] r34741 - pypy/branch/picklesupport Message-ID: <20061118171248.0ABD8100C1@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:12:47 2006 New Revision: 34741 Removed: pypy/branch/picklesupport/ Log: This branch was merged. From arigo at codespeak.net Sat Nov 18 18:14:26 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:14:26 +0100 (CET) Subject: [pypy-svn] r34742 - pypy/branch/pycollect-dist-pypy Message-ID: <20061118171426.24EFF100C4@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:14:25 2006 New Revision: 34742 Removed: pypy/branch/pycollect-dist-pypy/ Log: Completely outdated. Probably merged actually. From arigo at codespeak.net Sat Nov 18 18:15:33 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:15:33 +0100 (CET) Subject: [pypy-svn] r34743 - pypy/branch/pycompiler Message-ID: <20061118171533.70A00100C4@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:15:32 2006 New Revision: 34743 Removed: pypy/branch/pycompiler/ Log: merged. From arigo at codespeak.net Sat Nov 18 18:16:18 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:16:18 +0100 (CET) Subject: [pypy-svn] r34744 - pypy/branch/pypy-compiler Message-ID: <20061118171618.DD436100C4@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:16:17 2006 New Revision: 34744 Removed: pypy/branch/pypy-compiler/ Log: Unused old branch. From arigo at codespeak.net Sat Nov 18 18:17:46 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:17:46 +0100 (CET) Subject: [pypy-svn] r34745 - pypy/branch/refactor-file Message-ID: <20061118171746.89341100C9@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:17:45 2006 New Revision: 34745 Removed: pypy/branch/refactor-file/ Log: branch merged. From arigo at codespeak.net Sat Nov 18 18:18:47 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:18:47 +0100 (CET) Subject: [pypy-svn] r34746 - pypy/branch/resume-point-hack Message-ID: <20061118171847.6722D100CC@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:18:46 2006 New Revision: 34746 Removed: pypy/branch/resume-point-hack/ Log: (pedronis) technology included into the trunk. From arigo at codespeak.net Sat Nov 18 18:20:45 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 18:20:45 +0100 (CET) Subject: [pypy-svn] r34747 - in pypy: branch/0.6.x release/0.6.x Message-ID: <20061118172045.6D3C8100C9@code0.codespeak.net> Author: arigo Date: Sat Nov 18 18:20:43 2006 New Revision: 34747 Added: pypy/release/0.6.x/ - copied from r34746, pypy/branch/0.6.x/ Removed: pypy/branch/0.6.x/ Log: Move the 0.6.x release branch that was feeling lonely. From arigo at codespeak.net Sat Nov 18 20:59:14 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 20:59:14 +0100 (CET) Subject: [pypy-svn] r34748 - pypy/dist/pypy/translator/c/src Message-ID: <20061118195914.5207F100C3@code0.codespeak.net> Author: arigo Date: Sat Nov 18 20:59:12 2006 New Revision: 34748 Modified: pypy/dist/pypy/translator/c/src/obmalloc.c Log: Minor hacks at obmalloc.c to make its debugging malloc'er independent of the rest of Python too. Modified: pypy/dist/pypy/translator/c/src/obmalloc.c ============================================================================== --- pypy/dist/pypy/translator/c/src/obmalloc.c (original) +++ pypy/dist/pypy/translator/c/src/obmalloc.c Sat Nov 18 20:59:12 2006 @@ -430,7 +430,7 @@ if (bp == NULL) return NULL; -#ifdef PYMALLOC_DEBUG +#if 0 /* XXX removed for PyPy - #ifdef PYMALLOC_DEBUG */ if (Py_GETENV("PYTHONMALLOCSTATS")) _PyObject_DebugMallocStats(); #endif @@ -894,6 +894,16 @@ * it wraps a real allocator, adding extra debugging info to the memory blocks. */ +/* XXX added for PyPy for stand-alone usage */ +void Py_FatalError(const char *msg) +{ + fprintf(stderr, "Py_FatalError() called in obmalloc!\n%s\n", msg); + exit(1); +} +#define PyOS_snprintf snprintf +/* end of XXX */ + + /* Special bytes broadcast into debug memory blocks at appropriate times. * Strings of these are unlikely to be valid addresses, floats, ints or * 7-bit ASCII. From arigo at codespeak.net Sat Nov 18 23:09:41 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 23:09:41 +0100 (CET) Subject: [pypy-svn] r34749 - in pypy/dist/pypy: . interpreter module/_stackless module/_stackless/test Message-ID: <20061118220941.CFA91100C3@code0.codespeak.net> Author: arigo Date: Sat Nov 18 23:09:38 2006 New Revision: 34749 Added: pypy/dist/pypy/module/_stackless/clonable.py (contents, props changed) pypy/dist/pypy/module/_stackless/test/test_clonable.py (contents, props changed) Modified: pypy/dist/pypy/conftest.py pypy/dist/pypy/interpreter/mixedmodule.py pypy/dist/pypy/module/_stackless/__init__.py pypy/dist/pypy/module/_stackless/interp_clonable.py Log: (cfbolz a couple of days ago, arigo) Rewrite the app-level clonable coroutine by reusing as much existing code as possible, with a mixin, instead of copy-n-paste. Debugging of a stackless+framework pypy-c is in-progress... Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Sat Nov 18 23:09:38 2006 @@ -113,6 +113,9 @@ def unpackiterable(self, itr): return list(itr) + def is_true(self, obj): + return bool(obj) + class OpErrKeyboardInterrupt(KeyboardInterrupt): pass Modified: pypy/dist/pypy/interpreter/mixedmodule.py ============================================================================== --- pypy/dist/pypy/interpreter/mixedmodule.py (original) +++ pypy/dist/pypy/interpreter/mixedmodule.py Sat Nov 18 23:09:38 2006 @@ -88,7 +88,15 @@ if '__doc__' not in loaders: loaders['__doc__'] = cls.get__doc__ - buildloaders = classmethod(buildloaders) + buildloaders = classmethod(buildloaders) + + def extra_interpdef(self, name, spec): + cls = self.__class__ + pkgroot = cls.__module__ + loader = getinterpevalloader(pkgroot, spec) + space = self.space + w_obj = loader(space) + space.setattr(space.wrap(self), space.wrap(name), w_obj) def get__file__(cls, space): """ NOT_RPYTHON. Modified: pypy/dist/pypy/module/_stackless/__init__.py ============================================================================== --- pypy/dist/pypy/module/_stackless/__init__.py (original) +++ pypy/dist/pypy/module/_stackless/__init__.py Sat Nov 18 23:09:38 2006 @@ -14,7 +14,6 @@ interpleveldefs = { 'tasklet' : 'interp_stackless.tasklet', 'coroutine' : 'coroutine.AppCoroutine', - #'clonable' : 'clonable.ClonableCoroutine', 'greenlet' : 'interp_greenlet.AppGreenlet', 'usercostate': 'composable_coroutine.W_UserCoState', } @@ -24,8 +23,11 @@ # are not yet directly supported from pypy.module._stackless.coroutine import post_install as post_install_coro post_install_coro(self) - #from pypy.module._stackless.clonable import post_install as post_install_clonable - #post_install_clonable(self) from pypy.module._stackless.interp_greenlet import post_install as post_install_greenlet post_install_greenlet(self) + if self.space.config.translation.gc in ('framework', 'stacklessgc'): + from pypy.module._stackless.clonable import post_install as post_install_clonable + self.extra_interpdef('clonable', 'clonable.AppClonableCoroutine') + self.extra_interpdef('fork', 'clonable.fork') + post_install_clonable(self) Added: pypy/dist/pypy/module/_stackless/clonable.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_stackless/clonable.py Sat Nov 18 23:09:38 2006 @@ -0,0 +1,103 @@ +from pypy.interpreter.error import OperationError +from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import interp2app, ObjSpace, W_Root +from pypy.module._stackless.coroutine import AppCoroutine, AppCoState +from pypy.module._stackless.coroutine import makeStaticMethod +from pypy.module._stackless.interp_coroutine import AbstractThunk +from pypy.module._stackless.interp_clonable import InterpClonableMixin + + +class AppClonableCoroutine(AppCoroutine, InterpClonableMixin): + + def hello(self): + self.hello_local_pool() + AppCoroutine.hello(self) + + def goodbye(self): + AppCoroutine.goodbye(self) + self.goodbye_local_pool() + + def descr_method__new__(space, w_subtype): + co = space.allocate_instance(AppClonableCoroutine, w_subtype) + costate = AppClonableCoroutine._get_state(space) + AppClonableCoroutine.__init__(co, space, state=costate) + return space.wrap(co) + + def _get_state(space): + return space.fromcache(AppClonableCoState) + _get_state = staticmethod(_get_state) + + def w_getcurrent(space): + return space.wrap(AppClonableCoroutine._get_state(space).current) + w_getcurrent = staticmethod(w_getcurrent) + + def w_clone(self): + space = self.space + costate = self.costate + if costate.current is self: + raise OperationError(space.w_RuntimeError, + space.wrap("clone() cannot clone the " + "current coroutine" + "; use fork() instead")) + copy = AppClonableCoroutine(space, state=costate) + self.clone_into(copy) + return space.wrap(copy) + + def descr__reduce__(self, space): + raise OperationError(space.w_TypeError, + space.wrap("_stackless.clonable instances are " + "not picklable")) + + +AppClonableCoroutine.typedef = TypeDef("clonable", AppCoroutine.typedef, + __new__ = interp2app(AppClonableCoroutine.descr_method__new__.im_func), + getcurrent = interp2app(AppClonableCoroutine.w_getcurrent), + clone = interp2app(AppClonableCoroutine.w_clone), + __reduce__ = interp2app(AppClonableCoroutine.descr__reduce__, + unwrap_spec=['self', ObjSpace]), +) + +class AppClonableCoState(AppCoState): + def post_install(self): + self.current = self.main = AppClonableCoroutine(self.space, + is_main=True, + state=self) + +def post_install(module): + makeStaticMethod(module, 'clonable', 'getcurrent') + space = module.space + AppClonableCoroutine._get_state(space).post_install() + +# ____________________________________________________________ + +class ForkThunk(AbstractThunk): + def __init__(self, coroutine): + self.coroutine = coroutine + self.newcoroutine = None + def call(self): + oldcoro = self.coroutine + self.coroutine = None + newcoro = AppClonableCoroutine(oldcoro.space, state=oldcoro.costate) + oldcoro.clone_into(newcoro) + self.newcoroutine = newcoro + +def fork(space): + """Fork, as in the Unix fork(): the call returns twice, and the return + value of the call is either the new 'child' coroutine object (if returning + into the parent), or None (if returning into the child). This returns + into the parent first, which can switch to the child later. + """ + costate = AppClonableCoroutine._get_state(space) + current = costate.current + if current is costate.main: + raise OperationError(space.w_RuntimeError, + space.wrap("cannot fork() in the main " + "clonable coroutine")) + thunk = ForkThunk(current) + coro_fork = AppClonableCoroutine(space, state=costate) + coro_fork.bind(thunk) + coro_fork.switch() + # we resume here twice. The following would need explanations about + # why it returns the correct thing in both the parent and the child... + return space.wrap(thunk.newcoroutine) +fork.unwrap_spec = [ObjSpace] Modified: pypy/dist/pypy/module/_stackless/interp_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/interp_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/interp_clonable.py Sat Nov 18 23:09:38 2006 @@ -6,31 +6,46 @@ from pypy.tool import stdlib_opcode as pythonopcode -class InterpClonableCoroutine(Coroutine): + +class InterpClonableMixin: local_pool = None + _mixin_ = True - def hello(self): + def hello_local_pool(self): if we_are_translated(): self.saved_pool = gc_swap_pool(self.local_pool) - def goodbye(self): + def goodbye_local_pool(self): if we_are_translated(): self.local_pool = gc_swap_pool(self.saved_pool) - def clone(self): + def clone_into(self, copy): if not we_are_translated(): raise NotImplementedError - if self.getcurrent() is self: - raise RuntimeError("clone() cannot clone the current coroutine; " - "use fork() instead") if self.local_pool is None: # force it now self.local_pool = gc_swap_pool(gc_swap_pool(None)) # cannot gc_clone() directly self, because it is not in its own # local_pool. Moreover, it has a __del__, which cloning doesn't # support properly at the moment. - copy = InterpClonableCoroutine(self.costate) copy.parent = self.parent copy.frame, copy.local_pool = gc_clone(self.frame, self.local_pool) + + +class InterpClonableCoroutine(Coroutine, InterpClonableMixin): + + def hello(self): + self.hello_local_pool() + + def goodbye(self): + self.goodbye_local_pool() + + def clone(self): + # hack, this is overridden in AppClonableCoroutine + if self.getcurrent() is self: + raise RuntimeError("clone() cannot clone the current coroutine; " + "use fork() instead") + copy = InterpClonableCoroutine(self.costate) + self.clone_into(copy) return copy Added: pypy/dist/pypy/module/_stackless/test/test_clonable.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_stackless/test/test_clonable.py Sat Nov 18 23:09:38 2006 @@ -0,0 +1,83 @@ +from pypy.conftest import gettestobjspace, option +import py, sys + +# app-level testing of coroutine cloning + +class AppTestClonable: + + def setup_class(cls): + if not option.runappdirect: + py.test.skip('pure appdirect test (run with -A)') + cls.space = space = gettestobjspace(usemodules=('_stackless',)) + if not space.is_true(space.appexec([], """(): + import _stackless + return hasattr(_stackless, 'clonable') + """)): + py.test.skip('no _stackless.clonable') + + + def test_solver(self): + import new, sys + + mod = new.module('mod') + sys.modules['mod'] = mod + try: + exec ''' +import _stackless + +class Fail(Exception): + pass + +class Success(Exception): + pass + +def first_solution(func): + global next_answer + co = _stackless.clonable() + co.bind(func) + pending = [(co, None)] + while pending: + co, next_answer = pending.pop() + try: + co.switch() + except Fail: + pass + except Success, e: + return e.args[0] + else: + # zero_or_one() called, clone the coroutine + co2 = co.clone() + pending.append((co2, 1)) + pending.append((co, 0)) + raise Fail("no solution") + +pending = [] +main = _stackless.clonable.getcurrent() + +def zero_or_one(): + main.switch() + return next_answer + +# ____________________________________________________________ + +invalid_prefixes = { + (0, 0): True, + (0, 1, 0): True, + (0, 1, 1): True, + (1, 0): True, + (1, 1, 0, 0): True, + } + +def example(): + test = [] + for n in range(5): + test.append(zero_or_one()) + if tuple(test) in invalid_prefixes: + raise Fail + raise Success(test) + +res = first_solution(example) +assert res == [1, 1, 0, 1, 0] +''' in mod.__dict__ + finally: + del sys.modules['mod'] From arigo at codespeak.net Sat Nov 18 23:15:20 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 18 Nov 2006 23:15:20 +0100 (CET) Subject: [pypy-svn] r34750 - in pypy/dist/pypy: rpython/lltypesystem rpython/memory/gctransform translator/backendopt Message-ID: <20061118221520.DC464100C3@code0.codespeak.net> Author: arigo Date: Sat Nov 18 23:15:17 2006 New Revision: 34750 Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py pypy/dist/pypy/rpython/memory/gctransform/framework.py pypy/dist/pypy/rpython/memory/gctransform/transform.py pypy/dist/pypy/translator/backendopt/graphanalyze.py Log: (pedronis, arigo) Ouah! A whole evening of installing Electric Fence and then Valgrind to get at the roots of this problem. Trivial, as usual: the unsafe_call operation is not considered as a call, so the GC roots are not pushed/popped around it. Bouh. Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py Sat Nov 18 23:15:17 2006 @@ -123,7 +123,7 @@ 'direct_call': LLOp(canraise=(Exception,)), 'indirect_call': LLOp(canraise=(Exception,)), - 'safe_call': LLOp(), + #'safe_call': LLOp(), 'unsafe_call': LLOp(canraise=(Exception,)), # __________ numeric operations __________ Modified: pypy/dist/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform/framework.py Sat Nov 18 23:15:17 2006 @@ -443,6 +443,7 @@ self.default(hop) gct_indirect_call = gct_direct_call + gct_unsafe_call = gct_direct_call def gct_malloc(self, hop): op = hop.spaceop Modified: pypy/dist/pypy/rpython/memory/gctransform/transform.py ============================================================================== --- pypy/dist/pypy/rpython/memory/gctransform/transform.py (original) +++ pypy/dist/pypy/rpython/memory/gctransform/transform.py Sat Nov 18 23:15:17 2006 @@ -313,8 +313,8 @@ hop.rename('bare_' + hop.spaceop.opname) gct_setarrayitem = gct_setfield - def gct_safe_call(self, hop): - hop.rename("direct_call") + #def gct_safe_call(self, hop): + # hop.rename("direct_call") def gct_zero_gc_pointers_inside(self, hop): pass Modified: pypy/dist/pypy/translator/backendopt/graphanalyze.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/graphanalyze.py (original) +++ pypy/dist/pypy/translator/backendopt/graphanalyze.py Sat Nov 18 23:15:17 2006 @@ -38,6 +38,8 @@ if op.args[-1].value is None: return True return self.analyze_indirect_call(op.args[-1].value, seen) + elif op.opname == "unsafe_call": + return True if self.operation_is_true(op): return True From antocuni at codespeak.net Sun Nov 19 14:45:43 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 19 Nov 2006 14:45:43 +0100 (CET) Subject: [pypy-svn] r34752 - pypy/dist/pypy/rlib/test Message-ID: <20061119134543.2BC22100B5@code0.codespeak.net> Author: antocuni Date: Sun Nov 19 14:45:42 2006 New Revision: 34752 Modified: pypy/dist/pypy/rlib/test/test_streamio.py Log: Test streamio also using ootypesystem. Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Sun Nov 19 14:45:42 2006 @@ -354,7 +354,7 @@ for seekto in range(0, end+1) for whence in [0, 1, 2]] random.shuffle(cases) - if isinstance(self, LLRtypeMixin): + if isinstance(self, (LLRtypeMixin, OORtypeMixin)): cases = cases[:7] # pick some cases at random - too slow! def f(): all = file.readall() @@ -387,7 +387,7 @@ for seekto in range(readto, end+1) for whence in [1, 2]] random.shuffle(cases) - if isinstance(self, LLRtypeMixin): + if isinstance(self, (LLRtypeMixin, OORtypeMixin)): cases = cases[:7] # pick some cases at random - too slow! def f(): for readto, seekto, whence in cases: @@ -415,6 +415,10 @@ LLRtypeMixin): pass +class TestBufferingInputStreamTestsOOinterp(BaseTestBufferingInputStreamTests, + OORtypeMixin): + pass + class TestBufferedRead: packets = ["a", "b", "\n", "def", "\nxy\npq\nuv", "wx"] lines = ["ab\n", "def\n", "xy\n", "pq\n", "uvwx"] @@ -509,7 +513,11 @@ class TestBufferingOutputStreamLLinterp(BaseTestBufferingOutputStream, LLRtypeMixin): pass - + +class TestBufferingOutputStreamOOinterp(BaseTestBufferingOutputStream, + OORtypeMixin): + pass + class BaseTestLineBufferingOutputStream(BaseRtypingTest): @@ -550,7 +558,11 @@ class TestLineBufferingOutputStreamLLinterp(BaseTestLineBufferingOutputStream, LLRtypeMixin): pass - + +class TestLineBufferingOutputStreamOOinterp(BaseTestLineBufferingOutputStream, + OORtypeMixin): + pass + class BaseTestCRLFFilter(BaseRtypingTest): @@ -575,6 +587,8 @@ class TestCRLFFilterLLinterp(BaseTestCRLFFilter, LLRtypeMixin): pass +class TestCRLFFilterOOinterp(BaseTestCRLFFilter, OORtypeMixin): + pass class TestMMapFile(BaseTestBufferingInputStreamTests): tfn = None @@ -678,6 +692,10 @@ BaseTestBufferingInputOutputStreamTests, LLRtypeMixin): pass +class TestBufferingInputOutputStreamTestsOOinterp( + BaseTestBufferingInputOutputStreamTests, OORtypeMixin): + pass + class BaseTestTextInputFilter(BaseRtypingTest): @@ -782,6 +800,9 @@ class TestTextInputFilterLLinterp(BaseTestTextInputFilter, LLRtypeMixin): pass +class TestTextInputFilterOOinterp(BaseTestTextInputFilter, OORtypeMixin): + pass + class BaseTestTextOutputFilter(BaseRtypingTest): @@ -862,6 +883,9 @@ class TestTextOutputFilterLLinterp(BaseTestTextOutputFilter, LLRtypeMixin): pass +class TestTextOutputFilterOOinterp(BaseTestTextOutputFilter, OORtypeMixin): + pass + class TestDecodingInputFilter: From arigo at codespeak.net Sun Nov 19 14:54:50 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 19 Nov 2006 14:54:50 +0100 (CET) Subject: [pypy-svn] r34753 - in pypy/dist/pypy/translator/c: . src Message-ID: <20061119135450.231DE100BC@code0.codespeak.net> Author: arigo Date: Sun Nov 19 14:54:48 2006 New Revision: 34753 Modified: pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/c/src/standalone.h Log: (pedronis, arigo) A makefile target 'debug_mem' that compiles without obmalloc, making debugging under valgrind possible. Note that for pypy-c translations you can recompile the main file only (testing_1.c) instead of all of them. Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Sun Nov 19 14:54:48 2006 @@ -864,6 +864,9 @@ debug_exc: \tmake CFLAGS="-g -DDO_LOG_EXC" +debug_mem: +\tmake CFLAGS="-g -DNO_OBMALLOC" + profile: \tmake CFLAGS="-pg $(CFLAGS)" LDFLAGS="-pg $(LDFLAGS)" 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 Nov 19 14:54:48 2006 @@ -5,8 +5,16 @@ #include #ifndef PYPY_NOT_MAIN_FILE -#ifndef WITH_PYMALLOC -#define WITH_PYMALLOC + +#ifdef NO_OBMALLOC +void *PyObject_Malloc(size_t n) { return malloc(n); } +void *PyObject_Realloc(void *p, size_t n) { return realloc(p, n); } +void PyObject_Free(void *p) { if (p) { *((int*)p) = 0xDDDDDDDD; } free(p); } +#else +# ifndef WITH_PYMALLOC +# define WITH_PYMALLOC +# endif +# include "obmalloc.c" #endif -#include "obmalloc.c" + #endif From antocuni at codespeak.net Sun Nov 19 15:08:06 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 19 Nov 2006 15:08:06 +0100 (CET) Subject: [pypy-svn] r34754 - pypy/dist/pypy/translator/cli/test Message-ID: <20061119140806.C4CCF100C0@code0.codespeak.net> Author: antocuni Date: Sun Nov 19 15:08:05 2006 New Revision: 34754 Added: pypy/dist/pypy/translator/cli/test/test_streamio.py (contents, props changed) Log: Test streamio with gencli. One test need to be fixed. Added: pypy/dist/pypy/translator/cli/test/test_streamio.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/cli/test/test_streamio.py Sun Nov 19 15:08:05 2006 @@ -0,0 +1,29 @@ +import py +from pypy.translator.cli.test.runtest import CliTest +from pypy.rlib.test.test_streamio import BaseTestBufferingInputStreamTests,\ + BaseTestBufferingOutputStream, BaseTestLineBufferingOutputStream,\ + BaseTestCRLFFilter, BaseTestBufferingInputOutputStreamTests,\ + BaseTestTextInputFilter, BaseTestTextOutputFilter + +class TestBufferingInputStreamTests(CliTest, BaseTestBufferingInputStreamTests): + pass + +class TestBufferingOutputStream(CliTest, BaseTestBufferingOutputStream): + pass + +class TestLineBufferingOutputStream(CliTest, BaseTestLineBufferingOutputStream): + def test_write(self): + py.test.skip('Fixme!') + +class TestCRLFFilter(CliTest, BaseTestCRLFFilter): + pass + +class TestBufferingInputOutputStreamTests(CliTest, BaseTestBufferingInputOutputStreamTests): + pass + +class TestTextInputFilter(CliTest, BaseTestTextInputFilter): + pass + +class TestTextOutputFilter(CliTest, BaseTestTextOutputFilter): + pass + From arigo at codespeak.net Sun Nov 19 17:37:05 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 19 Nov 2006 17:37:05 +0100 (CET) Subject: [pypy-svn] r34760 - in pypy/dist/pypy: rpython/lltypesystem translator/c translator/c/src Message-ID: <20061119163705.BEF93100C2@code0.codespeak.net> Author: arigo Date: Sun Nov 19 17:37:02 2006 New Revision: 34760 Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py pypy/dist/pypy/translator/c/exceptiontransform.py pypy/dist/pypy/translator/c/extfunc.py pypy/dist/pypy/translator/c/funcgen.py pypy/dist/pypy/translator/c/node.py pypy/dist/pypy/translator/c/src/exception.h Log: (pedronis, arigo) Replacing the 'debug_log_exc' operation with a somewhat improved version. The C code and its indirections are still rather obscure, and it's not the Ultimate Traceback Shower for RPython. Next time... Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py Sun Nov 19 17:37:02 2006 @@ -399,7 +399,6 @@ 'debug_view': LLOp(), 'debug_print': LLOp(), 'debug_pdb': LLOp(), - 'debug_log_exc': LLOp(), 'debug_assert': LLOp(canfold=True), 'debug_fatalerror': LLOp(), Modified: pypy/dist/pypy/translator/c/exceptiontransform.py ============================================================================== --- pypy/dist/pypy/translator/c/exceptiontransform.py (original) +++ pypy/dist/pypy/translator/c/exceptiontransform.py Sun Nov 19 17:37:02 2006 @@ -56,7 +56,6 @@ def rpyexc_occured(): exc_type = exc_data.exc_type - lloperation.llop.debug_log_exc(lltype.Void, exc_type) return exc_type is not null_type # XXX tmp HACK for genllvm @@ -64,7 +63,6 @@ # calling rpyexc_occured() from c code with lltype.Bool def _rpyexc_occured(): exc_type = exc_data.exc_type - lloperation.llop.debug_log_exc(lltype.Void, exc_type) return exc_type is not null_type def rpyexc_fetch_type(): @@ -87,7 +85,8 @@ rpyexc_occured, [], l2a(lltype.Bool)) self.rpyexc_occured_ptr = Constant(lltype.functionptr( RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred", - graph=rpyexc_occured_graph), + graph=rpyexc_occured_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_OCCURED_TYPE)) # XXX tmp HACK for genllvm @@ -96,7 +95,8 @@ _rpyexc_occured, [], l2a(lltype.Signed)) self._rpyexc_occured_ptr = Constant(lltype.functionptr( _RPYEXC_OCCURED_TYPE, "_RPyExceptionOccurred", - graph=_rpyexc_occured_graph), + graph=_rpyexc_occured_graph, + exception_policy="exc_helper"), lltype.Ptr(_RPYEXC_OCCURED_TYPE)) RPYEXC_FETCH_TYPE_TYPE = lltype.FuncType([], self.lltype_of_exception_type) @@ -105,7 +105,8 @@ l2a(self.lltype_of_exception_type)) self.rpyexc_fetch_type_ptr = Constant(lltype.functionptr( RPYEXC_FETCH_TYPE_TYPE, "RPyFetchExceptionType", - graph=rpyexc_fetch_type_graph), + graph=rpyexc_fetch_type_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_FETCH_TYPE_TYPE)) RPYEXC_FETCH_VALUE_TYPE = lltype.FuncType([], self.lltype_of_exception_value) @@ -114,7 +115,8 @@ l2a(self.lltype_of_exception_value)) self.rpyexc_fetch_value_ptr = Constant(lltype.functionptr( RPYEXC_FETCH_VALUE_TYPE, "RPyFetchExceptionValue", - graph=rpyexc_fetch_value_graph), + graph=rpyexc_fetch_value_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_FETCH_VALUE_TYPE)) RPYEXC_CLEAR = lltype.FuncType([], lltype.Void) @@ -122,7 +124,8 @@ rpyexc_clear, [], l2a(lltype.Void)) self.rpyexc_clear_ptr = Constant(lltype.functionptr( RPYEXC_CLEAR, "RPyClearException", - graph=rpyexc_clear_graph), + graph=rpyexc_clear_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_CLEAR)) RPYEXC_RAISE = lltype.FuncType([self.lltype_of_exception_type, @@ -134,7 +137,8 @@ l2a(lltype.Void)) self.rpyexc_raise_ptr = Constant(lltype.functionptr( RPYEXC_RAISE, "RPyRaiseException", - graph=rpyexc_raise_graph), + graph=rpyexc_raise_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_RAISE)) mixlevelannotator.finish() @@ -321,7 +325,6 @@ lltype.Bool) else: v_exc_type = self.ExcData_repr.getfield(self.cexcdata, 'exc_type', llops) - llops.genop('debug_log_exc', [v_exc_type], lltype.Void) var_exc_occured = llops.genop('ptr_nonzero', [v_exc_type], lltype.Bool) Modified: pypy/dist/pypy/translator/c/extfunc.py ============================================================================== --- pypy/dist/pypy/translator/c/extfunc.py (original) +++ pypy/dist/pypy/translator/c/extfunc.py Sun Nov 19 17:37:02 2006 @@ -208,7 +208,7 @@ yield ('RPYTHON_PYEXCCLASS2EXC', exceptiondata.fn_pyexcclass2exc) yield ('_RPyExceptionOccurred', exctransformer._rpyexc_occured_ptr.value) - yield ('RPyExceptionOccurred', exctransformer.rpyexc_occured_ptr.value) + yield ('RPyExceptionOccurred1', 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) Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Sun Nov 19 17:37:02 2006 @@ -27,7 +27,7 @@ if USESLOTS: __slots__ = """graph db gcpolicy - cpython_exc + exception_policy more_ll_values vars lltypes @@ -36,11 +36,11 @@ blocknum oldgraph""".split() - def __init__(self, graph, db, cpython_exc=False, functionname=None): + def __init__(self, graph, db, exception_policy=None, functionname=None): self.graph = graph self.db = db self.gcpolicy = db.gcpolicy - self.cpython_exc = cpython_exc + self.exception_policy = exception_policy self.functionname = functionname # apply the stackless transformation if db.stacklesstransformer: @@ -85,7 +85,7 @@ self.more_ll_values.append(link.llexitcase) elif link.exitcase is not None: mix.append(Constant(link.exitcase)) - if self.cpython_exc: + if self.exception_policy == "CPython": v, exc_cleanup_ops = self.graph.exc_cleanup mix.append(v) for cleanupop in exc_cleanup_ops: @@ -179,7 +179,7 @@ return self.db.get(ErrorValue(returnlltype)) def return_with_error(self): - if self.cpython_exc: + if self.exception_policy == "CPython": assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr v, exc_cleanup_ops = self.graph.exc_cleanup vanishing_exc_value = self.expr(v) @@ -226,13 +226,15 @@ if len(block.exits) == 0: assert len(block.inputargs) == 1 # regular return block - if self.cpython_exc: + if self.exception_policy == "CPython": assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr yield 'if (RPyExceptionOccurred()) {' yield '\tRPyConvertExceptionToCPython();' yield '\treturn NULL;' yield '}' retval = self.expr(block.inputargs[0]) + if self.exception_policy != "exc_helper": + yield 'RPY_DEBUG_RETURN();' yield 'return %s;' % retval continue elif block.exitswitch is None: @@ -717,10 +719,6 @@ c_string_constant(' '.join(format) + '\n\000'), ''.join([', ' + s for s in argv])) - def OP_DEBUG_LOG_EXC(self, op): - exc_type = self.expr(op.args[0]) - return 'RPY_LOG_EXC(%s);' % exc_type - def OP_DEBUG_ASSERT(self, op): return '/* debug_assert removed */' Modified: pypy/dist/pypy/translator/c/node.py ============================================================================== --- pypy/dist/pypy/translator/c/node.py (original) +++ pypy/dist/pypy/translator/c/node.py Sun Nov 19 17:37:02 2006 @@ -698,8 +698,9 @@ raise ValueError, "trying to compile suggested primitive %r" % ( fnobj._callable,) elif hasattr(fnobj, 'graph'): - cpython_exc = getattr(fnobj, 'exception_policy', None) == "CPython" - return [FunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)] + exception_policy = getattr(fnobj, 'exception_policy', None) + return [FunctionCodeGenerator(fnobj.graph, db, exception_policy, + functionname)] elif getattr(fnobj, 'external', None) == 'C': # deprecated case if hasattr(fnobj, 'includes'): 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 Sun Nov 19 17:37:02 2006 @@ -6,7 +6,9 @@ PyObject *RPythonError; #endif -#define RPY_LOG_EXC(exc_type) +/* just a renaming, unless DO_LOG_EXC is set */ +#define RPyExceptionOccurred RPyExceptionOccurred1 +#define RPY_DEBUG_RETURN() /* nothing */ #ifndef PyExceptionClass_Check /* Python < 2.5 */ # define PyExceptionClass_Check(x) PyClass_Check(x) @@ -21,13 +23,27 @@ /******************************************************************/ #ifdef DO_LOG_EXC -#undef RPY_LOG_EXC -#define RPY_LOG_EXC(exc_type) if(exc_type) { \ - fprintf(stderr, "propagating %s:%ld %s %s\n", \ - __FILE__, __LINE__, __FUNCTION__, \ - exc_type->ov_name->items); \ +#undef RPyExceptionOccurred +#undef RPY_DEBUG_RETURN +#define RPyExceptionOccurred() RPyDebugException(" noticing a") +#define RPY_DEBUG_RETURN() RPyDebugException("leaving with") +#define RPyDebugException(msg) ( \ + RPyExceptionOccurred1() \ + ? (RPyDebugReturnShowException(msg, __FILE__, __LINE__, __FUNCTION__), 1) \ + : 0 \ + ) +void RPyDebugReturnShowException(const char *msg, const char *filename, + long lineno, const char *functionname); +#ifndef PYPY_NOT_MAIN_FILE +void RPyDebugReturnShowException(const char *msg, const char *filename, + long lineno, const char *functionname) +{ + fprintf(stderr, "%s %s: %s:%ld %s\n", msg, + RPyFetchExceptionType()->ov_name->items, + filename, lineno, functionname); } #endif +#endif /* DO_LOG_EXC */ /* Hint: functions and macros not defined here, like RPyRaiseException, come from exctransformer via the table in extfunc.py. */ @@ -109,7 +125,7 @@ #else /* non-RPython version of exceptions, using CPython only */ /******************************************************************/ -#define RPyExceptionOccurred() PyErr_Occurred() +#define RPyExceptionOccurred1() PyErr_Occurred() #define RPyRaiseException(etype, evalue) PyErr_Restore(etype, evalue, NULL) #define RPyFetchException(etypevar, evaluevar, ignored) do { \ PyObject *__tb; \ From antocuni at codespeak.net Sun Nov 19 18:09:33 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Sun, 19 Nov 2006 18:09:33 +0100 (CET) Subject: [pypy-svn] r34761 - in pypy/dist/pypy/translator/cli: src test Message-ID: <20061119170933.3DA35100BC@code0.codespeak.net> Author: antocuni Date: Sun Nov 19 18:09:32 2006 New Revision: 34761 Modified: pypy/dist/pypy/translator/cli/src/pypylib.cs pypy/dist/pypy/translator/cli/test/test_streamio.py Log: bugfix, and don't skip the test that now passes. Modified: pypy/dist/pypy/translator/cli/src/pypylib.cs ============================================================================== --- pypy/dist/pypy/translator/cli/src/pypylib.cs (original) +++ pypy/dist/pypy/translator/cli/src/pypylib.cs Sun Nov 19 18:09:32 2006 @@ -273,7 +273,7 @@ if (stop > s.Length) stop = s.Length; int count=stop-start; - if (start > s.Length) + if (start > s.Length || stop == 0) return -1; return s.LastIndexOf(ch, stop-1, count); } Modified: pypy/dist/pypy/translator/cli/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_streamio.py (original) +++ pypy/dist/pypy/translator/cli/test/test_streamio.py Sun Nov 19 18:09:32 2006 @@ -12,8 +12,7 @@ pass class TestLineBufferingOutputStream(CliTest, BaseTestLineBufferingOutputStream): - def test_write(self): - py.test.skip('Fixme!') + pass class TestCRLFFilter(CliTest, BaseTestCRLFFilter): pass From fijal at codespeak.net Sun Nov 19 18:10:47 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 19 Nov 2006 18:10:47 +0100 (CET) Subject: [pypy-svn] r34762 - in pypy/dist/pypy/lib: constraint test2 Message-ID: <20061119171047.4573F100BC@code0.codespeak.net> Author: fijal Date: Sun Nov 19 18:10:46 2006 New Revision: 34762 Modified: pypy/dist/pypy/lib/constraint/ (props changed) pypy/dist/pypy/lib/test2/test_binascii.py (props changed) Log: Fixeol From fijal at codespeak.net Sun Nov 19 18:11:03 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 19 Nov 2006 18:11:03 +0100 (CET) Subject: [pypy-svn] r34763 - in pypy/dist/pypy/lib/pyontology: . test Message-ID: <20061119171103.89D86100C4@code0.codespeak.net> Author: fijal Date: Sun Nov 19 18:10:56 2006 New Revision: 34763 Modified: pypy/dist/pypy/lib/pyontology/sparql_grammar.py (props changed) pypy/dist/pypy/lib/pyontology/test/test_sparql.py (props changed) Log: Fixeol From fijal at codespeak.net Sun Nov 19 18:11:39 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 19 Nov 2006 18:11:39 +0100 (CET) Subject: [pypy-svn] r34764 - in pypy/dist/pypy/lib: . distributed test2 Message-ID: <20061119171139.312C3100BC@code0.codespeak.net> Author: fijal Date: Sun Nov 19 18:11:32 2006 New Revision: 34764 Added: pypy/dist/pypy/lib/distributed/ (props changed) pypy/dist/pypy/lib/distributed/__init__.py (contents, props changed) pypy/dist/pypy/lib/distributed/protocol.py - copied unchanged from r34690, pypy/dist/pypy/lib/distributed.py Removed: pypy/dist/pypy/lib/distributed.py Modified: pypy/dist/pypy/lib/test2/test_distributed.py Log: Moved distributed to it's own directory. More refactoring planned. Added: pypy/dist/pypy/lib/distributed/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/distributed/__init__.py Sun Nov 19 18:11:32 2006 @@ -0,0 +1,2 @@ + +from protocol import RemoteProtocol, test_env Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Sun Nov 19 18:11:32 2006 @@ -16,10 +16,9 @@ def test_init(self): import distributed - distributed.proxy def test_protocol(self): - from distributed import AbstractProtocol + from distributed.protocol import AbstractProtocol protocol = AbstractProtocol() for item in ("aaa", 3, u"aa", 344444444444444444L, 1.2, (1, "aa")): assert protocol.unwrap(protocol.wrap(item)) == item @@ -33,7 +32,7 @@ def test_protocol_run(self): l = [1,2,3] - from distributed import LocalProtocol + from distributed.protocol import LocalProtocol protocol = LocalProtocol() wrap = protocol.wrap unwrap = protocol.unwrap @@ -47,7 +46,7 @@ def f(x, y): return x + y - from distributed import LocalProtocol + from distributed.protocol import LocalProtocol protocol = LocalProtocol() wrap = protocol.wrap unwrap = protocol.unwrap @@ -99,7 +98,7 @@ def __len__(self): return self.x + 8 - from distributed import LocalProtocol + from distributed.protocol import LocalProtocol protocol = LocalProtocol() wrap = protocol.wrap unwrap = protocol.unwrap From fijal at codespeak.net Sun Nov 19 18:34:42 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 19 Nov 2006 18:34:42 +0100 (CET) Subject: [pypy-svn] r34765 - pypy/dist/pypy/lib/distributed Message-ID: <20061119173442.A312E100BE@code0.codespeak.net> Author: fijal Date: Sun Nov 19 18:34:40 2006 New Revision: 34765 Added: pypy/dist/pypy/lib/distributed/objkeeper.py (contents, props changed) Modified: pypy/dist/pypy/lib/distributed/protocol.py Log: Separated part of logic into abstract "ObjKeeper" which traces information about exported/imported objects. Added: pypy/dist/pypy/lib/distributed/objkeeper.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/distributed/objkeeper.py Sun Nov 19 18:34:40 2006 @@ -0,0 +1,63 @@ + +""" objkeeper - Storage for remoteprotocol +""" + +class ObjKeeper(object): + def __init__(self, exported_names = {}): + self.exported_objects = [] # list of object that we've exported outside + self.exported_names = exported_names # dictionary of visible objects + self.exported_types = {} # list of exported types + self.remote_types = {} + self.remote_objects = {} + self.exported_types_id = 0 # unique id of exported types + + def register_object(self, obj): + # XXX: At some point it makes sense not to export them again and again... + self.exported_objects.append(obj) + return len(self.exported_objects) - 1 + + def register_type(self, protocol, tp): + try: + return self.exported_types[tp] + except KeyError: + #print "Registering type %s as %s" % (tp, self.type_id) + self.exported_types[tp] = self.exported_types_id + tp_id = self.exported_types_id + self.exported_types_id += 1 + + # XXX: We don't support inheritance here, nor recursive types + # shall we??? + _dict = dict([(key, protocol.wrap(getattr(tp, key))) for key in dir(tp) + if key not in ('__dict__', '__weakref__', '__class__', '__new__', + '__base__', '__flags__', '__mro__', '__bases__')]) + protocol.send(("type_reg", (tp_id, + tp.__name__, _dict))) + return tp_id + + def fake_remote_type(self, protocol, type_id, _name, _dict): + print "Faking type %s as %s" % (_name, type_id) + # create and register new type + d = dict([(key, None) for key in _dict]) + if '__doc__' in _dict: + d['__doc__'] = protocol.unwrap(_dict['__doc__']) + tp = type(_name, (object,), d) + self.remote_types[type_id] = tp + for key, value in _dict.items(): + if key != '__doc__': + try: + setattr(tp, key, protocol.unwrap(value)) + except TypeError: + # XXX this stays here for debugging reasons + import pdb;pdb.set_trace() + + def get_type(self, id): + return self.remote_types[id] + + def get_object(self, id): + return self.exported_objects[id] + + def register_remote_object(self, controller, id): + self.remote_objects[controller] = id + + def get_remote_object(self, controller): + return self.remote_objects[controller] Modified: pypy/dist/pypy/lib/distributed/protocol.py ============================================================================== --- pypy/dist/pypy/lib/distributed/protocol.py (original) +++ pypy/dist/pypy/lib/distributed/protocol.py Sun Nov 19 18:34:40 2006 @@ -41,12 +41,13 @@ except ImportError: raise ImportError("Cannot work without transparent proxy functional") +from distributed.objkeeper import ObjKeeper + # XXX We do not make any garbage collection. We'll need it at some point """ TODO list: -1. Move it to more than one file 2. Refactor it a bit (split class into logical/bookkeeper one) 3. Add some garbage collection 4. Add caching of objects that are presented (even on name level) @@ -83,14 +84,11 @@ type_letters = dict([(value, key) for key, value in letter_types.items()]) assert len(type_letters) == len(letter_types) - def __init__(self): - self.remote_objects = {} # a dictionary controller --> id - self.objs = [] # we just store everything, maybe later - # we'll need some kind of garbage collection - - def register_obj(self, obj): - self.objs.append(obj) - return len(self.objs) - 1 + def __init__(self, exported_names={}): + self.keeper = ObjKeeper(exported_names) + #self.remote_objects = {} # a dictionary controller --> id + #self.objs = [] # we just store everything, maybe later + # # we'll need some kind of garbage collection def wrap(self, obj): """ Wrap an object as sth prepared for sending @@ -98,7 +96,7 @@ tp = type(obj) ctrl = get_transparent_controller(obj) if ctrl: - return "tp", self.remote_objects[ctrl] + return "tp", self.keeper.get_remote_object(ctrl) elif obj is None: return self.type_letters[tp] elif tp in self.immutable_primitives: @@ -108,7 +106,7 @@ # we just pack all of the items return ('t', tuple([self.wrap(elem) for elem in obj])) elif tp in (list, dict, types.FunctionType): - id = self.register_obj(obj) + id = self.keeper.register_object(obj) return (self.type_letters[tp], id) elif tp is type: id = self.register_type(obj) @@ -120,7 +118,7 @@ return (self.type_letters[tp], (type_id, \ self.wrap(obj.im_func.func_name), w_func, w_self)) else: - id = self.register_obj(obj) + id = self.keeper.register_object(obj) type_id = self.register_type(tp) return ("cus", (type_id, id)) @@ -132,7 +130,7 @@ tp_letter, obj_data = data tp = self.letter_types[tp_letter] if tp is None: - return self.objs[obj_data] + return self.keeper.get_object(obj_data) elif tp in self.immutable_primitives: return obj_data # this is the object elif tp is tuple: @@ -140,7 +138,7 @@ elif tp in (list, dict, types.FunctionType): id = obj_data ro = RemoteObject(self, id) - self.remote_objects[ro.perform] = id + self.keeper.register_remote_object(ro.perform, id) return proxy(tp, ro.perform) elif tp is types.MethodType: type_id, w_name, w_func, w_self = obj_data @@ -161,7 +159,7 @@ type_id, id = obj_data real_tp = self.get_type(type_id) ro = RemoteObject(self, id) - self.remote_objects[ro.perform] = id + self.keeper.register_remote_object(ro.perform, id) return proxy(real_tp, ro.perform) else: raise NotImplementedError("Cannot unwrap %s" % (data,)) @@ -180,6 +178,12 @@ kwargs = dict([(self.unwrap(key), self.unwrap(val)) for key, val in kwargs.items()]) return args, kwargs + def register_type(self, tp): + return self.keeper.register_type(self, tp) + + def get_type(self, id): + return self.keeper.get_type(id) + class LocalProtocol(AbstractProtocol): """ This is stupid protocol for testing purposes only """ @@ -188,7 +192,7 @@ self.types = [] def perform(self, id, name, *args, **kwargs): - obj = self.objs[id] + obj = self.keeper.get_object(id) # we pack and than unpack, for tests args, kwargs = self.pack_args(args, kwargs) assert isinstance(name, str) @@ -214,17 +218,17 @@ command, data = receive() if command == 'get': # XXX: Error recovery anyone??? - send(("finished", wrap(protocol.exported_names[data]))) + send(("finished", wrap(protocol.keeper.exported_names[data]))) elif command == 'call': id, name, args, kwargs = data args, kwargs = protocol.unpack_args(args, kwargs) - retval = getattr(protocol.objs[id], name)(*args, **kwargs) + retval = getattr(protocol.keeper.get_object(id), name)(*args, **kwargs) send(("finished", wrap(retval))) elif command == 'finished': return unwrap(data) elif command == 'type_reg': type_id, name, _dict = data - protocol.register_fake_type(type_id, name, _dict) + protocol.keeper.fake_remote_type(protocol, type_id, name, _dict) else: raise NotImplementedError("command %s" % command) @@ -232,13 +236,13 @@ #def __init__(self, gateway, remote_code): # self.gateway = gateway def __init__(self, send, receive, exported_names={}): - super(RemoteProtocol, self).__init__() - self.exported_names = exported_names + super(RemoteProtocol, self).__init__(exported_names) + #self.exported_names = exported_names self.send = send self.receive = receive - self.type_cache = {} - self.type_id = 0 - self.remote_types = {} + #self.type_cache = {} + #self.type_id = 0 + #self.remote_types = {} def perform(self, id, name, *args, **kwargs): args, kwargs = self.pack_args(args, kwargs) @@ -250,46 +254,6 @@ self.send(("get", name)) retval = remote_loop(self) return retval - - def register_type(self, tp): - try: - return self.type_cache[tp] - except KeyError: - print "Registering type %s as %s" % (tp, self.type_id) - self.type_cache[tp] = self.type_id - tp_id = self.type_id - self.type_id += 1 - - # XXX: We don't support inheritance here, nor recursive types - # shall we??? - _dict = dict([(key, self.wrap(getattr(tp, key))) for key in dir(tp) - if key not in ('__dict__', '__weakref__', '__class__', '__new__', - '__base__', '__flags__', '__mro__', '__bases__')]) - self.send(("type_reg", (tp_id, - tp.__name__, _dict))) - return tp_id - - def register_fake_type(self, type_id, _name, _dict): - print "Faking type %s as %s" % (_name, type_id) - # create and register new type - d = dict([(key, None) for key in _dict]) - if '__doc__' in _dict: - d['__doc__'] = self.unwrap(_dict['__doc__']) - tp = type(_name, (object,), d) - self.remote_types[type_id] = tp - for key, value in _dict.items(): - if key != '__doc__': - try: - setattr(tp, key, self.unwrap(value)) - except TypeError: - import pdb;pdb.set_trace() - - def get_type(self, id): - try: - return self.remote_types[id] - except KeyError: - print "Warning!!! Type %d is not present by now" % id - return object class RemoteObject(object): def __init__(self, protocol, id): From cfbolz at codespeak.net Sun Nov 19 18:42:44 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 19 Nov 2006 18:42:44 +0100 (CET) Subject: [pypy-svn] r34766 - in pypy/dist/pypy: module/_file module/_file/test rlib rlib/test Message-ID: <20061119174244.D2189100BE@code0.codespeak.net> Author: cfbolz Date: Sun Nov 19 18:42:42 2006 New Revision: 34766 Modified: pypy/dist/pypy/module/_file/app_file.py pypy/dist/pypy/module/_file/test/test_file.py pypy/dist/pypy/rlib/streamio.py pypy/dist/pypy/rlib/test/test_streamio.py Log: fix newlines attribute of files Modified: pypy/dist/pypy/module/_file/app_file.py ============================================================================== --- pypy/dist/pypy/module/_file/app_file.py (original) +++ pypy/dist/pypy/module/_file/app_file.py Sun Nov 19 18:42:42 2006 @@ -50,10 +50,25 @@ def getnewlines(self): "end-of-line convention used in this file" - if isinstance(self.stream, _sio.TextInputFilter): - return self.stream.getnewlines() - else: + + newlines = self.stream.getnewlines() + if newlines == 0: return None + if newlines in [1, 2, 4]: + if newlines == 1: + return "\r" + elif newlines == 2: + return "\n" + else: + return "\r\n" + result = [] + if newlines & 1: + result.append('\r') + if newlines & 2: + result.append('\n') + if newlines & 4: + result.append('\r\n') + return tuple(result) mode = property(lambda self: self._mode, doc = "file mode ('r', 'U', 'w', 'a', " Modified: pypy/dist/pypy/module/_file/test/test_file.py ============================================================================== --- pypy/dist/pypy/module/_file/test/test_file.py (original) +++ pypy/dist/pypy/module/_file/test/test_file.py Sun Nov 19 18:42:42 2006 @@ -61,3 +61,13 @@ f.close() assert oct(os.stat(self.temppath).st_mode & 0777 | umask) == oct(0666) + def test_newlines(self): + import _file, os + f = _file.file(self.temppath, "wb") + f.write("\r\n") + assert f.newlines is None + f.close() + f = _file.file(self.temppath, "rU") + res = f.read() + assert res == "\n" + assert f.newlines == "\r\n" Modified: pypy/dist/pypy/rlib/streamio.py ============================================================================== --- pypy/dist/pypy/rlib/streamio.py (original) +++ pypy/dist/pypy/rlib/streamio.py Sun Nov 19 18:42:42 2006 @@ -206,6 +206,9 @@ def try_to_find_file_descriptor(self): return -1 + def getnewlines(self): + return 0 + class DiskFile(Stream): @@ -352,6 +355,7 @@ ("close", []), ("peek", []), ("try_to_find_file_descriptor", []), + ("getnewlines", []), ]) def PassThrough(meth_name, flush_buffers): @@ -735,25 +739,7 @@ self.CRLF = False def getnewlines(self): - foundchars = self.CR * 1 + self.NL * 2 + self.CRLF * 4 - if not foundchars: - return None - if foundchars in [1, 2, 4]: - if self.CR: - return '\r' - elif self.NL: - return '\n' - else: - return '\r\n' - else: - result = [] - if self.CR: - result.append('\r') - if self.NL: - result.append('\n') - if self.CRLF: - result.append('\r\n') - return tuple(result) + return self.CR * 1 + self.NL * 2 + self.CRLF * 4 def read(self, n): """Read up to n bytes.""" Modified: pypy/dist/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/dist/pypy/rlib/test/test_streamio.py (original) +++ pypy/dist/pypy/rlib/test/test_streamio.py Sun Nov 19 18:42:42 2006 @@ -735,15 +735,13 @@ ] expected_newlines = [ - (["abcd"], [None]), - (["abcd\n"], ["\n"]), - (["abcd\r\n"],["\r\n"]), - (["abcd\r"],[None]), # wrong, but requires precognition to fix - (["abcd\r", "\nefgh"], [None, "\r\n"]), - (["abcd", "\nefg\r", "hij", "k\r\n"], [None, "\n", ("\r", "\n"), - ("\r", "\n", "\r\n")]), - (["abcd", "\refg\r", "\nhij", "k\n"], [None, "\r", ("\r", "\r\n"), - ("\r", "\n", "\r\n")]) + (["abcd"], [0]), + (["abcd\n"], [2]), + (["abcd\r\n"],[4]), + (["abcd\r"],[0]), # wrong, but requires precognition to fix + (["abcd\r", "\nefgh"], [0, 4]), + (["abcd", "\nefg\r", "hij", "k\r\n"], [0, 2, 3, 7]), + (["abcd", "\refg\r", "\nhij", "k\n"], [0, 1, 5, 7]) ] def test_read(self): @@ -792,7 +790,18 @@ bufs.append(data) assert "".join(bufs) == all self.interpret(f, []) - + + def test_newlines_attribute(self): + for packets, expected in self.expected_newlines: + base = TReader(packets) + filter = streamio.TextInputFilter(base) + def f(): + for e in expected: + filter.read(100) + assert filter.getnewlines() == e + self.interpret(f, []) + + class TestTextInputFilter(BaseTestTextInputFilter): def interpret(self, func, args): return func(*args) @@ -921,22 +930,6 @@ filter.write(c) assert base.buf == data -class OldDisabledTests: - def test_readlines(self): - # This also tests next() and __iter__() - file = self.makeStream() - assert file.readlines() == self.lines - - - def test_newlines_attribute(self): - - for packets, expected in self.expected_newlines: - base = TReader(packets) - filter = streamio.TextInputFilter(base) - for e in expected: - filter.read(100) - assert filter.newlines == e - # Speed test From arigo at codespeak.net Sun Nov 19 19:25:56 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 19 Nov 2006 19:25:56 +0100 (CET) Subject: [pypy-svn] r34767 - in pypy/dist/pypy: rlib rpython rpython/lltypesystem translator/backendopt translator/c translator/c/src translator/llvm Message-ID: <20061119182556.8DCAB100BE@code0.codespeak.net> Author: arigo Date: Sun Nov 19 19:25:50 2006 New Revision: 34767 Modified: pypy/dist/pypy/rlib/objectmodel.py pypy/dist/pypy/rpython/llinterp.py pypy/dist/pypy/rpython/lltypesystem/lloperation.py pypy/dist/pypy/rpython/lltypesystem/opimpl.py pypy/dist/pypy/rpython/lltypesystem/rlist.py pypy/dist/pypy/rpython/lltypesystem/rstr.py pypy/dist/pypy/rpython/rlist.py pypy/dist/pypy/translator/backendopt/inline.py pypy/dist/pypy/translator/c/funcgen.py pypy/dist/pypy/translator/c/genc.py pypy/dist/pypy/translator/c/src/support.h pypy/dist/pypy/translator/llvm/opwriter.py Log: (pedronis, arigo) A more persistent 'debug_assert' operation, with a nice function interface in objectmodel too. Unknown overhead :-( It is compiled to a call to the C macro RPyAssert(), which is by default #defined to nothing. To enable, use any of the makefile's "debug" targets. Added a lot of debug_assert() in rlist. Now a debug-compiled pypy-c should no longer be able to crash obscurely after it popped from an empty list. Modified: pypy/dist/pypy/rlib/objectmodel.py ============================================================================== --- pypy/dist/pypy/rlib/objectmodel.py (original) +++ pypy/dist/pypy/rlib/objectmodel.py Sun Nov 19 19:25:50 2006 @@ -190,8 +190,23 @@ resulttype = hop.r_result.lowleveltype) - -# __ hlinvoke XXX this doesn't seem completely the right place for this +def debug_assert(x, msg): + """After translation to C, this becomes an RPyAssert.""" + assert x, msg + +class Entry(ExtRegistryEntry): + _about_ = debug_assert + + def compute_result_annotation(self, s_x, s_msg): + assert s_msg.is_constant(), ("debug_assert(x, msg): " + "the msg must be constant") + return None + + def specialize_call(self, hop): + from pypy.rpython.lltypesystem import lltype + vlist = hop.inputargs(lltype.Bool, lltype.Void) + hop.genop('debug_assert', vlist) + def hlinvoke(repr, llcallable, *args): raise TypeError, "hlinvoke is meant to be rtyped and not called direclty" Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Sun Nov 19 19:25:50 2006 @@ -448,9 +448,8 @@ import pdb pdb.set_trace() - def op_debug_log_exc(self, exc_type): - # do nothing, this is useful in compiled code - pass + def op_debug_assert(self, x, msg): + assert x, msg def op_debug_fatalerror(self, ll_msg, ll_exc=None): msg = ''.join(ll_msg.chars) Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py Sun Nov 19 19:25:50 2006 @@ -399,7 +399,7 @@ 'debug_view': LLOp(), 'debug_print': LLOp(), 'debug_pdb': LLOp(), - 'debug_assert': LLOp(canfold=True), + 'debug_assert': LLOp(), 'debug_fatalerror': LLOp(), # __________ instrumentation _________ Modified: pypy/dist/pypy/rpython/lltypesystem/opimpl.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/opimpl.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/opimpl.py Sun Nov 19 19:25:50 2006 @@ -359,20 +359,6 @@ raise TypeError("cannot fold getfield on mutable array") return p[index] - -def op_debug_assert(expr, *ll_args): - if not isinstance(expr, str): - if hasattr(expr, 'chars'): # for lltypesystem - expr = ''.join(expr.chars) - elif hasattr(expr, '_str'): # for ootypesystem - expr = expr._str - else: - raise TypeError("what is %r??" % (expr,)) - names = ['v%d' % i for i in range(len(ll_args))] - d = dict(zip(names, ll_args)) - names = tuple(names) - assert eval(expr % names, d) - # ____________________________________________________________ def get_op_impl(opname): Modified: pypy/dist/pypy/rpython/lltypesystem/rlist.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rlist.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rlist.py Sun Nov 19 19:25:50 2006 @@ -16,6 +16,7 @@ Bool, nullptr, typeMethod from pypy.rpython.lltypesystem import rstr from pypy.rpython import robject +from pypy.rlib.objectmodel import debug_assert # ____________________________________________________________ # @@ -374,6 +375,7 @@ # Accessor methods def ll_newlist(LIST, length): + debug_assert(length >= 0, "negative list length") l = malloc(LIST) l.length = length l.items = malloc(LIST.items.TO, length) @@ -387,19 +389,18 @@ def ll_items(l): return l.items -from pypy.rpython.lltypesystem.lloperation import llop - def ll_getitem_fast(l, index): - llop.debug_assert(Void, "%s < %s.length # getitem out of bounds", index, l) + debug_assert(index < l.length, "getitem out of bounds") return l.ll_items()[index] def ll_setitem_fast(l, index, item): - llop.debug_assert(Void, "%s < %s.length # setitem out of bounds", index, l) + debug_assert(index < l.length, "setitem out of bounds") l.ll_items()[index] = item # fixed size versions def ll_fixed_newlist(LIST, length): + debug_assert(length >= 0, "negative fixed list length") l = malloc(LIST, length) return l ll_fixed_newlist = typeMethod(ll_fixed_newlist) @@ -412,9 +413,11 @@ return l def ll_fixed_getitem_fast(l, index): + debug_assert(index < len(l), "fixed getitem out of bounds") return l[index] def ll_fixed_setitem_fast(l, index, item): + debug_assert(index < len(l), "fixed setitem out of bounds") l[index] = item def newlist(llops, r_list, items_v): Modified: pypy/dist/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rstr.py Sun Nov 19 19:25:50 2006 @@ -2,6 +2,7 @@ from pypy.annotation.pairtype import pairtype from pypy.rpython.error import TyperError from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated +from pypy.rlib.objectmodel import debug_assert from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rlib.rarithmetic import _hash_string from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -109,10 +110,8 @@ resulttype=pyobj_repr, _callable= lambda chars, sz: pyobjectptr(''.join(chars))) -from pypy.rpython.lltypesystem.lloperation import llop - def mallocstr(length): - llop.debug_assert(Void, "%s >= 0 # negative string length", length) + debug_assert(length >= 0, "negative string length") r = malloc(STR, length) if not we_are_translated() or not malloc_zero_filled: r.hash = 0 Modified: pypy/dist/pypy/rpython/rlist.py ============================================================================== --- pypy/dist/pypy/rpython/rlist.py (original) +++ pypy/dist/pypy/rpython/rlist.py Sun Nov 19 19:25:50 2006 @@ -6,9 +6,8 @@ from pypy.rpython.rslice import AbstractSliceRepr from pypy.rpython.lltypesystem.lltype import typeOf, Ptr, Void, Signed, Bool from pypy.rpython.lltypesystem.lltype import nullptr, Char, UniChar -from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython import robject -from pypy.rlib.objectmodel import malloc_zero_filled +from pypy.rlib.objectmodel import malloc_zero_filled, debug_assert from pypy.rpython.annlowlevel import ADTInterface ADTIFixedList = ADTInterface(None, { @@ -474,6 +473,8 @@ def ll_insert_nonneg(l, index, newitem): length = l.ll_length() + debug_assert(0 <= index, "negative list insertion index") + debug_assert(index <= length, "list insertion index out of bound") l._ll_resize_ge(length+1) dst = length while dst > index: @@ -484,8 +485,12 @@ ll_insert_nonneg.oopspec = 'list.insert(l, index, newitem)' def ll_pop_nonneg(func, l, index): - if func is dum_checkidx and (index >= l.ll_length()): - raise IndexError + debug_assert(index >= 0, "unexpectedly negative list pop index") + if func is dum_checkidx: + if index >= l.ll_length(): + raise IndexError + else: + debug_assert(index < l.ll_length(), "list pop index out of bound") res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res @@ -495,6 +500,7 @@ length = l.ll_length() if func is dum_checkidx and (length == 0): raise IndexError + debug_assert(length > 0, "pop from empty list") index = length - 1 newlength = index res = l.ll_getitem_fast(index) @@ -509,6 +515,7 @@ length = l.ll_length() if func is dum_checkidx and (length == 0): raise IndexError + debug_assert(length > 0, "pop(0) from empty list") newlength = length - 1 res = l.ll_getitem_fast(0) j = 0 @@ -528,8 +535,12 @@ length = l.ll_length() if index < 0: index += length - if func is dum_checkidx and (index < 0 or index >= length): - raise IndexError + if func is dum_checkidx: + if index < 0 or index >= length: + raise IndexError + else: + debug_assert(index >= 0, "negative list pop index out of bound") + debug_assert(index < length, "list pop index out of bound") res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res @@ -548,8 +559,12 @@ ll_reverse.oopspec = 'list.reverse(l)' def ll_getitem_nonneg(func, l, index): - if func is dum_checkidx and (index >= l.ll_length()): - raise IndexError + debug_assert(index >= 0, "unexpectedly negative list getitem index") + if func is dum_checkidx: + if index >= l.ll_length(): + raise IndexError + else: + debug_assert(index < l.ll_length(), "list getitem index out of bound") return l.ll_getitem_fast(index) ll_getitem_nonneg.oopspec = 'list.getitem(l, index)' @@ -557,14 +572,22 @@ length = l.ll_length() if index < 0: index += length - if func is dum_checkidx and (index < 0 or index >= length): - raise IndexError + if func is dum_checkidx: + if index < 0 or index >= length: + raise IndexError + else: + debug_assert(index >= 0, "negative list getitem index out of bound") + debug_assert(index < length, "list getitem index out of bound") return l.ll_getitem_fast(index) ll_getitem.oopspec = 'list.getitem(l, index)' def ll_setitem_nonneg(func, l, index, newitem): - if func is dum_checkidx and (index >= l.ll_length()): - raise IndexError + debug_assert(index >= 0, "unexpectedly negative list setitem index") + if func is dum_checkidx: + if index >= l.ll_length(): + raise IndexError + else: + debug_assert(index < l.ll_length(), "list setitem index out of bound") l.ll_setitem_fast(index, newitem) ll_setitem_nonneg.oopspec = 'list.setitem(l, index, newitem)' @@ -572,15 +595,23 @@ length = l.ll_length() if index < 0: index += length - if func is dum_checkidx and (index < 0 or index >= length): - raise IndexError + if func is dum_checkidx: + if index < 0 or index >= length: + raise IndexError + else: + debug_assert(index >= 0, "negative list setitem index out of bound") + debug_assert(index < length, "list setitem index out of bound") l.ll_setitem_fast(index, newitem) ll_setitem.oopspec = 'list.setitem(l, index, newitem)' def ll_delitem_nonneg(func, l, index): + debug_assert(index >= 0, "unexpectedly negative list delitem index") length = l.ll_length() - if func is dum_checkidx and (index >= length): - raise IndexError + if func is dum_checkidx: + if index >= length: + raise IndexError + else: + debug_assert(index < length, "list delitem index out of bound") newlength = length - 1 j = index j1 = j+1 @@ -599,8 +630,12 @@ length = l.ll_length() if i < 0: i += length - if func is dum_checkidx and (i < 0 or i >= length): - raise IndexError + if func is dum_checkidx: + if i < 0 or i >= length: + raise IndexError + else: + debug_assert(i >= 0, "negative list delitem index out of bound") + debug_assert(i < length, "list delitem index out of bound") ll_delitem_nonneg(dum_nocheck, l, i) ll_delitem.oopspec = 'list.delitem(l, i)' @@ -619,6 +654,8 @@ def ll_listslice_startonly(RESLIST, l1, start): len1 = l1.ll_length() + debug_assert(start >= 0, "unexpectedly negative list slice start") + debug_assert(start <= len1, "list slice start larger than list length") newlength = len1 - start l = RESLIST.ll_newlist(newlength) j = 0 @@ -633,6 +670,9 @@ start = slice.start stop = slice.stop length = l1.ll_length() + debug_assert(start >= 0, "unexpectedly negative list slice start") + debug_assert(start <= length, "list slice start larger than list length") + debug_assert(stop >= start, "list slice stop smaller than start") if stop > length: stop = length newlength = stop - start @@ -647,8 +687,7 @@ def ll_listslice_minusone(RESLIST, l1): newlength = l1.ll_length() - 1 - llop.debug_assert(Void, "%s >= 0 # empty list is sliced with [:-1]", - newlength) + debug_assert(newlength >= 0, "empty list is sliced with [:-1]") l = RESLIST.ll_newlist(newlength) j = 0 while j < newlength: @@ -657,6 +696,8 @@ return l def ll_listdelslice_startonly(l, start): + debug_assert(start >= 0, "del l[start:] with unexpectedly negative start") + debug_assert(start <= l.ll_length(), "del l[start:] with start > len(l)") newlength = start null = ll_null_item(l) if null is not None: @@ -670,6 +711,9 @@ start = slice.start stop = slice.stop length = l.ll_length() + debug_assert(start >= 0, "del l[start:x] with unexpectedly negative start") + debug_assert(start <= length, "del l[start:x] with start > len(l)") + debug_assert(stop >= start, "del l[x:y] with x > y") if stop > length: stop = length newlength = length - (stop-start) @@ -689,11 +733,12 @@ def ll_listsetslice(l1, slice, l2): count = l2.ll_length() - llop.debug_assert(Void, - "%s == %s - %s # setslice cannot resize lists in RPython", - count, slice.stop, slice.start) - # XXX but it should be easy enough to support, soon start = slice.start + debug_assert(start >= 0, "l[start:x] = l with unexpectedly negative start") + debug_assert(start <= l1.ll_length(), "l[start:x] = l with start > len(l)") + debug_assert(count == slice.stop - start, + "setslice cannot resize lists in RPython") + # XXX but it should be easy enough to support, soon j = start i = 0 while i < count: Modified: pypy/dist/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/dist/pypy/translator/backendopt/inline.py (original) +++ pypy/dist/pypy/translator/backendopt/inline.py Sun Nov 19 19:25:50 2006 @@ -464,6 +464,7 @@ 'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme 'resume_point': sys.maxint, # XXX bit extreme 'instrument_count': 0, + 'debug_assert': -1, } def block_weight(block, weights=OP_WEIGHTS): @@ -476,7 +477,7 @@ total += weights.get(op.opname, 1) if block.exitswitch is not None: total += 1 - return total + return max(0, total) def measure_median_execution_cost(graph): Modified: pypy/dist/pypy/translator/c/funcgen.py ============================================================================== --- pypy/dist/pypy/translator/c/funcgen.py (original) +++ pypy/dist/pypy/translator/c/funcgen.py Sun Nov 19 19:25:50 2006 @@ -720,7 +720,8 @@ ''.join([', ' + s for s in argv])) def OP_DEBUG_ASSERT(self, op): - return '/* debug_assert removed */' + return 'RPyAssert(%s, %s);' % (self.expr(op.args[0]), + c_string_constant(op.args[1].value)) def OP_DEBUG_FATALERROR(self, op): # XXX Modified: pypy/dist/pypy/translator/c/genc.py ============================================================================== --- pypy/dist/pypy/translator/c/genc.py (original) +++ pypy/dist/pypy/translator/c/genc.py Sun Nov 19 19:25:50 2006 @@ -859,13 +859,13 @@ \trm -f $(OBJECTS) $(TARGET) debug: -\tmake CFLAGS="-g" +\tmake CFLAGS="-g -DRPY_ASSERT" debug_exc: -\tmake CFLAGS="-g -DDO_LOG_EXC" +\tmake CFLAGS="-g -DRPY_ASSERT -DDO_LOG_EXC" debug_mem: -\tmake CFLAGS="-g -DNO_OBMALLOC" +\tmake CFLAGS="-g -DRPY_ASSERT -DNO_OBMALLOC" profile: \tmake CFLAGS="-pg $(CFLAGS)" LDFLAGS="-pg $(LDFLAGS)" 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 Sun Nov 19 19:25:50 2006 @@ -25,6 +25,26 @@ memcpy(itemsarray->items, PyString_AS_STRING(s), \ itemsarray->length) +#ifdef RPY_ASSERT +# define RPyAssert(x, msg) \ + if (!(x)) RPyAssertFailed(__FILE__, __LINE__, __FUNCTION__, msg) + +void RPyAssertFailed(const char* filename, long lineno, + const char* function, const char *msg); +# ifndef PYPY_NOT_MAIN_FILE +void RPyAssertFailed(const char* filename, long lineno, + const char* function, const char *msg) { + fprintf(stderr, + "PyPy assertion failed at %s:%d:\n" + "in %s: %s\n", + filename, lineno, function, msg); + abort(); +} +# endif +#else +# define RPyAssert(x, msg) /* nothing */ +#endif + #ifdef __RPyListOfString_New /* :-( */ # define HAVE_RPY_LIST_OF_STRING #endif Modified: pypy/dist/pypy/translator/llvm/opwriter.py ============================================================================== --- pypy/dist/pypy/translator/llvm/opwriter.py (original) +++ pypy/dist/pypy/translator/llvm/opwriter.py Sun Nov 19 19:25:50 2006 @@ -172,11 +172,8 @@ float_abs = int_abs llong_abs = int_abs - def debug_log_exc(self, opr): - # XXX tmp - pass - def debug_assert(self, opr): + # XXX could do something about assertions pass def int_pow(self, opr): From cfbolz at codespeak.net Sun Nov 19 19:46:09 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sun, 19 Nov 2006 19:46:09 +0100 (CET) Subject: [pypy-svn] r34768 - pypy/dist/pypy/interpreter/astcompiler Message-ID: <20061119184609.78412100BE@code0.codespeak.net> Author: cfbolz Date: Sun Nov 19 19:46:08 2006 New Revision: 34768 Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Log: add default for attribute localsfullyknown (mostly to avoid my own confusion) Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Sun Nov 19 19:46:08 2006 @@ -137,6 +137,8 @@ """Defines basic code generator for Python bytecode """ + localsfullyknown = False + def __init__(self, space, graph): self.space = space self.setups = [] From fijal at codespeak.net Mon Nov 20 11:35:59 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 20 Nov 2006 11:35:59 +0100 (CET) Subject: [pypy-svn] r34770 - pypy/dist/pypy/translator/js/modules/test Message-ID: <20061120103559.767DB1008B@code0.codespeak.net> Author: fijal Date: Mon Nov 20 11:35:57 2006 New Revision: 34770 Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Don't run PDB Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 20 11:35:57 2006 @@ -344,6 +344,6 @@ if var.startswith('code_'): # just build it #def f(): - assert rpython2javascript(sys.modules[__name__], [var]) - + assert rpython2javascript(sys.modules[__name__], [var], use_pdb=False) + TRANSLATING = False From fijal at codespeak.net Mon Nov 20 11:36:49 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 20 Nov 2006 11:36:49 +0100 (CET) Subject: [pypy-svn] r34771 - pypy/dist/pypy/translator/js Message-ID: <20061120103649.EEC121008B@code0.codespeak.net> Author: fijal Date: Mon Nov 20 11:36:45 2006 New Revision: 34771 Modified: pypy/dist/pypy/translator/js/opcodes.py Log: Ignore debug_assert Modified: pypy/dist/pypy/translator/js/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/js/opcodes.py (original) +++ pypy/dist/pypy/translator/js/opcodes.py Mon Nov 20 11:36:45 2006 @@ -145,6 +145,8 @@ 'cast_float_to_int': [PushAllArgs,_CastFun("Math.floor",1)], 'cast_float_to_uint': [PushAllArgs,_CastFun("Math.floor",1)], 'truncate_longlong_to_int': CopyName, + + 'debug_assert' : DoNothing, } for key, value in opcodes.iteritems(): From arigo at codespeak.net Mon Nov 20 11:51:57 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 11:51:57 +0100 (CET) Subject: [pypy-svn] r34772 - pypy/dist/pypy/translator/tool Message-ID: <20061120105157.9A18D1008E@code0.codespeak.net> Author: arigo Date: Mon Nov 20 11:51:56 2006 New Revision: 34772 Modified: pypy/dist/pypy/translator/tool/pdbplus.py Log: Minimal hack waiting for a better solution: raise NoTTY when trying to start a pdbplus and the output is captured by py.test. Modified: pypy/dist/pypy/translator/tool/pdbplus.py ============================================================================== --- pypy/dist/pypy/translator/tool/pdbplus.py (original) +++ pypy/dist/pypy/translator/tool/pdbplus.py Mon Nov 20 11:51:56 2006 @@ -1,12 +1,16 @@ import pdb import types import code +import sys from pypy.objspace.flow.model import FunctionGraph class _EnableGraphic: def __init__(self, port=None): self.port = port +class NoTTY(Exception): + pass + class PdbPlusShow(pdb.Pdb): def __init__(self, translator): @@ -20,6 +24,11 @@ t = t.tb_next self.interaction(t.tb_frame, t) + def preloop(self): + if not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty(): + raise NoTTY("Cannot start the debugger when stdout is captured.") + pdb.Pdb.preloop(self) + def expose(self, d): self.exposed.update(d) From guido at codespeak.net Mon Nov 20 12:03:32 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 20 Nov 2006 12:03:32 +0100 (CET) Subject: [pypy-svn] r34773 - pypy/dist/pypy/translator/js/doc Message-ID: <20061120110332.B7B621008E@code0.codespeak.net> Author: guido Date: Mon Nov 20 12:03:31 2006 New Revision: 34773 Modified: pypy/dist/pypy/translator/js/doc/dom.txt Log: Improved doctests a bit, added paragraph about CSS/style support. Modified: pypy/dist/pypy/translator/js/doc/dom.txt ============================================================================== --- pypy/dist/pypy/translator/js/doc/dom.txt (original) +++ pypy/dist/pypy/translator/js/doc/dom.txt Mon Nov 20 12:03:31 2006 @@ -49,12 +49,14 @@ Currently events aren't fired automatically, to test event handling an event must be explicitly instantiated and dispatched:: - >>> from pypy.translator.js.modules.dom import get_window - >>> window = get_window() - >>> document = window.document + >>> def handler(e): + ... e.foo = 'bar' + >>> body.addEventListener('click', handler, False) >>> e = document.createEvent('group is ignored') >>> e.initEvent('click', True, True) >>> document.getElementsByTagName('body')[0].dispatchEvent(e) + >>> e.foo + 'bar' (This would result in all handlers for the 'click' event registered on body (and if not cancelled, bubbling up to the document node) getting @@ -68,12 +70,10 @@ Example:: - >>> from pypy.translator.js.modules.dom import get_window >>> window.location 'about:blank' >>> window.self is window True - >>> document = window.document * Additional HTML functionality on Element and Document @@ -84,9 +84,22 @@ Example:: - >>> from pypy.translator.js.modules.dom import get_window - >>> document = get_window().document >>> body = document.getElementsByTagName('body')[0] >>> body.nodeName u'BODY' + * CSS support + + There is support for inline style tags, not for stylesheets. Style + attributes are read on accessing the style property, and the style property + is used on HTML serialization (using .innerHTML). + + Example:: + + >>> body.innerHTML = '
foo
' + >>> body.firstChild.style.backgroundColor + u'green' + >>> body.firstChild.style.backgroundColor = 'black' + >>> body.innerHTML + u'
foo
' + From guido at codespeak.net Mon Nov 20 12:04:46 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 20 Nov 2006 12:04:46 +0100 (CET) Subject: [pypy-svn] r34774 - in pypy/dist/pypy/translator/js/modules: . test Message-ID: <20061120110446.5BE3210094@code0.codespeak.net> Author: guido Date: Mon Nov 20 12:04:45 2006 New Revision: 34774 Modified: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Added Comment type, added missing __ne__ for nodes, and fixed support for using .innerHTML on nodes that only have text content. Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Mon Nov 20 12:04:45 2006 @@ -14,6 +14,7 @@ import time import re +import urllib from pypy.rpython.ootypesystem.bltregistry import BasicExternal, MethodDesc from pypy.rlib.nonconst import NonConstant @@ -87,6 +88,10 @@ original = getattr(other, '_original', other) return original is self._original + def __ne__(self, other): + original = getattr(other, '_original', other) + return original is not self._original + def getElementsByTagName(self, name): name = name.lower() return self.__getattr__('getElementsByTagName')(name) @@ -161,6 +166,9 @@ class Text(Node): nodeType = 3 +class Comment(Node): + nodeType = 8 + class Document(Node): nodeType = 9 @@ -706,6 +714,7 @@ 1: Element, 2: Attribute, 3: Text, + 8: Comment, 9: Document, } def _wrap(value): @@ -731,7 +740,9 @@ _singletons = ['link', 'meta'] def _serialize_html(node): ret = [] - if node.nodeType == 1: + if node.nodeType in [3, 8]: + return node.nodeValue + elif node.nodeType == 1: original = getattr(node, '_original', node) nodeName = original.nodeName ret += ['<', nodeName] @@ -755,6 +766,8 @@ ret += [''] else: ret.append(' />') + else: + raise ValueError('unsupported node type %s' % (node.nodeType,)) return ''.join(ret) # initialization Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 20 12:04:45 2006 @@ -188,6 +188,21 @@ body = code_set_innerHTML() assert body.innerHTML == '
some content
' assert body.childNodes[0].nodeName == 'DIV' + div = body.childNodes[0] + html = div.innerHTML + assert html == 'some content' + +def code_set_innerHTML_empty(): + window = get_window() + body = window.document.getElementsByTagName('body')[0] + body.innerHTML = '' + body.appendChild(window.document.createTextNode('foobar')) + return body + +def test_set_innerHTML_empty(): + body = code_set_innerHTML_empty() + html = body.innerHTML + assert html == 'foobar' def code_event_init_1(): window = get_window() From fijal at codespeak.net Mon Nov 20 12:14:23 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 20 Nov 2006 12:14:23 +0100 (CET) Subject: [pypy-svn] r34777 - in pypy/dist/pypy/lib: distributed test2 Message-ID: <20061120111423.B03BE10094@code0.codespeak.net> Author: fijal Date: Mon Nov 20 12:14:21 2006 New Revision: 34777 Modified: pypy/dist/pypy/lib/distributed/objkeeper.py pypy/dist/pypy/lib/distributed/protocol.py pypy/dist/pypy/lib/test2/test_distributed.py Log: Added list/dict forcing. Modified: pypy/dist/pypy/lib/distributed/objkeeper.py ============================================================================== --- pypy/dist/pypy/lib/distributed/objkeeper.py (original) +++ pypy/dist/pypy/lib/distributed/objkeeper.py Mon Nov 20 12:14:21 2006 @@ -20,7 +20,7 @@ try: return self.exported_types[tp] except KeyError: - #print "Registering type %s as %s" % (tp, self.type_id) + print "Registering type %s as %s" % (tp, self.exported_types_id) self.exported_types[tp] = self.exported_types_id tp_id = self.exported_types_id self.exported_types_id += 1 Modified: pypy/dist/pypy/lib/distributed/protocol.py ============================================================================== --- pypy/dist/pypy/lib/distributed/protocol.py (original) +++ pypy/dist/pypy/lib/distributed/protocol.py Mon Nov 20 12:14:21 2006 @@ -42,16 +42,16 @@ raise ImportError("Cannot work without transparent proxy functional") from distributed.objkeeper import ObjKeeper +import sys # XXX We do not make any garbage collection. We'll need it at some point """ TODO list: -2. Refactor it a bit (split class into logical/bookkeeper one) -3. Add some garbage collection -4. Add caching of objects that are presented (even on name level) -5. Add exceptions, frames and error handling +1. Add some garbage collection +2. Add caching of objects that are presented (even on name level) +3. Add exceptions, frames and error handling """ from pypymagic import pypy_repr @@ -61,6 +61,7 @@ class AbstractProtocol(object): immutable_primitives = (str, int, float, long, unicode, bool, types.NotImplementedType) + mutable_primitives = (list, dict, types.FunctionType, types.FrameType) letter_types = { 'l' : list, @@ -80,6 +81,7 @@ 'meth' : types.MethodType, 'type' : type, 'tp' : None, + 'fr' : types.FrameType, } type_letters = dict([(value, key) for key, value in letter_types.items()]) assert len(type_letters) == len(letter_types) @@ -105,22 +107,25 @@ elif tp is tuple: # we just pack all of the items return ('t', tuple([self.wrap(elem) for elem in obj])) - elif tp in (list, dict, types.FunctionType): + elif tp in self.mutable_primitives: id = self.keeper.register_object(obj) return (self.type_letters[tp], id) elif tp is type: - id = self.register_type(obj) - return (self.type_letters[tp], id) + try: + return self.type_letters[tp], self.type_letters[obj] + except KeyError: + id = self.register_type(obj) + return (self.type_letters[tp], id) elif tp is types.MethodType: - type_id = self.register_type(obj.im_class) + w_class = self.wrap(obj.im_class) w_func = self.wrap(obj.im_func) w_self = self.wrap(obj.im_self) - return (self.type_letters[tp], (type_id, \ + return (self.type_letters[tp], (w_class, \ self.wrap(obj.im_func.func_name), w_func, w_self)) else: id = self.keeper.register_object(obj) - type_id = self.register_type(tp) - return ("cus", (type_id, id)) + w_tp = self.wrap(tp) + return ("cus", (w_tp, id)) def unwrap(self, data): """ Unwrap an object @@ -135,14 +140,16 @@ return obj_data # this is the object elif tp is tuple: return tuple([self.unwrap(i) for i in obj_data]) - elif tp in (list, dict, types.FunctionType): + elif tp in self.mutable_primitives: id = obj_data - ro = RemoteObject(self, id) + ro = RemoteBuiltinObject(self, id) self.keeper.register_remote_object(ro.perform, id) - return proxy(tp, ro.perform) + p = proxy(tp, ro.perform) + ro.obj = p + return p elif tp is types.MethodType: - type_id, w_name, w_func, w_self = obj_data - tp = self.get_type(type_id) + w_class, w_name, w_func, w_self = obj_data + tp = self.unwrap(w_class) name = self.unwrap(w_name) self_ = self.unwrap(w_self) if self_: @@ -151,16 +158,19 @@ setattr(tp, name, func) return getattr(tp, name) elif tp is type: + if isinstance(obj_data, str): + return self.letter_types[obj_data] id = obj_data - elem = self.get_type(obj_data) - return elem + return self.get_type(obj_data) elif tp is object: # we need to create a proper type - type_id, id = obj_data - real_tp = self.get_type(type_id) + w_tp, id = obj_data + real_tp = self.unwrap(w_tp) ro = RemoteObject(self, id) self.keeper.register_remote_object(ro.perform, id) - return proxy(real_tp, ro.perform) + p = proxy(real_tp, ro.perform) + ro.obj = p + return p else: raise NotImplementedError("Cannot unwrap %s" % (data,)) @@ -169,14 +179,22 @@ # some simple wrappers def pack_args(self, args, kwargs): - args = [self.wrap(i) for i in args] - kwargs = dict([(self.wrap(key), self.wrap(val)) for key, val in kwargs.items()]) - return args, kwargs + return self.pack_list(args), self.pack_dict(kwargs) + + def pack_list(self, lst): + return [self.wrap(i) for i in lst] + + def pack_dict(self, d): + return dict([(self.wrap(key), self.wrap(val)) for key, val in d.items()]) def unpack_args(self, args, kwargs): - args = [self.unwrap(i) for i in args] - kwargs = dict([(self.unwrap(key), self.unwrap(val)) for key, val in kwargs.items()]) - return args, kwargs + return self.unpack_list(args), self.unpack_dict(kwargs) + + def unpack_list(self, lst): + return [self.unwrap(i) for i in lst] + + def unpack_dict(self, d): + return dict([(self.unwrap(key), self.unwrap(val)) for key, val in d.items()]) def register_type(self, tp): return self.keeper.register_type(self, tp) @@ -229,6 +247,13 @@ elif command == 'type_reg': type_id, name, _dict = data protocol.keeper.fake_remote_type(protocol, type_id, name, _dict) + elif command == 'force': + obj = protocol.keeper.get_object(data) + w_obj = protocol.pack(obj) + send(("forced", w_obj)) + elif command == 'forced': + obj = protocol.unpack(data) + return obj else: raise NotImplementedError("command %s" % command) @@ -254,6 +279,28 @@ self.send(("get", name)) retval = remote_loop(self) return retval + + def force(self, id): + self.send(("force", id)) + retval = remote_loop(self) + return retval + + def pack(self, obj): + if isinstance(obj, list): + return "l", self.pack_list(obj) + elif isinstance(obj, dict): + return "d", self.pack_dict(obj) + else: + raise NotImplementedError("Cannot pack %s" % obj) + + def unpack(self, data): + letter, w_obj = data + if letter == 'l': + return self.unpack_list(w_obj) + elif letter == 'd': + return self.unpack_dict(w_obj) + else: + raise NotImplementedError("Cannot unpack %s" % (data,)) class RemoteObject(object): def __init__(self, protocol, id): @@ -263,6 +310,22 @@ def perform(self, name, *args, **kwargs): return self.protocol.perform(self.id, name, *args, **kwargs) +class RemoteBuiltinObject(RemoteObject): + def __init__(self, protocol, id): + self.id = id + self.protocol = protocol + self.forced = False + + def perform(self, name, *args, **kwargs): + # XXX: Check who really goes here + if self.forced: + return getattr(self.obj, name)(*args, **kwargs) + if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__ge__', '__le__', + '__cmp__'): + self.obj = self.protocol.force(self.id) + return getattr(self.obj, name)(*args, **kwargs) + return self.protocol.perform(self.id, name, *args, **kwargs) + def test_env(exported_names): from stackless import channel, tasklet, run # XXX: This is a hack, proper support for recursive type is needed Modified: pypy/dist/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_distributed.py (original) +++ pypy/dist/pypy/lib/test2/test_distributed.py Mon Nov 20 12:14:21 2006 @@ -89,7 +89,18 @@ protocol = test_env({"f":f}) fun = protocol.get_remote("f") assert fun(8) == 16 - + + def test_remote_dict(self): + #skip("Land of infinite recursion") + from distributed import test_env + d = {'a':3} + protocol = test_env({'d':d}) + xd = protocol.get_remote('d') + #assert d['a'] == xd['a'] + assert d.keys() == xd.keys() + assert d.values() == xd.values() + assert d == xd + def test_local_obj(self): class A: def __init__(self, x): @@ -159,3 +170,13 @@ xa = protocol.get_remote('a') xa.meth(B()) assert xa.perform() == 4 + + def test_frame(self): + #skip("Land of infinite recursion") + import sys + from distributed import test_env + f = sys._getframe() + protocol = test_env({'f':f}) + xf = protocol.get_remote('f') + assert f.f_globals.keys() == xf.f_globals.keys() + assert f.f_locals.keys() == xf.f_locals.keys() From arigo at codespeak.net Mon Nov 20 12:14:33 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 12:14:33 +0100 (CET) Subject: [pypy-svn] r34778 - pypy/dist/pypy/rpython Message-ID: <20061120111433.AC8AE1009F@code0.codespeak.net> Author: arigo Date: Mon Nov 20 12:14:32 2006 New Revision: 34778 Modified: pypy/dist/pypy/rpython/llinterp.py Log: Forgot to remove safe_call from here. Modified: pypy/dist/pypy/rpython/llinterp.py ============================================================================== --- pypy/dist/pypy/rpython/llinterp.py (original) +++ pypy/dist/pypy/rpython/llinterp.py Mon Nov 20 12:14:32 2006 @@ -558,8 +558,6 @@ return exceptiontransform.error_value(FTYPE.RESULT) raise - op_safe_call = op_direct_call - def op_indirect_call(self, f, *args): graphs = args[-1] args = args[:-1] From pedronis at codespeak.net Mon Nov 20 12:26:40 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Nov 2006 12:26:40 +0100 (CET) Subject: [pypy-svn] r34779 - pypy/dist/pypy/translator/cl Message-ID: <20061120112640.A768210098@code0.codespeak.net> Author: pedronis Date: Mon Nov 20 12:26:38 2006 New Revision: 34779 Modified: pypy/dist/pypy/translator/cl/opformatter.py Log: support as debug_assert as doing nothing in the cl backend Modified: pypy/dist/pypy/translator/cl/opformatter.py ============================================================================== --- pypy/dist/pypy/translator/cl/opformatter.py (original) +++ pypy/dist/pypy/translator/cl/opformatter.py Mon Nov 20 12:26:38 2006 @@ -21,6 +21,10 @@ def nop(self, result, arg): yield "(setf %s %s)" % (result, arg) + + def op_debug_assert(self, result, *args): + return [] + op_same_as = nop op_ooupcast = nop op_oodowncast = nop From arigo at codespeak.net Mon Nov 20 13:36:35 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 13:36:35 +0100 (CET) Subject: [pypy-svn] r34787 - in pypy/dist/pypy: interpreter module/_stackless Message-ID: <20061120123635.E18BB1008B@code0.codespeak.net> Author: arigo Date: Mon Nov 20 13:36:29 2006 New Revision: 34787 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/module/_stackless/clonable.py pypy/dist/pypy/module/_stackless/coroutine.py pypy/dist/pypy/module/_stackless/interp_clonable.py pypy/dist/pypy/module/_stackless/interp_greenlet.py Log: (pedronis around, arigo) Wack trying to make AppClonableCoroutine do the right thing... Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Mon Nov 20 13:36:29 2006 @@ -38,45 +38,41 @@ if not frame.hide(): self.framestack.pop() - # coroutine: subcontext support - def subcontext_new(coobj): - coobj.framestack = new_framestack() - coobj.w_tracefunc = None - coobj.w_profilefunc = None - coobj.is_tracing = 0 - subcontext_new = staticmethod(subcontext_new) - - def subcontext_enter(self, next): - self.framestack = next.framestack - self.w_tracefunc = next.w_tracefunc - self.w_profilefunc = next.w_profilefunc - self.is_tracing = next.is_tracing - - def subcontext_leave(self, current): - current.framestack = self.framestack - current.w_tracefunc = self.w_tracefunc - current.w_profilefunc = self.w_profilefunc - current.is_tracing = self.is_tracing - - # coroutine: I think this is all, folks! - - # well, not quite: we need an interface for pickling - def subcontext_getstate(coobj): - # we just save the framestack - space = coobj.space - items = [space.wrap(item) for item in coobj.framestack.items] - return space.newtuple(items) - subcontext_getstate = staticmethod(subcontext_getstate) - - def subcontext_setstate(coobj, w_state): - from pypy.interpreter.pyframe import PyFrame - space = coobj.space - items = [space.interp_w(PyFrame, item) - for item in space.unpackiterable(w_state)] - coobj.framestack.items = items - subcontext_setstate = staticmethod(subcontext_setstate) - # coroutine: now I really I think this is all, folks! + class Subcontext(object): + # coroutine: subcontext support + + def __init__(self): + self.framestack = new_framestack() + self.w_tracefunc = None + self.w_profilefunc = None + self.is_tracing = 0 + + def enter(self, ec): + ec.framestack = self.framestack + ec.w_tracefunc = self.w_tracefunc + ec.w_profilefunc = self.w_profilefunc + ec.is_tracing = self.is_tracing + + def leave(self, ec): + self.framestack = ec.framestack + self.w_tracefunc = ec.w_tracefunc + self.w_profilefunc = ec.w_profilefunc + self.is_tracing = ec.is_tracing + + # the following interface is for pickling and unpickling + def getstate(self, space): + # we just save the framestack + items = [space.wrap(item) for item in self.framestack.items] + return space.newtuple(items) + + def setstate(self, space, w_state): + from pypy.interpreter.pyframe import PyFrame + items = [space.interp_w(PyFrame, w_item) + for w_item in space.unpackiterable(w_state)] + self.framestack.items = items + # coroutine: I think this is all, folks! + def get_builtin(self): try: Modified: pypy/dist/pypy/module/_stackless/clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/clonable.py (original) +++ pypy/dist/pypy/module/_stackless/clonable.py Mon Nov 20 13:36:29 2006 @@ -9,6 +9,11 @@ class AppClonableCoroutine(AppCoroutine, InterpClonableMixin): + def newsubctx(self): + self.hello_local_pool() + AppCoroutine.newsubctx(self) + self.goodbye_local_pool() + def hello(self): self.hello_local_pool() AppCoroutine.hello(self) @@ -40,7 +45,7 @@ "current coroutine" "; use fork() instead")) copy = AppClonableCoroutine(space, state=costate) - self.clone_into(copy) + copy.subctx = self.clone_into(copy, self.subctx) return space.wrap(copy) def descr__reduce__(self, space): @@ -59,9 +64,8 @@ class AppClonableCoState(AppCoState): def post_install(self): - self.current = self.main = AppClonableCoroutine(self.space, - is_main=True, - state=self) + self.current = self.main = AppClonableCoroutine(self.space, state=self) + self.main.subctx.framestack = None # wack def post_install(module): makeStaticMethod(module, 'clonable', 'getcurrent') Modified: pypy/dist/pypy/module/_stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/coroutine.py Mon Nov 20 13:36:29 2006 @@ -45,26 +45,25 @@ def call(self): costate = self.costate w_result = self.space.call_args(self.w_func, self.args) - #XXX: unreachable code ? rstack.resume_point("appthunk", costate, returns=w_result) costate.w_tempval = w_result class AppCoroutine(Coroutine): # XXX, StacklessFlags): - def __init__(self, space, is_main=False, state=None): + def __init__(self, space, state): self.space = space - if state is None: - state = self._get_state(space) Coroutine.__init__(self, state) self.flags = 0 - self.framestack = None - if not is_main: - space.getexecutioncontext().subcontext_new(self) + self.newsubctx() + + def newsubctx(self): + ec = self.space.getexecutioncontext() + self.subctx = ec.Subcontext() def descr_method__new__(space, w_subtype): co = space.allocate_instance(AppCoroutine, w_subtype) - AppCoroutine.__init__(co, space) + AppCoroutine.__init__(co, space, AppCoroutine._get_state(space)) return space.wrap(co) def _get_state(space): @@ -109,11 +108,11 @@ def hello(self): ec = self.space.getexecutioncontext() - ec.subcontext_enter(self) + self.subctx.enter(ec) def goodbye(self): ec = self.space.getexecutioncontext() - ec.subcontext_leave(self) + self.subctx.leave(ec) def w_kill(self): self.kill() @@ -160,7 +159,7 @@ ] tup_state = [ w(self.flags), - ec.subcontext_getstate(self), + self.subctx.getstate(space), w_thunk, w(self.parent), ] @@ -176,7 +175,7 @@ self.flags = space.int_w(w_flags) self.parent = space.interp_w(AppCoroutine, w_parent, can_be_None=True) ec = self.space.getexecutioncontext() - ec.subcontext_setstate(self, w_state) + self.subctx.setstate(self.space, w_state) self.reconstruct_framechain() if space.is_w(w_thunk, space.w_None): self.thunk = None @@ -192,7 +191,7 @@ def reconstruct_framechain(self): from pypy.interpreter.pyframe import PyFrame from pypy.rlib.rstack import resume_state_create - if self.framestack.empty(): + if self.subctx.framestack.empty(): self.frame = None return @@ -206,7 +205,7 @@ # rstack.resume_point("appthunk", costate, returns=w_result) appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate) chain = appthunk_frame - for frame in self.framestack.items: + for frame in self.subctx.framestack.items: assert isinstance(frame, PyFrame) # rstack.resume_point("evalframe", self, executioncontext, returns=result) evalframe_frame = resume_state_create(chain, "evalframe", frame, ec) @@ -253,8 +252,8 @@ def w_descr__framestack(space, self): assert isinstance(self, AppCoroutine) - if self.framestack: - items = [space.wrap(item) for item in self.framestack.items] + if self.subctx.framestack is not None: + items = [space.wrap(item) for item in self.subctx.framestack.items] return space.newtuple(items) else: return space.newtuple([]) @@ -305,5 +304,5 @@ self.space = space def post_install(self): - self.current = self.main = AppCoroutine(self.space, is_main=True, - state=self) + self.current = self.main = AppCoroutine(self.space, state=self) + self.main.subctx.framestack = None # wack Modified: pypy/dist/pypy/module/_stackless/interp_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/interp_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/interp_clonable.py Mon Nov 20 13:36:29 2006 @@ -18,17 +18,25 @@ def goodbye_local_pool(self): if we_are_translated(): self.local_pool = gc_swap_pool(self.saved_pool) + self.saved_pool = None - def clone_into(self, copy): + def clone_into(self, copy, extradata=None): if not we_are_translated(): raise NotImplementedError - if self.local_pool is None: # force it now - self.local_pool = gc_swap_pool(gc_swap_pool(None)) # cannot gc_clone() directly self, because it is not in its own # local_pool. Moreover, it has a __del__, which cloning doesn't # support properly at the moment. copy.parent = self.parent - copy.frame, copy.local_pool = gc_clone(self.frame, self.local_pool) + # the hello/goodbye pair has two purposes: it forces + # self.local_pool to be computed even if it was None up to now, + # and it puts the 'data' tuple in the correct pool to be cloned. + self.hello_local_pool() + data = (self.frame, extradata) + self.goodbye_local_pool() + # clone! + data, copy.local_pool = gc_clone(data, self.local_pool) + copy.frame, extradata = data + return extradata class InterpClonableCoroutine(Coroutine, InterpClonableMixin): Modified: pypy/dist/pypy/module/_stackless/interp_greenlet.py ============================================================================== --- pypy/dist/pypy/module/_stackless/interp_greenlet.py (original) +++ pypy/dist/pypy/module/_stackless/interp_greenlet.py Mon Nov 20 13:36:29 2006 @@ -60,8 +60,10 @@ assert isinstance(w_parent, AppGreenlet) self.w_parent = w_parent Coroutine.__init__(self, state) - if not is_main: - space.getexecutioncontext().subcontext_new(self) + self.subctx = space.getexecutioncontext().Subcontext() + if is_main: + self.subctx.framestack = None # wack + else: self.bind(GreenletThunk(space, state, self)) def descr_method__new__(space, w_subtype, w_callable): @@ -75,11 +77,11 @@ def hello(self): ec = self.space.getexecutioncontext() - ec.subcontext_enter(self) + self.subctx.enter(ec) def goodbye(self): ec = self.space.getexecutioncontext() - ec.subcontext_leave(self) + self.subctx.leave(ec) def w_getcurrent(space): return space.wrap(AppGreenlet._get_state(space).current) @@ -143,10 +145,11 @@ def w_get_frame(space, w_self): self = space.interp_w(AppGreenlet, w_self) - if not self.has_ever_run or space.is_true(self.w_dead): + if (not self.has_ever_run or space.is_true(self.w_dead) or + self.costate.current is self): return space.w_None try: - return self.framestack.top(0) + return self.subctx.framestack.top(0) except IndexError: return space.w_None From pedronis at codespeak.net Mon Nov 20 14:04:12 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Nov 2006 14:04:12 +0100 (CET) Subject: [pypy-svn] r34788 - pypy/dist/pypy/jit/timeshifter Message-ID: <20061120130412.8F8A410060@code0.codespeak.net> Author: pedronis Date: Mon Nov 20 14:04:10 2006 New Revision: 34788 Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py Log: fix debug_assert related failures. Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Mon Nov 20 14:04:10 2006 @@ -492,7 +492,7 @@ [c_opdesc, v_jitstate] + args_v, ts.s_RedBox) - def translate_op_debug_log_exc(self, hop): # don't timeshift debug_log_exc + def translate_op_debug_assert(self, hop): pass def translate_op_keepalive(self,hop): From arigo at codespeak.net Mon Nov 20 14:04:57 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 14:04:57 +0100 (CET) Subject: [pypy-svn] r34789 - in pypy/dist/pypy/rpython: . lltypesystem test Message-ID: <20061120130457.3EA5B10060@code0.codespeak.net> Author: arigo Date: Mon Nov 20 14:04:52 2006 New Revision: 34789 Modified: pypy/dist/pypy/rpython/lltypesystem/rtupletype.py pypy/dist/pypy/rpython/rtuple.py pypy/dist/pypy/rpython/test/test_rtuple.py Log: Forbit id() and 'is' between RPython tuples. Add a hint that will mean for the jit that we don't care about preserving the identity of tuples. Modified: pypy/dist/pypy/rpython/lltypesystem/rtupletype.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rtupletype.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rtupletype.py Mon Nov 20 14:04:52 2006 @@ -10,5 +10,6 @@ return Void # empty tuple else: fields = [('item%d' % i, TYPE) for i, TYPE in enumerate(field_lltypes)] - kwds = {'hints': {'immutable': True}} + kwds = {'hints': {'immutable': True, + 'noidentity': True}} return Ptr(GcStruct('tuple%d' % len(field_lltypes), *fields, **kwds)) Modified: pypy/dist/pypy/rpython/rtuple.py ============================================================================== --- pypy/dist/pypy/rpython/rtuple.py (original) +++ pypy/dist/pypy/rpython/rtuple.py Mon Nov 20 14:04:52 2006 @@ -124,6 +124,9 @@ def rtype_len(self, hop): return hop.inputconst(Signed, len(self.items_r)) + def rtype_id(self, hop): + raise TyperError("cannot ask for the id() of a tuple") + def get_ll_eq_function(self): return gen_eq_function(self.items_r) @@ -218,7 +221,10 @@ items_v.append(item_v) return r_from.newtuple(llops, r_to, items_v) return NotImplemented - + + def rtype_is_((robj1, robj2), hop): + raise TyperError("cannot compare tuples with 'is'") + class AbstractTupleIteratorRepr(IteratorRepr): 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 Mon Nov 20 14:04:52 2006 @@ -106,11 +106,11 @@ 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) + return x, y, z def f(): return g(5) res = self.interpret(f, []) - assert res is True + assert res.item0 == res.item1 == res.item2 def test_inst_tuple_getitem(self): class A: From arigo at codespeak.net Mon Nov 20 14:36:01 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 14:36:01 +0100 (CET) Subject: [pypy-svn] r34790 - in pypy/dist/pypy/rpython: . test Message-ID: <20061120133601.CFC1F1006C@code0.codespeak.net> Author: arigo Date: Mon Nov 20 14:35:57 2006 New Revision: 34790 Modified: pypy/dist/pypy/rpython/rpbc.py pypy/dist/pypy/rpython/test/test_rpbc.py Log: Yet another rpbc conversion case that we didn't need so far. Modified: pypy/dist/pypy/rpython/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/rpbc.py (original) +++ pypy/dist/pypy/rpython/rpbc.py Mon Nov 20 14:35:57 2006 @@ -744,6 +744,8 @@ return v if r_clspbc1.lowleveltype is Void: return inputconst(r_clspbc2, r_clspbc1.s_pbc.const) + if r_clspbc2.lowleveltype is Void: + return inputconst(Void, r_clspbc2.s_pbc.const) return NotImplemented def adjust_shape(hop2, s_shape): 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 Nov 20 14:35:57 2006 @@ -1458,6 +1458,25 @@ res = self.interpret(call_functionarg, []) assert res == 2 * 42 + 4 + def test_convert_multiple_classes_to_single(self): + class A: + result = 321 + def meth(self, n): + if n: + return A + else: + return B + class B(A): + result = 123 + def meth(self, n): + return B + def f(n): + A().meth(n) + cls = B().meth(n) + return cls().result + res = self.interpret(f, [5]) + assert res == 123 + # 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 arigo at codespeak.net Mon Nov 20 15:55:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 15:55:29 +0100 (CET) Subject: [pypy-svn] r34795 - pypy/dist/pypy/module/_stackless Message-ID: <20061120145529.2535010079@code0.codespeak.net> Author: arigo Date: Mon Nov 20 15:55:27 2006 New Revision: 34795 Modified: pypy/dist/pypy/module/_stackless/coroutine.py Log: Made the AppCoroutine state argument optional again, for the cclp. Modified: pypy/dist/pypy/module/_stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/coroutine.py Mon Nov 20 15:55:27 2006 @@ -51,8 +51,10 @@ class AppCoroutine(Coroutine): # XXX, StacklessFlags): - def __init__(self, space, state): + def __init__(self, space, state=None): self.space = space + if state is None: + state = AppCoroutine._get_state(space) Coroutine.__init__(self, state) self.flags = 0 self.newsubctx() @@ -63,7 +65,7 @@ def descr_method__new__(space, w_subtype): co = space.allocate_instance(AppCoroutine, w_subtype) - AppCoroutine.__init__(co, space, AppCoroutine._get_state(space)) + AppCoroutine.__init__(co, space) return space.wrap(co) def _get_state(space): From antocuni at codespeak.net Mon Nov 20 16:15:03 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Mon, 20 Nov 2006 16:15:03 +0100 (CET) Subject: [pypy-svn] r34797 - in pypy/dist/pypy/translator: cli/test oosupport Message-ID: <20061120151503.0381110077@code0.codespeak.net> Author: antocuni Date: Mon Nov 20 16:15:02 2006 New Revision: 34797 Modified: pypy/dist/pypy/translator/cli/test/test_dict.py pypy/dist/pypy/translator/oosupport/constant.py Log: Since tuples need to be fully initialized for computing the right hash code it's necessary to initialize dictionaries after the tuples. Modified: pypy/dist/pypy/translator/cli/test/test_dict.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dict.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dict.py Mon Nov 20 16:15:02 2006 @@ -35,3 +35,9 @@ class TestCliConstantDict(CliTest, BaseTestRconstantdict): def test_constant_r_dict(self): py.test.skip('r_dict is not supported, yet') + + def test_tuple_as_key(self): + mydict = {('r',): 42} + def fn(ch): + return mydict[(ch,)] + assert self.interpret(fn, ['r']) == 42 Modified: pypy/dist/pypy/translator/oosupport/constant.py ============================================================================== --- pypy/dist/pypy/translator/oosupport/constant.py (original) +++ pypy/dist/pypy/translator/oosupport/constant.py Mon Nov 20 16:15:02 2006 @@ -597,6 +597,8 @@ # Dictionary constants class DictConst(AbstractConst): + PRIORITY = 90 + def __init__(self, db, dict, count): AbstractConst.__init__(self, db, dict, count) self.name = 'DICT__%d' % count From pedronis at codespeak.net Mon Nov 20 16:52:24 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Nov 2006 16:52:24 +0100 (CET) Subject: [pypy-svn] r34798 - in pypy/dist/pypy/jit: codegen/i386 codegen/llgraph codegen/ppc codegen/ppc/test timeshifter timeshifter/test Message-ID: <20061120155224.7D8C51007B@code0.codespeak.net> Author: pedronis Date: Mon Nov 20 16:52:17 2006 New Revision: 34798 Modified: pypy/dist/pypy/jit/codegen/i386/rgenop.py pypy/dist/pypy/jit/codegen/llgraph/rgenop.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/ppc/test/test_genc_ts.py pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/jit/timeshifter/rtimeshift.py pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Log: (arre, pedronis) implement jit support for getarraysubstruct. with a test. We implemented it in the timeshifter, i386 backend, and tried in the ppc one but we could not test it. Modified: pypy/dist/pypy/jit/codegen/i386/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/i386/rgenop.py Mon Nov 20 16:52:17 2006 @@ -297,6 +297,12 @@ op = eax return self.returnvar(op) + def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): + self.mc.MOV(edx, gv_ptr.operand(self)) + op = self.itemaddr(edx, arraytoken, gv_index) + self.mc.LEA(eax, op) + return self.returnvar(eax) + def genop_getarraysize(self, arraytoken, gv_ptr): lengthoffset, startoffset, itemoffset = arraytoken self.mc.MOV(edx, gv_ptr.operand(self)) @@ -813,6 +819,9 @@ def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index): return dummy_var + def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): + return dummy_var + def genop_getarraysize(self, arraytoken, gv_ptr): return dummy_var Modified: pypy/dist/pypy/jit/codegen/llgraph/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llgraph/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/llgraph/rgenop.py Mon Nov 20 16:52:17 2006 @@ -107,6 +107,11 @@ return LLVar(llimpl.genop(self.b, 'getarrayitem', vars_gv, gv_ITEMTYPE.v)) + def genop_getarraysubstruct(self, gv_ITEMTYPE, gv_ptr, gv_index): + vars_gv = [gv_ptr.v, gv_index.v] + return LLVar(llimpl.genop(self.b, 'getarraysubstruct', vars_gv, + gv_ITEMTYPE.v)) + def genop_setarrayitem(self, gv_ITEMTYPE, gv_ptr, gv_index, gv_value): vars_gv = [gv_ptr.v, gv_index.v, gv_value.v] return LLVar(llimpl.genop(self.b, 'setarrayitem', vars_gv, @@ -232,7 +237,10 @@ @staticmethod @specialize.memo() def arrayToken(A): - return LLConst(llimpl.constTYPE(A.OF)) + ITEMTYPE = A.OF + if isinstance(ITEMTYPE, lltype.ContainerType): + ITEMTYPE = lltype.Ptr(ITEMTYPE) + return LLConst(llimpl.constTYPE(ITEMTYPE)) @staticmethod @specialize.memo() Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Mon Nov 20 16:52:17 2006 @@ -251,6 +251,22 @@ gv_result, [gv_ptr, gv_itemoffset])) return gv_result + def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): + # xxx not tested + _, _, itemsize = arraytoken + assert itemsize == 4 + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + gv_result = Var() + if gv_itemoffset.fits_in_immediate(): + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_result, [gv_ptr, gv_itemoffset])) + else: + self.insns.append( + insn.Insn_GPR__GPR_GPR(RPPCAssembler.add, + gv_result, [gv_ptr, gv_itemoffset])) + return gv_result + def genop_getarraysize(self, arraytoken, gv_ptr): lengthoffset, _, _ = arraytoken gv_result = Var() Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_genc_ts.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_genc_ts.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_genc_ts.py Mon Nov 20 16:52:17 2006 @@ -1,3 +1,4 @@ +import py from pypy.jit.codegen.i386.test.test_genc_ts import I386TimeshiftingTestMixin from pypy.jit.timeshifter.test import test_timeshift from pypy.jit.codegen.ppc.rgenop import RPPCGenOp @@ -5,7 +6,7 @@ class PPCTimeshiftingTestMixin(I386TimeshiftingTestMixin): RGenOp = RPPCGenOp -class TestTimeshiftI386(PPCTimeshiftingTestMixin, +class TestTimeshiftPPC(PPCTimeshiftingTestMixin, test_timeshift.TestTimeshift): # for the individual tests see Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Mon Nov 20 16:52:17 2006 @@ -652,6 +652,27 @@ [v_jitstate, c_fielddesc, v_argbox ], ts.s_RedBox) + def translate_op_getarraysubstruct(self, hop): + 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 + v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE), + self.getredrepr(lltype.Signed)) + fielddesc = rcontainer.ArrayFieldDesc(self.RGenOp, PTRTYPE.TO) + c_fielddesc = inputconst(lltype.Void, fielddesc) + s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) + v_jitstate = hop.llops.getjitstate() + return hop.llops.genmixlevelhelpercall( + rtimeshift.ll_gengetarraysubstruct, + [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_cast_pointer(self, hop): FROM_TYPE = originalconcretetype(hop.args_s[0]) [v_argbox] = hop.inputargs(self.getredrepr(FROM_TYPE)) Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py Mon Nov 20 16:52:17 2006 @@ -125,6 +125,19 @@ return fielddesc.redboxcls(fielddesc.kind, genvar) +def ll_gengetarraysubstruct(jitstate, fielddesc, argbox, indexbox): + if fielddesc.immutable and argbox.is_constant() and indexbox.is_constant(): + array = rvalue.ll_getvalue(argbox, fielddesc.PTRTYPE) + res = array[rvalue.ll_getvalue(indexbox, lltype.Signed)] + return rvalue.ll_fromvalue(jitstate, res) + genvar = jitstate.curbuilder.genop_getarraysubstruct( + fielddesc.arraytoken, + argbox.getgenvar(jitstate.curbuilder), + indexbox.getgenvar(jitstate.curbuilder)) + + return fielddesc.redboxcls(fielddesc.kind, genvar) + + def ll_gensetarrayitem(jitstate, fielddesc, destbox, indexbox, valuebox): genvar = jitstate.curbuilder.genop_setarrayitem( fielddesc.arraytoken, Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Mon Nov 20 16:52:17 2006 @@ -739,6 +739,32 @@ 'setarrayitem': 2, 'getarrayitem': 1, 'getarraysize': 1, 'int_mul': 1}) + def test_red_struct_array(self): + S = lltype.Struct('s', ('x', lltype.Signed)) + A = lltype.GcArray(S) + def ll_function(x, y, n): + a = lltype.malloc(A, 2) + a[0].x = x + a[1].x = y + return a[n].x*len(a) + + res = self.timeshift(ll_function, [21, -21, 0], [], + policy=P_NOVIRTUAL) + assert res == 42 + self.check_insns({'malloc_varsize': 1, 'ptr_iszero': 1, + 'getarraysubstruct': 3, + 'setfield': 2, 'getfield': 1, + 'getarraysize': 1, 'int_mul': 1}) + + res = self.timeshift(ll_function, [21, -21, 1], [], + policy=P_NOVIRTUAL) + assert res == -42 + self.check_insns({'malloc_varsize': 1, 'ptr_iszero': 1, + 'getarraysubstruct': 3, + 'setfield': 2, 'getfield': 1, + 'getarraysize': 1, 'int_mul': 1}) + + def test_red_varsized_struct(self): A = lltype.Array(lltype.Signed) S = lltype.GcStruct('S', ('foo', lltype.Signed), ('a', A)) From mwh at codespeak.net Mon Nov 20 17:14:29 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 20 Nov 2006 17:14:29 +0100 (CET) Subject: [pypy-svn] r34799 - pypy/dist/pypy/jit/codegen/ppc Message-ID: <20061120161429.D16C21007C@code0.codespeak.net> Author: mwh Date: Mon Nov 20 17:14:28 2006 New Revision: 34799 Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py Log: i've tested this now :-) Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Mon Nov 20 17:14:28 2006 @@ -252,7 +252,6 @@ return gv_result def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): - # xxx not tested _, _, itemsize = arraytoken assert itemsize == 4 gv_itemoffset = self.itemoffset(arraytoken, gv_index) From pedronis at codespeak.net Mon Nov 20 18:23:29 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Nov 2006 18:23:29 +0100 (CET) Subject: [pypy-svn] r34800 - pypy/dist/pypy/jit/timeshifter/test Message-ID: <20061120172329.4692710076@code0.codespeak.net> Author: pedronis Date: Mon Nov 20 18:23:25 2006 New Revision: 34800 Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Log: (arigo, arre, pedronis) a new work in progress test about deepfrozen, and compile time tuples. the test in this form in not completely correct. Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Mon Nov 20 18:23:25 2006 @@ -1068,3 +1068,14 @@ res = self.timeshift(f, [0], [0], policy=P_NOVIRTUAL) assert res == 42 self.check_insns({}) + + def test_green_tuple(self): + py.test.skip("WIP") + d = {(4, 5): 42, (6, 7): 12} + def f(a, b): + d1 = hint(d, deepfreeze=True) + return d1[a, b] + + res = self.timeshift(f, [0, 4, 5], [0, 1, 2], policy=P_NOVIRTUAL) + assert res == 42 + self.check_insns({}) From pedronis at codespeak.net Mon Nov 20 18:25:08 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Nov 2006 18:25:08 +0100 (CET) Subject: [pypy-svn] r34801 - pypy/dist/pypy/jit/timeshifter Message-ID: <20061120172508.8357410082@code0.codespeak.net> Author: pedronis Date: Mon Nov 20 18:24:59 2006 New Revision: 34801 Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py Log: (arre, arigo around, pedronis) some support for immutable noidentity structures to fall back to compile time constants. Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/dist/pypy/jit/timeshifter/rcontainer.py Mon Nov 20 18:24:59 2006 @@ -2,6 +2,10 @@ from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cachedtype from pypy.jit.timeshifter import rvalue +from pypy.rlib.unroll import unrolling_iterable + +from pypy.rpython.lltypesystem import lloperation +debug_print = lloperation.llop.debug_print class AbstractContainer(object): __slots__ = [] @@ -23,6 +27,7 @@ arrayfielddesc = None alloctoken = None varsizealloctoken = None + materialize = None def __init__(self, RGenOp, TYPE): self.TYPE = TYPE @@ -58,6 +63,22 @@ self.fielddesc_by_name = fielddesc_by_name self.innermostdesc = innermostdesc + self.immutable = TYPE._hints.get('immutable', False) + self.noidentity = TYPE._hints.get('noidentity', False) + + if self.immutable and self.noidentity: + descs = unrolling_iterable(fielddescs) + def materialize(rgenop, boxes): + s = lltype.malloc(TYPE) + i = 0 + for desc in descs: + v = rvalue.ll_getvalue(boxes[i], desc.RESTYPE) + setattr(s, desc.fieldname, v) + i = i + 1 + return rgenop.genconst(s) + + self.materialize = materialize + def getfielddesc(self, name): return self.fielddesc_by_name[name] @@ -208,6 +229,16 @@ typedesc = self.typedesc boxes = self.content_boxes self.content_boxes = None + if typedesc.materialize is not None: + for box in boxes: + if box is None or not box.is_constant(): + break + else: + gv = typedesc.materialize(builder.rgenop, boxes) + self.ownbox.genvar = gv + self.ownbox.content = None + return + debug_print(lltype.Void, "FORCE CONTAINER") genvar = builder.genop_malloc_fixedsize(typedesc.alloctoken) # force the box pointing to this VirtualStruct self.ownbox.genvar = genvar From arigo at codespeak.net Mon Nov 20 19:11:10 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 19:11:10 +0100 (CET) Subject: [pypy-svn] r34804 - pypy/dist/pypy/jit/timeshifter Message-ID: <20061120181110.19EB610081@code0.codespeak.net> Author: arigo Date: Mon Nov 20 19:11:07 2006 New Revision: 34804 Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py Log: Remove the unused graphs during jitting (hint-annotated but not timeshifted). Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Mon Nov 20 19:11:07 2006 @@ -160,6 +160,10 @@ if nextgraph not in seen: pending.append(nextgraph) seen[nextgraph] = True + # only keep the hint-annotated graphs that are really useful + self.annotator.translator.graphs = [graph + for graph in self.annotator.translator.graphs + if graph in seen] if view: self.annotator.translator.view() # in the middle for graph in seen: From arigo at codespeak.net Mon Nov 20 19:53:51 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 19:53:51 +0100 (CET) Subject: [pypy-svn] r34805 - in pypy/dist/pypy/annotation: . test Message-ID: <20061120185351.57C5D10081@code0.codespeak.net> Author: arigo Date: Mon Nov 20 19:53:44 2006 New Revision: 34805 Modified: pypy/dist/pypy/annotation/binaryop.py pypy/dist/pypy/annotation/builtin.py pypy/dist/pypy/annotation/dictdef.py pypy/dist/pypy/annotation/model.py pypy/dist/pypy/annotation/test/test_annrpython.py pypy/dist/pypy/annotation/unaryop.py Log: Introduced annmodel.s_Bool as a prebuilt SomeBool(). Be careful to never add a 'const' or 'knowntypedata' to it, though. Modified: pypy/dist/pypy/annotation/binaryop.py ============================================================================== --- pypy/dist/pypy/annotation/binaryop.py (original) +++ pypy/dist/pypy/annotation/binaryop.py Mon Nov 20 19:53:44 2006 @@ -5,7 +5,7 @@ import py import operator from pypy.annotation.pairtype import pair, pairtype -from pypy.annotation.model import SomeObject, SomeInteger, SomeBool +from pypy.annotation.model import SomeObject, SomeInteger, SomeBool, s_Bool from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeUnicodeCodePoint from pypy.annotation.model import SomeTuple, SomeImpossibleValue, s_ImpossibleValue @@ -112,42 +112,42 @@ return immutablevalue(obj1.const < obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) - return SomeBool() + return s_Bool def le((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const <= obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) - return SomeBool() + return s_Bool def eq((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const == obj2.const) else: getbookkeeper().count("non_int_eq", obj1, obj2) - return SomeBool() + return s_Bool def ne((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const != obj2.const) else: getbookkeeper().count("non_int_eq", obj1, obj2) - return SomeBool() + return s_Bool def gt((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const > obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) - return SomeBool() + return s_Bool def ge((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const >= obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) - return SomeBool() + return s_Bool def cmp((obj1, obj2)): getbookkeeper().count("cmp", obj1, obj2) @@ -270,16 +270,15 @@ pow_ovf = _clone(pow, [ZeroDivisionError, OverflowError]) def _compare_helper((int1, int2), opname, operation): + r = SomeBool() if int1.is_immutable_constant() and int2.is_immutable_constant(): - r = immutablevalue(operation(int1.const, int2.const)) + r.const = operation(int1.const, int2.const) else: # XXX VERY temporary hack if (opname == 'ge' and int2.is_immutable_constant() and int2.const == 0 and not rarithmetic.signedtype(int1.knowntype)): - r = immutablevalue(True) - else: - r = SomeBool() + r.const = True knowntypedata = {} # XXX HACK HACK HACK # propagate nonneg information between the two arguments @@ -386,7 +385,7 @@ def eq((lst1, lst2)): lst1.listdef.agree(lst2.listdef) - return SomeBool() + return s_Bool ne = eq Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Mon Nov 20 19:53:44 2006 @@ -4,7 +4,7 @@ import sys from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool -from pypy.annotation.model import SomeString, SomeTuple, SomeSlice +from pypy.annotation.model import SomeString, SomeTuple, SomeSlice, s_Bool from pypy.annotation.model import SomeUnicodeCodePoint, SomeAddress from pypy.annotation.model import SomeFloat, SomeWeakGcAddress, unionof from pypy.annotation.model import SomePBC, SomeInstance, SomeDict @@ -339,7 +339,7 @@ raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" def test(*args): - return SomeBool() + return s_Bool def import_func(*args): return SomeObject() @@ -517,7 +517,7 @@ def instanceof(i, I): assert I.is_constant() assert isinstance(I.const, ootype.Instance) - return SomeBool() + return s_Bool def classof(i): assert isinstance(i, SomeOOInstance) @@ -526,7 +526,7 @@ def subclassof(class1, class2): assert isinstance(class1, SomeOOClass) assert isinstance(class2, SomeOOClass) - return SomeBool() + return s_Bool def runtimenew(c): assert isinstance(c, SomeOOClass) Modified: pypy/dist/pypy/annotation/dictdef.py ============================================================================== --- pypy/dist/pypy/annotation/dictdef.py (original) +++ pypy/dist/pypy/annotation/dictdef.py Mon Nov 20 19:53:44 2006 @@ -1,5 +1,5 @@ from pypy.annotation.model import SomeObject, s_ImpossibleValue -from pypy.annotation.model import SomeInteger, SomeBool, unionof +from pypy.annotation.model import SomeInteger, s_Bool, unionof from pypy.annotation.model import SomeInstance from pypy.annotation.listdef import ListItem @@ -62,7 +62,7 @@ def check_eqfn(annotator, graph): s = annotator.binding(graph.getreturnvar()) - assert SomeBool().contains(s), ( + assert s_Bool.contains(s), ( "the custom eq function of an r_dict must return a boolean" " (got %r)" % (s,)) self.bookkeeper.emulate_pbc_call(myeq, self.s_rdict_eqfn, [s_key, s_key], Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Mon Nov 20 19:53:44 2006 @@ -474,6 +474,7 @@ s_None = SomePBC([], can_be_None=True) +s_Bool = SomeBool() s_ImpossibleValue = SomeImpossibleValue() # ____________________________________________________________ @@ -549,7 +550,7 @@ NUMBER = object() annotation_to_ll_map = [ (s_None, lltype.Void), # also matches SomeImpossibleValue() - (SomeBool(), lltype.Bool), + (s_Bool, lltype.Bool), (SomeInteger(knowntype=r_ulonglong), NUMBER), (SomeFloat(), lltype.Float), (SomeChar(), lltype.Char), Modified: pypy/dist/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_annrpython.py (original) +++ pypy/dist/pypy/annotation/test/test_annrpython.py Mon Nov 20 19:53:44 2006 @@ -44,6 +44,9 @@ def setup_class(cls): cls.space = FlowObjSpace() + def teardown_method(self, meth): + assert annmodel.s_Bool == annmodel.SomeBool() + class RPythonAnnotator(_RPythonAnnotator): def build_types(self, *args): s = _RPythonAnnotator.build_types(self, *args) Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Mon Nov 20 19:53:44 2006 @@ -7,7 +7,7 @@ SomeDict, SomeUnicodeCodePoint, SomeTuple, SomeImpossibleValue, \ SomeInstance, SomeBuiltin, SomeFloat, SomeIterator, SomePBC, \ SomeExternalObject, SomeTypedAddressAccess, SomeAddress, \ - SomeCTypesObject, s_ImpossibleValue, \ + SomeCTypesObject, s_ImpossibleValue, s_Bool, \ unionof, set, missing_operation, add_knowntypedata from pypy.annotation.bookkeeper import getbookkeeper from pypy.annotation import builtin @@ -60,24 +60,22 @@ s_cls, vars) if obj.is_constant() and s_cls.is_constant(): return immutablevalue(issubclass(obj.const, s_cls.const)) - return SomeBool() + return s_Bool def len(obj): return SomeInteger(nonneg=True) - def is_true_behavior(obj): + def is_true_behavior(obj, s): if obj.is_immutable_constant(): - return immutablevalue(bool(obj.const)) + s.const = bool(obj.const) else: s_len = obj.len() if s_len.is_immutable_constant(): - return immutablevalue(s_len.const > 0) - else: - return SomeBool() + s.const = s_len.const > 0 def is_true(s_obj): - r = s_obj.is_true_behavior() - assert isinstance(r, SomeBool) + r = SomeBool() + s_obj.is_true_behavior(r) bk = getbookkeeper() knowntypedata = r.knowntypedata = {} @@ -174,7 +172,7 @@ return SomeObject() def op_contains(obj, s_element): - return SomeBool() + return s_Bool def hint(self, *args_s): return self @@ -192,7 +190,7 @@ def is_true(self): if self.is_immutable_constant(): return getbookkeeper().immutablevalue(bool(self.const)) - return SomeBool() + return s_Bool def hash(flt): return SomeInteger() @@ -318,7 +316,7 @@ def op_contains(lst, s_element): lst.listdef.generalize(s_element) - return SomeBool() + return s_Bool def hint(lst, *args_s): hints = args_s[-1].const @@ -399,16 +397,16 @@ def op_contains(dct, s_element): dct.dictdef.generalize_key(s_element) - return SomeBool() + return s_Bool class __extend__(SomeString): def method_startswith(str, frag): - return SomeBool() + return s_Bool def method_endswith(str, frag): - return SomeBool() + return s_Bool def method_find(str, frag, start=None, end=None): return SomeInteger() @@ -468,22 +466,22 @@ return immutablevalue(1) def method_isspace(chr): - return SomeBool() + return s_Bool def method_isdigit(chr): - return SomeBool() + return s_Bool def method_isalpha(chr): - return SomeBool() + return s_Bool def method_isalnum(chr): - return SomeBool() + return s_Bool def method_islower(chr): - return SomeBool() + return s_Bool def method_isupper(chr): - return SomeBool() + return s_Bool class __extend__(SomeUnicodeCodePoint): @@ -548,11 +546,9 @@ getbookkeeper().needs_hash_support[ins.classdef] = True return SomeInteger() - def is_true_behavior(ins): - if ins.can_be_None: - return SomeBool() - else: - return immutablevalue(True) + def is_true_behavior(ins, s): + if not ins.can_be_None: + s.const = True class __extend__(SomeBuiltin): @@ -594,13 +590,11 @@ d = [desc.bind_under(classdef, name) for desc in pbc.descriptions] return SomePBC(d, can_be_None=pbc.can_be_None) - def is_true_behavior(pbc): + def is_true_behavior(pbc, s): if pbc.isNone(): - return immutablevalue(False) - elif pbc.can_be_None: - return SomeBool() - else: - return immutablevalue(True) + s.const = False + elif not pbc.can_be_None: + s.const = True class __extend__(SomeExternalObject): @@ -649,7 +643,7 @@ return ll_to_annotation(v) def is_true(p): - return SomeBool() + return s_Bool class __extend__(SomeExternalBuiltin): def getattr(p, s_attr): @@ -680,7 +674,7 @@ return obj.knowntype.get_field(name) def is_true(p): - return SomeBool() + return s_Bool class __extend__(SomeLLADTMeth): @@ -706,7 +700,7 @@ setattr(r.ootype._example(), s_attr.const, v._example()) def is_true(p): - return SomeBool() + return s_Bool class __extend__(SomeOOBoundMeth): def simple_call(m, *args_s): @@ -739,7 +733,7 @@ return SomeObject() def is_true(cto): - return SomeBool() + return s_Bool def simple_call(cto, *args_s): # for variables containing ctypes function pointers @@ -761,4 +755,4 @@ getattr.can_only_throw = [] def is_true(s_addr): - return SomeBool() + return s_Bool From pedronis at codespeak.net Mon Nov 20 20:04:47 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Nov 2006 20:04:47 +0100 (CET) Subject: [pypy-svn] r34806 - in pypy/dist/pypy: annotation rpython Message-ID: <20061120190447.6D2B110074@code0.codespeak.net> Author: pedronis Date: Mon Nov 20 20:04:38 2006 New Revision: 34806 Modified: pypy/dist/pypy/annotation/builtin.py pypy/dist/pypy/annotation/model.py pypy/dist/pypy/rpython/annlowlevel.py Log: (arigo, pedronis) move not_const to model.py; make it so that the result of hint is never a constant. Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Mon Nov 20 20:04:38 2006 @@ -10,7 +10,7 @@ from pypy.annotation.model import SomePBC, SomeInstance, SomeDict from pypy.annotation.model import SomeExternalObject from pypy.annotation.model import annotation_to_lltype, lltype_to_annotation, ll_to_annotation -from pypy.annotation.model import add_knowntypedata +from pypy.annotation.model import add_knowntypedata, not_const from pypy.annotation.model import s_ImpossibleValue from pypy.annotation.bookkeeper import getbookkeeper from pypy.annotation import description @@ -299,7 +299,7 @@ return immutablevalue(None) def robjmodel_hint(s, **kwds_s): - return s + return not_const(s) def llmemory_cast_ptr_to_adr(s): return SomeAddress() Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Mon Nov 20 20:04:38 2006 @@ -659,6 +659,18 @@ r[truth_v] = unionof(ktd1[truth_v], ktd2[truth_v]) return r +def not_const(s_obj): + if s_obj.is_constant(): + new_s_obj = SomeObject() + new_s_obj.__class__ = s_obj.__class__ + dic = new_s_obj.__dict__ = s_obj.__dict__.copy() + if 'const' in dic: + del new_s_obj.const + else: + del new_s_obj.const_box + s_obj = new_s_obj + return s_obj + # ____________________________________________________________ # internal Modified: pypy/dist/pypy/rpython/annlowlevel.py ============================================================================== --- pypy/dist/pypy/rpython/annlowlevel.py (original) +++ pypy/dist/pypy/rpython/annlowlevel.py Mon Nov 20 20:04:38 2006 @@ -10,16 +10,6 @@ from pypy.rpython import extfunctable, extregistry from pypy.objspace.flow.model import Constant -def not_const(s_obj): # xxx move it somewhere else - if s_obj.is_constant(): - new_s_obj = annmodel.SomeObject() - new_s_obj.__class__ = s_obj.__class__ - new_s_obj.__dict__ = s_obj.__dict__.copy() - del new_s_obj.const - s_obj = new_s_obj - return s_obj - - class KeyComp(object): def __init__(self, val): self.val = val @@ -59,7 +49,7 @@ key.append(KeyComp(s_obj.const)) new_args_s.append(s_obj) else: - new_args_s.append(not_const(s_obj)) + new_args_s.append(annmodel.not_const(s_obj)) try: key.append(annmodel.annotation_to_lltype(s_obj)) except ValueError: From arigo at codespeak.net Mon Nov 20 20:05:59 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 20:05:59 +0100 (CET) Subject: [pypy-svn] r34807 - in pypy/dist/pypy/jit/hintannotator: . test Message-ID: <20061120190559.35F2710077@code0.codespeak.net> Author: arigo Date: Mon Nov 20 20:05:55 2006 New Revision: 34807 Modified: pypy/dist/pypy/jit/hintannotator/model.py pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Log: (pedronis, arigo) deepfreezing variables too, so that the timeshifted graphs can constant-fold accesses if the redboxes turn out to be compile-time constants. Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Mon Nov 20 20:05:55 2006 @@ -125,9 +125,10 @@ class SomeLLAbstractValue(annmodel.SomeObject): - def __init__(self, T): + def __init__(self, T, deepfrozen=False): self.concretetype = T assert self.__class__ != SomeLLAbstractValue + self.deepfrozen = deepfrozen def is_green(self, frame=None): return False @@ -138,11 +139,10 @@ def __init__(self, T, origins, eager_concrete=False, myorigin=None, deepfrozen=False): - SomeLLAbstractValue.__init__(self, T) + SomeLLAbstractValue.__init__(self, T, deepfrozen) self.origins = origins self.eager_concrete = eager_concrete self.myorigin = myorigin - self.deepfrozen = deepfrozen assert myorigin is None or myorigin.spaceop is not None def fmt_origins(self, origins): @@ -281,7 +281,7 @@ def getfield(hs_v1, hs_fieldname): S = hs_v1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) - return SomeLLAbstractVariable(FIELD_TYPE) + return SomeLLAbstractVariable(FIELD_TYPE, hs_v1.deepfrozen) def setfield(hs_v1, hs_fieldname, hs_value): pass @@ -289,7 +289,7 @@ def getsubstruct(hs_v1, hs_fieldname): S = hs_v1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) - return SomeLLAbstractVariable(lltype.Ptr(FIELD_TYPE)) + return SomeLLAbstractVariable(lltype.Ptr(FIELD_TYPE), hs_v1.deepfrozen) ## def getarrayitem(hs_v1, hs_index): ## ARRAY = hs_v1.concretetype.TO @@ -437,11 +437,16 @@ class __extend__(pairtype(SomeLLAbstractValue, SomeLLAbstractValue)): def getarrayitem((hs_v1, hs_v2)): - return SomeLLAbstractVariable(hs_v1.concretetype.TO.OF) + return SomeLLAbstractVariable(hs_v1.concretetype.TO.OF, + hs_v1.deepfrozen) def setarrayitem((hs_v1, hs_v2), hs_v3): pass + def getarraysubstruct((hs_v1, hs_v2)): + return SomeLLAbstractVariable(lltype.Ptr(hs_v1.concretetype.TO.OF), + hs_v1.deepfrozen) + def union((hs_v1, hs_v2)): raise annmodel.UnionError("%s %s don't mix" % (hs_v1, hs_v2)) Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/dist/pypy/jit/hintannotator/test/test_annotator.py Mon Nov 20 20:05:55 2006 @@ -525,6 +525,17 @@ assert isinstance(ha.binding(v2), SomeLLAbstractConstant) assert ha.binding(v1).deepfrozen +def test_deepfreeze_variables(): + l1 = [[1], [2, 3], [4], []] + def ll_function(i): + i = hint(i, variable=True) + l = hint(l1, deepfreeze=True) + return l[i] + + hs, ha = hannotate(ll_function, [int], annotator=True, policy=P_NOVIRTUAL) + assert isinstance(hs, SomeLLAbstractVariable) + assert hs.deepfrozen + def test_propagate_fixing_across_func_arguments(): def ll_func2(z): z = hint(z, concrete=True) From arigo at codespeak.net Mon Nov 20 20:16:30 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 20 Nov 2006 20:16:30 +0100 (CET) Subject: [pypy-svn] r34808 - pypy/dist/pypy/jit/hintannotator Message-ID: <20061120191630.1853D1007C@code0.codespeak.net> Author: arigo Date: Mon Nov 20 20:16:27 2006 New Revision: 34808 Modified: pypy/dist/pypy/jit/hintannotator/model.py Log: (pedronis, arigo) Trying to get the union() handle deepfreezing... Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Mon Nov 20 20:16:27 2006 @@ -198,6 +198,7 @@ class SomeLLAbstractContainer(SomeLLAbstractValue): + deepfrozen = False # XXX for now def __init__(self, contentdef): self.contentdef = contentdef @@ -249,6 +250,15 @@ else: return hs.concretetype +def deepunfreeze(hs): + if hs.deepfrozen: + hs1 = annmodel.SomeObject() + hs1.__class__ = hs.__class__ + hs1.__dict__ = hs.__dict__.copy() + hs1.deepfrozen = False + hs = hs1 + return hs + # ____________________________________________________________ # operations @@ -448,22 +458,33 @@ hs_v1.deepfrozen) def union((hs_v1, hs_v2)): + if hs_v1.deepfrozen != hs_v2.deepfrozen: + hs_v1 = deepunfreeze(hs_v1) + hs_v2 = deepunfreeze(hs_v2) + if hs_v1 == hs_v2: + return hs_v1 + return pair(hs_v1, hs_v2).union_frozen_equal() + + def invalid_union((hs_v1, hs_v2)): raise annmodel.UnionError("%s %s don't mix" % (hs_v1, hs_v2)) + union_frozen_equal = invalid_union + class __extend__(pairtype(SomeLLAbstractVariable, SomeLLAbstractConstant), pairtype(SomeLLAbstractConstant, SomeLLAbstractVariable)): - def union((hs_v1, hs_v2)): + def union_frozen_equal((hs_v1, hs_v2)): assert hs_v1.concretetype == hs_v2.concretetype - if getattr(hs_v1, 'eager_concrete', False) or getattr(hs_v2, 'eager_concrete', False): - raise annmodel.UnionError("%s %s don't mix" % (hs_v1, hs_v2)) - return SomeLLAbstractVariable(hs_v1.concretetype) + if (getattr(hs_v1, 'eager_concrete', False) or + getattr(hs_v2, 'eager_concrete', False)): + pair(hs_v1, hs_v2).invalid_union() + return SomeLLAbstractVariable(hs_v1.concretetype, hs_v1.deepfrozen) class __extend__(pairtype(SomeLLAbstractConstant, SomeLLAbstractConstant)): - def union((hs_c1, hs_c2)): + def union_frozen_equal((hs_c1, hs_c2)): assert hs_c1.concretetype == hs_c2.concretetype d = newset(hs_c1.origins, hs_c2.origins) if hs_c1.myorigin is hs_c2.myorigin: @@ -474,7 +495,7 @@ eager_concrete = hs_c1.eager_concrete and hs_c2.eager_concrete, myorigin = myorigin, - deepfrozen = hs_c1.deepfrozen and hs_c2.deepfrozen) + deepfrozen = hs_c1.deepfrozen) def getarrayitem((hs_c1, hs_index)): @@ -501,9 +522,9 @@ class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractContainer)): - def union((hs_cont1, hs_cont2)): + def union_frozen_equal((hs_cont1, hs_cont2)): contentdef = hs_cont1.contentdef.union(hs_cont2.contentdef) - return SomeLLAbstractContainer(contentdef) + return SomeLLAbstractContainer(contentdef) # XXX deepfrozen? def ptr_eq((hs_cont1, hs_cont2)): return SomeLLAbstractConstant(lltype.Bool, {}) @@ -513,15 +534,15 @@ class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractValue)): - def union((hs_cont1, hs_val2)): + def union_frozen_equal((hs_cont1, hs_val2)): hs_cont1.contentdef.mark_degenerated() assert hs_cont1.concretetype == hs_val2.concretetype - return SomeLLAbstractVariable(hs_cont1.concretetype) + return SomeLLAbstractVariable(hs_cont1.concretetype) # XXX deepfrozen? class __extend__(pairtype(SomeLLAbstractValue, SomeLLAbstractContainer)): - def union((hs_val1, hs_cont2)): - return pair(hs_cont2, hs_val1).union() + def union_frozen_equal((hs_val1, hs_cont2)): + return pair(hs_cont2, hs_val1).union_frozen_equal() class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractValue), From pedronis at codespeak.net Mon Nov 20 21:13:44 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 20 Nov 2006 21:13:44 +0100 (CET) Subject: [pypy-svn] r34810 - in pypy/dist/pypy/jit/timeshifter: . test Message-ID: <20061120201344.E6F351007F@code0.codespeak.net> Author: pedronis Date: Mon Nov 20 21:13:39 2006 New Revision: 34810 Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/jit/timeshifter/rtimeshift.py pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Log: (arigo, pedronis) implement support for deepfrozen in the timeshifter, fix the folding of getfield and getarrayitem, support for pointer equality ops. => the strange test passes (but slow..ly) Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Mon Nov 20 21:13:39 2006 @@ -460,9 +460,9 @@ del link.args[0] # Void link.args = [v_jitstate] + link.args - def generic_translate_operation(self, hop, force=False): + def generic_translate_operation(self, hop): # detect constant-foldable all-green operations - if not force and hop.spaceop.opname not in rtimeshift.FOLDABLE_OPS: + if hop.spaceop.opname not in rtimeshift.FOLDABLE_GREEN_OPS: return None green = True for r_arg in hop.args_r: @@ -526,49 +526,39 @@ ts.s_RedBox) # non virtual case 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 - v_argbox, c_fieldname = hop.inputargs(self.getredrepr(PTRTYPE), green_void_repr) v_argbox = hop.llops.as_ptrredbox(v_argbox) + c_deepfrozen = inputconst(lltype.Bool, hop.args_s[0].deepfrozen) structdesc = rcontainer.StructTypeDesc(self.RGenOp, PTRTYPE.TO) fielddesc = structdesc.getfielddesc(c_fieldname.value) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) v_jitstate = hop.llops.getjitstate() return hop.llops.genmixlevelhelpercall(rtimeshift.ll_gengetfield, - [ts.s_JITState, s_fielddesc, ts.s_PtrRedBox], - [v_jitstate, c_fielddesc, v_argbox ], + [ts.s_JITState, annmodel.s_Bool, s_fielddesc, ts.s_PtrRedBox], + [v_jitstate , c_deepfrozen , c_fielddesc, v_argbox ], ts.s_RedBox) def translate_op_getarrayitem(self, hop): 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 v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE), self.getredrepr(lltype.Signed)) + c_deepfrozen = inputconst(lltype.Bool, hop.args_s[0].deepfrozen) fielddesc = rcontainer.ArrayFieldDesc(self.RGenOp, PTRTYPE.TO) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) v_jitstate = hop.llops.getjitstate() return hop.llops.genmixlevelhelpercall( rtimeshift.ll_gengetarrayitem, - [ts.s_JITState, s_fielddesc, ts.s_RedBox, ts.s_RedBox], - [v_jitstate, c_fielddesc, v_argbox, v_index ], + [ts.s_JITState, annmodel.s_Bool, s_fielddesc, + ts.s_RedBox, ts.s_RedBox], + [v_jitstate, c_deepfrozen, c_fielddesc, + v_argbox, v_index ], ts.s_RedBox) def translate_op_getarraysize(self, hop): - res = self.generic_translate_operation(hop, force=True) - if res is not None: - return res - PTRTYPE = originalconcretetype(hop.args_s[0]) ts = self [v_argbox] = hop.inputargs(self.getredrepr(PTRTYPE)) @@ -658,11 +648,6 @@ def translate_op_getarraysubstruct(self, hop): 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 v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE), self.getredrepr(lltype.Signed)) @@ -710,20 +695,37 @@ ts = self PTRTYPE = originalconcretetype(hop.args_s[0]) v_argbox, = hop.inputargs(self.getredrepr(PTRTYPE)) + v_argbox = hop.llops.as_ptrredbox(v_argbox) v_jitstate = hop.llops.getjitstate() c_reverse = hop.inputconst(lltype.Bool, reverse) return hop.llops.genmixlevelhelpercall(rtimeshift.ll_genptrnonzero, - [ts.s_JITState, ts.s_RedBox, annmodel.SomeBool()], - [v_jitstate, v_argbox, c_reverse ], + [ts.s_JITState, ts.s_PtrRedBox, annmodel.s_Bool], + [v_jitstate , v_argbox , c_reverse ], ts.s_RedBox) def translate_op_ptr_iszero(self, hop): return self.translate_op_ptr_nonzero(hop, reverse=True) + def translate_op_ptr_eq(self, hop, reverse=False): + ts = self + PTRTYPE = originalconcretetype(hop.args_s[0]) + r_ptr = self.getredrepr(PTRTYPE) + v_argbox0, v_argbox1 = hop.inputargs(r_ptr, r_ptr) + v_argbox0 = hop.llops.as_ptrredbox(v_argbox0) + v_argbox1 = hop.llops.as_ptrredbox(v_argbox1) + v_jitstate = hop.llops.getjitstate() + c_reverse = hop.inputconst(lltype.Bool, reverse) + return hop.llops.genmixlevelhelpercall(rtimeshift.ll_genptreq, + [ts.s_JITState, ts.s_PtrRedBox, ts.s_PtrRedBox, annmodel.s_Bool], + [v_jitstate , v_argbox0 , v_argbox1 , c_reverse ], + ts.s_RedBox) - # special operations inserted by the HintGraphTransformer + def translate_op_ptr_ne(self, hop): + return self.translate_op_ptr_eq(hop, reverse=True) + # special operations inserted by the HintGraphTransformer + def translate_op_ensure_queue(self, hop, prefix=''): mpfamily = hop.args_v[0].value subclass = self.get_dispatch_subclass(mpfamily) Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py Mon Nov 20 21:13:39 2006 @@ -10,6 +10,10 @@ FOLDABLE_OPS = dict.fromkeys(lloperation.enum_foldable_ops()) +FOLDABLE_GREEN_OPS = FOLDABLE_OPS.copy() +FOLDABLE_GREEN_OPS['getfield'] = None +FOLDABLE_GREEN_OPS['getarrayitem'] = None + debug_view = lloperation.llop.debug_view debug_print = lloperation.llop.debug_print @@ -96,8 +100,8 @@ genvar = jitstate.curbuilder.genop_malloc_varsize(alloctoken, gv_size) return rvalue.PtrRedBox(contdesc.ptrkind, genvar) -def ll_gengetfield(jitstate, fielddesc, argbox): - if fielddesc.immutable and argbox.is_constant(): +def ll_gengetfield(jitstate, deepfrozen, fielddesc, argbox): + if (fielddesc.immutable or deepfrozen) and argbox.is_constant(): res = getattr(rvalue.ll_getvalue(argbox, fielddesc.PTRTYPE), fielddesc.fieldname) return rvalue.ll_fromvalue(jitstate, res) @@ -113,8 +117,9 @@ return rvalue.ll_fromvalue(jitstate, res) return argbox.op_getsubstruct(jitstate, fielddesc) -def ll_gengetarrayitem(jitstate, fielddesc, argbox, indexbox): - if fielddesc.immutable and argbox.is_constant() and indexbox.is_constant(): +def ll_gengetarrayitem(jitstate, deepfrozen, fielddesc, argbox, indexbox): + if ((fielddesc.immutable or deepfrozen) and argbox.is_constant() + and indexbox.is_constant()): array = rvalue.ll_getvalue(argbox, fielddesc.PTRTYPE) res = array[rvalue.ll_getvalue(indexbox, lltype.Signed)] return rvalue.ll_fromvalue(jitstate, res) @@ -126,7 +131,7 @@ return fielddesc.redboxcls(fielddesc.kind, genvar) def ll_gengetarraysubstruct(jitstate, fielddesc, argbox, indexbox): - if fielddesc.immutable and argbox.is_constant() and indexbox.is_constant(): + if argbox.is_constant() and indexbox.is_constant(): array = rvalue.ll_getvalue(argbox, fielddesc.PTRTYPE) res = array[rvalue.ll_getvalue(indexbox, lltype.Signed)] return rvalue.ll_fromvalue(jitstate, res) @@ -162,7 +167,6 @@ if argbox.is_constant(): addr = rvalue.ll_getvalue(argbox, llmemory.Address) return rvalue.ll_fromvalue(jitstate, bool(addr) ^ reverse) - assert isinstance(argbox, rvalue.PtrRedBox) builder = jitstate.curbuilder if argbox.content is None: gv_addr = argbox.getgenvar(builder) @@ -174,6 +178,23 @@ gv_res = builder.rgenop.genconst(True ^ reverse) return rvalue.IntRedBox(builder.rgenop.kindToken(lltype.Bool), gv_res) +def ll_genptreq(jitstate, argbox0, argbox1, reverse): + builder = jitstate.curbuilder + if argbox0.content is not None or argbox1.content is not None: + equal = argbox0.content is argbox1.content + return rvalue.ll_fromvalue(jitstate, equal ^ reverse) + elif argbox0.is_constant() and argbox1.is_constant(): + addr0 = rvalue.ll_getvalue(argbox0, llmemory.Address) + addr1 = rvalue.ll_getvalue(argbox1, llmemory.Address) + return rvalue.ll_fromvalue(jitstate, (addr0 == addr1) ^ reverse) + gv_addr0 = argbox0.getgenvar(builder) + gv_addr1 = argbox1.getgenvar(builder) + if reverse: + gv_res = builder.genop2("ptr_ne", gv_addr0, gv_addr1) + else: + gv_res = builder.genop2("ptr_eq", gv_addr0, gv_addr1) + return rvalue.IntRedBox(builder.rgenop.kindToken(lltype.Bool), gv_res) + # ____________________________________________________________ # other jitstate/graph level operations Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Mon Nov 20 21:13:39 2006 @@ -1069,13 +1069,12 @@ assert res == 42 self.check_insns({}) - def test_green_tuple(self): - py.test.skip("WIP") + def test_compile_time_const_tuple(self): d = {(4, 5): 42, (6, 7): 12} def f(a, b): d1 = hint(d, deepfreeze=True) return d1[a, b] - res = self.timeshift(f, [0, 4, 5], [0, 1, 2], policy=P_NOVIRTUAL) + res = self.timeshift(f, [4, 5], [0, 1], policy=P_NOVIRTUAL) assert res == 42 self.check_insns({}) From arigo at codespeak.net Tue Nov 21 00:05:31 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 21 Nov 2006 00:05:31 +0100 (CET) Subject: [pypy-svn] r34816 - pypy/dist/pypy/jit/codegen/llvm Message-ID: <20061120230531.97ABF1006C@code0.codespeak.net> Author: arigo Date: Tue Nov 21 00:05:20 2006 New Revision: 34816 Modified: pypy/dist/pypy/jit/codegen/llvm/ (props changed) Log: svn:ignore the build subdirectory. From arigo at codespeak.net Tue Nov 21 00:11:11 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 21 Nov 2006 00:11:11 +0100 (CET) Subject: [pypy-svn] r34817 - in pypy/dist/pypy: jit/hintannotator jit/timeshifter jit/timeshifter/test rpython/lltypesystem Message-ID: <20061120231111.B79461006C@code0.codespeak.net> Author: arigo Date: Tue Nov 21 00:11:03 2006 New Revision: 34817 Added: pypy/dist/pypy/jit/timeshifter/test/test_vdict.py (contents, props changed) pypy/dist/pypy/jit/timeshifter/vdict.py (contents, props changed) Modified: pypy/dist/pypy/jit/hintannotator/model.py pypy/dist/pypy/jit/timeshifter/oop.py pypy/dist/pypy/jit/timeshifter/vlist.py pypy/dist/pypy/rpython/lltypesystem/rdict.py Log: (pedronis, arigo) Starting oopspec'ed dict support. As usual, kind of easy but a lot of mess to get correctly typed while still avoiding total specialization explosion. Modified: pypy/dist/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/dist/pypy/jit/hintannotator/model.py (original) +++ pypy/dist/pypy/jit/hintannotator/model.py Tue Nov 21 00:11:03 2006 @@ -576,6 +576,8 @@ operation_name, args = ll_func.oopspec.split('(', 1) assert args.endswith(')') args = args[:-1] + ',' # trailing comma to force tuple syntax + if args.strip() == ',': + args = '()' argnames = ll_func.func_code.co_varnames[:len(args_hs)] d = dict(zip(argnames, args_hs)) argtuple = eval(args, d) Modified: pypy/dist/pypy/jit/timeshifter/oop.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/oop.py (original) +++ pypy/dist/pypy/jit/timeshifter/oop.py Tue Nov 21 00:11:03 2006 @@ -22,6 +22,8 @@ operation_name, args = ll_func.oopspec.split('(', 1) assert args.endswith(')') args = args[:-1] + ',' # trailing comma to force tuple syntax + if args.strip() == ',': + args = '()' argnames = ll_func.func_code.co_varnames[:nb_args] d = dict(zip(argnames, [Index(n) for n in range(nb_args)])) self.argtuple = eval(args, d) @@ -55,6 +57,10 @@ typename, method = 'list', 'oop_newlist' SELFTYPE = FUNCTYPE.RESULT.TO self.is_method = False + elif operation_name == 'newdict': + typename, method = 'dict', 'oop_newdict' + SELFTYPE = FUNCTYPE.RESULT.TO + self.is_method = False else: typename, method = operation_name.split('.') method = 'oop_%s_%s' % (typename, method) Added: pypy/dist/pypy/jit/timeshifter/test/test_vdict.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/timeshifter/test/test_vdict.py Tue Nov 21 00:11:03 2006 @@ -0,0 +1,19 @@ +from pypy.annotation.policy import AnnotatorPolicy +from pypy.jit.timeshifter.test.test_timeshift import TimeshiftingTests + +P_OOPSPEC = AnnotatorPolicy() +P_OOPSPEC.novirtualcontainer = True +P_OOPSPEC.oopspec = True + + +class TestVDict(TimeshiftingTests): + + def test_vdict(self): + def ll_function(): + dic = {} + dic[12] = 34 + dic[13] = 35 + return dic[12] + res = self.timeshift(ll_function, [], [], policy=P_OOPSPEC) + assert res == 34 + self.check_insns({}) Added: pypy/dist/pypy/jit/timeshifter/vdict.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/timeshifter/vdict.py Tue Nov 21 00:11:03 2006 @@ -0,0 +1,253 @@ +import operator +from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem import rdict +from pypy.jit.timeshifter.rcontainer import AbstractContainer, cachedtype +from pypy.jit.timeshifter import rvalue +from pypy.rlib.objectmodel import r_dict + +HASH = lltype.Signed + + +class LLEqDesc(object): + __metaclass__ = cachedtype + + def __init__(self, KEY, keyeq, keyhash): + # this makes one version of the following function per KEY, + # which is supposed to be the ll type of x and y + + def lleq(x, y): + return keyeq(x, y) + def llhash(x): + return keyhash(x) + + class VirtualDict(AbstractVirtualDict): + + def make_item_boxes(self): + self.item_boxes = r_dict(lleq, llhash) + + def getboxes(self): + return self.item_boxes.values() + + def getitems_and_makeempty(self, rgenop): + result = [(rgenop.genconst(key), box, llhash(key)) + for key, box in self.item_boxes.iteritems()] + self.item_boxes = None + return result + + def getitem(self, keybox): + key = rvalue.ll_getvalue(keybox, KEY) + return self.item_boxes[key] + + def setitem(self, keybox, valuebox): + key = rvalue.ll_getvalue(keybox, KEY) + self.item_boxes[key] = valuebox + + def copy_from(self, other, memo): + assert isinstance(other, VirtualDict) + self.make_item_boxes() + for key, valuebox in other.item_boxes.iteritems(): + self.item_boxes[key] = valuebox.copy(memo) + + def replace(self, memo): + changes = [] + for key, valuebox in self.item_boxes.iteritems(): + newbox = valuebox.replace(memo) + if newbox is not valuebox: + changes.append((key, newbox)) + for key, newbox in changes: + self.item_boxes[key] = newbox + + + class FrozenVirtualDict(AbstractFrozenVirtualDict): + + def freeze_from(self, vdict, memo): + assert isinstance(vdict, VirtualDict) + frozens = [] + for key, valuebox in vdict.item_boxes.iteritems(): + frozens.append((key, valuebox.freeze(memo))) + self.fz_item_boxes = frozens + + def same_keys_as(self, vdict, boxes): + assert isinstance(vdict, VirtualDict) + self_boxes = self.fz_item_boxes + vdict_boxes = vdict.item_boxes + if len(self_boxes) != len(vdict_boxes): + return False + for key, selfbox in self_boxes: + try: + vdictbox = vdict_boxes[key] + except KeyError: + return False + boxes.append((selfbox, vdictbox)) + return True + + + self.VirtualDict = VirtualDict + self.FrozenVirtualDict = FrozenVirtualDict + + VirtualDict.FrozenVirtualDict = FrozenVirtualDict + + +class DictTypeDesc(object): + __metaclass__ = cachedtype + + def __init__(self, hrtyper, DICT): + RGenOp = hrtyper.RGenOp + rtyper = hrtyper.rtyper + bk = rtyper.annotator.bookkeeper + self.DICT = DICT + self.DICTPTR = lltype.Ptr(DICT) + self.ptrkind = RGenOp.kindToken(self.DICTPTR) + + argtypes = [bk.immutablevalue(DICT)] + ll_newdict_ptr = rtyper.annotate_helper_fn(rdict.ll_newdict, + argtypes) + self.gv_ll_newdict = RGenOp.constPrebuiltGlobal(ll_newdict_ptr) + self.tok_ll_newdict = RGenOp.sigToken(lltype.typeOf(ll_newdict_ptr).TO) + + argtypes = [self.DICTPTR, DICT.KEY, DICT.VALUE, HASH] + ll_insertclean = rtyper.annotate_helper_fn(rdict.ll_dict_insertclean, + argtypes) + self.gv_ll_insertclean = RGenOp.constPrebuiltGlobal(ll_insertclean) + self.tok_ll_insertclean = RGenOp.sigToken( + lltype.typeOf(ll_insertclean).TO) + + # XXX some fishing that only works if the DICT does not come from + # an r_dict + if DICT.keyeq is None: + keyeq = operator.eq + else: + assert isinstance(DICT.keyeq, lltype.staticAdtMethod) + keyeq = DICT.keyeq.__get__(42) + assert isinstance(DICT.keyhash, lltype.staticAdtMethod) + keyhash = DICT.keyhash.__get__(42) + keydesc = LLEqDesc(DICT.KEY, keyeq, keyhash) + self.VirtualDict = keydesc.VirtualDict + + def _freeze_(self): + return True + + def factory(self): + vdict = self.VirtualDict(self) + box = rvalue.PtrRedBox(self.ptrkind) + box.content = vdict + vdict.ownbox = box + return box + +TypeDesc = DictTypeDesc + + +class AbstractFrozenVirtualDict(AbstractContainer): + __slots__ = ('typedesc',) + + def __init__(self, typedesc): + self.typedesc = typedesc + #self.fz_item_boxes initialized later + + def exactmatch(self, vdict, outgoingvarboxes, memo): + assert isinstance(vdict, AbstractVirtualDict) + contmemo = memo.containers + if self in contmemo: + ok = vdict is contmemo[self] + if not ok: + outgoingvarboxes.append(vdict.ownbox) + return ok + if vdict in contmemo: + assert contmemo[vdict] is not self + outgoingvarboxes.append(vdict.ownbox) + return False + assert self.typedesc is vdict.typedesc + boxes = [] + if not self.same_keys_as(vdict, boxes): + outgoingvarboxes.append(vdict.ownbox) + return False + contmemo[self] = vdict + contmemo[vdict] = self + fullmatch = True + for selfbox, vdictbox in boxes: + if not selfbox.exactmatch(vdictbox, + outgoingvarboxes, + memo): + fullmatch = False + return fullmatch + + +class AbstractVirtualDict(AbstractContainer): + __slots__ = ('typedesc', 'ownbox') # and no item_boxes + + def __init__(self, typedesc): + self.typedesc = typedesc + self.make_item_boxes() + # self.ownbox = ... set in factory() + + def enter_block(self, incoming, memo): + contmemo = memo.containers + if self not in contmemo: + contmemo[self] = None + for box in self.getboxes(): + box.enter_block(incoming, memo) + + def force_runtime_container(self, builder): + typedesc = self.typedesc + items = self.getitems_and_makeempty(builder.rgenop) + + args_gv = [None] + gv_dict = builder.genop_call(typedesc.tok_ll_newdict, + typedesc.gv_ll_newdict, + args_gv) + self.ownbox.genvar = gv_dict + self.ownbox.content = None + for gv_key, valuebox, hash in items: + gv_hash = builder.rgenop.genconst(hash) + gv_value = valuebox.getgenvar(builder) + args_gv = [gv_dict, gv_key, gv_value, gv_hash] + builder.genop_call(typedesc.tok_ll_insertclean, + typedesc.gv_ll_insertclean, + args_gv) + + def freeze(self, memo): + contmemo = memo.containers + try: + return contmemo[self] + except KeyError: + result = contmemo[self] = self.FrozenVirtualDict(self.typedesc) + result.freeze_from(self, memo) + return result + + def copy(self, memo): + contmemo = memo.containers + try: + return contmemo[self] + except KeyError: + result = contmemo[self] = self.__class__(self.typedesc) + result.copy_from(self, memo) + result.ownbox = self.ownbox.copy(memo) + return result + + def replace(self, memo): + contmemo = memo.containers + if self not in contmemo: + contmemo[self] = None + self.replace(memo) + self.ownbox = self.ownbox.replace(memo) + + +def oop_newdict(jitstate, oopspecdesc): + return oopspecdesc.typedesc.factory() + +def oop_dict_setitem(jitstate, oopspecdesc, selfbox, keybox, valuebox): + content = selfbox.content + if isinstance(content, AbstractVirtualDict) and keybox.is_constant(): + content.setitem(keybox, valuebox) + else: + oopspecdesc.residual_call(jitstate, [selfbox, keybox, valuebox]) + +def oop_dict_getitem(jitstate, oopspecdesc, selfbox, keybox): + content = selfbox.content + if isinstance(content, AbstractVirtualDict) and keybox.is_constant(): + try: + return content.getitem(keybox) + except KeyError: + return oopspecdesc.residual_exception(jitstate, KeyError) + else: + return oopspecdesc.residual_call(jitstate, [selfbox, keybox]) Modified: pypy/dist/pypy/jit/timeshifter/vlist.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/vlist.py (original) +++ pypy/dist/pypy/jit/timeshifter/vlist.py Tue Nov 21 00:11:03 2006 @@ -26,6 +26,9 @@ self.tok_ll_setitem_fast = RGenOp.sigToken( lltype.typeOf(ll_setitem_fast).TO) + def _freeze_(self): + return True + def factory(self, length, itembox): vlist = VirtualList(self, length, itembox) box = rvalue.PtrRedBox(self.ptrkind) Modified: pypy/dist/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rdict.py Tue Nov 21 00:11:03 2006 @@ -170,6 +170,8 @@ 'keyeq': ll_keyeq, 'paranoia': False, } + adtmeths['KEY'] = self.DICTKEY + adtmeths['VALUE'] = self.DICTVALUE self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths, *fields)) @@ -394,6 +396,7 @@ return entry.value else: raise KeyError +ll_dict_getitem.oopspec = 'dict.getitem(d, key)' def ll_dict_setitem(d, key, value): hash = d.keyhash(key) @@ -414,6 +417,7 @@ d.num_pristine_entries -= 1 if d.num_pristine_entries <= len(d.entries) / 3: ll_dict_resize(d) +ll_dict_setitem.oopspec = 'dict.setitem(d, key, value)' def ll_dict_insertclean(d, key, value, hash): # Internal routine used by ll_dict_resize() to insert an item which is @@ -554,6 +558,7 @@ d.num_items = 0 d.num_pristine_entries = DICT_INITSIZE return d +ll_newdict.oopspec = 'newdict()' def ll_newdict_size(DICT, length_estimate): length_estimate = (length_estimate // 2) * 3 @@ -565,6 +570,7 @@ d.num_items = 0 d.num_pristine_entries = DICT_INITSIZE return d +ll_newdict_size.oopspec = 'newdict()' def rtype_r_dict(hop): From ale at codespeak.net Tue Nov 21 14:00:52 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Tue, 21 Nov 2006 14:00:52 +0100 (CET) Subject: [pypy-svn] r34822 - in pypy/dist/pypy/lib/pyontology: . test Message-ID: <20061121130052.696A410076@code0.codespeak.net> Author: ale Date: Tue Nov 21 14:00:50 2006 New Revision: 34822 Modified: pypy/dist/pypy/lib/pyontology/constraint_classes.py pypy/dist/pypy/lib/pyontology/pyontology.py pypy/dist/pypy/lib/pyontology/test/test_ontology.py Log: Going back to generator interface + bugfixes Modified: pypy/dist/pypy/lib/pyontology/constraint_classes.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/constraint_classes.py (original) +++ pypy/dist/pypy/lib/pyontology/constraint_classes.py Tue Nov 21 14:00:50 2006 @@ -502,11 +502,12 @@ property = dom.property indi = dom.getValues() prop = Linkeddict(domains[property].getValues()) + remove = [] for v in indi: if not v in prop: - dom.removeValue(v) + remove.append(v) else: prop_val = prop[v] if not val in prop_val: - dom.removeValue(v) - + remove.append(v) + dom.removeValues(remove) Modified: pypy/dist/pypy/lib/pyontology/pyontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/pyontology.py (original) +++ pypy/dist/pypy/lib/pyontology/pyontology.py Tue Nov 21 14:00:50 2006 @@ -170,9 +170,9 @@ self.values[value] = True def getValues(self): - #for key in self.values: - # yield key - return self.values.keys() + for key in self.values: + yield key + #return self.values.keys() def __iter__(self): return iter(self.values.keys()) @@ -228,9 +228,13 @@ def __eq__(self, other): #log("CMP %r,%r %i"%(self.name,other, len(self.differentfrom))) #assert isinstance(other, ClassDomain) - if ((hasattr(other,'uri') and self.uri == other.uri) or - (not hasattr(other,'uri') and self.uri == other) or - other in self.sameas): + if hasattr(other,'uri'): + if self.uri == other.uri: + return True + elif not hasattr(other,'uri'): + if self.uri == other: + return True + elif other in self.sameas: return True if not other or other in self.differentfrom: return False @@ -278,9 +282,7 @@ res = [] for k,vals in items: for v in vals: - #yield (k,v) - res.append((k,v)) - return res + yield (k,v) def getValuesPrKey(self, key= None): if key: @@ -516,8 +518,8 @@ constraint.narrow(self.variables) # except ConsistencyFailure, e: # print "FAilure", e - things = self.variables['owl_Thing'].getValues() - things += self.variables['owl_Literal'].getValues() + things = list(self.variables['owl_Thing'].getValues()) + things += list(self.variables['owl_Literal'].getValues()) self.variables['owl_Thing'].setValues(things) def _sparql(self, query): @@ -652,10 +654,17 @@ query_dom[prop] = self.variables[prop] p_vals = self.variables[prop].getValues() sub = self.make_var(Thing, trip[0]) - self.variables[sub].setValues([v[0] for v in p_vals]) + vals = set([v[0] for v in p_vals]) + if self.variables[sub].size(): + vals &= set(self.variables[sub].getValues()) + self.variables[sub].setValues(vals) obj = self.make_var(Thing, trip[2]) - self.variables[obj].setValues([v[1] for v in p_vals]) - con = Expression([sub,prop,obj], "%s == (%s, %s)" %(prop, sub, obj)) + vals = set([v[1] for v in p_vals]) + if self.variables[obj].size(): + vals &= set(self.variables[obj].getValues()) + self.variables[obj].setValues(vals) + con = PropertyConstrain3(prop, sub, obj) +# con = Expression([sub,prop,obj], "%s == (%s, %s)" %(prop, sub, obj)) query_constr.append(con) elif case == 6: @@ -688,20 +697,22 @@ for v in vars]) dom.update(query_dom) - print dom # solve the repository and return the solution rep = Repository(dom.keys(), dom, query_constr) - res_s = Solver().solve(rep, 3) - #res_s = self.solve() + res_s = Solver(MyDistributor()).solve(rep, verbose=0) res = [] + query_vars = dict([('query_%s_'%name,name) for name in resvars]) for d in res_s: + res_dict = {} for k,v in d.items(): if hasattr(v,'uri'): val = v.uri else: val = v d[k] = unicode(val) - res.append(d) + if k in query_vars: + res_dict[query_vars[k]] = unicode(val) + res.append(res_dict) return res def consider_triple(self,(s, p, o)): Modified: pypy/dist/pypy/lib/pyontology/test/test_ontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/test/test_ontology.py (original) +++ pypy/dist/pypy/lib/pyontology/test/test_ontology.py Tue Nov 21 14:00:50 2006 @@ -173,7 +173,7 @@ O.type(sub, obj) O.type(obj, namespaces['owl']+"#Class") - assert O.variables[O.make_var(None, obj)].getValues()[0].__class__ == Individual + assert list(O.variables[O.make_var(None, obj)].getValues())[0].__class__ == Individual # test for multiple types # test for type hierarchy From guido at codespeak.net Tue Nov 21 14:16:34 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Tue, 21 Nov 2006 14:16:34 +0100 (CET) Subject: [pypy-svn] r34824 - pypy/dist/pypy/tool/build Message-ID: <20061121131634.D5B2210074@code0.codespeak.net> Author: guido Date: Tue Nov 21 14:16:33 2006 New Revision: 34824 Modified: pypy/dist/pypy/tool/build/README.txt Log: Added note about how the tool keeps re-queueing on failing compilations and disconnects. Modified: pypy/dist/pypy/tool/build/README.txt ============================================================================== --- pypy/dist/pypy/tool/build/README.txt (original) +++ pypy/dist/pypy/tool/build/README.txt Tue Nov 21 14:16:33 2006 @@ -35,7 +35,8 @@ If there isn't one, the server walks through a list of connected participating clients to see if one of them can handle the job, and if so dispatches the compilation. If there's no participating client to handle the job, it gets -queued until there is. +queued until there is. Also, if a client crashes during compilation, the job +gets re-queued. This process will continue until a suitable build is available. Once a build is available, the server will send an email to all email addresses (it could be that more than one person asked for some build at the same time!) From ale at codespeak.net Tue Nov 21 14:48:20 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Tue, 21 Nov 2006 14:48:20 +0100 (CET) Subject: [pypy-svn] r34825 - in pypy/dist/pypy/lib/pyontology: . test Message-ID: <20061121134820.5659E10076@code0.codespeak.net> Author: ale Date: Tue Nov 21 14:48:18 2006 New Revision: 34825 Modified: pypy/dist/pypy/lib/pyontology/constraint_classes.py pypy/dist/pypy/lib/pyontology/pyontology.py pypy/dist/pypy/lib/pyontology/test/test_sparql.py Log: Added special Solver to handle gererator based domains. Modified: pypy/dist/pypy/lib/pyontology/constraint_classes.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/constraint_classes.py (original) +++ pypy/dist/pypy/lib/pyontology/constraint_classes.py Tue Nov 21 14:48:18 2006 @@ -1,11 +1,85 @@ from logilab.constraint.propagation import AbstractDomain, AbstractConstraint,\ - ConsistencyFailure + ConsistencyFailure, Solver +from logilab.constraint.distributors import DichotomyDistributor, SplitDistributor from rdflib import URIRef import autopath import py from pypy.tool.ansi_print import ansi_log log = py.log.Producer("Constraint") py.log.setconsumer("Constraint", None) +import math + +class MySolver(Solver): + + def _solve(self, repository, recursion_level=0): + """main generator""" + solve = self._solve + verbose = self.verbose + if recursion_level > self.max_depth: + self.max_depth = recursion_level + if verbose: + print strftime('%H:%M:%S'), + print '*** [%d] Solve called with repository' % recursion_level, + print repository + try: + foundSolution = repository.consistency(verbose) + except ConsistencyFailure, exc: + if verbose: + print strftime('%H:%M:%S'), exc + pass + else: + if foundSolution: + solution = {} + for variable, domain in repository.getDomains().items(): + solution[variable] = list(domain.getValues())[0] + if verbose: + print strftime('%H:%M:%S'), '### Found Solution', solution + print '-'*80 + yield solution + else: + for repo in repository.distribute(self._distributor, + verbose): + for solution in solve(repo, recursion_level+1): + if solution is not None: + yield solution + + if recursion_level == 0 and self.verbose: + print strftime('%H:%M:%S'),'Finished search' + print strftime('%H:%M:%S'), + print 'Maximum recursion depth = ', self.max_depth + + +class MyDistributor(SplitDistributor): + + def __init__(self): + SplitDistributor.__init__(self,2) + self.to_split = None + + def nb_subdomains(self, domains): + """See AbstractDistributor""" + self.to_split = self.findSmallestDomain(domains) + if self.nb_subspaces: + return min(self.nb_subspaces, domains[self.to_split].size()) + else: + return domains[self.to_split].size() + + def _distribute(self, *args): + """See AbstractDistributor""" + variable = self.to_split + nb_subspaces = len(args) + values = list(args[0][variable].getValues()) + nb_elts = max(1, len(values)*1./nb_subspaces) + slices = [(int(math.floor(index * nb_elts)), + int(math.floor((index + 1) * nb_elts))) + for index in range(nb_subspaces)] + if self.verbose: + print 'Distributing domain for variable', variable + modified = [] + for (dom, (end, start)) in zip(args, slices) : + dom[variable].removeValues(values[:end]) + dom[variable].removeValues(values[start:]) + modified.append(dom[variable]) + return modified class OwlConstraint(AbstractConstraint): @@ -115,7 +189,7 @@ # Narrow the list of properties (instances of some property type) # to those who has a pair (self.variable, self.object) dom = domains[self.prop] - vals = list(dom.getValues()) + vals = dom.getValues() for p in vals: if not ((self.variable, self.object) in domains[p]): dom.removeValue(p) @@ -133,7 +207,7 @@ # to those who has a pair (self.variable, self.object) dom = domains[self.prop] sub = domains[self.variable] - vals = list(dom.getValues()) + vals = dom.getValues() keep = [] for p in vals: items = domains[p].getValuesPrKey() @@ -144,6 +218,36 @@ keep.append(key) sub.removeValues([v for v in sub.getValues() if not v in keep]) +import time +class PropertyConstrain3(AbstractConstraint): + cost = 1 + def __init__(self, prop, variable, cls_or_restriction): + AbstractConstraint.__init__(self, [ prop]) + self.object = cls_or_restriction + self.variable = variable + self.prop = prop + + def narrow(self, domains): + # Narrow the domains of object and variable to those values + # that are connected by self.prop + dom = domains[self.prop] + sub = domains[self.variable] + obj = domains[self.object] + vals_dict = dom._dict + + keep = set() + sub_rem = [] + for v in sub.getValues(): + if not v in vals_dict: + sub_rem.append(v) + #sub.removeValue(v) + else: + for o in dom.getValuesPrKey(v): + keep.add(o) + remove = [x for x in obj.getValues() if not x in keep] + sub.removeValues(sub_rem) + obj.removeValues(remove) + class MemberConstraint(AbstractConstraint): cost = 1 @@ -485,12 +589,13 @@ remove = [] for v in indi: if not v in prop: - dom.removeValue(v) + remove.append(v) else: prop_val = prop[v] for p in prop_val: if not p in val: - dom.removeValue(v) + remove.append(v) + dom.removeValues(remove) class HasvalueConstraint(OneofPropertyConstraint): @@ -509,5 +614,7 @@ else: prop_val = prop[v] if not val in prop_val: - remove.append(v) + remove.append(v) dom.removeValues(remove) + + Modified: pypy/dist/pypy/lib/pyontology/pyontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/pyontology.py (original) +++ pypy/dist/pypy/lib/pyontology/pyontology.py Tue Nov 21 14:48:18 2006 @@ -1,11 +1,12 @@ import autopath from rdflib import Graph, URIRef, BNode, Literal as rdflib_literal -from logilab.constraint import Repository, Solver +from logilab.constraint import Repository from logilab.constraint.fd import Expression, FiniteDomain as fd from logilab.constraint.propagation import AbstractDomain, AbstractConstraint,\ ConsistencyFailure from pypy.lib.pyontology.sparql_grammar import SPARQLGrammar as SP from constraint_classes import * +Solver = MySolver import sys, py import datetime, time from urllib2 import URLError @@ -650,9 +651,11 @@ query_constr.append(PropertyConstrain2(prop_name, sub_name, obj)) elif case == 5: # return the values of p + #import pdb + ##pdb.set_trace() prop = self.make_var(Property, URIRef(trip[1])) query_dom[prop] = self.variables[prop] - p_vals = self.variables[prop].getValues() + p_vals = list(self.variables[prop].getValues()) sub = self.make_var(Thing, trip[0]) vals = set([v[0] for v in p_vals]) if self.variables[sub].size(): @@ -683,9 +686,6 @@ self.variables[prop].setValues(p_vals) sub = self.make_var(Thing, trip[0]) obj = self.make_var(Thing, trip[2]) - things = self.variables['owl_Thing'].getValues() - things += self.variables['owl_Literal'].getValues() - self.variables[obj].setValues(things) con = Expression([sub,prop,obj], "%s[0] == %s and %s[1] == %s" %(prop, sub, prop, obj)) query_constr.append(con) # call finish on the variables in the query Modified: pypy/dist/pypy/lib/pyontology/test/test_sparql.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/test/test_sparql.py (original) +++ pypy/dist/pypy/lib/pyontology/test/test_sparql.py Tue Nov 21 14:48:18 2006 @@ -92,7 +92,7 @@ O.add_file("testont.rdf") O.attach_fd() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' def test_case_2(): "for all p's return p if p[0]==s and p[1]==o """ @@ -104,7 +104,7 @@ res = O.sparql(query) assert list(O.variables['query_x_'].getValues())[0] == 'ns_p' - assert res[0]['query_x_'] == 'ns_p' + assert res[0]['x'] == 'ns_p' def test_case_3(): """search for s in p""" @@ -117,8 +117,7 @@ # import pdb # pdb.set_trace() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0] == '123' - assert res[0]['query_x_'] == '123' + assert res[0]['x'] == '123' def test_case_4(): """ search for s in p """ @@ -129,9 +128,9 @@ O.attach_fd() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' - assert list(O.variables['query_y_'].getValues())[0] == 'ns_p' #u'http://example.org/ns#p' - assert res[0]['query_x_'] == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' + assert res[0]['y'] == 'ns_p' #u'http://example.org/ns#p' + assert res[0]['x'] == u'http://example.org/ns#sub' def test_case_5(): """ for all p's return p[0] if p[1]==o """ @@ -142,9 +141,9 @@ O.attach_fd() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' - assert list(O.variables['query_y_'].getValues())[0] == u'123' - assert res[0]['query_x_'] == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' + assert res[0]['y'] == u'123' + assert res[0]['x'] == u'http://example.org/ns#sub' def test_case_6(): """ return the values of p """ @@ -156,11 +155,12 @@ O.attach_fd() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' - assert res[0]['query_x_'] == u'http://example.org/ns#sub' + assert list(O.variables['x'].getValues())[0].uri == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' def test_case_7(): """ for all p's return p[1] if p[0]==s """ + py.test.skip("Doesn't work yet due to changed generatorinterface") query = qt_proto % ('?x ?y ?z', '?x ?y ?z .') O = Ontology() @@ -169,7 +169,7 @@ res = O.sparql(query) assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' - assert res[0]['query_x_'] == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' query1 = """ PREFIX ltw : @@ -189,9 +189,9 @@ SELECT ?project WHERE { ?project ltw:funded_by ltw:BMBF . - ?project ltw:date_begin ?date_begin . - ?project ltw:date_end ?date_end . - FILTER ( ?date_begin < 2007 ) . + ?project ltw:dateStart ?date_begin . + ?project ltw:dateEnd ?date_end . + FILTER ( ?date_begin < 2007 ) . FILTER ( ?date_end >= 2006) . }""" #which project is funded in a technological area (i.e. Semantic web), @@ -212,8 +212,19 @@ res = O.sparql(query1) assert len(res) == 1 - assert res[0]['query_activity_'] == u'http://www.lt-world.org/ltw.owl#obj_59754' - assert res[0]['query_person_'] == u'\nKlara Vicsi' + assert res[0]['activity'] == u'http://www.lt-world.org/ltw.owl#obj_59754' + assert res[0]['person'] == u'\nKlara Vicsi' + +def test_query2(): + py.test.skip("Doesn't work yet") + O = Ontology() + O.add_file("testont2.rdf") + O.attach_fd() + + res = O.sparql(query2) + assert len(res) == 1 + assert res[0]['activity'] == u'http://www.lt-world.org/ltw.owl#obj_59754' + assert res[0]['person'] == u'\nKlara Vicsi' import xmlrpclib, socket, os, signal @@ -243,4 +254,4 @@ print "test_xmlrpc" server = xmlrpclib.ServerProxy("http://localhost:9000", allow_none=True) result = server.sparql(qt_proto % ('?x', 'ns:sub ns:p ?x .')) - assert result[0]['query_x_'] == '123' + assert result[0]['x'] == '123' From ale at codespeak.net Tue Nov 21 15:53:49 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Tue, 21 Nov 2006 15:53:49 +0100 (CET) Subject: [pypy-svn] r34827 - in pypy/dist/pypy/lib/pyontology: . test Message-ID: <20061121145349.AF40310079@code0.codespeak.net> Author: ale Date: Tue Nov 21 15:53:48 2006 New Revision: 34827 Modified: pypy/dist/pypy/lib/pyontology/constraint_classes.py pypy/dist/pypy/lib/pyontology/pyontology.py pypy/dist/pypy/lib/pyontology/test/test_sparql.py Log: Make a test pass, adding a generator aware Expression (from logilab.constraint.fd) Modified: pypy/dist/pypy/lib/pyontology/constraint_classes.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/constraint_classes.py (original) +++ pypy/dist/pypy/lib/pyontology/constraint_classes.py Tue Nov 21 15:53:48 2006 @@ -1,6 +1,7 @@ from logilab.constraint.propagation import AbstractDomain, AbstractConstraint,\ ConsistencyFailure, Solver from logilab.constraint.distributors import DichotomyDistributor, SplitDistributor +from logilab.constraint.fd import Expression from rdflib import URIRef import autopath import py @@ -48,6 +49,35 @@ print strftime('%H:%M:%S'), print 'Maximum recursion depth = ', self.max_depth +class MyExpression(Expression): + + def _assign_values(self, domains): + variables = [] + kwargs = {} + for variable in self._variables: + domain = domains[variable] + values = list(domain.getValues()) + variables.append((domain.size(), [variable, values, 0, len(values)])) + kwargs[variable] = values[0] + # sort variables to instanciate those with fewer possible values first + variables.sort() + + go_on = 1 + while go_on: + yield kwargs + # try to instanciate the next variable + for size, curr in variables: + if (curr[2] + 1) < curr[-1]: + curr[2] += 1 + kwargs[curr[0]] = curr[1][curr[2]] + break + else: + curr[2] = 0 + kwargs[curr[0]] = curr[1][0] + else: + # it's over + go_on = 0 + class MyDistributor(SplitDistributor): Modified: pypy/dist/pypy/lib/pyontology/pyontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/pyontology.py (original) +++ pypy/dist/pypy/lib/pyontology/pyontology.py Tue Nov 21 15:53:48 2006 @@ -1,12 +1,13 @@ import autopath from rdflib import Graph, URIRef, BNode, Literal as rdflib_literal from logilab.constraint import Repository -from logilab.constraint.fd import Expression, FiniteDomain as fd +from logilab.constraint.fd import FiniteDomain as fd from logilab.constraint.propagation import AbstractDomain, AbstractConstraint,\ ConsistencyFailure from pypy.lib.pyontology.sparql_grammar import SPARQLGrammar as SP from constraint_classes import * Solver = MySolver +Expression = MyExpression import sys, py import datetime, time from urllib2 import URLError Modified: pypy/dist/pypy/lib/pyontology/test/test_sparql.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/test/test_sparql.py (original) +++ pypy/dist/pypy/lib/pyontology/test/test_sparql.py Tue Nov 21 15:53:48 2006 @@ -91,6 +91,7 @@ O = Ontology() O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) assert res[0]['x'] == u'http://example.org/ns#sub' @@ -102,6 +103,7 @@ O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) assert list(O.variables['query_x_'].getValues())[0] == 'ns_p' assert res[0]['x'] == 'ns_p' @@ -114,8 +116,7 @@ O.add_file("testont.rdf") O.attach_fd() -# import pdb -# pdb.set_trace() + O.finish() res = O.sparql(query) assert res[0]['x'] == '123' @@ -126,6 +127,7 @@ O = Ontology() O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) assert res[0]['x'] == u'http://example.org/ns#sub' @@ -139,6 +141,7 @@ O = Ontology() O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) assert res[0]['x'] == u'http://example.org/ns#sub' @@ -153,6 +156,7 @@ O = Ontology() O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) assert list(O.variables['x'].getValues())[0].uri == u'http://example.org/ns#sub' @@ -160,13 +164,13 @@ def test_case_7(): """ for all p's return p[1] if p[0]==s """ - py.test.skip("Doesn't work yet due to changed generatorinterface") + #py.test.skip("Doesn't work yet due to changed generatorinterface") query = qt_proto % ('?x ?y ?z', '?x ?y ?z .') O = Ontology() O.add_file("testont.rdf") O.attach_fd() - + O.finish() res = O.sparql(query) assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' assert res[0]['x'] == u'http://example.org/ns#sub' From pedronis at codespeak.net Tue Nov 21 16:32:30 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Nov 2006 16:32:30 +0100 (CET) Subject: [pypy-svn] r34828 - in pypy/dist/pypy: annotation rpython Message-ID: <20061121153230.5D32410072@code0.codespeak.net> Author: pedronis Date: Tue Nov 21 16:32:28 2006 New Revision: 34828 Modified: pypy/dist/pypy/annotation/bookkeeper.py pypy/dist/pypy/rpython/rpbc.py Log: (arre, arigo around, pedronis) crash with a more sensible and understandable error (instead of IndexError insided the bookkeeper) when the program is calling a constant None. Modified: pypy/dist/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/dist/pypy/annotation/bookkeeper.py Tue Nov 21 16:32:28 2006 @@ -247,6 +247,8 @@ def consider_call_site_for_pbc(self, s_callable, opname, args_s, s_result): descs = s_callable.descriptions.keys() + if not descs: + return family = descs[0].getcallfamily() args = self.build_args(opname, args_s) s_callable.getKind().consider_call_site(self, family, descs, args, Modified: pypy/dist/pypy/rpython/rpbc.py ============================================================================== --- pypy/dist/pypy/rpython/rpbc.py (original) +++ pypy/dist/pypy/rpython/rpbc.py Tue Nov 21 16:32:28 2006 @@ -567,6 +567,12 @@ def rtype_is_true(self, hop): return Constant(False, Bool) + def none_call(self, hop): + raise TyperError("attempt to call constant None") + + rtype_simple_call = none_call + rtype_call_args = none_call + none_frozen_pbc_repr = NoneFrozenPBCRepr() From pedronis at codespeak.net Tue Nov 21 17:15:57 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Nov 2006 17:15:57 +0100 (CET) Subject: [pypy-svn] r34831 - in pypy/dist/pypy: annotation rpython Message-ID: <20061121161557.C20F910072@code0.codespeak.net> Author: pedronis Date: Tue Nov 21 17:15:56 2006 New Revision: 34831 Modified: pypy/dist/pypy/annotation/binaryop.py pypy/dist/pypy/rpython/rint.py Log: (arre, arigo, pedronis) constant fold when possible binary and/or/xor on booleans in the annotator. Modified: pypy/dist/pypy/annotation/binaryop.py ============================================================================== --- pypy/dist/pypy/annotation/binaryop.py (original) +++ pypy/dist/pypy/annotation/binaryop.py Tue Nov 21 17:15:56 2006 @@ -334,6 +334,36 @@ s.knowntypedata = ktd return s + def and_((boo1, boo2)): + s = SomeBool() + if boo1.is_constant(): + if not boo1.const: + s.const = False + else: + return boo2 + if boo2.is_constant(): + if not boo2.const: + s.const = False + return s + + def or_((boo1, boo2)): + s = SomeBool() + if boo1.is_constant(): + if boo1.const: + s.const = True + else: + return boo2 + if boo2.is_constant(): + if boo2.const: + s.const = True + return s + + def xor((boo1, boo2)): + s = SomeBool() + if boo1.is_constant() and boo2.is_constant(): + s.const = boo1.const ^ boo2.const + return s + class __extend__(pairtype(SomeString, SomeString)): def union((str1, str2)): Modified: pypy/dist/pypy/rpython/rint.py ============================================================================== --- pypy/dist/pypy/rpython/rint.py (original) +++ pypy/dist/pypy/rpython/rint.py Tue Nov 21 17:15:56 2006 @@ -174,10 +174,16 @@ appendix = op_appendices[implicit_exc] func += '_' + appendix - repr = hop.rtyper.makerepr(hop.s_result) + r_result = hop.rtyper.makerepr(hop.s_result) + if r_result.lowleveltype == Bool: + repr = signed_repr + else: + repr = r_result vlist = hop.inputargs(repr, repr) hop.exception_is_here() - return hop.genop(repr.opprefix+func, vlist, resulttype=repr) + v_res = hop.genop(repr.opprefix+func, vlist, resulttype=repr) + v_res = hop.llops.convertvar(v_res, repr, r_result) + return v_res #Helper functions for comparisons From pedronis at codespeak.net Tue Nov 21 17:18:55 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 21 Nov 2006 17:18:55 +0100 (CET) Subject: [pypy-svn] r34832 - pypy/dist/pypy/jit/timeshifter Message-ID: <20061121161855.2294210075@code0.codespeak.net> Author: pedronis Date: Tue Nov 21 17:18:46 2006 New Revision: 34832 Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/jit/timeshifter/oop.py pypy/dist/pypy/jit/timeshifter/rtimeshift.py pypy/dist/pypy/jit/timeshifter/vdict.py Log: (arre, arigo, pedronis) add support for folding at compile-time oop container ops on deep-frozen containers, enabled with .couldfold on the respective oop_ helper. Enabled only for virtual dict getitem in this check-in. Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Tue Nov 21 17:18:46 2006 @@ -1044,7 +1044,10 @@ # Pass them as constant Nones. ts = self ll_handler = oopspecdesc.ll_handler - missing_args = ((ll_handler.func_code.co_argcount - 2) - + + couldfold = oopspecdesc.couldfold + + missing_args = ((ll_handler.func_code.co_argcount - 2 - couldfold) - len(oopspecdesc.argtuple)) assert missing_args >= 0 if missing_args > 0: @@ -1054,9 +1057,17 @@ args_v.extend([hop.llops.genconst(ll_None)] * missing_args) args_s = [ts.s_RedBox] * len(args_v) + if oopspecdesc.is_method: args_s[0] = ts.s_PtrRedBox # for more precise annotations args_v[0] = hop.llops.as_ptrredbox(args_v[0]) + + if couldfold: + args_s.insert(0, annmodel.s_Bool) + hs_self = hop.args_s[oopspecdesc.argtuple[0].n] + c_deepfrozen = inputconst(lltype.Bool, hs_self.deepfrozen) + args_v.insert(0, c_deepfrozen) + RESULT = originalconcretetype(hop.s_result) if RESULT is lltype.Void: s_result = annmodel.s_None Modified: pypy/dist/pypy/jit/timeshifter/oop.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/oop.py (original) +++ pypy/dist/pypy/jit/timeshifter/oop.py Tue Nov 21 17:18:46 2006 @@ -3,6 +3,7 @@ from pypy.jit.timeshifter.rcontainer import cachedtype from pypy.jit.timeshifter import rvalue, rtimeshift from pypy.translator.c import exceptiontransform +from pypy.rlib.unroll import unrolling_iterable class Index: @@ -13,6 +14,8 @@ class OopSpecDesc: __metaclass__ = cachedtype + do_call = None + def __init__(self, hrtyper, fnobj): ll_func = fnobj._callable FUNCTYPE = lltype.typeOf(fnobj) @@ -42,15 +45,18 @@ RGenOp = hrtyper.RGenOp self.args_gv = [None] * nb_args - self.gv_fnptr = RGenOp.constPrebuiltGlobal(fnobj._as_ptr()) - self.result_kind = RGenOp.kindToken(FUNCTYPE.RESULT) + fnptr = fnobj._as_ptr() + self.gv_fnptr = RGenOp.constPrebuiltGlobal(fnptr) + result_kind = RGenOp.kindToken(FUNCTYPE.RESULT) + self.result_kind = result_kind if FUNCTYPE.RESULT is lltype.Void: self.errorbox = None else: error_value = exceptiontransform.error_value(FUNCTYPE.RESULT) self.errorbox = rvalue.redbox_from_prebuilt_value(RGenOp, error_value) - self.redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT) + redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT) + self.redboxbuilder = redboxbuilder self.sigtoken = RGenOp.sigToken(FUNCTYPE) if operation_name == 'newlist': @@ -71,6 +77,7 @@ None, None, [method]) self.typedesc = vmodule.TypeDesc(hrtyper, SELFTYPE) self.ll_handler = getattr(vmodule, method) + self.couldfold = getattr(self.ll_handler, 'couldfold', False) # exception handling graph = fnobj.graph @@ -78,15 +85,42 @@ self.can_raise = etrafo.raise_analyzer.analyze_direct_call(graph) self.fetch_global_excdata = hrtyper.fetch_global_excdata - def residual_call(self, jitstate, argboxes): + if self.couldfold: + ARGS = FUNCTYPE.ARGS + argpos = unrolling_iterable(enumerate(self.argpositions)) + + def do_call(rgenop, argboxes): + args = (None,)*nb_args + for i, pos in argpos: + if pos >= 0: + T = ARGS[pos] + v = rvalue.ll_getvalue(argboxes[i], T) + args = args[:pos] +(v,) + args[pos+1:] + result = fnptr(*args) + if FUNCTYPE.RESULT == lltype.Void: + return None + gv_result = rgenop.genconst(result) + return redboxbuilder(result_kind, gv_result) + + self.do_call = do_call + + def residual_call(self, jitstate, argboxes, deepfrozen=False): builder = jitstate.curbuilder args_gv = self.args_gv[:] argpositions = self.argpositions + fold = deepfrozen for i in range(len(argpositions)): pos = argpositions[i] if pos >= 0: gv_arg = argboxes[i].getgenvar(builder) args_gv[pos] = gv_arg + fold &= gv_arg.is_const + if fold: + try: + return self.do_call(builder.rgenop, argboxes) + except Exception, e: + jitstate.residual_exception(e) + return self.errorbox gv_result = builder.genop_call(self.sigtoken, self.gv_fnptr, args_gv) if self.can_raise: self.fetch_global_excdata(jitstate) @@ -94,11 +128,7 @@ def residual_exception(self, jitstate, ExcCls): ll_evalue = get_ll_instance_for_exccls(ExcCls) - ll_etype = ll_evalue.typeptr - etypebox = rvalue.ll_fromvalue(jitstate, ll_etype) - evaluebox = rvalue.ll_fromvalue(jitstate, ll_evalue) - rtimeshift.setexctypebox (jitstate, etypebox ) - rtimeshift.setexcvaluebox(jitstate, evaluebox) + jitstate.residual_ll_exception(ll_evalue) return self.errorbox residual_exception._annspecialcase_ = 'specialize:arg(2)' Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py Tue Nov 21 17:18:46 2006 @@ -828,6 +828,17 @@ self.exc_value_box = self.exc_value_box.replace(memo) + def residual_ll_exception(self, ll_evalue): + ll_etype = ll_evalue.typeptr + etypebox = rvalue.ll_fromvalue(self, ll_etype) + evaluebox = rvalue.ll_fromvalue(self, ll_evalue) + setexctypebox (self, etypebox ) + setexcvaluebox(self, evaluebox) + + def residual_exception(self, e): + self.residual_ll_exception(cast_instance_to_base_ptr(e)) + + def ensure_queue(jitstate, DispatchQueueClass): return DispatchQueueClass() ensure_queue._annspecialcase_ = 'specialize:arg(1)' Modified: pypy/dist/pypy/jit/timeshifter/vdict.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/vdict.py (original) +++ pypy/dist/pypy/jit/timeshifter/vdict.py Tue Nov 21 17:18:46 2006 @@ -242,7 +242,7 @@ else: oopspecdesc.residual_call(jitstate, [selfbox, keybox, valuebox]) -def oop_dict_getitem(jitstate, oopspecdesc, selfbox, keybox): +def oop_dict_getitem(jitstate, oopspecdesc, deepfrozen, selfbox, keybox): content = selfbox.content if isinstance(content, AbstractVirtualDict) and keybox.is_constant(): try: @@ -250,4 +250,6 @@ except KeyError: return oopspecdesc.residual_exception(jitstate, KeyError) else: - return oopspecdesc.residual_call(jitstate, [selfbox, keybox]) + return oopspecdesc.residual_call(jitstate, [selfbox, keybox], + deepfrozen=deepfrozen) +oop_dict_getitem.couldfold = True From arigo at codespeak.net Tue Nov 21 19:10:01 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 21 Nov 2006 19:10:01 +0100 (CET) Subject: [pypy-svn] r34839 - in pypy/dist/pypy: jit/timeshifter jit/timeshifter/test lang/automata rpython rpython/lltypesystem Message-ID: <20061121181001.740C410075@code0.codespeak.net> Author: arigo Date: Tue Nov 21 19:09:56 2006 New Revision: 34839 Modified: pypy/dist/pypy/jit/timeshifter/oop.py pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/jit/timeshifter/transform.py pypy/dist/pypy/jit/timeshifter/vdict.py pypy/dist/pypy/lang/automata/dfa.py pypy/dist/pypy/rpython/annlowlevel.py pypy/dist/pypy/rpython/lltypesystem/rdict.py pypy/dist/pypy/rpython/rbuiltin.py Log: (pedronis, arre, arigo) A new DFA test, this time with a recognizer main loop that's quite of close to the original. Modified: pypy/dist/pypy/jit/timeshifter/oop.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/oop.py (original) +++ pypy/dist/pypy/jit/timeshifter/oop.py Tue Nov 21 19:09:56 2006 @@ -89,7 +89,7 @@ ARGS = FUNCTYPE.ARGS argpos = unrolling_iterable(enumerate(self.argpositions)) - def do_call(rgenop, argboxes): + def do_call(jitstate, argboxes): args = (None,)*nb_args for i, pos in argpos: if pos >= 0: @@ -99,8 +99,7 @@ result = fnptr(*args) if FUNCTYPE.RESULT == lltype.Void: return None - gv_result = rgenop.genconst(result) - return redboxbuilder(result_kind, gv_result) + return rvalue.ll_fromvalue(jitstate, result) self.do_call = do_call @@ -117,7 +116,7 @@ fold &= gv_arg.is_const if fold: try: - return self.do_call(builder.rgenop, argboxes) + return self.do_call(jitstate, argboxes) except Exception, e: jitstate.residual_exception(e) return self.errorbox Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Tue Nov 21 19:09:56 2006 @@ -3,6 +3,7 @@ from pypy.jit.timeshifter.test.test_timeshift import hannotate, getargtypes from pypy.jit.timeshifter.hrtyper import HintRTyper from pypy.jit.timeshifter.test.test_timeshift import P_NOVIRTUAL +from pypy.jit.timeshifter.test.test_vlist import P_OOPSPEC from pypy.rpython.llinterp import LLInterpreter from pypy.objspace.flow.model import checkgraph, summary from pypy.rlib.objectmodel import hint @@ -171,6 +172,21 @@ res = self.timeshift_from_portal(main, recognizeparts, [1, 0], policy=P_NOVIRTUAL) assert not res + def test_dfa_compile3(self): + from pypy.lang.automata.dfa import getautomaton, recognize3 + def main(gets): + auto = getautomaton() + s = ["aaaaaaaaaab", "aaaa"][gets] + return recognize3(auto, s) + + res = self.timeshift_from_portal(main, recognize3, [0], + policy=P_OOPSPEC) + assert res + + res = self.timeshift_from_portal(main, recognize3, [1], + policy=P_OOPSPEC) + assert not res + def test_method_call_promote(self): class Base(object): pass Modified: pypy/dist/pypy/jit/timeshifter/transform.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/transform.py (original) +++ pypy/dist/pypy/jit/timeshifter/transform.py Tue Nov 21 19:09:56 2006 @@ -442,7 +442,8 @@ if spaceop.opname == 'direct_call': c_func = spaceop.args[0] fnobj = c_func.value._obj - if hasattr(fnobj._callable, 'oopspec'): + if (hasattr(fnobj._callable, 'oopspec') and + getattr(self.hannotator.policy, 'oopspec', False)): return 'oopspec' for v in spaceop.args: Modified: pypy/dist/pypy/jit/timeshifter/vdict.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/vdict.py (original) +++ pypy/dist/pypy/jit/timeshifter/vdict.py Tue Nov 21 19:09:56 2006 @@ -253,3 +253,17 @@ return oopspecdesc.residual_call(jitstate, [selfbox, keybox], deepfrozen=deepfrozen) oop_dict_getitem.couldfold = True + +def oop_dict_contains(jitstate, oopspecdesc, deepfrozen, selfbox, keybox): + content = selfbox.content + if isinstance(content, AbstractVirtualDict) and keybox.is_constant(): + try: + content.getitem(keybox) + res = True + except KeyError: + res = False + return rvalue.ll_fromvalue(jitstate, res) + else: + return oopspecdesc.residual_call(jitstate, [selfbox, keybox], + deepfrozen=deepfrozen) +oop_dict_contains.couldfold = True Modified: pypy/dist/pypy/lang/automata/dfa.py ============================================================================== --- pypy/dist/pypy/lang/automata/dfa.py (original) +++ pypy/dist/pypy/lang/automata/dfa.py Tue Nov 21 19:09:56 2006 @@ -31,7 +31,7 @@ def __repr__(self): from pprint import pformat return "DFA%s" % (pformat( - self.num_states, self.transitions, self.final_states)) + (self.num_states, self.transitions, self.final_states))) def getautomaton(): " simple example of handcrafted dfa " @@ -130,3 +130,24 @@ res = hint(res, concrete=True) res = hint(res, variable=True) return res + +# a version of recognize() full of hints, but otherwise not too modified + +def recognize3(automaton, s): + automaton = hint(automaton, deepfreeze=True) + hint(automaton, concrete=True) + state = 0 + + index = 0 + while index < len(s): + hint(None, global_merge_point=True) + char = s[index] + index += 1 + char = hint(char, promote=True) + try: + state = automaton.get_transition(state, char) + except KeyError: + return False + state = hint(state, promote=True) + + return state in automaton.final_states Modified: pypy/dist/pypy/rpython/annlowlevel.py ============================================================================== --- pypy/dist/pypy/rpython/annlowlevel.py (original) +++ pypy/dist/pypy/rpython/annlowlevel.py Tue Nov 21 19:09:56 2006 @@ -349,6 +349,7 @@ def cast_instance_to_base_ptr(instance): return cast_object_to_ptr(base_ptr_lltype(), instance) +cast_instance_to_base_ptr._annspecialcase_ = 'specialize:argtype(0)' def base_ptr_lltype(): from pypy.rpython.lltypesystem.rclass import OBJECTPTR Modified: pypy/dist/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/dist/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/dist/pypy/rpython/lltypesystem/rdict.py Tue Nov 21 19:09:56 2006 @@ -735,3 +735,4 @@ def ll_contains(d, key): entry = ll_dict_lookup(d, key, d.keyhash(key)) return entry.valid() +ll_contains.oopspec = 'dict.contains(d, key)' Modified: pypy/dist/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/dist/pypy/rpython/rbuiltin.py (original) +++ pypy/dist/pypy/rpython/rbuiltin.py Tue Nov 21 19:09:56 2006 @@ -624,6 +624,7 @@ hints[key[2:]] = s_value.const v = hop.inputarg(hop.args_r[0], arg=0) c_hint = hop.inputconst(lltype.Void, hints) + hop.exception_cannot_occur() return hop.genop('hint', [v, c_hint], resulttype=v.concretetype) BUILTIN_TYPER[objectmodel.hint] = rtype_hint From arigo at codespeak.net Tue Nov 21 23:07:30 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 21 Nov 2006 23:07:30 +0100 (CET) Subject: [pypy-svn] r34842 - pypy/dist/pypy/annotation Message-ID: <20061121220730.A4B4010072@code0.codespeak.net> Author: arigo Date: Tue Nov 21 23:07:29 2006 New Revision: 34842 Modified: pypy/dist/pypy/annotation/annrpython.py pypy/dist/pypy/annotation/model.py pypy/dist/pypy/annotation/unaryop.py Log: (pedronis, arre, arigo) We need a version of 'getattr' that doesn't give blocked blocks when applied to classes that are never instantiated, but still seen because of an isinstance(). Modified: pypy/dist/pypy/annotation/annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/annrpython.py (original) +++ pypy/dist/pypy/annotation/annrpython.py Tue Nov 21 23:07:29 2006 @@ -564,6 +564,10 @@ # later by reflowing). Throw the BlockedInference up to # processblock(). raise + + except annmodel.HarmlesslyBlocked: + return + else: # dead code removal: don't follow all exits if the exitswitch # is known Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Tue Nov 21 23:07:29 2006 @@ -713,6 +713,11 @@ return s_ImpossibleValue setattr(cls, name, default_op) +class HarmlesslyBlocked(Exception): + """Raised by the unaryop/binaryop to signal a harmless kind of + BlockedInference: the current block is blocked, but not in a way + that gives 'Blocked block' errors at the end of annotation.""" + # # safety check that no-one is trying to make annotation and translation # faster by providing the -O option to Python. Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Tue Nov 21 23:07:29 2006 @@ -8,7 +8,7 @@ SomeInstance, SomeBuiltin, SomeFloat, SomeIterator, SomePBC, \ SomeExternalObject, SomeTypedAddressAccess, SomeAddress, \ SomeCTypesObject, s_ImpossibleValue, s_Bool, \ - unionof, set, missing_operation, add_knowntypedata + unionof, set, missing_operation, add_knowntypedata, HarmlesslyBlocked from pypy.annotation.bookkeeper import getbookkeeper from pypy.annotation import builtin from pypy.annotation.binaryop import _clone ## XXX where to put this? @@ -524,6 +524,9 @@ s_result = ins.classdef.lookup_filter(s_result, attr) elif isinstance(s_result, SomeImpossibleValue): ins.classdef.check_missing_attribute_update(attr) + if ins.classdef.classdesc.allslots is not None: + if attr in ins.classdef.classdesc.allslots: + raise HarmlesslyBlocked("getattr on a slot") return s_result return SomeObject() getattr.can_only_throw = [] From arigo at codespeak.net Tue Nov 21 23:09:50 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 21 Nov 2006 23:09:50 +0100 (CET) Subject: [pypy-svn] r34843 - in pypy/dist/pypy/jit: codegen/i386/test timeshifter timeshifter/test Message-ID: <20061121220950.9F20410072@code0.codespeak.net> Author: arigo Date: Tue Nov 21 23:09:47 2006 New Revision: 34843 Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py pypy/dist/pypy/jit/timeshifter/rcontainer.py pypy/dist/pypy/jit/timeshifter/rtimeshift.py pypy/dist/pypy/jit/timeshifter/rvalue.py pypy/dist/pypy/jit/timeshifter/test/test_promotion.py pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py pypy/dist/pypy/jit/timeshifter/vdict.py pypy/dist/pypy/jit/timeshifter/vlist.py Log: (pedronis, arre, arigo) Make PartialDataStruct survive across merges, at least as long as their information doesn't conflict with another merged path's information. (Missing: make recursive PartialDataStructs survive too) Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py (original) +++ pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py Tue Nov 21 23:09:47 2006 @@ -140,6 +140,9 @@ def check_insns(self, expected=None, **counts): "Cannot check instructions in the generated assembler." + def check_flexswitches(self, expected_count): + "Cannot check instructions in the generated assembler." + class TestTimeshiftI386(I386TimeshiftingTestMixin, test_timeshift.TestTimeshift): Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/dist/pypy/jit/timeshifter/rcontainer.py Tue Nov 21 23:09:47 2006 @@ -19,6 +19,15 @@ def op_getsubstruct(self, jitstate, fielddesc): raise NotImplementedError + +class VirtualContainer(AbstractContainer): + __slots__ = [] + + +class FrozenContainer(AbstractContainer): + __slots__ = [] + + # ____________________________________________________________ class StructTypeDesc(object): @@ -158,7 +167,7 @@ # ____________________________________________________________ -class FrozenVirtualStruct(AbstractContainer): +class FrozenVirtualStruct(FrozenContainer): def __init__(self, typedesc): self.typedesc = typedesc @@ -199,6 +208,7 @@ ownbox = typedesc.factory() contmemo[self] = ownbox vstruct = ownbox.content + assert isinstance(vstruct, VirtualStruct) self_boxes = self.fz_content_boxes for i in range(len(self_boxes)): fz_box = self_boxes[i] @@ -207,11 +217,7 @@ return ownbox -class AbstractStruct(AbstractContainer): - pass - - -class VirtualStruct(AbstractStruct): +class VirtualStruct(VirtualContainer): def __init__(self, typedesc): self.typedesc = typedesc @@ -284,8 +290,46 @@ def op_getsubstruct(self, jitstate, fielddesc): return self.ownbox +# ____________________________________________________________ -class PartialDataStruct(AbstractStruct): +class FrozenPartialDataStruct(AbstractContainer): + + def __init__(self): + self.fz_data = [] + + def getfzbox(self, searchindex): + for index, fzbox in self.fz_data: + if index == searchindex: + return fzbox + else: + return None + + def match(self, box, partialdatamatch): + content = box.content + if not isinstance(content, PartialDataStruct): + return False + + cankeep = {} + for index, subbox in content.data: + selfbox = self.getfzbox(index) + if selfbox is not None and selfbox.is_constant_equal(subbox): + cankeep[index] = None + fullmatch = len(cankeep) == len(self.fz_data) + try: + prevkeep = partialdatamatch[box] + except KeyError: + partialdatamatch[box] = cankeep + else: + if prevkeep is not None: + d = {} + for index in prevkeep: + if index in cankeep: + d[index] = None + partialdatamatch[box] = d + return fullmatch + + +class PartialDataStruct(AbstractContainer): def __init__(self): self.data = [] @@ -307,6 +351,19 @@ else: self.data.append((searchindex, box)) + def partialfreeze(self, memo): + contmemo = memo.containers + assert self not in contmemo # contmemo no longer used + result = contmemo[self] = FrozenPartialDataStruct() + for index, box in self.data: + if box.is_constant(): + frozenbox = box.freeze(memo) + result.fz_data.append((index, frozenbox)) + if len(result.fz_data) == 0: + return None + else: + return result + def copy(self, memo): result = PartialDataStruct() for index, box in self.data: @@ -325,3 +382,18 @@ contmemo[self] = None for index, box in self.data: box.enter_block(incoming, memo) + + def cleanup_partial_data(self, keep): + if keep is None: + return None + j = 0 + data = self.data + for i in range(len(data)): + item = data[i] + if item[0] in keep: + data[j] = item + j += 1 + if j == 0: + return None + del data[j:] + return self Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py Tue Nov 21 23:09:47 2006 @@ -2,7 +2,7 @@ from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem import lltype, lloperation, llmemory from pypy.jit.hintannotator.model import originalconcretetype -from pypy.jit.timeshifter import rvalue +from pypy.jit.timeshifter import rvalue, rcontainer from pypy.rlib.unroll import unrolling_iterable from pypy.rpython.annlowlevel import cachedtype, base_ptr_lltype from pypy.rpython.annlowlevel import cast_instance_to_base_ptr @@ -219,6 +219,7 @@ outgoingvarboxes = [] res = frozen.exactmatch(jitstate, outgoingvarboxes, memo) assert res, "exactmatch() failed" + cleanup_partial_data(memo.partialdatamatch) newblock = enter_next_block(jitstate, outgoingvarboxes) states_dic[key] = frozen, newblock if global_resumer is not None and global_resumer is not return_marker: @@ -251,6 +252,7 @@ # We need a more general block. Do it by generalizing all the # redboxes from outgoingvarboxes, by making them variables. # Then we make a new block based on this new state. + cleanup_partial_data(memo.partialdatamatch) replace_memo = rvalue.copy_memo() for box in outgoingvarboxes: box.forcevar(jitstate.curbuilder, replace_memo) @@ -262,6 +264,14 @@ return False # continue retrieve_jitstate_for_merge._annspecialcase_ = "specialize:arglltype(2)" +def cleanup_partial_data(partialdatamatch): + # remove entries from PartialDataStruct unless they matched + # their frozen equivalent + for box, keep in partialdatamatch.iteritems(): + content = box.content + if isinstance(content, rcontainer.PartialDataStruct): + box.content = content.cleanup_partial_data(keep) + def merge_generalized(jitstate): resuming = jitstate.resuming if resuming is None: Modified: pypy/dist/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/dist/pypy/jit/timeshifter/rvalue.py Tue Nov 21 23:09:47 2006 @@ -14,7 +14,9 @@ return Memo() def exactmatch_memo(): - return Memo() + memo = Memo() + memo.partialdatamatch = {} + return memo def copy_memo(): return Memo() @@ -242,29 +244,35 @@ try: return boxmemo[self] except KeyError: + content = self.content if not self.genvar: - assert self.content is not None + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.VirtualContainer) result = FrozenPtrVirtual(self.kind) boxmemo[self] = result - result.fz_content = self.content.freeze(memo) + result.fz_content = content.freeze(memo) + return result + elif self.genvar.is_const: + result = FrozenPtrConst(self.kind, self.genvar) + elif content is None: + result = FrozenPtrVar(self.kind) else: - if self.is_constant(): - result = FrozenPtrConst(self.kind, self.genvar) - else: - result = FrozenPtrVar(self.kind) - # if self.content is not None, it's a PartialDataStruct - # - for now, we always remove it while freezing so that - # we exactly match our frozen version - # XXX unsure if it's the correct place to do that. - # XXX maybe in exactmatch?? - self.content = None + # if self.content is not None, it's a PartialDataStruct + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.PartialDataStruct) + result = FrozenPtrVarWithPartialData(self.kind) boxmemo[self] = result + result.fz_partialcontent = content.partialfreeze(memo) + return result + boxmemo[self] = result return result def getgenvar(self, builder): if not self.genvar: - assert self.content - self.content.force_runtime_container(builder) + content = self.content + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.VirtualContainer) + content.force_runtime_container(builder) assert self.genvar return self.genvar @@ -288,28 +296,21 @@ def __init__(self, kind): self.kind = kind + def is_constant_equal(self, box): + return False -class FrozenIntConst(FrozenValue): - def __init__(self, kind, gv_const): - self.kind = kind - self.gv_const = gv_const +class FrozenConst(FrozenValue): def exactmatch(self, box, outgoingvarboxes, memo): - if (box.is_constant() and - self.gv_const.revealconst(lltype.Signed) == - box.genvar.revealconst(lltype.Signed)): + if self.is_constant_equal(box): return True else: outgoingvarboxes.append(box) return False - def unfreeze(self, incomingvarboxes, memo): - # XXX could return directly the original IntRedBox - return IntRedBox(self.kind, self.gv_const) - -class FrozenIntVar(FrozenValue): +class FrozenVar(FrozenValue): def exactmatch(self, box, outgoingvarboxes, memo): memo = memo.boxes @@ -323,6 +324,25 @@ outgoingvarboxes.append(box) return False + +class FrozenIntConst(FrozenConst): + + def __init__(self, kind, gv_const): + self.kind = kind + self.gv_const = gv_const + + def is_constant_equal(self, box): + return (box.is_constant() and + self.gv_const.revealconst(lltype.Signed) == + box.genvar.revealconst(lltype.Signed)) + + def unfreeze(self, incomingvarboxes, memo): + # XXX could return directly the original IntRedBox + return IntRedBox(self.kind, self.gv_const) + + +class FrozenIntVar(FrozenVar): + def unfreeze(self, incomingvarboxes, memo): memo = memo.boxes if self not in memo: @@ -334,38 +354,22 @@ return memo[self] -class FrozenDoubleConst(FrozenValue): +class FrozenDoubleConst(FrozenConst): def __init__(self, kind, gv_const): self.kind = kind self.gv_const = gv_const - def exactmatch(self, box, outgoingvarboxes, memo): - if (box.is_constant() and - self.gv_const.revealconst(lltype.Float) == - box.genvar.revealconst(lltype.Float)): - return True - else: - outgoingvarboxes.append(box) - return False + def is_constant_equal(self, box): + return (box.is_constant() and + self.gv_const.revealconst(lltype.Float) == + box.genvar.revealconst(lltype.Float)) def unfreeze(self, incomingvarboxes, memo): return DoubleRedBox(self.kind, self.gv_const) -class FrozenDoubleVar(FrozenValue): - - def exactmatch(self, box, outgoingvarboxes, memo): - memo = memo.boxes - if self not in memo: - memo[self] = box - outgoingvarboxes.append(box) - return True - elif memo[self] is box: - return True - else: - outgoingvarboxes.append(box) - return False +class FrozenDoubleVar(FrozenVar): def unfreeze(self, incomingvarboxes, memo): memo = memo.boxes @@ -378,38 +382,32 @@ return memo[self] -class FrozenPtrConst(FrozenValue): +class FrozenPtrConst(FrozenConst): def __init__(self, kind, gv_const): self.kind = kind self.gv_const = gv_const + def is_constant_equal(self, box): + return (box.is_constant() and + self.gv_const.revealconst(llmemory.Address) == + box.genvar.revealconst(llmemory.Address)) + def exactmatch(self, box, outgoingvarboxes, memo): - if (box.is_constant() and - self.gv_const.revealconst(llmemory.Address) == - box.genvar.revealconst(llmemory.Address)): - return True - else: - outgoingvarboxes.append(box) - return False + assert isinstance(box, PtrRedBox) + memo.partialdatamatch[box] = None # could do better + return FrozenConst.exactmatch(self, box, outgoingvarboxes, memo) def unfreeze(self, incomingvarboxes, memo): return PtrRedBox(self.kind, self.gv_const) -class FrozenPtrVar(FrozenValue): +class FrozenPtrVar(FrozenVar): def exactmatch(self, box, outgoingvarboxes, memo): - memo = memo.boxes - if self not in memo: - memo[self] = box - outgoingvarboxes.append(box) - return True - elif memo[self] is box: - return True - else: - outgoingvarboxes.append(box) - return False + assert isinstance(box, PtrRedBox) + memo.partialdatamatch[box] = None + return FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) def unfreeze(self, incomingvarboxes, memo): memo = memo.boxes @@ -422,6 +420,19 @@ return memo[self] +class FrozenPtrVarWithPartialData(FrozenPtrVar): + + def exactmatch(self, box, outgoingvarboxes, memo): + if self.fz_partialcontent is None: + return FrozenPtrVar.exactmatch(self, box, outgoingvarboxes, memo) + assert isinstance(box, PtrRedBox) + partialdatamatch = self.fz_partialcontent.match(box, + memo.partialdatamatch) + # skip the parent's exactmatch()! + exact = FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) + return exact and partialdatamatch + + class FrozenPtrVirtual(FrozenValue): def exactmatch(self, box, outgoingvarboxes, memo): Modified: pypy/dist/pypy/jit/timeshifter/test/test_promotion.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_promotion.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_promotion.py Tue Nov 21 23:09:47 2006 @@ -263,3 +263,28 @@ res = self.timeshift(ll_function, [5, 100], [0], policy=P_NOVIRTUAL) assert res == 115 + + def test_remembers_across_mp(self): + def ll_function(x, flag): + hint(None, global_merge_point=True) + hint(x.field, promote=True) + m = x.field + if flag: + m += 1 * flag + else: + m += 2 + flag + hint(x.field, promote=True) + return m + x.field + + S = lltype.GcStruct('S', ('field', lltype.Signed), + hints={'immutable': True}) + + def struct_S(string): + s = lltype.malloc(S) + s.field = int(string) + return s + ll_function.convert_arguments = [struct_S, int] + + res = self.timeshift(ll_function, ["20", 0], [], policy=P_NOVIRTUAL) + assert res == 42 + self.check_flexswitches(1) Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Tue Nov 21 23:09:47 2006 @@ -5,7 +5,7 @@ from pypy.jit.hintannotator.model import * from pypy.jit.timeshifter.hrtyper import HintRTyper, originalconcretetype from pypy.jit.timeshifter import rtimeshift, rvalue -from pypy.objspace.flow.model import summary +from pypy.objspace.flow.model import summary, Variable from pypy.rpython.lltypesystem import lltype, llmemory, rstr from pypy.rlib.objectmodel import hint, keepalive_until_here from pypy.rlib.unroll import unrolling_iterable @@ -320,6 +320,14 @@ for opname, count in counts.items(): assert self.insns.get(opname, 0) == count + def check_flexswitches(self, expected_count): + count = 0 + for block in self.residual_graph.iterblocks(): + if (isinstance(block.exitswitch, Variable) and + block.exitswitch.concretetype is lltype.Signed): + count += 1 + assert count == expected_count + class TestTimeshift(TimeshiftingTests): Modified: pypy/dist/pypy/jit/timeshifter/vdict.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/vdict.py (original) +++ pypy/dist/pypy/jit/timeshifter/vdict.py Tue Nov 21 23:09:47 2006 @@ -1,12 +1,16 @@ import operator from pypy.rpython.lltypesystem import lltype from pypy.rpython.lltypesystem import rdict -from pypy.jit.timeshifter.rcontainer import AbstractContainer, cachedtype +from pypy.jit.timeshifter.rcontainer import VirtualContainer, FrozenContainer +from pypy.jit.timeshifter.rcontainer import cachedtype from pypy.jit.timeshifter import rvalue from pypy.rlib.objectmodel import r_dict HASH = lltype.Signed +# XXXXXXXXXX! ARGH. +# cannot use a dictionary as the item_boxes at all, because of order issues + class LLEqDesc(object): __metaclass__ = cachedtype @@ -48,7 +52,7 @@ for key, valuebox in other.item_boxes.iteritems(): self.item_boxes[key] = valuebox.copy(memo) - def replace(self, memo): + def internal_replace(self, memo): changes = [] for key, valuebox in self.item_boxes.iteritems(): newbox = valuebox.replace(memo) @@ -137,7 +141,7 @@ TypeDesc = DictTypeDesc -class AbstractFrozenVirtualDict(AbstractContainer): +class AbstractFrozenVirtualDict(FrozenContainer): __slots__ = ('typedesc',) def __init__(self, typedesc): @@ -171,10 +175,18 @@ fullmatch = False return fullmatch + def freeze_from(self, vdict, memo): + raise NotImplementedError + + def same_keys_as(self, vdict, boxes): + raise NotImplementedError + -class AbstractVirtualDict(AbstractContainer): +class AbstractVirtualDict(VirtualContainer): __slots__ = ('typedesc', 'ownbox') # and no item_boxes + FrozenVirtualDict = AbstractFrozenVirtualDict # overridden in subclasses + def __init__(self, typedesc): self.typedesc = typedesc self.make_item_boxes() @@ -228,9 +240,30 @@ contmemo = memo.containers if self not in contmemo: contmemo[self] = None - self.replace(memo) + self.internal_replace(memo) self.ownbox = self.ownbox.replace(memo) + def make_item_boxes(self): + raise NotImplementedError + + def getboxes(self): + raise NotImplementedError + + def getitems_and_makeempty(self, rgenop): + raise NotImplementedError + + def getitem(self, keybox): + raise NotImplementedError + + def setitem(self, keybox, valuebox): + raise NotImplementedError + + def copy_from(self, other, memo): + raise NotImplementedError + + def internal_replace(self, memo): + raise NotImplementedError + def oop_newdict(jitstate, oopspecdesc): return oopspecdesc.typedesc.factory() Modified: pypy/dist/pypy/jit/timeshifter/vlist.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/vlist.py (original) +++ pypy/dist/pypy/jit/timeshifter/vlist.py Tue Nov 21 23:09:47 2006 @@ -1,5 +1,6 @@ from pypy.rpython.lltypesystem import lltype -from pypy.jit.timeshifter.rcontainer import AbstractContainer, cachedtype +from pypy.jit.timeshifter.rcontainer import VirtualContainer, FrozenContainer +from pypy.jit.timeshifter.rcontainer import cachedtype from pypy.jit.timeshifter import rvalue @@ -39,7 +40,7 @@ TypeDesc = ListTypeDesc -class FrozenVirtualList(AbstractContainer): +class FrozenVirtualList(FrozenContainer): def __init__(self, typedesc): self.typedesc = typedesc @@ -74,7 +75,7 @@ return fullmatch -class VirtualList(AbstractContainer): +class VirtualList(VirtualContainer): def __init__(self, typedesc, length=0, itembox=None): self.typedesc = typedesc From ale at codespeak.net Wed Nov 22 10:48:42 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Wed, 22 Nov 2006 10:48:42 +0100 (CET) Subject: [pypy-svn] r34851 - pypy/extradoc/publication Message-ID: <20061122094842.5ACE410068@code0.codespeak.net> Author: ale Date: Wed Nov 22 10:48:24 2006 New Revision: 34851 Added: pypy/extradoc/publication/ED1206_20-23.pdf Log: An article to appear in "Elektronik & Data" a danish magazine for professional developers of electronics, embedded systems and FPGA systems. Added: pypy/extradoc/publication/ED1206_20-23.pdf ============================================================================== Files (empty file) and pypy/extradoc/publication/ED1206_20-23.pdf Wed Nov 22 10:48:24 2006 differ From radix at codespeak.net Wed Nov 22 18:20:04 2006 From: radix at codespeak.net (radix at codespeak.net) Date: Wed, 22 Nov 2006 18:20:04 +0100 (CET) Subject: [pypy-svn] r34868 - pypy/dist/pypy/rlib/parsing/test Message-ID: <20061122172004.7AD4210064@code0.codespeak.net> Author: radix Date: Wed Nov 22 18:20:03 2006 New Revision: 34868 Modified: pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py Log: at risk of being flamed - a failing (skipped) unit test for buggy auto-generated transformer The problem is that a rule like: list: "(" sexpr* ")"; generates a visit_list method that assumes there will always be three children, but in reality there can be two or three. Modified: pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py Wed Nov 22 18:20:03 2006 @@ -260,6 +260,29 @@ assert [c.symbol for c in t.children[0].children] == ["QUOTED_STRING"] * 2 t = parse("['a']") +def test_transform_star(): + py.test.skip("This needs to be fixed - generated transformer is buggy") + regexs, rules, transformer = parse_ebnf(""" + IGNORE: " "; + ATOM: "[\+a-zA-Z_][a-zA-Z0-9_]*"; + + sexpr: ATOM | list; + list: "(" sexpr* ")"; +""") + parse = make_parse_function(regexs, rules) + tree = parse("()") + print transformer + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(transformer).compile() in ns + ToAST = ns["ToAST"] + list_expr = tree.visit(ToAST()).children[0] + assert list_expr.symbol == 'list' + # should have two children, "(" and ")" + assert len(list_expr.children) == 2 + assert list_expr.children[0].symbol == '(' + assert list_expr.children[1].symbol == ')' + + def test_quoting(): regexs, rules, transformer = parse_ebnf(""" ATOM: "[a-z]*"; From cfbolz at codespeak.net Wed Nov 22 18:53:15 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 22 Nov 2006 18:53:15 +0100 (CET) Subject: [pypy-svn] r34872 - pypy/dist/pypy/rlib/parsing/test Message-ID: <20061122175315.956A210064@code0.codespeak.net> Author: cfbolz Date: Wed Nov 22 18:53:14 2006 New Revision: 34872 Modified: pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py Log: always use an explicit namespace for less confusion Modified: pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py Wed Nov 22 18:53:14 2006 @@ -55,7 +55,9 @@ """) parse = make_parse_function(regexs, rules) print transformer - exec py.code.Source(transformer).compile() + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(transformer).compile() in ns + ToAST = ns["ToAST"] tree = parse("(0 +! 10) *! (999 +! 10) +! 1") print transformer tree = tree.visit(ToAST()) @@ -127,7 +129,9 @@ parse = make_parse_function(regexs, rules) tree = parse("x * floor + 1") print transformer - exec py.code.Source(transformer).compile() + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(transformer).compile() in ns + ToAST = ns["ToAST"] tree = tree.visit(ToAST()) assert tree.children[2].symbol == "NUMBER" @@ -238,7 +242,9 @@ 'tokenizer': '[object Object]', 'varDecls': '' }""") - exec py.code.Source(transformer).compile() + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(transformer).compile() in ns + ToAST = ns["ToAST"] print transformer t = t.visit(ToAST()) From pedronis at codespeak.net Wed Nov 22 20:02:29 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 22 Nov 2006 20:02:29 +0100 (CET) Subject: [pypy-svn] r34876 - pypy/dist/pypy/jit/timeshifter Message-ID: <20061122190229.3F48B10064@code0.codespeak.net> Author: pedronis Date: Wed Nov 22 20:02:23 2006 New Revision: 34876 Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py pypy/dist/pypy/jit/timeshifter/vlist.py Log: (arre, pedronis) implement unfreeze for frozen virtual lists Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/dist/pypy/jit/timeshifter/rcontainer.py Wed Nov 22 20:02:23 2006 @@ -27,6 +27,11 @@ class FrozenContainer(AbstractContainer): __slots__ = [] + def exactmatch(self, vstruct, outgoingvarboxes, memo): + raise NotImplementedError + + def unfreeze(self, incomingvarboxes, memo): + raise NotImplementedError # ____________________________________________________________ Modified: pypy/dist/pypy/jit/timeshifter/vlist.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/vlist.py (original) +++ pypy/dist/pypy/jit/timeshifter/vlist.py Wed Nov 22 20:02:23 2006 @@ -74,6 +74,24 @@ fullmatch = False return fullmatch + def unfreeze(self, incomingvarboxes, memo): + contmemo = memo.containers + if self in contmemo: + return contmemo[self] + typedesc = self.typedesc + self_boxes = self.fz_item_boxes + length = len(self_boxes) + ownbox = typedesc.factory(length, None) + contmemo[self] = ownbox + vlist = ownbox.content + assert isinstance(vlist, VirtualList) + for i in range(length): + fz_box = self_boxes[i] + vlist.item_boxes[i] = fz_box.unfreeze(incomingvarboxes, + memo) + return ownbox + + class VirtualList(VirtualContainer): From pedronis at codespeak.net Wed Nov 22 20:05:18 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 22 Nov 2006 20:05:18 +0100 (CET) Subject: [pypy-svn] r34877 - pypy/dist/pypy/jit/timeshifter/test Message-ID: <20061122190518.11CEC10064@code0.codespeak.net> Author: pedronis Date: Wed Nov 22 20:05:17 2006 New Revision: 34877 Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py pypy/dist/pypy/jit/timeshifter/test/test_tlc.py Log: (arre, pedronis) flag small on tests to control if the intermediate graphs are too huge to be worth showing normally, instead with small=False only the hint-annotated graph and the generated graphs will be shown. Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Wed Nov 22 20:05:17 2006 @@ -13,6 +13,8 @@ class PortalTest(object): from pypy.jit.codegen.llgraph.rgenop import RGenOp + small = True + def setup_class(cls): cls._cache = {} cls._cache_order = [] @@ -53,13 +55,13 @@ self.hrtyper = HintRTyper(ha, self.rtyper, self.RGenOp) origportalgraph = graphof(t, portal) self.hrtyper.specialize(origportalgraph=origportalgraph, - view = conftest.option.view) + view = conftest.option.view and self.small) for graph in ha.translator.graphs: checkgraph(graph) t.graphs.append(graph) - if conftest.option.view: + if conftest.option.view and self.small: t.view() self.postprocess_timeshifting() self.readportalgraph = self.hrtyper.readportalgraph Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Wed Nov 22 20:05:17 2006 @@ -63,6 +63,8 @@ class TimeshiftingTests(object): from pypy.jit.codegen.llgraph.rgenop import RGenOp + small = True + def setup_class(cls): cls._cache = {} cls._cache_order = [] @@ -98,7 +100,7 @@ # make the timeshifted graphs hrtyper = HintRTyper(ha, rtyper, self.RGenOp) - hrtyper.specialize(view = conftest.option.view) + hrtyper.specialize(view = conftest.option.view and self.small) fresh_jitstate = hrtyper.ll_fresh_jitstate finish_jitstate = hrtyper.ll_finish_jitstate @@ -218,7 +220,7 @@ self.rtyper = rtyper self.hrtyper = hrtyper self.annotate_interface_functions() - if conftest.option.view: + if conftest.option.view and self.small: from pypy.translator.tool.graphpage import FlowGraphPage FlowGraphPage(t, ha.translator.graphs).display() Modified: pypy/dist/pypy/jit/timeshifter/test/test_tlc.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_tlc.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_tlc.py Wed Nov 22 20:05:17 2006 @@ -21,6 +21,7 @@ class TestTLC(PortalTest): + small = False def test_factorial(self): code = tlc.compile(FACTORIAL_SOURCE) From pedronis at codespeak.net Wed Nov 22 20:06:26 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 22 Nov 2006 20:06:26 +0100 (CET) Subject: [pypy-svn] r34878 - pypy/dist/pypy/jit/tl Message-ID: <20061122190626.D87E310061@code0.codespeak.net> Author: pedronis Date: Wed Nov 22 20:06:25 2006 New Revision: 34878 Modified: pypy/dist/pypy/jit/tl/tlc.py Log: (arre, pedronis) started experimenting with adding some promotes in the tlc: tests still pass and promotions occurs but we force virtual int boxes too often, we need to investigate that... Modified: pypy/dist/pypy/jit/tl/tlc.py ============================================================================== --- pypy/dist/pypy/jit/tl/tlc.py (original) +++ pypy/dist/pypy/jit/tl/tlc.py Wed Nov 22 20:06:25 2006 @@ -184,10 +184,14 @@ elif opcode == SUB: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(b.sub(a)) elif opcode == MUL: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(b.mul(a)) elif opcode == DIV: @@ -208,6 +212,8 @@ elif opcode == LE: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(IntObj(not a.lt(b))) elif opcode == GT: @@ -219,7 +225,9 @@ stack.append(IntObj(not b.lt(a))) elif opcode == BR_COND: - if stack.pop().t(): + cond = stack.pop() + hint(cond, promote=True) + if cond.t(): pc += char2int(code[pc]) pc += 1 From pedronis at codespeak.net Wed Nov 22 21:26:51 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 22 Nov 2006 21:26:51 +0100 (CET) Subject: [pypy-svn] r34879 - in pypy/dist/pypy/jit: timeshifter tl Message-ID: <20061122202651.DDF7910072@code0.codespeak.net> Author: pedronis Date: Wed Nov 22 21:26:44 2006 New Revision: 34879 Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py pypy/dist/pypy/jit/tl/tlc.py Log: (arigo around, pedronis) oops, promoting an object instead of its type. Slightly saner code, we still need to be much more careful about merges and likeyl split more to avoid forcing. Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/dist/pypy/jit/timeshifter/rcontainer.py Wed Nov 22 21:26:44 2006 @@ -6,6 +6,7 @@ from pypy.rpython.lltypesystem import lloperation debug_print = lloperation.llop.debug_print +debug_pdb = lloperation.llop.debug_pdb class AbstractContainer(object): __slots__ = [] @@ -250,6 +251,7 @@ self.ownbox.content = None return debug_print(lltype.Void, "FORCE CONTAINER") + #debug_pdb(lltype.Void) genvar = builder.genop_malloc_fixedsize(typedesc.alloctoken) # force the box pointing to this VirtualStruct self.ownbox.genvar = genvar Modified: pypy/dist/pypy/jit/tl/tlc.py ============================================================================== --- pypy/dist/pypy/jit/tl/tlc.py (original) +++ pypy/dist/pypy/jit/tl/tlc.py Wed Nov 22 21:26:44 2006 @@ -226,7 +226,7 @@ elif opcode == BR_COND: cond = stack.pop() - hint(cond, promote=True) + hint(cond.__class__, promote=True) if cond.t(): pc += char2int(code[pc]) pc += 1 From pedronis at codespeak.net Wed Nov 22 22:24:36 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 22 Nov 2006 22:24:36 +0100 (CET) Subject: [pypy-svn] r34880 - pypy/dist/pypy/jit/codegen/llgraph Message-ID: <20061122212436.E387410072@code0.codespeak.net> Author: pedronis Date: Wed Nov 22 22:24:33 2006 New Revision: 34880 Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py Log: try avoiding to display lots of empty blocks which are not so relevant, makes for more readable partial genereted graphs. Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llgraph/llimpl.py (original) +++ pypy/dist/pypy/jit/codegen/llgraph/llimpl.py Wed Nov 22 22:24:33 2006 @@ -396,6 +396,7 @@ from pypy import conftest if conftest.option.view: graph = from_opaque_object(graph) + eliminate_empty_blocks(graph) graph.show() # ____________________________________________________________ From ericvrp at codespeak.net Thu Nov 23 10:15:17 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Thu, 23 Nov 2006 10:15:17 +0100 (CET) Subject: [pypy-svn] r34883 - pypy/dist/pypy/jit/codegen/llvm Message-ID: <20061123091517.60A0010061@code0.codespeak.net> Author: ericvrp Date: Thu Nov 23 10:15:01 2006 New Revision: 34883 Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Log: small error message improvement and using a helper to make the llvm jit codegen work with older ctypes too. Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Thu Nov 23 10:15:01 2006 @@ -7,6 +7,7 @@ This file contains the ctypes specification to use the llvmjit library! ''' from pypy.rpython.rctypes import implementation +from pypy.rpython.rctypes.tool.util import load_library from ctypes import _CFuncPtr, _FUNCFLAG_CDECL from ctypes import * @@ -31,10 +32,10 @@ if not os.path.exists(path): import py - py.test.skip("libllvmjit.so compilation failed (no llvm headers?)") + py.test.skip("libllvmjit.so compilation failed (no llvm headers or llvm version not up to date?)") #load the actual library -llvmjit = cdll.LoadLibrary(os.path.abspath(path)) +llvmjit = load_library(os.path.abspath(path)) class _FuncPtr(_CFuncPtr): _flags_ = _FUNCFLAG_CDECL # aaarghdistutilsunixaaargh (may need something different for standalone builds...) From ale at codespeak.net Thu Nov 23 12:03:15 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 23 Nov 2006 12:03:15 +0100 (CET) Subject: [pypy-svn] r34886 - in pypy/branch/mininal-c-backend/pypy/translator: . c c/src c/test Message-ID: <20061123110315.738FB10061@code0.codespeak.net> Author: ale Date: Thu Nov 23 12:03:10 2006 New Revision: 34886 Added: pypy/branch/mininal-c-backend/pypy/translator/c/src/instrument.h - copied unchanged from r34885, pypy/dist/pypy/translator/c/src/instrument.h Modified: pypy/branch/mininal-c-backend/pypy/translator/c/database.py pypy/branch/mininal-c-backend/pypy/translator/c/exceptiontransform.py pypy/branch/mininal-c-backend/pypy/translator/c/extfunc.py pypy/branch/mininal-c-backend/pypy/translator/c/funcgen.py pypy/branch/mininal-c-backend/pypy/translator/c/genc.py pypy/branch/mininal-c-backend/pypy/translator/c/node.py pypy/branch/mininal-c-backend/pypy/translator/c/src/exception.h pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h pypy/branch/mininal-c-backend/pypy/translator/c/src/obmalloc.c pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h pypy/branch/mininal-c-backend/pypy/translator/c/src/support.h pypy/branch/mininal-c-backend/pypy/translator/c/test/test_standalone.py pypy/branch/mininal-c-backend/pypy/translator/driver.py Log: svn merge -r 34627:HEAD Modified: pypy/branch/mininal-c-backend/pypy/translator/c/database.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/database.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/database.py Thu Nov 23 12:03:10 2006 @@ -62,6 +62,8 @@ self.gctransformer = self.gcpolicy.transformerclass(translator) self.completed = False + self.instrument_ncounter = 0 + def gettypedefnode(self, T, varlength=1): if varlength <= 1: varlength = 1 # it's C after all Modified: pypy/branch/mininal-c-backend/pypy/translator/c/exceptiontransform.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/exceptiontransform.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/exceptiontransform.py Thu Nov 23 12:03:10 2006 @@ -56,7 +56,6 @@ def rpyexc_occured(): exc_type = exc_data.exc_type - lloperation.llop.debug_log_exc(lltype.Void, exc_type) return exc_type is not null_type # XXX tmp HACK for genllvm @@ -64,7 +63,6 @@ # calling rpyexc_occured() from c code with lltype.Bool def _rpyexc_occured(): exc_type = exc_data.exc_type - lloperation.llop.debug_log_exc(lltype.Void, exc_type) return exc_type is not null_type def rpyexc_fetch_type(): @@ -87,7 +85,8 @@ rpyexc_occured, [], l2a(lltype.Bool)) self.rpyexc_occured_ptr = Constant(lltype.functionptr( RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred", - graph=rpyexc_occured_graph), + graph=rpyexc_occured_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_OCCURED_TYPE)) # XXX tmp HACK for genllvm @@ -96,7 +95,8 @@ _rpyexc_occured, [], l2a(lltype.Signed)) self._rpyexc_occured_ptr = Constant(lltype.functionptr( _RPYEXC_OCCURED_TYPE, "_RPyExceptionOccurred", - graph=_rpyexc_occured_graph), + graph=_rpyexc_occured_graph, + exception_policy="exc_helper"), lltype.Ptr(_RPYEXC_OCCURED_TYPE)) RPYEXC_FETCH_TYPE_TYPE = lltype.FuncType([], self.lltype_of_exception_type) @@ -105,7 +105,8 @@ l2a(self.lltype_of_exception_type)) self.rpyexc_fetch_type_ptr = Constant(lltype.functionptr( RPYEXC_FETCH_TYPE_TYPE, "RPyFetchExceptionType", - graph=rpyexc_fetch_type_graph), + graph=rpyexc_fetch_type_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_FETCH_TYPE_TYPE)) RPYEXC_FETCH_VALUE_TYPE = lltype.FuncType([], self.lltype_of_exception_value) @@ -114,7 +115,8 @@ l2a(self.lltype_of_exception_value)) self.rpyexc_fetch_value_ptr = Constant(lltype.functionptr( RPYEXC_FETCH_VALUE_TYPE, "RPyFetchExceptionValue", - graph=rpyexc_fetch_value_graph), + graph=rpyexc_fetch_value_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_FETCH_VALUE_TYPE)) RPYEXC_CLEAR = lltype.FuncType([], lltype.Void) @@ -122,7 +124,8 @@ rpyexc_clear, [], l2a(lltype.Void)) self.rpyexc_clear_ptr = Constant(lltype.functionptr( RPYEXC_CLEAR, "RPyClearException", - graph=rpyexc_clear_graph), + graph=rpyexc_clear_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_CLEAR)) RPYEXC_RAISE = lltype.FuncType([self.lltype_of_exception_type, @@ -134,7 +137,8 @@ l2a(lltype.Void)) self.rpyexc_raise_ptr = Constant(lltype.functionptr( RPYEXC_RAISE, "RPyRaiseException", - graph=rpyexc_raise_graph), + graph=rpyexc_raise_graph, + exception_policy="exc_helper"), lltype.Ptr(RPYEXC_RAISE)) mixlevelannotator.finish() @@ -321,7 +325,6 @@ lltype.Bool) else: v_exc_type = self.ExcData_repr.getfield(self.cexcdata, 'exc_type', llops) - llops.genop('debug_log_exc', [v_exc_type], lltype.Void) var_exc_occured = llops.genop('ptr_nonzero', [v_exc_type], lltype.Bool) Modified: pypy/branch/mininal-c-backend/pypy/translator/c/extfunc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/extfunc.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/extfunc.py Thu Nov 23 12:03:10 2006 @@ -208,7 +208,7 @@ yield ('RPYTHON_PYEXCCLASS2EXC', exceptiondata.fn_pyexcclass2exc) yield ('_RPyExceptionOccurred', exctransformer._rpyexc_occured_ptr.value) - yield ('RPyExceptionOccurred', exctransformer.rpyexc_occured_ptr.value) + yield ('RPyExceptionOccurred1', 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) Modified: pypy/branch/mininal-c-backend/pypy/translator/c/funcgen.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/funcgen.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/funcgen.py Thu Nov 23 12:03:10 2006 @@ -27,7 +27,7 @@ if USESLOTS: __slots__ = """graph db gcpolicy - cpython_exc + exception_policy more_ll_values vars lltypes @@ -36,11 +36,11 @@ blocknum oldgraph""".split() - def __init__(self, graph, db, cpython_exc=False, functionname=None): + def __init__(self, graph, db, exception_policy=None, functionname=None): self.graph = graph self.db = db self.gcpolicy = db.gcpolicy - self.cpython_exc = cpython_exc + self.exception_policy = exception_policy self.functionname = functionname # apply the stackless transformation if db.stacklesstransformer: @@ -85,7 +85,7 @@ self.more_ll_values.append(link.llexitcase) elif link.exitcase is not None: mix.append(Constant(link.exitcase)) - if self.cpython_exc: + if self.exception_policy == "CPython": v, exc_cleanup_ops = self.graph.exc_cleanup mix.append(v) for cleanupop in exc_cleanup_ops: @@ -179,7 +179,7 @@ return self.db.get(ErrorValue(returnlltype)) def return_with_error(self): - if self.cpython_exc: + if self.exception_policy == "CPython": assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr v, exc_cleanup_ops = self.graph.exc_cleanup vanishing_exc_value = self.expr(v) @@ -226,13 +226,15 @@ if len(block.exits) == 0: assert len(block.inputargs) == 1 # regular return block - if self.cpython_exc: + if self.exception_policy == "CPython": assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr yield 'if (RPyExceptionOccurred()) {' yield '\tRPyConvertExceptionToCPython();' yield '\treturn NULL;' yield '}' retval = self.expr(block.inputargs[0]) + if self.exception_policy != "exc_helper": + yield 'RPY_DEBUG_RETURN();' yield 'return %s;' % retval continue elif block.exitswitch is None: @@ -717,12 +719,9 @@ c_string_constant(' '.join(format) + '\n\000'), ''.join([', ' + s for s in argv])) - def OP_DEBUG_LOG_EXC(self, op): - exc_type = self.expr(op.args[0]) - return 'RPY_LOG_EXC(%s);' % exc_type - def OP_DEBUG_ASSERT(self, op): - return '/* debug_assert removed */' + return 'RPyAssert(%s, %s);' % (self.expr(op.args[0]), + c_string_constant(op.args[1].value)) def OP_DEBUG_FATALERROR(self, op): # XXX @@ -736,6 +735,13 @@ msg = 'RPyString_AsString(%s)' % self.expr(msg) return 'fprintf(stderr, "%%s\\n", %s); abort();' % msg + + def OP_INSTRUMENT_COUNT(self, op): + counter_label = op.args[1].value + self.db.instrument_ncounter = max(self.db.instrument_ncounter, + counter_label+1) + counter_label = self.expr(op.args[1]) + return 'INSTRUMENT_COUNT(%s);' % counter_label assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator) Modified: pypy/branch/mininal-c-backend/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/genc.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/genc.py Thu Nov 23 12:03:10 2006 @@ -5,7 +5,7 @@ from pypy.translator.c.extfunc import pre_include_code_lines from pypy.translator.gensupp import uniquemodulename, NameManager from pypy.translator.tool.cbuild import compile_c_module -from pypy.translator.tool.cbuild import build_executable, CCompiler +from pypy.translator.tool.cbuild import build_executable, CCompiler, ProfOpt 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 @@ -132,6 +132,7 @@ if CBuilder.have___thread is None: CBuilder.have___thread = check_under_under_thread() if not self.standalone: + assert not self.config.translation.instrument from pypy.translator.c.symboltable import SymbolTable # XXX fix symboltable #self.symboltable = SymbolTable() @@ -140,6 +141,8 @@ exports = self.exports, symboltable = self.symboltable) else: + if self.config.translation.instrument: + defines['INSTRUMENT'] = 1 if CBuilder.have___thread: if not self.config.translation.no__thread: defines['USE___THREAD'] = 1 @@ -224,12 +227,19 @@ from distutils import sysconfig python_inc = sysconfig.get_python_inc() cc = self.config.translation.cc - profopt = self.config.translation.profopt + profbased = None + if self.config.translation.instrumentctl is not None: + profbased = self.config.translation.instrumentctl + else: + profopt = self.config.translation.profopt + if profopt is not None: + profbased = (ProfOpt, profopt) + return CCompiler( [self.c_source_filename] + self.extrafiles, include_dirs = [autopath.this_dir, python_inc] + extra_includes, libraries = self.libraries, - compiler_exe = cc, profopt = profopt) + compiler_exe = cc, profbased = profbased) def compile(self): assert self.c_source_filename @@ -641,6 +651,13 @@ gen_startupcode(f, database) f.close() + + if 'INSTRUMENT' in defines: + fi = incfilename.open('a') + n = database.instrument_ncounter + print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n + fi.close() + return filename, sg.getextrafiles() @@ -842,10 +859,13 @@ \trm -f $(OBJECTS) $(TARGET) debug: -\tmake CFLAGS="-g" +\tmake CFLAGS="-g -DRPY_ASSERT" debug_exc: -\tmake CFLAGS="-g -DDO_LOG_EXC" +\tmake CFLAGS="-g -DRPY_ASSERT -DDO_LOG_EXC" + +debug_mem: +\tmake CFLAGS="-g -DRPY_ASSERT -DNO_OBMALLOC" profile: \tmake CFLAGS="-pg $(CFLAGS)" LDFLAGS="-pg $(LDFLAGS)" Modified: pypy/branch/mininal-c-backend/pypy/translator/c/node.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/node.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/node.py Thu Nov 23 12:03:10 2006 @@ -698,8 +698,9 @@ raise ValueError, "trying to compile suggested primitive %r" % ( fnobj._callable,) elif hasattr(fnobj, 'graph'): - cpython_exc = getattr(fnobj, 'exception_policy', None) == "CPython" - return [FunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)] + exception_policy = getattr(fnobj, 'exception_policy', None) + return [FunctionCodeGenerator(fnobj.graph, db, exception_policy, + functionname)] elif getattr(fnobj, 'external', None) == 'C': # deprecated case if hasattr(fnobj, 'includes'): Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/exception.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/exception.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/exception.h Thu Nov 23 12:03:10 2006 @@ -6,7 +6,9 @@ PyObject *RPythonError; #endif -#define RPY_LOG_EXC(exc_type) +/* just a renaming, unless DO_LOG_EXC is set */ +#define RPyExceptionOccurred RPyExceptionOccurred1 +#define RPY_DEBUG_RETURN() /* nothing */ #ifndef PyExceptionClass_Check /* Python < 2.5 */ # define PyExceptionClass_Check(x) PyClass_Check(x) @@ -21,13 +23,27 @@ /******************************************************************/ #ifdef DO_LOG_EXC -#undef RPY_LOG_EXC -#define RPY_LOG_EXC(exc_type) if(exc_type) { \ - fprintf(stderr, "propagating %s:%ld %s %s\n", \ - __FILE__, __LINE__, __FUNCTION__, \ - exc_type->ov_name->items); \ +#undef RPyExceptionOccurred +#undef RPY_DEBUG_RETURN +#define RPyExceptionOccurred() RPyDebugException(" noticing a") +#define RPY_DEBUG_RETURN() RPyDebugException("leaving with") +#define RPyDebugException(msg) ( \ + RPyExceptionOccurred1() \ + ? (RPyDebugReturnShowException(msg, __FILE__, __LINE__, __FUNCTION__), 1) \ + : 0 \ + ) +void RPyDebugReturnShowException(const char *msg, const char *filename, + long lineno, const char *functionname); +#ifndef PYPY_NOT_MAIN_FILE +void RPyDebugReturnShowException(const char *msg, const char *filename, + long lineno, const char *functionname) +{ + fprintf(stderr, "%s %s: %s:%ld %s\n", msg, + RPyFetchExceptionType()->ov_name->items, + filename, lineno, functionname); } #endif +#endif /* DO_LOG_EXC */ /* Hint: functions and macros not defined here, like RPyRaiseException, come from exctransformer via the table in extfunc.py. */ @@ -109,7 +125,7 @@ #else /* non-RPython version of exceptions, using CPython only */ /******************************************************************/ -#define RPyExceptionOccurred() PyErr_Occurred() +#define RPyExceptionOccurred1() PyErr_Occurred() #define RPyRaiseException(etype, evalue) PyErr_Restore(etype, evalue, NULL) #define RPyFetchException(etypevar, evaluevar, ignored) do { \ PyObject *__tb; \ Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h Thu Nov 23 12:03:10 2006 @@ -30,6 +30,8 @@ #include "src/float.h" #include "src/address.h" +#include "src/instrument.h" + /* optional assembler bits */ #if defined(__GNUC__) && defined(__i386__) # include "src/asm_gcc_x86.h" Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h Thu Nov 23 12:03:10 2006 @@ -20,6 +20,9 @@ char *errmsg; int i, exitcode; RPyListOfString *list; + + instrument_setup(); + errmsg = RPython_StartupCode(); if (errmsg) goto error; Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/obmalloc.c ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/obmalloc.c (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/obmalloc.c Thu Nov 23 12:03:10 2006 @@ -430,7 +430,7 @@ if (bp == NULL) return NULL; -#ifdef PYMALLOC_DEBUG +#if 0 /* XXX removed for PyPy - #ifdef PYMALLOC_DEBUG */ if (Py_GETENV("PYTHONMALLOCSTATS")) _PyObject_DebugMallocStats(); #endif @@ -894,6 +894,16 @@ * it wraps a real allocator, adding extra debugging info to the memory blocks. */ +/* XXX added for PyPy for stand-alone usage */ +void Py_FatalError(const char *msg) +{ + fprintf(stderr, "Py_FatalError() called in obmalloc!\n%s\n", msg); + exit(1); +} +#define PyOS_snprintf snprintf +/* end of XXX */ + + /* Special bytes broadcast into debug memory blocks at appropriate times. * Strings of these are unlikely to be valid addresses, floats, ints or * 7-bit ASCII. Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h Thu Nov 23 12:03:10 2006 @@ -5,8 +5,16 @@ #include #ifndef PYPY_NOT_MAIN_FILE -#ifndef WITH_PYMALLOC -#define WITH_PYMALLOC + +#ifdef NO_OBMALLOC +void *PyObject_Malloc(size_t n) { return malloc(n); } +void *PyObject_Realloc(void *p, size_t n) { return realloc(p, n); } +void PyObject_Free(void *p) { if (p) { *((int*)p) = 0xDDDDDDDD; } free(p); } +#else +# ifndef WITH_PYMALLOC +# define WITH_PYMALLOC +# endif +# include "obmalloc.c" #endif -#include "obmalloc.c" + #endif Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/support.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/support.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/support.h Thu Nov 23 12:03:10 2006 @@ -25,6 +25,26 @@ memcpy(itemsarray->items, PyString_AS_STRING(s), \ itemsarray->length) +#ifdef RPY_ASSERT +# define RPyAssert(x, msg) \ + if (!(x)) RPyAssertFailed(__FILE__, __LINE__, __FUNCTION__, msg) + +void RPyAssertFailed(const char* filename, long lineno, + const char* function, const char *msg); +# ifndef PYPY_NOT_MAIN_FILE +void RPyAssertFailed(const char* filename, long lineno, + const char* function, const char *msg) { + fprintf(stderr, + "PyPy assertion failed at %s:%d:\n" + "in %s: %s\n", + filename, lineno, function, msg); + abort(); +} +# endif +#else +# define RPyAssert(x, msg) /* nothing */ +#endif + #ifdef __RPyListOfString_New /* :-( */ # define HAVE_RPY_LIST_OF_STRING #endif Modified: pypy/branch/mininal-c-backend/pypy/translator/c/test/test_standalone.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/test/test_standalone.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/test/test_standalone.py Thu Nov 23 12:03:10 2006 @@ -1,7 +1,10 @@ +import py +import sys, os + from pypy.translator.translator import TranslationContext from pypy.translator.c.genc import CStandaloneBuilder from pypy.annotation.listdef import s_list_of_strings -import os +from pypy.tool.udir import udir def test_hello_world(): @@ -47,3 +50,61 @@ '''argument lengths: [2, 5]\n''') # NB. RPython has only str, not repr, so str() on a list of strings # gives the strings unquoted in the list + +def test_counters(): + if sys.platform == 'win32': + py.test.skip("instrument counters support is unix only for now") + from pypy.rpython.lltypesystem import lltype + from pypy.rpython.lltypesystem.lloperation import llop + def entry_point(argv): + llop.instrument_count(lltype.Void, 'test', 2) + llop.instrument_count(lltype.Void, 'test', 1) + llop.instrument_count(lltype.Void, 'test', 1) + llop.instrument_count(lltype.Void, 'test', 2) + llop.instrument_count(lltype.Void, 'test', 1) + return 0 + t = TranslationContext() + t.config.translation.instrument = True + t.buildannotator().build_types(entry_point, [s_list_of_strings]) + t.buildrtyper().specialize() + + cbuilder = CStandaloneBuilder(t, entry_point, config=t.config) # xxx + cbuilder.generate_source() + cbuilder.compile() + + counters_fname = udir.join("_counters_") + os.putenv('_INSTRUMENT_COUNTERS', str(counters_fname)) + try: + data = cbuilder.cmdexec() + finally: + os.unsetenv('_INSTRUMENT_COUNTERS') + + f = counters_fname.open('rb') + counters_data = f.read() + f.close() + + import struct + counters = struct.unpack("LLL", counters_data) + + assert counters == (0,3,2) + +def test_prof_inline(): + if sys.platform == 'win32': + py.test.skip("instrumentation support is unix only for now") + def add(a,b): + return a + b - b + b - b + b - b + b - b + b - b + b - b + b + def entry_point(argv): + tot = 0 + x = int(argv[1]) + while x > 0: + tot = add(tot, x) + x -= 1 + os.write(1, str(tot)) + return 0 + from pypy.translator.interactive import Translation + t = Translation(entry_point, backend='c', standalone=True) + t.backendopt(profile_based_inline="500") + exe = t.compile() + out = py.process.cmdexec("%s 500" % exe) + assert int(out) == 500*501/2 + Modified: pypy/branch/mininal-c-backend/pypy/translator/driver.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/driver.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/driver.py Thu Nov 23 12:03:10 2006 @@ -51,6 +51,31 @@ def backend_to_typesystem(backend): return _BACKEND_TO_TYPESYSTEM.get(backend, 'ootype') + +class Instrument(Exception): + pass + + +class ProfInstrument(object): + name = "profinstrument" + def __init__(self, datafile, compiler): + self.datafile = datafile + self.compiler = compiler + + def first(self): + self.compiler._build() + + def probe(self, exe, args): + from py.compat import subprocess + env = os.environ.copy() + env['_INSTRUMENT_COUNTERS'] = str(self.datafile) + subprocess.call([exe, args], env=env) + + def after(self): + # xxx + os._exit(0) + + class TranslationDriver(SimpleTaskEngine): def __init__(self, setopts=None, default_goal=None, disable=[], @@ -183,6 +208,40 @@ self.entry_point = entry_point self.translator = translator + self.translator.driver_instrument_result = self.instrument_result + + def instrument_result(self, args): + backend, ts = self.get_backend_and_type_system() + if backend != 'c' or sys.platform == 'win32': + raise Exception("instrumentation requires the c backend" + " and unix for now") + from pypy.tool.udir import udir + + datafile = udir.join('_instrument_counters') + makeProfInstrument = lambda compiler: ProfInstrument(datafile, compiler) + + pid = os.fork() + if pid == 0: + # child compiling and running with instrumentation + self.config.translation.instrument = True + self.config.translation.instrumentctl = (makeProfInstrument, + args) + raise Instrument + else: + pid, status = os.waitpid(pid, 0) + if os.WIFEXITED(status): + status = os.WEXITSTATUS(status) + if status != 0: + raise Exception, "instrumentation child failed: %d" % status + else: + raise Exception, "instrumentation child aborted" + import array, struct + n = datafile.size()//struct.calcsize('L') + datafile = datafile.open('rb') + counters = array.array('L') + counters.fromfile(datafile, n) + datafile.close() + return counters def info(self, msg): log.info(msg) @@ -194,9 +253,16 @@ return else: self.log.info("%s..." % title) - res = func() + instrument = False + try: + res = func() + except Instrument: + instrument = True if not func.task_idempotent: self.done[goal] = True + if instrument: + self.proceed('compile') + assert False, 'we should not get here' return res def task_annotate(self): From ale at codespeak.net Thu Nov 23 12:29:25 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 23 Nov 2006 12:29:25 +0100 (CET) Subject: [pypy-svn] r34887 - in pypy/branch/mininal-c-backend/pypy: . annotation annotation/test config doc interpreter interpreter/astcompiler jit/codegen/i386 jit/codegen/i386/test jit/codegen/llgraph jit/codegen/llvm jit/codegen/llvm/lib jit/codegen/llvm/test jit/codegen/ppc jit/codegen/ppc/test jit/hintannotator jit/hintannotator/test jit/timeshifter jit/timeshifter/test jit/tl lang/automata lib lib/constraint lib/distributed lib/pyontology lib/pyontology/test lib/test2 module/__builtin__ module/__builtin__/test module/_file module/_file/test module/_stackless module/_stackless/test module/pypymagic module/pypymagic/test module/rctime/test objspace objspace/cclp objspace/std objspace/std/test rlib rlib/parsing/test rlib/test rpython rpython/lltypesystem rpython/memory/gctransform rpython/test tool/build translator translator/asm/ppcgen translator/backendopt translator/backendopt/test translator/cl translator/cli translator/cli/src translator/cli/test translator/js translator/js/demo/jsdemo translator/js/demo/jsdemo/test translator/js/doc translator/js/modules translator/js/modules/test translator/llvm translator/oosupport translator/test translator/tool Message-ID: <20061123112925.8C2971005A@code0.codespeak.net> Author: ale Date: Thu Nov 23 12:28:43 2006 New Revision: 34887 Added: pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/test/test_genc_ts.py - copied unchanged from r34886, pypy/dist/pypy/jit/codegen/ppc/test/test_genc_ts.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_vdict.py - copied unchanged from r34886, pypy/dist/pypy/jit/timeshifter/test/test_vdict.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/vdict.py - copied unchanged from r34886, pypy/dist/pypy/jit/timeshifter/vdict.py pypy/branch/mininal-c-backend/pypy/lib/distributed/ (props changed) - copied from r34886, pypy/dist/pypy/lib/distributed/ pypy/branch/mininal-c-backend/pypy/lib/distributed/__init__.py - copied unchanged from r34886, pypy/dist/pypy/lib/distributed/__init__.py pypy/branch/mininal-c-backend/pypy/lib/distributed/objkeeper.py - copied unchanged from r34886, pypy/dist/pypy/lib/distributed/objkeeper.py pypy/branch/mininal-c-backend/pypy/lib/distributed/protocol.py - copied unchanged from r34886, pypy/dist/pypy/lib/distributed/protocol.py pypy/branch/mininal-c-backend/pypy/module/_stackless/clonable.py (props changed) - copied unchanged from r34886, pypy/dist/pypy/module/_stackless/clonable.py pypy/branch/mininal-c-backend/pypy/module/_stackless/test/test_clonable.py - copied unchanged from r34886, pypy/dist/pypy/module/_stackless/test/test_clonable.py pypy/branch/mininal-c-backend/pypy/module/pypymagic/test/test_special.py - copied unchanged from r34886, pypy/dist/pypy/module/pypymagic/test/test_special.py pypy/branch/mininal-c-backend/pypy/rpython/controllerentry.py - copied unchanged from r34886, pypy/dist/pypy/rpython/controllerentry.py pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_streamio.py - copied unchanged from r34885, pypy/dist/pypy/translator/cli/test/test_streamio.py pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/support.py - copied unchanged from r34885, pypy/dist/pypy/translator/js/demo/jsdemo/support.py pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/test/ (props changed) - copied from r34885, pypy/dist/pypy/translator/js/demo/jsdemo/test/ pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/test/__init__.py - copied unchanged from r34885, pypy/dist/pypy/translator/js/demo/jsdemo/test/__init__.py pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/test/test_demo.py - copied unchanged from r34885, pypy/dist/pypy/translator/js/demo/jsdemo/test/test_demo.py Removed: pypy/branch/mininal-c-backend/pypy/lib/_osfilewrapper.py pypy/branch/mininal-c-backend/pypy/lib/distributed.py pypy/branch/mininal-c-backend/pypy/lib/test2/test_osfilewrapper.py pypy/branch/mininal-c-backend/pypy/module/__builtin__/test/test_special.py Modified: pypy/branch/mininal-c-backend/pypy/annotation/annrpython.py pypy/branch/mininal-c-backend/pypy/annotation/binaryop.py pypy/branch/mininal-c-backend/pypy/annotation/bookkeeper.py pypy/branch/mininal-c-backend/pypy/annotation/builtin.py pypy/branch/mininal-c-backend/pypy/annotation/dictdef.py pypy/branch/mininal-c-backend/pypy/annotation/model.py pypy/branch/mininal-c-backend/pypy/annotation/test/test_annrpython.py pypy/branch/mininal-c-backend/pypy/annotation/unaryop.py pypy/branch/mininal-c-backend/pypy/config/pypyoption.py pypy/branch/mininal-c-backend/pypy/conftest.py pypy/branch/mininal-c-backend/pypy/doc/_ref.txt pypy/branch/mininal-c-backend/pypy/doc/stackless.txt pypy/branch/mininal-c-backend/pypy/interpreter/astcompiler/pycodegen.py pypy/branch/mininal-c-backend/pypy/interpreter/executioncontext.py pypy/branch/mininal-c-backend/pypy/interpreter/mixedmodule.py pypy/branch/mininal-c-backend/pypy/jit/codegen/i386/rgenop.py pypy/branch/mininal-c-backend/pypy/jit/codegen/i386/test/test_genc_ts.py pypy/branch/mininal-c-backend/pypy/jit/codegen/llgraph/llimpl.py pypy/branch/mininal-c-backend/pypy/jit/codegen/llgraph/rgenop.py pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/ (props changed) pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/llvmjit.py pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/test/test_llvmjit.py pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/conftest.py pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/instruction.py pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/regalloc.py pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/rgenop.py pypy/branch/mininal-c-backend/pypy/jit/hintannotator/model.py pypy/branch/mininal-c-backend/pypy/jit/hintannotator/test/test_annotator.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/hrtyper.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/oop.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rcontainer.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rtimeshift.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rvalue.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_portal.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_promotion.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_timeshift.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_tlc.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/transform.py pypy/branch/mininal-c-backend/pypy/jit/timeshifter/vlist.py pypy/branch/mininal-c-backend/pypy/jit/tl/tlc.py pypy/branch/mininal-c-backend/pypy/lang/automata/dfa.py pypy/branch/mininal-c-backend/pypy/lib/constraint/ (props changed) pypy/branch/mininal-c-backend/pypy/lib/pyontology/constraint_classes.py pypy/branch/mininal-c-backend/pypy/lib/pyontology/pyontology.py pypy/branch/mininal-c-backend/pypy/lib/pyontology/sparql_grammar.py (props changed) pypy/branch/mininal-c-backend/pypy/lib/pyontology/test/test_ontology.py pypy/branch/mininal-c-backend/pypy/lib/pyontology/test/test_sparql.py (contents, props changed) pypy/branch/mininal-c-backend/pypy/lib/stackless.py pypy/branch/mininal-c-backend/pypy/lib/test2/test_binascii.py (props changed) pypy/branch/mininal-c-backend/pypy/lib/test2/test_distributed.py pypy/branch/mininal-c-backend/pypy/module/__builtin__/__init__.py pypy/branch/mininal-c-backend/pypy/module/__builtin__/importing.py pypy/branch/mininal-c-backend/pypy/module/__builtin__/special.py pypy/branch/mininal-c-backend/pypy/module/_file/app_file.py pypy/branch/mininal-c-backend/pypy/module/_file/test/test_file.py pypy/branch/mininal-c-backend/pypy/module/_stackless/__init__.py pypy/branch/mininal-c-backend/pypy/module/_stackless/coroutine.py pypy/branch/mininal-c-backend/pypy/module/_stackless/interp_clonable.py pypy/branch/mininal-c-backend/pypy/module/_stackless/interp_greenlet.py pypy/branch/mininal-c-backend/pypy/module/pypymagic/__init__.py pypy/branch/mininal-c-backend/pypy/module/pypymagic/interp_magic.py pypy/branch/mininal-c-backend/pypy/module/rctime/test/test_rctime.py pypy/branch/mininal-c-backend/pypy/objspace/cclp/misc.py pypy/branch/mininal-c-backend/pypy/objspace/logic.py pypy/branch/mininal-c-backend/pypy/objspace/std/multimethod.py pypy/branch/mininal-c-backend/pypy/objspace/std/objspace.py pypy/branch/mininal-c-backend/pypy/objspace/std/proxyobject.py pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_multimethod.py pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy.py pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy_function.py pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy_internals.py pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_strjoinobject.py pypy/branch/mininal-c-backend/pypy/objspace/std/transparent.py pypy/branch/mininal-c-backend/pypy/rlib/objectmodel.py pypy/branch/mininal-c-backend/pypy/rlib/parsing/test/test_ebnfparse.py pypy/branch/mininal-c-backend/pypy/rlib/streamio.py pypy/branch/mininal-c-backend/pypy/rlib/test/test_streamio.py pypy/branch/mininal-c-backend/pypy/rpython/annlowlevel.py pypy/branch/mininal-c-backend/pypy/rpython/callparse.py pypy/branch/mininal-c-backend/pypy/rpython/llinterp.py pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/lloperation.py pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/opimpl.py pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rdict.py pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rlist.py pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rstr.py pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rtupletype.py pypy/branch/mininal-c-backend/pypy/rpython/memory/gctransform/framework.py pypy/branch/mininal-c-backend/pypy/rpython/memory/gctransform/transform.py pypy/branch/mininal-c-backend/pypy/rpython/rbuiltin.py pypy/branch/mininal-c-backend/pypy/rpython/rint.py pypy/branch/mininal-c-backend/pypy/rpython/rlist.py pypy/branch/mininal-c-backend/pypy/rpython/rpbc.py pypy/branch/mininal-c-backend/pypy/rpython/rtuple.py pypy/branch/mininal-c-backend/pypy/rpython/test/test_rpbc.py pypy/branch/mininal-c-backend/pypy/rpython/test/test_rtuple.py pypy/branch/mininal-c-backend/pypy/tool/build/README.txt pypy/branch/mininal-c-backend/pypy/translator/asm/ppcgen/ppc_assembler.py pypy/branch/mininal-c-backend/pypy/translator/backendopt/all.py pypy/branch/mininal-c-backend/pypy/translator/backendopt/graphanalyze.py pypy/branch/mininal-c-backend/pypy/translator/backendopt/inline.py pypy/branch/mininal-c-backend/pypy/translator/backendopt/test/test_inline.py pypy/branch/mininal-c-backend/pypy/translator/cl/opformatter.py pypy/branch/mininal-c-backend/pypy/translator/cli/constant.py pypy/branch/mininal-c-backend/pypy/translator/cli/database.py pypy/branch/mininal-c-backend/pypy/translator/cli/dotnet.py pypy/branch/mininal-c-backend/pypy/translator/cli/function.py pypy/branch/mininal-c-backend/pypy/translator/cli/ilgenerator.py pypy/branch/mininal-c-backend/pypy/translator/cli/src/pypylib.cs pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_constant.py pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_dict.py pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_dotnet.py pypy/branch/mininal-c-backend/pypy/translator/interactive.py pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/example.py pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/pythonconsole.py pypy/branch/mininal-c-backend/pypy/translator/js/doc/dom.txt pypy/branch/mininal-c-backend/pypy/translator/js/modules/dom.py pypy/branch/mininal-c-backend/pypy/translator/js/modules/test/test_dom.py pypy/branch/mininal-c-backend/pypy/translator/js/opcodes.py pypy/branch/mininal-c-backend/pypy/translator/llvm/opwriter.py pypy/branch/mininal-c-backend/pypy/translator/oosupport/constant.py pypy/branch/mininal-c-backend/pypy/translator/test/test_interactive.py pypy/branch/mininal-c-backend/pypy/translator/tool/cbuild.py pypy/branch/mininal-c-backend/pypy/translator/tool/pdbplus.py Log: svn merge -r 34627:HEAD to branch Modified: pypy/branch/mininal-c-backend/pypy/annotation/annrpython.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/annotation/annrpython.py (original) +++ pypy/branch/mininal-c-backend/pypy/annotation/annrpython.py Thu Nov 23 12:28:43 2006 @@ -564,6 +564,10 @@ # later by reflowing). Throw the BlockedInference up to # processblock(). raise + + except annmodel.HarmlesslyBlocked: + return + else: # dead code removal: don't follow all exits if the exitswitch # is known Modified: pypy/branch/mininal-c-backend/pypy/annotation/binaryop.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/annotation/binaryop.py (original) +++ pypy/branch/mininal-c-backend/pypy/annotation/binaryop.py Thu Nov 23 12:28:43 2006 @@ -5,7 +5,7 @@ import py import operator from pypy.annotation.pairtype import pair, pairtype -from pypy.annotation.model import SomeObject, SomeInteger, SomeBool +from pypy.annotation.model import SomeObject, SomeInteger, SomeBool, s_Bool from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeUnicodeCodePoint from pypy.annotation.model import SomeTuple, SomeImpossibleValue, s_ImpossibleValue @@ -112,42 +112,42 @@ return immutablevalue(obj1.const < obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) - return SomeBool() + return s_Bool def le((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const <= obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) - return SomeBool() + return s_Bool def eq((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const == obj2.const) else: getbookkeeper().count("non_int_eq", obj1, obj2) - return SomeBool() + return s_Bool def ne((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const != obj2.const) else: getbookkeeper().count("non_int_eq", obj1, obj2) - return SomeBool() + return s_Bool def gt((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const > obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) - return SomeBool() + return s_Bool def ge((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(obj1.const >= obj2.const) else: getbookkeeper().count("non_int_comp", obj1, obj2) - return SomeBool() + return s_Bool def cmp((obj1, obj2)): getbookkeeper().count("cmp", obj1, obj2) @@ -270,16 +270,15 @@ pow_ovf = _clone(pow, [ZeroDivisionError, OverflowError]) def _compare_helper((int1, int2), opname, operation): + r = SomeBool() if int1.is_immutable_constant() and int2.is_immutable_constant(): - r = immutablevalue(operation(int1.const, int2.const)) + r.const = operation(int1.const, int2.const) else: # XXX VERY temporary hack if (opname == 'ge' and int2.is_immutable_constant() and int2.const == 0 and not rarithmetic.signedtype(int1.knowntype)): - r = immutablevalue(True) - else: - r = SomeBool() + r.const = True knowntypedata = {} # XXX HACK HACK HACK # propagate nonneg information between the two arguments @@ -335,6 +334,36 @@ s.knowntypedata = ktd return s + def and_((boo1, boo2)): + s = SomeBool() + if boo1.is_constant(): + if not boo1.const: + s.const = False + else: + return boo2 + if boo2.is_constant(): + if not boo2.const: + s.const = False + return s + + def or_((boo1, boo2)): + s = SomeBool() + if boo1.is_constant(): + if boo1.const: + s.const = True + else: + return boo2 + if boo2.is_constant(): + if boo2.const: + s.const = True + return s + + def xor((boo1, boo2)): + s = SomeBool() + if boo1.is_constant() and boo2.is_constant(): + s.const = boo1.const ^ boo2.const + return s + class __extend__(pairtype(SomeString, SomeString)): def union((str1, str2)): @@ -386,7 +415,7 @@ def eq((lst1, lst2)): lst1.listdef.agree(lst2.listdef) - return SomeBool() + return s_Bool ne = eq Modified: pypy/branch/mininal-c-backend/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/annotation/bookkeeper.py (original) +++ pypy/branch/mininal-c-backend/pypy/annotation/bookkeeper.py Thu Nov 23 12:28:43 2006 @@ -247,6 +247,8 @@ def consider_call_site_for_pbc(self, s_callable, opname, args_s, s_result): descs = s_callable.descriptions.keys() + if not descs: + return family = descs[0].getcallfamily() args = self.build_args(opname, args_s) s_callable.getKind().consider_call_site(self, family, descs, args, Modified: pypy/branch/mininal-c-backend/pypy/annotation/builtin.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/annotation/builtin.py (original) +++ pypy/branch/mininal-c-backend/pypy/annotation/builtin.py Thu Nov 23 12:28:43 2006 @@ -4,13 +4,13 @@ import sys from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool -from pypy.annotation.model import SomeString, SomeTuple, SomeSlice +from pypy.annotation.model import SomeString, SomeTuple, SomeSlice, s_Bool from pypy.annotation.model import SomeUnicodeCodePoint, SomeAddress from pypy.annotation.model import SomeFloat, SomeWeakGcAddress, unionof from pypy.annotation.model import SomePBC, SomeInstance, SomeDict from pypy.annotation.model import SomeExternalObject from pypy.annotation.model import annotation_to_lltype, lltype_to_annotation, ll_to_annotation -from pypy.annotation.model import add_knowntypedata +from pypy.annotation.model import add_knowntypedata, not_const from pypy.annotation.model import s_ImpossibleValue from pypy.annotation.bookkeeper import getbookkeeper from pypy.annotation import description @@ -299,7 +299,7 @@ return immutablevalue(None) def robjmodel_hint(s, **kwds_s): - return s + return not_const(s) def llmemory_cast_ptr_to_adr(s): return SomeAddress() @@ -339,7 +339,7 @@ raise TypeError, "unicodedate.decimal() calls should not happen at interp-level" def test(*args): - return SomeBool() + return s_Bool def import_func(*args): return SomeObject() @@ -517,7 +517,7 @@ def instanceof(i, I): assert I.is_constant() assert isinstance(I.const, ootype.Instance) - return SomeBool() + return s_Bool def classof(i): assert isinstance(i, SomeOOInstance) @@ -526,7 +526,7 @@ def subclassof(class1, class2): assert isinstance(class1, SomeOOClass) assert isinstance(class2, SomeOOClass) - return SomeBool() + return s_Bool def runtimenew(c): assert isinstance(c, SomeOOClass) Modified: pypy/branch/mininal-c-backend/pypy/annotation/dictdef.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/annotation/dictdef.py (original) +++ pypy/branch/mininal-c-backend/pypy/annotation/dictdef.py Thu Nov 23 12:28:43 2006 @@ -1,5 +1,5 @@ from pypy.annotation.model import SomeObject, s_ImpossibleValue -from pypy.annotation.model import SomeInteger, SomeBool, unionof +from pypy.annotation.model import SomeInteger, s_Bool, unionof from pypy.annotation.model import SomeInstance from pypy.annotation.listdef import ListItem @@ -62,7 +62,7 @@ def check_eqfn(annotator, graph): s = annotator.binding(graph.getreturnvar()) - assert SomeBool().contains(s), ( + assert s_Bool.contains(s), ( "the custom eq function of an r_dict must return a boolean" " (got %r)" % (s,)) self.bookkeeper.emulate_pbc_call(myeq, self.s_rdict_eqfn, [s_key, s_key], Modified: pypy/branch/mininal-c-backend/pypy/annotation/model.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/annotation/model.py (original) +++ pypy/branch/mininal-c-backend/pypy/annotation/model.py Thu Nov 23 12:28:43 2006 @@ -474,6 +474,7 @@ s_None = SomePBC([], can_be_None=True) +s_Bool = SomeBool() s_ImpossibleValue = SomeImpossibleValue() # ____________________________________________________________ @@ -549,7 +550,7 @@ NUMBER = object() annotation_to_ll_map = [ (s_None, lltype.Void), # also matches SomeImpossibleValue() - (SomeBool(), lltype.Bool), + (s_Bool, lltype.Bool), (SomeInteger(knowntype=r_ulonglong), NUMBER), (SomeFloat(), lltype.Float), (SomeChar(), lltype.Char), @@ -658,6 +659,18 @@ r[truth_v] = unionof(ktd1[truth_v], ktd2[truth_v]) return r +def not_const(s_obj): + if s_obj.is_constant(): + new_s_obj = SomeObject() + new_s_obj.__class__ = s_obj.__class__ + dic = new_s_obj.__dict__ = s_obj.__dict__.copy() + if 'const' in dic: + del new_s_obj.const + else: + del new_s_obj.const_box + s_obj = new_s_obj + return s_obj + # ____________________________________________________________ # internal @@ -700,6 +713,11 @@ return s_ImpossibleValue setattr(cls, name, default_op) +class HarmlesslyBlocked(Exception): + """Raised by the unaryop/binaryop to signal a harmless kind of + BlockedInference: the current block is blocked, but not in a way + that gives 'Blocked block' errors at the end of annotation.""" + # # safety check that no-one is trying to make annotation and translation # faster by providing the -O option to Python. Modified: pypy/branch/mininal-c-backend/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/annotation/test/test_annrpython.py (original) +++ pypy/branch/mininal-c-backend/pypy/annotation/test/test_annrpython.py Thu Nov 23 12:28:43 2006 @@ -1,9 +1,11 @@ import autopath import py.test +from pypy import conftest from pypy.tool.udir import udir -from pypy.annotation.annrpython import annmodel +from pypy.annotation import model as annmodel +from pypy.annotation.annrpython import RPythonAnnotator as _RPythonAnnotator from pypy.translator.translator import graphof as tgraphof from pypy.annotation import policy from pypy.annotation import specialize @@ -42,7 +44,15 @@ def setup_class(cls): cls.space = FlowObjSpace() - from pypy.annotation.annrpython import RPythonAnnotator + def teardown_method(self, meth): + assert annmodel.s_Bool == annmodel.SomeBool() + + class RPythonAnnotator(_RPythonAnnotator): + def build_types(self, *args): + s = _RPythonAnnotator.build_types(self, *args) + if conftest.option.view: + self.translator.view() + return s def make_fun(self, func): import inspect @@ -55,11 +65,6 @@ funcgraph.source = inspect.getsource(func) return funcgraph - def show(self, a): - from pypy import conftest - if conftest.option.view: - a.translator.view() - def test_simple_func(self): """ one test source: @@ -2293,7 +2298,6 @@ a = self.RPythonAnnotator() a.build_types(f, []) - self.show(a) v1, v2 = graphof(a, readout).getargs() assert not a.bindings[v1].is_constant() assert not a.bindings[v2].is_constant() @@ -2323,7 +2327,6 @@ a = self.RPythonAnnotator() s = a.build_types(fun, [int]) - self.show(a) assert isinstance(s, annmodel.SomeChar) def test_range_nonneg(self): @@ -2334,7 +2337,6 @@ return 0 a = self.RPythonAnnotator() s = a.build_types(fun, [int, int]) - self.show(a) assert isinstance(s, annmodel.SomeInteger) assert s.nonneg @@ -2346,7 +2348,6 @@ return 0 a = self.RPythonAnnotator() s = a.build_types(fun, [int, int]) - self.show(a) assert isinstance(s, annmodel.SomeInteger) assert s.nonneg @@ -2403,6 +2404,40 @@ from pypy.annotation.classdef import NoSuchSlotError py.test.raises(NoSuchSlotError, a.build_types, fun, [int]) + + def test_simple_controllerentry(self): + from pypy.rpython.controllerentry import Controller, ControllerEntry + + class C: + "Imagine some magic here to have a foo attribute on instances" + + def fun(): + lst = [] + c = C() + c.foo = lst # side-effect on lst! well, it's a test + return c.foo, lst[0] + + class C_Controller(Controller): + knowntype = C + + def new(self): + return "4" + + def get_foo(self, obj): + return obj + "2" + + def set_foo(self, obj, value): + value.append(obj) + + class Entry(ControllerEntry): + _about_ = C + _controller_ = C_Controller + + a = self.RPythonAnnotator(policy=policy.AnnotatorPolicy()) + s = a.build_types(fun, []) + assert s.const == ("42", "4") + + def g(n): return [0,1,2,n] Modified: pypy/branch/mininal-c-backend/pypy/annotation/unaryop.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/annotation/unaryop.py (original) +++ pypy/branch/mininal-c-backend/pypy/annotation/unaryop.py Thu Nov 23 12:28:43 2006 @@ -7,8 +7,8 @@ SomeDict, SomeUnicodeCodePoint, SomeTuple, SomeImpossibleValue, \ SomeInstance, SomeBuiltin, SomeFloat, SomeIterator, SomePBC, \ SomeExternalObject, SomeTypedAddressAccess, SomeAddress, \ - SomeCTypesObject, s_ImpossibleValue, \ - unionof, set, missing_operation, add_knowntypedata + SomeCTypesObject, s_ImpossibleValue, s_Bool, \ + unionof, set, missing_operation, add_knowntypedata, HarmlesslyBlocked from pypy.annotation.bookkeeper import getbookkeeper from pypy.annotation import builtin from pypy.annotation.binaryop import _clone ## XXX where to put this? @@ -60,24 +60,22 @@ s_cls, vars) if obj.is_constant() and s_cls.is_constant(): return immutablevalue(issubclass(obj.const, s_cls.const)) - return SomeBool() + return s_Bool def len(obj): return SomeInteger(nonneg=True) - def is_true_behavior(obj): + def is_true_behavior(obj, s): if obj.is_immutable_constant(): - return immutablevalue(bool(obj.const)) + s.const = bool(obj.const) else: s_len = obj.len() if s_len.is_immutable_constant(): - return immutablevalue(s_len.const > 0) - else: - return SomeBool() + s.const = s_len.const > 0 def is_true(s_obj): - r = s_obj.is_true_behavior() - assert isinstance(r, SomeBool) + r = SomeBool() + s_obj.is_true_behavior(r) bk = getbookkeeper() knowntypedata = r.knowntypedata = {} @@ -174,7 +172,7 @@ return SomeObject() def op_contains(obj, s_element): - return SomeBool() + return s_Bool def hint(self, *args_s): return self @@ -192,7 +190,7 @@ def is_true(self): if self.is_immutable_constant(): return getbookkeeper().immutablevalue(bool(self.const)) - return SomeBool() + return s_Bool def hash(flt): return SomeInteger() @@ -318,7 +316,7 @@ def op_contains(lst, s_element): lst.listdef.generalize(s_element) - return SomeBool() + return s_Bool def hint(lst, *args_s): hints = args_s[-1].const @@ -399,16 +397,16 @@ def op_contains(dct, s_element): dct.dictdef.generalize_key(s_element) - return SomeBool() + return s_Bool class __extend__(SomeString): def method_startswith(str, frag): - return SomeBool() + return s_Bool def method_endswith(str, frag): - return SomeBool() + return s_Bool def method_find(str, frag, start=None, end=None): return SomeInteger() @@ -468,22 +466,22 @@ return immutablevalue(1) def method_isspace(chr): - return SomeBool() + return s_Bool def method_isdigit(chr): - return SomeBool() + return s_Bool def method_isalpha(chr): - return SomeBool() + return s_Bool def method_isalnum(chr): - return SomeBool() + return s_Bool def method_islower(chr): - return SomeBool() + return s_Bool def method_isupper(chr): - return SomeBool() + return s_Bool class __extend__(SomeUnicodeCodePoint): @@ -526,6 +524,9 @@ s_result = ins.classdef.lookup_filter(s_result, attr) elif isinstance(s_result, SomeImpossibleValue): ins.classdef.check_missing_attribute_update(attr) + if ins.classdef.classdesc.allslots is not None: + if attr in ins.classdef.classdesc.allslots: + raise HarmlesslyBlocked("getattr on a slot") return s_result return SomeObject() getattr.can_only_throw = [] @@ -548,11 +549,9 @@ getbookkeeper().needs_hash_support[ins.classdef] = True return SomeInteger() - def is_true_behavior(ins): - if ins.can_be_None: - return SomeBool() - else: - return immutablevalue(True) + def is_true_behavior(ins, s): + if not ins.can_be_None: + s.const = True class __extend__(SomeBuiltin): @@ -594,13 +593,11 @@ d = [desc.bind_under(classdef, name) for desc in pbc.descriptions] return SomePBC(d, can_be_None=pbc.can_be_None) - def is_true_behavior(pbc): + def is_true_behavior(pbc, s): if pbc.isNone(): - return immutablevalue(False) - elif pbc.can_be_None: - return SomeBool() - else: - return immutablevalue(True) + s.const = False + elif not pbc.can_be_None: + s.const = True class __extend__(SomeExternalObject): @@ -649,7 +646,7 @@ return ll_to_annotation(v) def is_true(p): - return SomeBool() + return s_Bool class __extend__(SomeExternalBuiltin): def getattr(p, s_attr): @@ -680,7 +677,7 @@ return obj.knowntype.get_field(name) def is_true(p): - return SomeBool() + return s_Bool class __extend__(SomeLLADTMeth): @@ -706,7 +703,7 @@ setattr(r.ootype._example(), s_attr.const, v._example()) def is_true(p): - return SomeBool() + return s_Bool class __extend__(SomeOOBoundMeth): def simple_call(m, *args_s): @@ -739,7 +736,7 @@ return SomeObject() def is_true(cto): - return SomeBool() + return s_Bool def simple_call(cto, *args_s): # for variables containing ctypes function pointers @@ -761,4 +758,4 @@ getattr.can_only_throw = [] def is_true(s_addr): - return SomeBool() + return s_Bool Modified: pypy/branch/mininal-c-backend/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/config/pypyoption.py (original) +++ pypy/branch/mininal-c-backend/pypy/config/pypyoption.py Thu Nov 23 12:28:43 2006 @@ -1,6 +1,6 @@ import autopath import py, os -from pypy.config.config import OptionDescription, BoolOption, IntOption +from pypy.config.config import OptionDescription, BoolOption, IntOption, ArbitraryOption from pypy.config.config import ChoiceOption, StrOption, to_optparse, Config modulepath = py.magic.autopath().dirpath().dirpath().join("module") @@ -58,6 +58,9 @@ BoolOption("logbytecodes", "keep track of bytecode usage", default=False), + + BoolOption("usepycfiles", "Write and read pyc files when importing", + default=True), OptionDescription("std", "Standard Object Space Options", [ BoolOption("withtproxy", "support transparent proxies", @@ -159,6 +162,12 @@ BoolOption("debug_transform", "Perform the debug transformation", default=False, cmdline="--debug-transform", negation=False), + BoolOption("instrument", "internal: turn instrumentation on", + default=False, cmdline=None), + + ArbitraryOption("instrumentctl", "internal", + default=None), + # portability options BoolOption("vanilla", "Try to be as portable as possible, which is not much", @@ -203,6 +212,10 @@ "optimizer remove the asserts", default=False), IntOption("inline_threshold", "Threshold when to inline functions", default=1, cmdline=None), + StrOption("profile_based_inline", + "Use call count profiling to drive inlining" + ", specify arguments", + default=None, cmdline="--prof-based-inline"), ]), OptionDescription("cli", "GenCLI options", [ Modified: pypy/branch/mininal-c-backend/pypy/conftest.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/conftest.py (original) +++ pypy/branch/mininal-c-backend/pypy/conftest.py Thu Nov 23 12:28:43 2006 @@ -113,6 +113,9 @@ def unpackiterable(self, itr): return list(itr) + def is_true(self, obj): + return bool(obj) + class OpErrKeyboardInterrupt(KeyboardInterrupt): pass Modified: pypy/branch/mininal-c-backend/pypy/doc/_ref.txt ============================================================================== --- pypy/branch/mininal-c-backend/pypy/doc/_ref.txt (original) +++ pypy/branch/mininal-c-backend/pypy/doc/_ref.txt Thu Nov 23 12:28:43 2006 @@ -1,4 +1,5 @@ .. _`demo/`: ../../demo +.. _`demo/pickle_coroutine.py`: ../../demo/pickle_coroutine.py .. _`lib-python/`: ../../lib-python .. _`lib-python/2.4.1/dis.py`: ../../lib-python/2.4.1/dis.py .. _`annotation/`: @@ -48,7 +49,10 @@ .. _`objspace/thunk.py`: ../../pypy/objspace/thunk.py .. _`objspace/trace.py`: .. _`pypy/objspace/trace.py`: ../../pypy/objspace/trace.py +.. _`pypy/rlib`: ../../pypy/rlib .. _`pypy/rlib/objectmodel.py`: ../../pypy/rlib/objectmodel.py +.. _`pypy/rlib/rarithmetic.py`: ../../pypy/rlib/rarithmetic.py +.. _`pypy/rlib/test`: ../../pypy/rlib/test .. _`pypy/rpython`: .. _`pypy/rpython/`: .. _`rpython/`: ../../pypy/rpython Modified: pypy/branch/mininal-c-backend/pypy/doc/stackless.txt ============================================================================== --- pypy/branch/mininal-c-backend/pypy/doc/stackless.txt (original) +++ pypy/branch/mininal-c-backend/pypy/doc/stackless.txt Thu Nov 23 12:28:43 2006 @@ -112,6 +112,42 @@ catch it, and that ``try: finally:`` clauses are not honored. This will be fixed in the future.) +Example +~~~~~~~ + +Here is a classical producer/consumer example: an algorithm computes a +sequence of values, while another consumes them. For our purposes we +assume that the producer can generate several values at once, and the +consumer can process up to 3 values in a batch - it can also process +batches with less than 3 values without waiting for the producer (which +would be messy to express with a classical Python generator). :: + + def producer(lst): + while True: + ...compute some more values... + lst.extend(new_values) + coro_consumer.switch() + + def consumer(lst): + while True: + # First ask the producer for more values if needed + while len(lst) == 0: + coro_producer.switch() + # Process the available values in a batch, but at most 3 + batch = lst[:3] + del lst[:3] + ...process batch... + + # Initialize two coroutines with a shared list as argument + exchangelst = [] + coro_producer = coroutine() + coro_producer.bind(producer, exchangelst) + coro_consumer = coroutine() + coro_consumer.bind(consumer, exchangelst) + + # Start running the consumer coroutine + coro_consumer.switch() + Tasklets and channels +++++++++++++++++++++ @@ -135,7 +171,7 @@ as possible. This makes the code somewhat unpythonic. Bird's eye view of tasklets and channels ----------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tasklets are a bit like threads: they encapsulate a function in such a way that they can be suspended/restarted any time. Unlike threads, they won't @@ -158,6 +194,44 @@ is removed from the scheduling queue and will be reinserted when it becomes unblocked. +Example +~~~~~~~ + +Here is a many-producers many-consumers example, where any consumer can +process the result of any producer. For this situation we set up a +single channel where all producer send, and on which all consumers +wait:: + + def producer(chan): + while True: + chan.send(...next value...) + + def consumer(chan): + while True: + x = chan.receive() + ...do something with x... + + # Set up the N producer and M consumer tasklets + common_channel = stackless.channel() + for i in range(N): + stackless.tasklet(producer, common_channel)() + for i in range(M): + stackless.tasklet(consumer, common_channel)() + + # Run it all + stackless.run() + +Each item sent over the channel is received by one of the waiting +consumers; which one is not specified. The producers block until their +item is consumed: the channel is not a queue, but rather a meeting point +which causes tasklets to block until both a consumer and a producer are +ready. In practice, the reason for having several consumers receiving +on a single channel is that some of the consumers can be busy in other +ways part of the time. For example, each consumer might receive a +database request, process it, and send the result to a further channel +before it asks for the next request. In this situation, further +requests can still be received by other consumers. + Greenlets +++++++++ @@ -169,8 +243,14 @@ precise tree, which fully determines their order of execution. For usage reference, see the documentation of the `Py lib greenlets`_. -The PyPy interface is identical, except that the ``greenlet`` class is -in the ``stackless`` module instead of in the ``py.magic`` module. +The PyPy interface is identical. You should use ``py.magic.greenlet`` +instead of ``stackless.greenlet`` directly, because the Py lib can now +give you the latter when you ask for the former on top of PyPy. + +PyPy's greenlets do not suffer from the cyclic GC limitation that the +CPython greenlets have: greenlets referencing each other via local +variables tend to leak on top of CPython (where it is mostly impossible +to do the right thing). It works correctly on top of PyPy. Coroutine Pickling @@ -222,7 +302,99 @@ interface that allows an RPython program to artifically rebuild a chain of calls in a reflective way, completely from scratch, and jump to it. -XXX examples, limitations? +Example +~~~~~~~ + +(See `demo/pickle_coroutine.py`_ for the complete source of this demo.) + +Consider a program which contains a part performing a long-running +computation:: + + def ackermann(x, y): + if x == 0: + return y + 1 + if y == 0: + return ackermann(x - 1, 1) + return ackermann(x - 1, ackermann(x, y - 1)) + +By using pickling, we can save the state of the computation while it is +running, for the purpose of restoring it later and continuing the +computation at another time or on a different machine. However, +pickling does not produce a whole-program dump: it can only pickle +individual coroutines. This means that the computation should be +started in its own coroutine:: + + # Make a coroutine that will run 'ackermann(3, 8)' + coro = coroutine() + coro.bind(ackermann, 3, 8) + + # Now start running the coroutine + result = coro.switch() + +The coroutine itself must switch back to the main program when it needs +to be interrupted (we can only pickle suspended coroutines). Due to +current limitations this requires an explicit check in the +``ackermann()`` function:: + + def ackermann(x, y): + if interrupt_flag: # test a global flag + main.switch() # and switch back to 'main' if it is set + if x == 0: + return y + 1 + if y == 0: + return ackermann(x - 1, 1) + return ackermann(x - 1, ackermann(x, y - 1)) + +The global ``interrupt_flag`` would be set for example by a timeout, or +by a signal handler reacting to Ctrl-C, etc. It causes the coroutine to +transfer control back to the main program. The execution comes back +just after the line ``coro.switch()``, where we can pickle the coroutine +if necessary:: + + if not coro.is_alive: + print "finished; the result is:", result + else: + # save the state of the suspended coroutine + f = open('demo.pickle', 'w') + pickle.dump(coro, f) + f.close() + +The process can then stop. At any later time, or on another machine, +we can reload the file and restart the coroutine with:: + + f = open('demo.pickle', 'r') + coro = pickle.load(f) + f.close() + result = coro.switch() + +Limitations +~~~~~~~~~~~ + +Coroutine pickling is subject to some limitations. First of all, it is +not a whole-program "memory dump". It means that only the "local" state +of a coroutine is saved. The local state is defined to include the +chain of calls and the local variables, but not for example the value of +any global variable. + +As in normal Python, the pickle will not include any function object's +code, any class definition, etc., but only references to functions and +classes. Unlike normal Python, the pickle contains frames. A pickled +frame stores a bytecode index, representing the current execution +position. This means that the user program cannot be modified *at all* +between pickling and unpickling! + +On the other hand, the pickled data is fairly independent from the +platform and from the PyPy version. + +Pickling/unpickling fails if the coroutine is suspended in a state that +involves Python frames which were *indirectly* called. To define this +more precisely, a Python function can issue a regular function or method +call to invoke another Python function - this is a *direct* call and can +be pickled and unpickled. But there are many ways to invoke a Python +function indirectly. For example, most operators can invoke a special +method ``__xyz__()`` on a class, various built-in functions can call +back Python functions, signals can invoke signal handlers, and so on. +These cases are not supported yet. Coroutine Cloning @@ -413,9 +585,34 @@ ...generators_view.getcurrent()... -Then the composition ``grab_values()`` works as expected. - -XXX a few words about how +Then the composition ``grab_values()`` works as expected, because the +two views are independent. The coroutine captured as ``self.caller`` in +the ``generator_iterator.next()`` method is the main coroutine of the +``generators_view``. It is no longer the same object as the main +coroutine of the ``producer_view``, so when ``data_producer()`` issues +the following command:: + + main_coro.switch() + +the control flow cannot accidentally jump back to +``generator_iterator.next()``. In other words, from the point of view +of ``producer_view``, the function ``grab_next_value()`` always runs in +its main coroutine ``main_coro`` and the function ``data_producer`` in +its coroutine ``producer_coro``. This is the case independently of +which ``generators_view``-based coroutine is the current one when +``grab_next_value()`` is called. + +Only code that has explicit access to the ``producer_view`` or its +coroutine objects can perform switches that are relevant for the +generator code. If the view object and the coroutine objects that share +this view are all properly encapsulated inside the generator logic, no +external code can accidentally temper with the expected control flow any +longer. + +In conclusion: we will probably change the app-level interface of PyPy's +stackless module in the future to not expose coroutines and greenlets at +all, but only views. They are not much more difficult to use, and they +scale automatically to larger programs. .. _`Stackless Python`: http://www.stackless.com Modified: pypy/branch/mininal-c-backend/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/branch/mininal-c-backend/pypy/interpreter/astcompiler/pycodegen.py Thu Nov 23 12:28:43 2006 @@ -137,6 +137,8 @@ """Defines basic code generator for Python bytecode """ + localsfullyknown = False + def __init__(self, space, graph): self.space = space self.setups = [] Modified: pypy/branch/mininal-c-backend/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/interpreter/executioncontext.py (original) +++ pypy/branch/mininal-c-backend/pypy/interpreter/executioncontext.py Thu Nov 23 12:28:43 2006 @@ -38,45 +38,41 @@ if not frame.hide(): self.framestack.pop() - # coroutine: subcontext support - def subcontext_new(coobj): - coobj.framestack = new_framestack() - coobj.w_tracefunc = None - coobj.w_profilefunc = None - coobj.is_tracing = 0 - subcontext_new = staticmethod(subcontext_new) - - def subcontext_enter(self, next): - self.framestack = next.framestack - self.w_tracefunc = next.w_tracefunc - self.w_profilefunc = next.w_profilefunc - self.is_tracing = next.is_tracing - - def subcontext_leave(self, current): - current.framestack = self.framestack - current.w_tracefunc = self.w_tracefunc - current.w_profilefunc = self.w_profilefunc - current.is_tracing = self.is_tracing - - # coroutine: I think this is all, folks! - - # well, not quite: we need an interface for pickling - def subcontext_getstate(coobj): - # we just save the framestack - space = coobj.space - items = [space.wrap(item) for item in coobj.framestack.items] - return space.newtuple(items) - subcontext_getstate = staticmethod(subcontext_getstate) - - def subcontext_setstate(coobj, w_state): - from pypy.interpreter.pyframe import PyFrame - space = coobj.space - items = [space.interp_w(PyFrame, item) - for item in space.unpackiterable(w_state)] - coobj.framestack.items = items - subcontext_setstate = staticmethod(subcontext_setstate) - # coroutine: now I really I think this is all, folks! + class Subcontext(object): + # coroutine: subcontext support + + def __init__(self): + self.framestack = new_framestack() + self.w_tracefunc = None + self.w_profilefunc = None + self.is_tracing = 0 + + def enter(self, ec): + ec.framestack = self.framestack + ec.w_tracefunc = self.w_tracefunc + ec.w_profilefunc = self.w_profilefunc + ec.is_tracing = self.is_tracing + + def leave(self, ec): + self.framestack = ec.framestack + self.w_tracefunc = ec.w_tracefunc + self.w_profilefunc = ec.w_profilefunc + self.is_tracing = ec.is_tracing + + # the following interface is for pickling and unpickling + def getstate(self, space): + # we just save the framestack + items = [space.wrap(item) for item in self.framestack.items] + return space.newtuple(items) + + def setstate(self, space, w_state): + from pypy.interpreter.pyframe import PyFrame + items = [space.interp_w(PyFrame, w_item) + for w_item in space.unpackiterable(w_state)] + self.framestack.items = items + # coroutine: I think this is all, folks! + def get_builtin(self): try: Modified: pypy/branch/mininal-c-backend/pypy/interpreter/mixedmodule.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/interpreter/mixedmodule.py (original) +++ pypy/branch/mininal-c-backend/pypy/interpreter/mixedmodule.py Thu Nov 23 12:28:43 2006 @@ -88,7 +88,15 @@ if '__doc__' not in loaders: loaders['__doc__'] = cls.get__doc__ - buildloaders = classmethod(buildloaders) + buildloaders = classmethod(buildloaders) + + def extra_interpdef(self, name, spec): + cls = self.__class__ + pkgroot = cls.__module__ + loader = getinterpevalloader(pkgroot, spec) + space = self.space + w_obj = loader(space) + space.setattr(space.wrap(self), space.wrap(name), w_obj) def get__file__(cls, space): """ NOT_RPYTHON. Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/i386/rgenop.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/i386/rgenop.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/i386/rgenop.py Thu Nov 23 12:28:43 2006 @@ -297,6 +297,12 @@ op = eax return self.returnvar(op) + def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): + self.mc.MOV(edx, gv_ptr.operand(self)) + op = self.itemaddr(edx, arraytoken, gv_index) + self.mc.LEA(eax, op) + return self.returnvar(eax) + def genop_getarraysize(self, arraytoken, gv_ptr): lengthoffset, startoffset, itemoffset = arraytoken self.mc.MOV(edx, gv_ptr.operand(self)) @@ -813,6 +819,9 @@ def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index): return dummy_var + def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): + return dummy_var + def genop_getarraysize(self, arraytoken, gv_ptr): return dummy_var Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/i386/test/test_genc_ts.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/i386/test/test_genc_ts.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/i386/test/test_genc_ts.py Thu Nov 23 12:28:43 2006 @@ -140,6 +140,9 @@ def check_insns(self, expected=None, **counts): "Cannot check instructions in the generated assembler." + def check_flexswitches(self, expected_count): + "Cannot check instructions in the generated assembler." + class TestTimeshiftI386(I386TimeshiftingTestMixin, test_timeshift.TestTimeshift): Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/llgraph/llimpl.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/llgraph/llimpl.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/llgraph/llimpl.py Thu Nov 23 12:28:43 2006 @@ -396,6 +396,7 @@ from pypy import conftest if conftest.option.view: graph = from_opaque_object(graph) + eliminate_empty_blocks(graph) graph.show() # ____________________________________________________________ Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/llgraph/rgenop.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/llgraph/rgenop.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/llgraph/rgenop.py Thu Nov 23 12:28:43 2006 @@ -107,6 +107,11 @@ return LLVar(llimpl.genop(self.b, 'getarrayitem', vars_gv, gv_ITEMTYPE.v)) + def genop_getarraysubstruct(self, gv_ITEMTYPE, gv_ptr, gv_index): + vars_gv = [gv_ptr.v, gv_index.v] + return LLVar(llimpl.genop(self.b, 'getarraysubstruct', vars_gv, + gv_ITEMTYPE.v)) + def genop_setarrayitem(self, gv_ITEMTYPE, gv_ptr, gv_index, gv_value): vars_gv = [gv_ptr.v, gv_index.v, gv_value.v] return LLVar(llimpl.genop(self.b, 'setarrayitem', vars_gv, @@ -232,7 +237,10 @@ @staticmethod @specialize.memo() def arrayToken(A): - return LLConst(llimpl.constTYPE(A.OF)) + ITEMTYPE = A.OF + if isinstance(ITEMTYPE, lltype.ContainerType): + ITEMTYPE = lltype.Ptr(ITEMTYPE) + return LLConst(llimpl.constTYPE(ITEMTYPE)) @staticmethod @specialize.memo() Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Thu Nov 23 12:28:43 2006 @@ -20,59 +20,45 @@ using namespace llvm; -ExecutionEngine* g_execution_engine; +Module* gp_module = new Module("llvmjit"); +ExecutionEngine* gp_execution_engine = ExecutionEngine::create( + new ExistingModuleProvider(gp_module), false); void restart() { - delete g_execution_engine; //XXX test if this correctly cleans up including generated code - g_execution_engine = NULL; + delete gp_execution_engine; //XXX test if this correctly cleans up including generated code + + gp_module = new Module("llvmjit"); + gp_execution_engine = ExecutionEngine::create(new ExistingModuleProvider(gp_module), false); } int compile(const char* llsource) { - Module* module = ParseAssemblyString(llsource, new Module("llvmjit")); + Module* module = ParseAssemblyString(llsource, gp_module); if (!module) { - std::cerr << "Error: can not parse " << llsource << "\n" << std::flush; + std::cerr << "Can not parse:\n" << llsource << "\n" << std::flush; return false; } - //std::ostream *Out = new std::ofstream("temp-libllvmjit.bc", - // std::ios::out | std::ios::trunc | std::ios::binary); - //WriteBytecodeToFile(module, *Out); //XXX what to do with the 3rd param (NoCompress)? - - ModuleProvider* module_provider = new ExistingModuleProvider(module); - if (!g_execution_engine) { - g_execution_engine = ExecutionEngine::create(module_provider, false); - } else { - g_execution_engine->addModuleProvider(module_provider); - } - return true; } void* find_function(const char* name) { - if (!g_execution_engine) return NULL; //note: decided not to be treated as an error - - return g_execution_engine->FindFunctionNamed(name); //note: can be NULL + return gp_execution_engine->FindFunctionNamed(name); //note: can be NULL } int execute(const void* function, int param) { //XXX allow different function signatures - if (!g_execution_engine) { - std::cerr << "Error: no llvm code compiled yet!\n" << std::flush; - return -1; - } - if (!function) { - std::cerr << "Error: no function supplied to libllvmjit.execute(...)\n" << std::flush; + std::cerr << "No function supplied to libllvmjit.execute(...)\n" << std::flush; return -1; } std::vector args; args.push_back((void*)param); - GenericValue gv = g_execution_engine->runFunction((Function*)function, args); + GenericValue gv = gp_execution_engine->runFunction((Function*)function, args); return gv.IntVal; } Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/llvmjit.py Thu Nov 23 12:28:43 2006 @@ -7,6 +7,7 @@ This file contains the ctypes specification to use the llvmjit library! ''' from pypy.rpython.rctypes import implementation +from pypy.rpython.rctypes.tool.util import load_library from ctypes import _CFuncPtr, _FUNCFLAG_CDECL from ctypes import * @@ -31,10 +32,10 @@ if not os.path.exists(path): import py - py.test.skip("libllvmjit.so compilation failed (no llvm headers?)") + py.test.skip("libllvmjit.so compilation failed (no llvm headers or llvm version not up to date?)") #load the actual library -llvmjit = cdll.LoadLibrary(os.path.abspath(path)) +llvmjit = load_library(os.path.abspath(path)) class _FuncPtr(_CFuncPtr): _flags_ = _FUNCFLAG_CDECL # aaarghdistutilsunixaaargh (may need something different for standalone builds...) @@ -56,11 +57,3 @@ execute.restype = c_int execute.argtypes = [c_void_p, c_int] -#helpers... -class FindFunction(object): - def __init__(self, function_name): - self.function = find_function(function_name) - - def __call__(self, param): #XXX this does not seem to translate, how to do it instead? - return execute(self.function, param) - Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/llvm/test/test_llvmjit.py Thu Nov 23 12:28:43 2006 @@ -27,7 +27,9 @@ ret int %n2 }''' -llacross1 = '''declare int %across2(int %n2) +llacross1 = '''declare int %across2(int) + +implementation int %across1(int %n) { block0: @@ -42,7 +44,9 @@ ret int %n3 }''' -llacross2 = '''declare int %across1(int %n2) +llacross2 = '''declare int %across1(int %dsf) + +implementation int %across2(int %n) { block0: @@ -60,10 +64,9 @@ #helpers def execute(llsource, function_name, param): assert llvmjit.compile(llsource) - f = llvmjit.FindFunction(function_name) - assert f.function - return llvmjit.execute(f.function, param) - #return function(param) #XXX this does not seem to translate, how to do it instead? + function = llvmjit.find_function(function_name) + assert function + return llvmjit.execute(function, param) #tests... def test_restart(): @@ -90,6 +93,10 @@ llvmjit.restart() assert execute(llsquare, 'square', 4) == 4 * 4 +def test_execute_nothing(): + llvmjit.restart() + assert llvmjit.execute(None, 4) == -1 #-1 == no function supplied + def test_execute_multiple(): llvmjit.restart() llvmjit.compile(llsquare) @@ -104,13 +111,13 @@ llvmjit.restart() llvmjit.compile(llsquare) llvmjit.compile(llmul2) - square = llvmjit.FindFunction('square') - mul2 = llvmjit.FindFunction('mul2') + square = llvmjit.find_function('square') + mul2 = llvmjit.find_function('mul2') for i in range(5): - assert square(i) == i * i - assert mul2(i) == i * 2 + assert llvmjit.execute(square, i) == i * i + assert llvmjit.execute(mul2 , i) == i * 2 -def DONTtest_execute_across_module(): +def test_execute_across_module(): def my_across1(n): return n * 3 @@ -126,11 +133,11 @@ llvmjit.restart() llvmjit.compile(llacross1) llvmjit.compile(llacross2) - across1to2 = llvmjit.FindFunction('across1to2') - across2to1 = llvmjit.FindFunction('across2to1') + across1to2 = llvmjit.find_function('across1to2') + across2to1 = llvmjit.find_function('across2to1') for i in range(5): - assert across1to2(i) == my_across1to2(i) - assert across2to1(i) == my_across2to1(i) + assert llvmjit.execute(across1to2, i) == my_across1to2(i) + assert llvmjit.execute(across2to1, i) == my_across2to1(i) def DONTtest_modify_global_data(): Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/conftest.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/conftest.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/conftest.py Thu Nov 23 12:28:43 2006 @@ -17,7 +17,10 @@ Option = py.test.Config.Option -option = py.test.Config.addoptions("ppc options", - Option('--trap', action="store_true", default=False, - dest="trap", +option = py.test.Config.addoptions("ppc options", + Option('--trap', action="store_true", default=False, + dest="trap", + help=""), + Option('--debug-print', action="store_true", default=False, + dest="debug_print", help="")) Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/instruction.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/instruction.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/instruction.py Thu Nov 23 12:28:43 2006 @@ -157,6 +157,44 @@ self.result_reg.number, self.imm.value) +class Insn_None__GPR_GPR_IMM(Insn): + def __init__(self, methptr, args): + Insn.__init__(self) + self.methptr = methptr + self.imm = args[2] + + self.result = None + self.result_regclass = NO_REGISTER + self.reg_args = args[:2] + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER] + def allocate(self, allocator): + self.reg1 = allocator.loc_of(self.reg_args[0]) + self.reg2 = allocator.loc_of(self.reg_args[1]) + def emit(self, asm): + self.methptr(asm, + self.reg1.number, + self.reg2.number, + self.imm.value) + +class Insn_None__GPR_GPR_GPR(Insn): + def __init__(self, methptr, args): + Insn.__init__(self) + self.methptr = methptr + + self.result = None + self.result_regclass = NO_REGISTER + self.reg_args = args + self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER, GP_REGISTER] + def allocate(self, allocator): + self.reg1 = allocator.loc_of(self.reg_args[0]) + self.reg2 = allocator.loc_of(self.reg_args[1]) + self.reg3 = allocator.loc_of(self.reg_args[2]) + def emit(self, asm): + self.methptr(asm, + self.reg1.number, + self.reg2.number, + self.reg3.number) + class CMPInsn(Insn): info = (0,0) # please the annotator for tests that don't use CMPW/CMPWI pass @@ -267,10 +305,16 @@ self.argnumber = argnumber self.arg = arg def allocate(self, allocator): - self.loc = allocator.loc_of(self.arg) + from pypy.jit.codegen.ppc.rgenop import Var + if isinstance(self.arg, Var): + self.loc = allocator.loc_of(self.arg) + else: + self.loc = None def emit(self, asm): targetreg = 3+self.argnumber - if self.loc.is_register: + if self.loc is None: + self.arg.load_now(asm, gprs[targetreg]) + elif self.loc.is_register: asm.mr(targetreg, self.loc.number) else: asm.lwz(targetreg, rFP, self.loc.offset) Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/regalloc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/regalloc.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/regalloc.py Thu Nov 23 12:28:43 2006 @@ -4,10 +4,15 @@ CMPInsn, Spill, Unspill, stack_slot, \ rSCRATCH +from pypy.jit.codegen.ppc.conftest import option + +DEBUG_PRINT = option.debug_print + class RegisterAllocation: def __init__(self, freeregs, initial_mapping, initial_spill_offset): - #print - #print "RegisterAllocation __init__", initial_mapping + if DEBUG_PRINT: + print + print "RegisterAllocation __init__", initial_mapping.items() self.insns = [] # output list of instructions @@ -74,7 +79,8 @@ if freeregs: reg = freeregs.pop() self.set(newarg, reg) - #print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) + if DEBUG_PRINT: + print "allocate_reg: Putting %r into fresh register %r" % (newarg, reg) return reg # if not, find something to spill @@ -93,11 +99,13 @@ self.spill(reg, argtospill) - #print "allocate_reg: Spilled %r to %r." % (argtospill, self.loc_of(argtospill)) + if DEBUG_PRINT: + print "allocate_reg: Spilled %r to %r." % (argtospill, self.loc_of(argtospill)) # update data structures to put newarg into the register self.set(newarg, reg) - #print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) + if DEBUG_PRINT: + print "allocate_reg: Put %r in stolen reg %r." % (newarg, reg) return reg def _promote(self, arg): @@ -127,32 +135,37 @@ # Walk through instructions in forward order for insn in insns2: - #print "Processing instruction", insn, - #print "with args", insn.reg_args, "and result", insn.result, ":" + if DEBUG_PRINT: + print "Processing instruction", insn, + print "with args", insn.reg_args, "and result", insn.result, ":" - #print "LRU list was:", self.lru + print "LRU list was:", self.lru # put things into the lru for arg in insn.reg_args: self._promote(arg) if insn.result: self._promote(insn.result) - #print "LRU list is now:", self.lru + if DEBUG_PRINT: + print "LRU list is now:", self.lru # We need to allocate a register for each used # argument that is not already in one for i in range(len(insn.reg_args)): arg = insn.reg_args[i] argcls = insn.reg_arg_regclasses[i] - #print "Allocating register for", arg, "..." + if DEBUG_PRINT: + print "Allocating register for", arg, "..." argloc = self.loc_of(arg) - #print "currently in", argloc + if DEBUG_PRINT: + print "currently in", argloc if not argloc.is_register: # It has no register now because it has been spilled self.forget(arg, argloc) newargloc = self._allocate_reg(argcls, arg) - #print "unspilling to", newargloc + if DEBUG_PRINT: + print "unspilling to", newargloc self.insns.append(Unspill(arg, newargloc, argloc)) self.free_stack_slots.append(argloc) elif argloc.regclass != argcls: @@ -174,13 +187,15 @@ self.insns.append( newargloc.move_from_gpr(self, gpr)) else: - #print "it was in ", argloc + if DEBUG_PRINT: + print "it was in ", argloc pass # Need to allocate a register for the destination assert not insn.result or insn.result not in self.var2loc if insn.result_regclass != NO_REGISTER: - #print "Allocating register for result %r..." % (insn.result,) + if DEBUG_PRINT: + print "Allocating register for result %r..." % (insn.result,) resultreg = self._allocate_reg(insn.result_regclass, insn.result) if isinstance(insn, CMPInsn): self.crfinfo[resultreg.number] = insn.info Modified: pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/codegen/ppc/rgenop.py Thu Nov 23 12:28:43 2006 @@ -14,12 +14,16 @@ from pypy.translator.asm.ppcgen.rassemblermaker import make_rassembler from pypy.translator.asm.ppcgen.ppc_assembler import MyPPCAssembler +from pypy.jit.codegen.i386.rgenop import gc_malloc_fnaddr + class RPPCAssembler(make_rassembler(MyPPCAssembler)): def emit(self, value): self.mc.write(value) NSAVEDREGISTERS = 19 +DEBUG_TRAP = option.trap + _var_index = [0] class Var(GenVar): def __init__(self): @@ -211,19 +215,100 @@ self.insns.append(insn.CALL(gv_result, gv_fnptr)) return gv_result -## def genop_getfield(self, fieldtoken, gv_ptr): -## def genop_setfield(self, fieldtoken, gv_ptr, gv_value): -## def genop_getsubstruct(self, fieldtoken, gv_ptr): -## def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index): -## def genop_getarraysize(self, arraytoken, gv_ptr): -## def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): -## def genop_malloc_fixedsize(self, alloctoken): -## def genop_malloc_varsize(self, varsizealloctoken, gv_size): + def genop_getfield(self, fieldtoken, gv_ptr): + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.lwz, + gv_result, [gv_ptr, IntConst(fieldtoken)])) + return gv_result + + def genop_setfield(self, fieldtoken, gv_ptr, gv_value): + gv_result = Var() + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(RPPCAssembler.stw, + [gv_value, gv_ptr, IntConst(fieldtoken)])) + return gv_result + + def genop_getsubstruct(self, fieldtoken, gv_ptr): + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_result, [gv_ptr, IntConst(fieldtoken)])) + return gv_result + + def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index): + _, _, itemsize = arraytoken + assert itemsize == 4 + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + gv_result = Var() + if gv_itemoffset.fits_in_immediate(): + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.lwz, + gv_result, [gv_ptr, gv_itemoffset])) + else: + self.insns.append( + insn.Insn_GPR__GPR_GPR(RPPCAssembler.lwzx, + gv_result, [gv_ptr, gv_itemoffset])) + return gv_result + + def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): + _, _, itemsize = arraytoken + assert itemsize == 4 + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + gv_result = Var() + if gv_itemoffset.fits_in_immediate(): + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_result, [gv_ptr, gv_itemoffset])) + else: + self.insns.append( + insn.Insn_GPR__GPR_GPR(RPPCAssembler.add, + gv_result, [gv_ptr, gv_itemoffset])) + return gv_result + + def genop_getarraysize(self, arraytoken, gv_ptr): + lengthoffset, _, _ = arraytoken + gv_result = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.lwz, + gv_result, [gv_ptr, IntConst(lengthoffset)])) + return gv_result + + def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): + _, _, itemsize = arraytoken + assert itemsize == 4 + gv_itemoffset = self.itemoffset(arraytoken, gv_index) + gv_result = Var() + if gv_itemoffset.fits_in_immediate(): + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(RPPCAssembler.stw, + [gv_value, gv_ptr, gv_itemoffset])) + else: + self.insns.append( + insn.Insn_None__GPR_GPR_GPR(RPPCAssembler.stwx, + [gv_value, gv_ptr, gv_itemoffset])) + + def genop_malloc_fixedsize(self, alloctoken): + return self.genop_call(1, # COUGH + IntConst(gc_malloc_fnaddr()), + [IntConst(alloctoken)]) + + def genop_malloc_varsize(self, varsizealloctoken, gv_size): + gv_itemoffset = self.itemoffset(varsizealloctoken, gv_size) + gv_result = self.genop_call(1, # COUGH + IntConst(gc_malloc_fnaddr()), + [gv_itemoffset]) + lengthoffset, _, _ = varsizealloctoken + self.insns.append( + insn.Insn_None__GPR_GPR_IMM(RPPCAssembler.stw, + [gv_size, gv_result, IntConst(lengthoffset)])) + return gv_result def genop_same_as(self, kindtoken, gv_arg): if not isinstance(gv_arg, Var): gv_result = Var() gv_arg.load(self.insns, gv_result) + return gv_result else: return gv_arg @@ -330,6 +415,20 @@ # ---------------------------------------------------------------- # ppc-specific interface: + def itemoffset(self, arraytoken, gv_index): + # if gv_index is constant, this can return a constant... + lengthoffset, startoffset, itemsize = arraytoken + + gv_offset = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.mulli, + gv_offset, [gv_index, IntConst(itemsize)])) + gv_itemoffset = Var() + self.insns.append( + insn.Insn_GPR__GPR_IMM(RPPCAssembler.addi, + gv_itemoffset, [gv_offset, IntConst(startoffset)])) + return gv_itemoffset + def make_fresh_from_jump(self, initial_var2loc): self.fresh_from_jump = True self.initial_var2loc = initial_var2loc @@ -337,7 +436,7 @@ def _write_prologue(self, sigtoken): numargs = sigtoken # for now - if not we_are_translated() and option.trap: + if DEBUG_TRAP: self.asm.trap() inputargs = [Var() for i in range(numargs)] assert self.initial_var2loc is None @@ -371,6 +470,8 @@ # save stack pointer into linkage area and set stack pointer for us. self.asm.stwu(rSP, rSP, -minspace) + self.emit_stack_adjustment() + return inputargs def _var_offset(self, v): @@ -399,8 +500,8 @@ allocator = RegisterAllocation( self.rgenop.freeregs, self.initial_var2loc, self.initial_spill_offset) self.insns = allocator.allocate_for_insns(self.insns) - if self.insns: - self.patch_stack_adjustment(self._stack_size(allocator.spill_offset)) + #if self.insns: + self.patch_stack_adjustment(self._stack_size(allocator.spill_offset)) for insn in self.insns: insn.emit(self.asm) return allocator @@ -549,12 +650,21 @@ insn.CMPWI(self.cmp2info['ne'], gv_result, [gv_arg, self.rgenop.genconst(0)])) return gv_result + def op_bool_not(self, gv_arg): + gv_result = Var() + self.insns.append( + insn.CMPWI(self.cmp2info['eq'], gv_result, [gv_arg, self.rgenop.genconst(0)])) + return gv_result + def op_int_neg(self, gv_arg): gv_result = Var() self.insns.append( insn.Insn_GPR__GPR(RPPCAssembler.neg, gv_result, gv_arg)) return gv_result + op_ptr_nonzero = op_int_is_true + op_ptr_iszero = op_bool_not # for now + class RPPCGenOp(AbstractRGenOp): @@ -607,21 +717,38 @@ ## @staticmethod ## def erasedType(T): -## @staticmethod -## @specialize.memo() -## def fieldToken(T, name): + @staticmethod + @specialize.memo() + def fieldToken(T, name): + return llmemory.offsetof(T, name) -## @staticmethod -## @specialize.memo() -## def allocToken(T): + @staticmethod + @specialize.memo() + def allocToken(T): + return llmemory.sizeof(T) -## @staticmethod -## @specialize.memo() -## def varsizeAllocToken(T): + @staticmethod + @specialize.memo() + def varsizeAllocToken(T): + if isinstance(T, lltype.Array): + return RPPCGenOp.arrayToken(T) + else: + # var-sized structs + arrayfield = T._arrayfld + ARRAYFIELD = getattr(T, arrayfield) + arraytoken = RPPCGenOp.arrayToken(ARRAYFIELD) + length_offset, items_offset, item_size = arraytoken + arrayfield_offset = llmemory.offsetof(T, arrayfield) + return (arrayfield_offset+length_offset, + arrayfield_offset+items_offset, + item_size) -## @staticmethod -## @specialize.memo() -## def arrayToken(A): + @staticmethod + @specialize.memo() + def arrayToken(A): + return (llmemory.ArrayLengthOffset(A), + llmemory.ArrayItemsOffset(A), + llmemory.ItemOffset(A.OF)) @staticmethod @specialize.memo() Modified: pypy/branch/mininal-c-backend/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/hintannotator/model.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/hintannotator/model.py Thu Nov 23 12:28:43 2006 @@ -125,9 +125,10 @@ class SomeLLAbstractValue(annmodel.SomeObject): - def __init__(self, T): + def __init__(self, T, deepfrozen=False): self.concretetype = T assert self.__class__ != SomeLLAbstractValue + self.deepfrozen = deepfrozen def is_green(self, frame=None): return False @@ -138,11 +139,10 @@ def __init__(self, T, origins, eager_concrete=False, myorigin=None, deepfrozen=False): - SomeLLAbstractValue.__init__(self, T) + SomeLLAbstractValue.__init__(self, T, deepfrozen) self.origins = origins self.eager_concrete = eager_concrete self.myorigin = myorigin - self.deepfrozen = deepfrozen assert myorigin is None or myorigin.spaceop is not None def fmt_origins(self, origins): @@ -198,6 +198,7 @@ class SomeLLAbstractContainer(SomeLLAbstractValue): + deepfrozen = False # XXX for now def __init__(self, contentdef): self.contentdef = contentdef @@ -249,6 +250,15 @@ else: return hs.concretetype +def deepunfreeze(hs): + if hs.deepfrozen: + hs1 = annmodel.SomeObject() + hs1.__class__ = hs.__class__ + hs1.__dict__ = hs.__dict__.copy() + hs1.deepfrozen = False + hs = hs1 + return hs + # ____________________________________________________________ # operations @@ -281,7 +291,7 @@ def getfield(hs_v1, hs_fieldname): S = hs_v1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) - return SomeLLAbstractVariable(FIELD_TYPE) + return SomeLLAbstractVariable(FIELD_TYPE, hs_v1.deepfrozen) def setfield(hs_v1, hs_fieldname, hs_value): pass @@ -289,7 +299,7 @@ def getsubstruct(hs_v1, hs_fieldname): S = hs_v1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) - return SomeLLAbstractVariable(lltype.Ptr(FIELD_TYPE)) + return SomeLLAbstractVariable(lltype.Ptr(FIELD_TYPE), hs_v1.deepfrozen) ## def getarrayitem(hs_v1, hs_index): ## ARRAY = hs_v1.concretetype.TO @@ -437,28 +447,44 @@ class __extend__(pairtype(SomeLLAbstractValue, SomeLLAbstractValue)): def getarrayitem((hs_v1, hs_v2)): - return SomeLLAbstractVariable(hs_v1.concretetype.TO.OF) + return SomeLLAbstractVariable(hs_v1.concretetype.TO.OF, + hs_v1.deepfrozen) def setarrayitem((hs_v1, hs_v2), hs_v3): pass + def getarraysubstruct((hs_v1, hs_v2)): + return SomeLLAbstractVariable(lltype.Ptr(hs_v1.concretetype.TO.OF), + hs_v1.deepfrozen) + def union((hs_v1, hs_v2)): + if hs_v1.deepfrozen != hs_v2.deepfrozen: + hs_v1 = deepunfreeze(hs_v1) + hs_v2 = deepunfreeze(hs_v2) + if hs_v1 == hs_v2: + return hs_v1 + return pair(hs_v1, hs_v2).union_frozen_equal() + + def invalid_union((hs_v1, hs_v2)): raise annmodel.UnionError("%s %s don't mix" % (hs_v1, hs_v2)) + union_frozen_equal = invalid_union + class __extend__(pairtype(SomeLLAbstractVariable, SomeLLAbstractConstant), pairtype(SomeLLAbstractConstant, SomeLLAbstractVariable)): - def union((hs_v1, hs_v2)): + def union_frozen_equal((hs_v1, hs_v2)): assert hs_v1.concretetype == hs_v2.concretetype - if getattr(hs_v1, 'eager_concrete', False) or getattr(hs_v2, 'eager_concrete', False): - raise annmodel.UnionError("%s %s don't mix" % (hs_v1, hs_v2)) - return SomeLLAbstractVariable(hs_v1.concretetype) + if (getattr(hs_v1, 'eager_concrete', False) or + getattr(hs_v2, 'eager_concrete', False)): + pair(hs_v1, hs_v2).invalid_union() + return SomeLLAbstractVariable(hs_v1.concretetype, hs_v1.deepfrozen) class __extend__(pairtype(SomeLLAbstractConstant, SomeLLAbstractConstant)): - def union((hs_c1, hs_c2)): + def union_frozen_equal((hs_c1, hs_c2)): assert hs_c1.concretetype == hs_c2.concretetype d = newset(hs_c1.origins, hs_c2.origins) if hs_c1.myorigin is hs_c2.myorigin: @@ -469,7 +495,7 @@ eager_concrete = hs_c1.eager_concrete and hs_c2.eager_concrete, myorigin = myorigin, - deepfrozen = hs_c1.deepfrozen and hs_c2.deepfrozen) + deepfrozen = hs_c1.deepfrozen) def getarrayitem((hs_c1, hs_index)): @@ -496,9 +522,9 @@ class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractContainer)): - def union((hs_cont1, hs_cont2)): + def union_frozen_equal((hs_cont1, hs_cont2)): contentdef = hs_cont1.contentdef.union(hs_cont2.contentdef) - return SomeLLAbstractContainer(contentdef) + return SomeLLAbstractContainer(contentdef) # XXX deepfrozen? def ptr_eq((hs_cont1, hs_cont2)): return SomeLLAbstractConstant(lltype.Bool, {}) @@ -508,15 +534,15 @@ class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractValue)): - def union((hs_cont1, hs_val2)): + def union_frozen_equal((hs_cont1, hs_val2)): hs_cont1.contentdef.mark_degenerated() assert hs_cont1.concretetype == hs_val2.concretetype - return SomeLLAbstractVariable(hs_cont1.concretetype) + return SomeLLAbstractVariable(hs_cont1.concretetype) # XXX deepfrozen? class __extend__(pairtype(SomeLLAbstractValue, SomeLLAbstractContainer)): - def union((hs_val1, hs_cont2)): - return pair(hs_cont2, hs_val1).union() + def union_frozen_equal((hs_val1, hs_cont2)): + return pair(hs_cont2, hs_val1).union_frozen_equal() class __extend__(pairtype(SomeLLAbstractContainer, SomeLLAbstractValue), @@ -550,6 +576,8 @@ operation_name, args = ll_func.oopspec.split('(', 1) assert args.endswith(')') args = args[:-1] + ',' # trailing comma to force tuple syntax + if args.strip() == ',': + args = '()' argnames = ll_func.func_code.co_varnames[:len(args_hs)] d = dict(zip(argnames, args_hs)) argtuple = eval(args, d) Modified: pypy/branch/mininal-c-backend/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/hintannotator/test/test_annotator.py Thu Nov 23 12:28:43 2006 @@ -525,6 +525,17 @@ assert isinstance(ha.binding(v2), SomeLLAbstractConstant) assert ha.binding(v1).deepfrozen +def test_deepfreeze_variables(): + l1 = [[1], [2, 3], [4], []] + def ll_function(i): + i = hint(i, variable=True) + l = hint(l1, deepfreeze=True) + return l[i] + + hs, ha = hannotate(ll_function, [int], annotator=True, policy=P_NOVIRTUAL) + assert isinstance(hs, SomeLLAbstractVariable) + assert hs.deepfrozen + def test_propagate_fixing_across_func_arguments(): def ll_func2(z): z = hint(z, concrete=True) Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/hrtyper.py Thu Nov 23 12:28:43 2006 @@ -160,6 +160,10 @@ if nextgraph not in seen: pending.append(nextgraph) seen[nextgraph] = True + # only keep the hint-annotated graphs that are really useful + self.annotator.translator.graphs = [graph + for graph in self.annotator.translator.graphs + if graph in seen] if view: self.annotator.translator.view() # in the middle for graph in seen: @@ -456,9 +460,9 @@ del link.args[0] # Void link.args = [v_jitstate] + link.args - def generic_translate_operation(self, hop, force=False): + def generic_translate_operation(self, hop): # detect constant-foldable all-green operations - if not force and hop.spaceop.opname not in rtimeshift.FOLDABLE_OPS: + if hop.spaceop.opname not in rtimeshift.FOLDABLE_GREEN_OPS: return None green = True for r_arg in hop.args_r: @@ -492,7 +496,7 @@ [c_opdesc, v_jitstate] + args_v, ts.s_RedBox) - def translate_op_debug_log_exc(self, hop): # don't timeshift debug_log_exc + def translate_op_debug_assert(self, hop): pass def translate_op_keepalive(self,hop): @@ -522,49 +526,39 @@ ts.s_RedBox) # non virtual case 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 - v_argbox, c_fieldname = hop.inputargs(self.getredrepr(PTRTYPE), green_void_repr) v_argbox = hop.llops.as_ptrredbox(v_argbox) + c_deepfrozen = inputconst(lltype.Bool, hop.args_s[0].deepfrozen) structdesc = rcontainer.StructTypeDesc(self.RGenOp, PTRTYPE.TO) fielddesc = structdesc.getfielddesc(c_fieldname.value) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) v_jitstate = hop.llops.getjitstate() return hop.llops.genmixlevelhelpercall(rtimeshift.ll_gengetfield, - [ts.s_JITState, s_fielddesc, ts.s_PtrRedBox], - [v_jitstate, c_fielddesc, v_argbox ], + [ts.s_JITState, annmodel.s_Bool, s_fielddesc, ts.s_PtrRedBox], + [v_jitstate , c_deepfrozen , c_fielddesc, v_argbox ], ts.s_RedBox) def translate_op_getarrayitem(self, hop): 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 v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE), self.getredrepr(lltype.Signed)) + c_deepfrozen = inputconst(lltype.Bool, hop.args_s[0].deepfrozen) fielddesc = rcontainer.ArrayFieldDesc(self.RGenOp, PTRTYPE.TO) c_fielddesc = inputconst(lltype.Void, fielddesc) s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) v_jitstate = hop.llops.getjitstate() return hop.llops.genmixlevelhelpercall( rtimeshift.ll_gengetarrayitem, - [ts.s_JITState, s_fielddesc, ts.s_RedBox, ts.s_RedBox], - [v_jitstate, c_fielddesc, v_argbox, v_index ], + [ts.s_JITState, annmodel.s_Bool, s_fielddesc, + ts.s_RedBox, ts.s_RedBox], + [v_jitstate, c_deepfrozen, c_fielddesc, + v_argbox, v_index ], ts.s_RedBox) def translate_op_getarraysize(self, hop): - res = self.generic_translate_operation(hop, force=True) - if res is not None: - return res - PTRTYPE = originalconcretetype(hop.args_s[0]) ts = self [v_argbox] = hop.inputargs(self.getredrepr(PTRTYPE)) @@ -652,6 +646,22 @@ [v_jitstate, c_fielddesc, v_argbox ], ts.s_RedBox) + def translate_op_getarraysubstruct(self, hop): + PTRTYPE = originalconcretetype(hop.args_s[0]) + ts = self + v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE), + self.getredrepr(lltype.Signed)) + fielddesc = rcontainer.ArrayFieldDesc(self.RGenOp, PTRTYPE.TO) + c_fielddesc = inputconst(lltype.Void, fielddesc) + s_fielddesc = ts.rtyper.annotator.bookkeeper.immutablevalue(fielddesc) + v_jitstate = hop.llops.getjitstate() + return hop.llops.genmixlevelhelpercall( + rtimeshift.ll_gengetarraysubstruct, + [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_cast_pointer(self, hop): FROM_TYPE = originalconcretetype(hop.args_s[0]) [v_argbox] = hop.inputargs(self.getredrepr(FROM_TYPE)) @@ -685,19 +695,36 @@ ts = self PTRTYPE = originalconcretetype(hop.args_s[0]) v_argbox, = hop.inputargs(self.getredrepr(PTRTYPE)) + v_argbox = hop.llops.as_ptrredbox(v_argbox) v_jitstate = hop.llops.getjitstate() c_reverse = hop.inputconst(lltype.Bool, reverse) return hop.llops.genmixlevelhelpercall(rtimeshift.ll_genptrnonzero, - [ts.s_JITState, ts.s_RedBox, annmodel.SomeBool()], - [v_jitstate, v_argbox, c_reverse ], + [ts.s_JITState, ts.s_PtrRedBox, annmodel.s_Bool], + [v_jitstate , v_argbox , c_reverse ], ts.s_RedBox) def translate_op_ptr_iszero(self, hop): return self.translate_op_ptr_nonzero(hop, reverse=True) + def translate_op_ptr_eq(self, hop, reverse=False): + ts = self + PTRTYPE = originalconcretetype(hop.args_s[0]) + r_ptr = self.getredrepr(PTRTYPE) + v_argbox0, v_argbox1 = hop.inputargs(r_ptr, r_ptr) + v_argbox0 = hop.llops.as_ptrredbox(v_argbox0) + v_argbox1 = hop.llops.as_ptrredbox(v_argbox1) + v_jitstate = hop.llops.getjitstate() + c_reverse = hop.inputconst(lltype.Bool, reverse) + return hop.llops.genmixlevelhelpercall(rtimeshift.ll_genptreq, + [ts.s_JITState, ts.s_PtrRedBox, ts.s_PtrRedBox, annmodel.s_Bool], + [v_jitstate , v_argbox0 , v_argbox1 , c_reverse ], + ts.s_RedBox) + + def translate_op_ptr_ne(self, hop): + return self.translate_op_ptr_eq(hop, reverse=True) - # special operations inserted by the HintGraphTransformer + # special operations inserted by the HintGraphTransformer def translate_op_ensure_queue(self, hop, prefix=''): mpfamily = hop.args_v[0].value @@ -1017,7 +1044,10 @@ # Pass them as constant Nones. ts = self ll_handler = oopspecdesc.ll_handler - missing_args = ((ll_handler.func_code.co_argcount - 2) - + + couldfold = oopspecdesc.couldfold + + missing_args = ((ll_handler.func_code.co_argcount - 2 - couldfold) - len(oopspecdesc.argtuple)) assert missing_args >= 0 if missing_args > 0: @@ -1027,9 +1057,17 @@ args_v.extend([hop.llops.genconst(ll_None)] * missing_args) args_s = [ts.s_RedBox] * len(args_v) + if oopspecdesc.is_method: args_s[0] = ts.s_PtrRedBox # for more precise annotations args_v[0] = hop.llops.as_ptrredbox(args_v[0]) + + if couldfold: + args_s.insert(0, annmodel.s_Bool) + hs_self = hop.args_s[oopspecdesc.argtuple[0].n] + c_deepfrozen = inputconst(lltype.Bool, hs_self.deepfrozen) + args_v.insert(0, c_deepfrozen) + RESULT = originalconcretetype(hop.s_result) if RESULT is lltype.Void: s_result = annmodel.s_None Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/oop.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/oop.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/oop.py Thu Nov 23 12:28:43 2006 @@ -3,6 +3,7 @@ from pypy.jit.timeshifter.rcontainer import cachedtype from pypy.jit.timeshifter import rvalue, rtimeshift from pypy.translator.c import exceptiontransform +from pypy.rlib.unroll import unrolling_iterable class Index: @@ -13,6 +14,8 @@ class OopSpecDesc: __metaclass__ = cachedtype + do_call = None + def __init__(self, hrtyper, fnobj): ll_func = fnobj._callable FUNCTYPE = lltype.typeOf(fnobj) @@ -22,6 +25,8 @@ operation_name, args = ll_func.oopspec.split('(', 1) assert args.endswith(')') args = args[:-1] + ',' # trailing comma to force tuple syntax + if args.strip() == ',': + args = '()' argnames = ll_func.func_code.co_varnames[:nb_args] d = dict(zip(argnames, [Index(n) for n in range(nb_args)])) self.argtuple = eval(args, d) @@ -40,21 +45,28 @@ RGenOp = hrtyper.RGenOp self.args_gv = [None] * nb_args - self.gv_fnptr = RGenOp.constPrebuiltGlobal(fnobj._as_ptr()) - self.result_kind = RGenOp.kindToken(FUNCTYPE.RESULT) + fnptr = fnobj._as_ptr() + self.gv_fnptr = RGenOp.constPrebuiltGlobal(fnptr) + result_kind = RGenOp.kindToken(FUNCTYPE.RESULT) + self.result_kind = result_kind if FUNCTYPE.RESULT is lltype.Void: self.errorbox = None else: error_value = exceptiontransform.error_value(FUNCTYPE.RESULT) self.errorbox = rvalue.redbox_from_prebuilt_value(RGenOp, error_value) - self.redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT) + redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT) + self.redboxbuilder = redboxbuilder self.sigtoken = RGenOp.sigToken(FUNCTYPE) if operation_name == 'newlist': typename, method = 'list', 'oop_newlist' SELFTYPE = FUNCTYPE.RESULT.TO self.is_method = False + elif operation_name == 'newdict': + typename, method = 'dict', 'oop_newdict' + SELFTYPE = FUNCTYPE.RESULT.TO + self.is_method = False else: typename, method = operation_name.split('.') method = 'oop_%s_%s' % (typename, method) @@ -65,6 +77,7 @@ None, None, [method]) self.typedesc = vmodule.TypeDesc(hrtyper, SELFTYPE) self.ll_handler = getattr(vmodule, method) + self.couldfold = getattr(self.ll_handler, 'couldfold', False) # exception handling graph = fnobj.graph @@ -72,15 +85,41 @@ self.can_raise = etrafo.raise_analyzer.analyze_direct_call(graph) self.fetch_global_excdata = hrtyper.fetch_global_excdata - def residual_call(self, jitstate, argboxes): + if self.couldfold: + ARGS = FUNCTYPE.ARGS + argpos = unrolling_iterable(enumerate(self.argpositions)) + + def do_call(jitstate, argboxes): + args = (None,)*nb_args + for i, pos in argpos: + if pos >= 0: + T = ARGS[pos] + v = rvalue.ll_getvalue(argboxes[i], T) + args = args[:pos] +(v,) + args[pos+1:] + result = fnptr(*args) + if FUNCTYPE.RESULT == lltype.Void: + return None + return rvalue.ll_fromvalue(jitstate, result) + + self.do_call = do_call + + def residual_call(self, jitstate, argboxes, deepfrozen=False): builder = jitstate.curbuilder args_gv = self.args_gv[:] argpositions = self.argpositions + fold = deepfrozen for i in range(len(argpositions)): pos = argpositions[i] if pos >= 0: gv_arg = argboxes[i].getgenvar(builder) args_gv[pos] = gv_arg + fold &= gv_arg.is_const + if fold: + try: + return self.do_call(jitstate, argboxes) + except Exception, e: + jitstate.residual_exception(e) + return self.errorbox gv_result = builder.genop_call(self.sigtoken, self.gv_fnptr, args_gv) if self.can_raise: self.fetch_global_excdata(jitstate) @@ -88,11 +127,7 @@ def residual_exception(self, jitstate, ExcCls): ll_evalue = get_ll_instance_for_exccls(ExcCls) - ll_etype = ll_evalue.typeptr - etypebox = rvalue.ll_fromvalue(jitstate, ll_etype) - evaluebox = rvalue.ll_fromvalue(jitstate, ll_evalue) - rtimeshift.setexctypebox (jitstate, etypebox ) - rtimeshift.setexcvaluebox(jitstate, evaluebox) + jitstate.residual_ll_exception(ll_evalue) return self.errorbox residual_exception._annspecialcase_ = 'specialize:arg(2)' Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rcontainer.py Thu Nov 23 12:28:43 2006 @@ -2,6 +2,11 @@ from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cachedtype from pypy.jit.timeshifter import rvalue +from pypy.rlib.unroll import unrolling_iterable + +from pypy.rpython.lltypesystem import lloperation +debug_print = lloperation.llop.debug_print +debug_pdb = lloperation.llop.debug_pdb class AbstractContainer(object): __slots__ = [] @@ -15,6 +20,20 @@ def op_getsubstruct(self, jitstate, fielddesc): raise NotImplementedError + +class VirtualContainer(AbstractContainer): + __slots__ = [] + + +class FrozenContainer(AbstractContainer): + __slots__ = [] + + def exactmatch(self, vstruct, outgoingvarboxes, memo): + raise NotImplementedError + + def unfreeze(self, incomingvarboxes, memo): + raise NotImplementedError + # ____________________________________________________________ class StructTypeDesc(object): @@ -23,6 +42,7 @@ arrayfielddesc = None alloctoken = None varsizealloctoken = None + materialize = None def __init__(self, RGenOp, TYPE): self.TYPE = TYPE @@ -58,6 +78,22 @@ self.fielddesc_by_name = fielddesc_by_name self.innermostdesc = innermostdesc + self.immutable = TYPE._hints.get('immutable', False) + self.noidentity = TYPE._hints.get('noidentity', False) + + if self.immutable and self.noidentity: + descs = unrolling_iterable(fielddescs) + def materialize(rgenop, boxes): + s = lltype.malloc(TYPE) + i = 0 + for desc in descs: + v = rvalue.ll_getvalue(boxes[i], desc.RESTYPE) + setattr(s, desc.fieldname, v) + i = i + 1 + return rgenop.genconst(s) + + self.materialize = materialize + def getfielddesc(self, name): return self.fielddesc_by_name[name] @@ -137,7 +173,7 @@ # ____________________________________________________________ -class FrozenVirtualStruct(AbstractContainer): +class FrozenVirtualStruct(FrozenContainer): def __init__(self, typedesc): self.typedesc = typedesc @@ -178,6 +214,7 @@ ownbox = typedesc.factory() contmemo[self] = ownbox vstruct = ownbox.content + assert isinstance(vstruct, VirtualStruct) self_boxes = self.fz_content_boxes for i in range(len(self_boxes)): fz_box = self_boxes[i] @@ -186,11 +223,7 @@ return ownbox -class AbstractStruct(AbstractContainer): - pass - - -class VirtualStruct(AbstractStruct): +class VirtualStruct(VirtualContainer): def __init__(self, typedesc): self.typedesc = typedesc @@ -208,6 +241,17 @@ typedesc = self.typedesc boxes = self.content_boxes self.content_boxes = None + if typedesc.materialize is not None: + for box in boxes: + if box is None or not box.is_constant(): + break + else: + gv = typedesc.materialize(builder.rgenop, boxes) + self.ownbox.genvar = gv + self.ownbox.content = None + return + debug_print(lltype.Void, "FORCE CONTAINER") + #debug_pdb(lltype.Void) genvar = builder.genop_malloc_fixedsize(typedesc.alloctoken) # force the box pointing to this VirtualStruct self.ownbox.genvar = genvar @@ -253,8 +297,46 @@ def op_getsubstruct(self, jitstate, fielddesc): return self.ownbox +# ____________________________________________________________ -class PartialDataStruct(AbstractStruct): +class FrozenPartialDataStruct(AbstractContainer): + + def __init__(self): + self.fz_data = [] + + def getfzbox(self, searchindex): + for index, fzbox in self.fz_data: + if index == searchindex: + return fzbox + else: + return None + + def match(self, box, partialdatamatch): + content = box.content + if not isinstance(content, PartialDataStruct): + return False + + cankeep = {} + for index, subbox in content.data: + selfbox = self.getfzbox(index) + if selfbox is not None and selfbox.is_constant_equal(subbox): + cankeep[index] = None + fullmatch = len(cankeep) == len(self.fz_data) + try: + prevkeep = partialdatamatch[box] + except KeyError: + partialdatamatch[box] = cankeep + else: + if prevkeep is not None: + d = {} + for index in prevkeep: + if index in cankeep: + d[index] = None + partialdatamatch[box] = d + return fullmatch + + +class PartialDataStruct(AbstractContainer): def __init__(self): self.data = [] @@ -276,6 +358,19 @@ else: self.data.append((searchindex, box)) + def partialfreeze(self, memo): + contmemo = memo.containers + assert self not in contmemo # contmemo no longer used + result = contmemo[self] = FrozenPartialDataStruct() + for index, box in self.data: + if box.is_constant(): + frozenbox = box.freeze(memo) + result.fz_data.append((index, frozenbox)) + if len(result.fz_data) == 0: + return None + else: + return result + def copy(self, memo): result = PartialDataStruct() for index, box in self.data: @@ -294,3 +389,18 @@ contmemo[self] = None for index, box in self.data: box.enter_block(incoming, memo) + + def cleanup_partial_data(self, keep): + if keep is None: + return None + j = 0 + data = self.data + for i in range(len(data)): + item = data[i] + if item[0] in keep: + data[j] = item + j += 1 + if j == 0: + return None + del data[j:] + return self Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rtimeshift.py Thu Nov 23 12:28:43 2006 @@ -2,7 +2,7 @@ from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem import lltype, lloperation, llmemory from pypy.jit.hintannotator.model import originalconcretetype -from pypy.jit.timeshifter import rvalue +from pypy.jit.timeshifter import rvalue, rcontainer from pypy.rlib.unroll import unrolling_iterable from pypy.rpython.annlowlevel import cachedtype, base_ptr_lltype from pypy.rpython.annlowlevel import cast_instance_to_base_ptr @@ -10,6 +10,10 @@ FOLDABLE_OPS = dict.fromkeys(lloperation.enum_foldable_ops()) +FOLDABLE_GREEN_OPS = FOLDABLE_OPS.copy() +FOLDABLE_GREEN_OPS['getfield'] = None +FOLDABLE_GREEN_OPS['getarrayitem'] = None + debug_view = lloperation.llop.debug_view debug_print = lloperation.llop.debug_print @@ -96,8 +100,8 @@ genvar = jitstate.curbuilder.genop_malloc_varsize(alloctoken, gv_size) return rvalue.PtrRedBox(contdesc.ptrkind, genvar) -def ll_gengetfield(jitstate, fielddesc, argbox): - if fielddesc.immutable and argbox.is_constant(): +def ll_gengetfield(jitstate, deepfrozen, fielddesc, argbox): + if (fielddesc.immutable or deepfrozen) and argbox.is_constant(): res = getattr(rvalue.ll_getvalue(argbox, fielddesc.PTRTYPE), fielddesc.fieldname) return rvalue.ll_fromvalue(jitstate, res) @@ -113,8 +117,9 @@ return rvalue.ll_fromvalue(jitstate, res) return argbox.op_getsubstruct(jitstate, fielddesc) -def ll_gengetarrayitem(jitstate, fielddesc, argbox, indexbox): - if fielddesc.immutable and argbox.is_constant() and indexbox.is_constant(): +def ll_gengetarrayitem(jitstate, deepfrozen, fielddesc, argbox, indexbox): + if ((fielddesc.immutable or deepfrozen) and argbox.is_constant() + and indexbox.is_constant()): array = rvalue.ll_getvalue(argbox, fielddesc.PTRTYPE) res = array[rvalue.ll_getvalue(indexbox, lltype.Signed)] return rvalue.ll_fromvalue(jitstate, res) @@ -125,6 +130,19 @@ return fielddesc.redboxcls(fielddesc.kind, genvar) +def ll_gengetarraysubstruct(jitstate, fielddesc, argbox, indexbox): + if argbox.is_constant() and indexbox.is_constant(): + array = rvalue.ll_getvalue(argbox, fielddesc.PTRTYPE) + res = array[rvalue.ll_getvalue(indexbox, lltype.Signed)] + return rvalue.ll_fromvalue(jitstate, res) + genvar = jitstate.curbuilder.genop_getarraysubstruct( + fielddesc.arraytoken, + argbox.getgenvar(jitstate.curbuilder), + indexbox.getgenvar(jitstate.curbuilder)) + + return fielddesc.redboxcls(fielddesc.kind, genvar) + + def ll_gensetarrayitem(jitstate, fielddesc, destbox, indexbox, valuebox): genvar = jitstate.curbuilder.genop_setarrayitem( fielddesc.arraytoken, @@ -149,7 +167,6 @@ if argbox.is_constant(): addr = rvalue.ll_getvalue(argbox, llmemory.Address) return rvalue.ll_fromvalue(jitstate, bool(addr) ^ reverse) - assert isinstance(argbox, rvalue.PtrRedBox) builder = jitstate.curbuilder if argbox.content is None: gv_addr = argbox.getgenvar(builder) @@ -161,6 +178,23 @@ gv_res = builder.rgenop.genconst(True ^ reverse) return rvalue.IntRedBox(builder.rgenop.kindToken(lltype.Bool), gv_res) +def ll_genptreq(jitstate, argbox0, argbox1, reverse): + builder = jitstate.curbuilder + if argbox0.content is not None or argbox1.content is not None: + equal = argbox0.content is argbox1.content + return rvalue.ll_fromvalue(jitstate, equal ^ reverse) + elif argbox0.is_constant() and argbox1.is_constant(): + addr0 = rvalue.ll_getvalue(argbox0, llmemory.Address) + addr1 = rvalue.ll_getvalue(argbox1, llmemory.Address) + return rvalue.ll_fromvalue(jitstate, (addr0 == addr1) ^ reverse) + gv_addr0 = argbox0.getgenvar(builder) + gv_addr1 = argbox1.getgenvar(builder) + if reverse: + gv_res = builder.genop2("ptr_ne", gv_addr0, gv_addr1) + else: + gv_res = builder.genop2("ptr_eq", gv_addr0, gv_addr1) + return rvalue.IntRedBox(builder.rgenop.kindToken(lltype.Bool), gv_res) + # ____________________________________________________________ # other jitstate/graph level operations @@ -185,6 +219,7 @@ outgoingvarboxes = [] res = frozen.exactmatch(jitstate, outgoingvarboxes, memo) assert res, "exactmatch() failed" + cleanup_partial_data(memo.partialdatamatch) newblock = enter_next_block(jitstate, outgoingvarboxes) states_dic[key] = frozen, newblock if global_resumer is not None and global_resumer is not return_marker: @@ -217,6 +252,7 @@ # We need a more general block. Do it by generalizing all the # redboxes from outgoingvarboxes, by making them variables. # Then we make a new block based on this new state. + cleanup_partial_data(memo.partialdatamatch) replace_memo = rvalue.copy_memo() for box in outgoingvarboxes: box.forcevar(jitstate.curbuilder, replace_memo) @@ -228,6 +264,14 @@ return False # continue retrieve_jitstate_for_merge._annspecialcase_ = "specialize:arglltype(2)" +def cleanup_partial_data(partialdatamatch): + # remove entries from PartialDataStruct unless they matched + # their frozen equivalent + for box, keep in partialdatamatch.iteritems(): + content = box.content + if isinstance(content, rcontainer.PartialDataStruct): + box.content = content.cleanup_partial_data(keep) + def merge_generalized(jitstate): resuming = jitstate.resuming if resuming is None: @@ -794,6 +838,17 @@ self.exc_value_box = self.exc_value_box.replace(memo) + def residual_ll_exception(self, ll_evalue): + ll_etype = ll_evalue.typeptr + etypebox = rvalue.ll_fromvalue(self, ll_etype) + evaluebox = rvalue.ll_fromvalue(self, ll_evalue) + setexctypebox (self, etypebox ) + setexcvaluebox(self, evaluebox) + + def residual_exception(self, e): + self.residual_ll_exception(cast_instance_to_base_ptr(e)) + + def ensure_queue(jitstate, DispatchQueueClass): return DispatchQueueClass() ensure_queue._annspecialcase_ = 'specialize:arg(1)' Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/rvalue.py Thu Nov 23 12:28:43 2006 @@ -14,7 +14,9 @@ return Memo() def exactmatch_memo(): - return Memo() + memo = Memo() + memo.partialdatamatch = {} + return memo def copy_memo(): return Memo() @@ -242,29 +244,35 @@ try: return boxmemo[self] except KeyError: + content = self.content if not self.genvar: - assert self.content is not None + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.VirtualContainer) result = FrozenPtrVirtual(self.kind) boxmemo[self] = result - result.fz_content = self.content.freeze(memo) + result.fz_content = content.freeze(memo) + return result + elif self.genvar.is_const: + result = FrozenPtrConst(self.kind, self.genvar) + elif content is None: + result = FrozenPtrVar(self.kind) else: - if self.is_constant(): - result = FrozenPtrConst(self.kind, self.genvar) - else: - result = FrozenPtrVar(self.kind) - # if self.content is not None, it's a PartialDataStruct - # - for now, we always remove it while freezing so that - # we exactly match our frozen version - # XXX unsure if it's the correct place to do that. - # XXX maybe in exactmatch?? - self.content = None + # if self.content is not None, it's a PartialDataStruct + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.PartialDataStruct) + result = FrozenPtrVarWithPartialData(self.kind) boxmemo[self] = result + result.fz_partialcontent = content.partialfreeze(memo) + return result + boxmemo[self] = result return result def getgenvar(self, builder): if not self.genvar: - assert self.content - self.content.force_runtime_container(builder) + content = self.content + from pypy.jit.timeshifter import rcontainer + assert isinstance(content, rcontainer.VirtualContainer) + content.force_runtime_container(builder) assert self.genvar return self.genvar @@ -288,28 +296,21 @@ def __init__(self, kind): self.kind = kind + def is_constant_equal(self, box): + return False -class FrozenIntConst(FrozenValue): - def __init__(self, kind, gv_const): - self.kind = kind - self.gv_const = gv_const +class FrozenConst(FrozenValue): def exactmatch(self, box, outgoingvarboxes, memo): - if (box.is_constant() and - self.gv_const.revealconst(lltype.Signed) == - box.genvar.revealconst(lltype.Signed)): + if self.is_constant_equal(box): return True else: outgoingvarboxes.append(box) return False - def unfreeze(self, incomingvarboxes, memo): - # XXX could return directly the original IntRedBox - return IntRedBox(self.kind, self.gv_const) - -class FrozenIntVar(FrozenValue): +class FrozenVar(FrozenValue): def exactmatch(self, box, outgoingvarboxes, memo): memo = memo.boxes @@ -323,6 +324,25 @@ outgoingvarboxes.append(box) return False + +class FrozenIntConst(FrozenConst): + + def __init__(self, kind, gv_const): + self.kind = kind + self.gv_const = gv_const + + def is_constant_equal(self, box): + return (box.is_constant() and + self.gv_const.revealconst(lltype.Signed) == + box.genvar.revealconst(lltype.Signed)) + + def unfreeze(self, incomingvarboxes, memo): + # XXX could return directly the original IntRedBox + return IntRedBox(self.kind, self.gv_const) + + +class FrozenIntVar(FrozenVar): + def unfreeze(self, incomingvarboxes, memo): memo = memo.boxes if self not in memo: @@ -334,38 +354,22 @@ return memo[self] -class FrozenDoubleConst(FrozenValue): +class FrozenDoubleConst(FrozenConst): def __init__(self, kind, gv_const): self.kind = kind self.gv_const = gv_const - def exactmatch(self, box, outgoingvarboxes, memo): - if (box.is_constant() and - self.gv_const.revealconst(lltype.Float) == - box.genvar.revealconst(lltype.Float)): - return True - else: - outgoingvarboxes.append(box) - return False + def is_constant_equal(self, box): + return (box.is_constant() and + self.gv_const.revealconst(lltype.Float) == + box.genvar.revealconst(lltype.Float)) def unfreeze(self, incomingvarboxes, memo): return DoubleRedBox(self.kind, self.gv_const) -class FrozenDoubleVar(FrozenValue): - - def exactmatch(self, box, outgoingvarboxes, memo): - memo = memo.boxes - if self not in memo: - memo[self] = box - outgoingvarboxes.append(box) - return True - elif memo[self] is box: - return True - else: - outgoingvarboxes.append(box) - return False +class FrozenDoubleVar(FrozenVar): def unfreeze(self, incomingvarboxes, memo): memo = memo.boxes @@ -378,38 +382,32 @@ return memo[self] -class FrozenPtrConst(FrozenValue): +class FrozenPtrConst(FrozenConst): def __init__(self, kind, gv_const): self.kind = kind self.gv_const = gv_const + def is_constant_equal(self, box): + return (box.is_constant() and + self.gv_const.revealconst(llmemory.Address) == + box.genvar.revealconst(llmemory.Address)) + def exactmatch(self, box, outgoingvarboxes, memo): - if (box.is_constant() and - self.gv_const.revealconst(llmemory.Address) == - box.genvar.revealconst(llmemory.Address)): - return True - else: - outgoingvarboxes.append(box) - return False + assert isinstance(box, PtrRedBox) + memo.partialdatamatch[box] = None # could do better + return FrozenConst.exactmatch(self, box, outgoingvarboxes, memo) def unfreeze(self, incomingvarboxes, memo): return PtrRedBox(self.kind, self.gv_const) -class FrozenPtrVar(FrozenValue): +class FrozenPtrVar(FrozenVar): def exactmatch(self, box, outgoingvarboxes, memo): - memo = memo.boxes - if self not in memo: - memo[self] = box - outgoingvarboxes.append(box) - return True - elif memo[self] is box: - return True - else: - outgoingvarboxes.append(box) - return False + assert isinstance(box, PtrRedBox) + memo.partialdatamatch[box] = None + return FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) def unfreeze(self, incomingvarboxes, memo): memo = memo.boxes @@ -422,6 +420,19 @@ return memo[self] +class FrozenPtrVarWithPartialData(FrozenPtrVar): + + def exactmatch(self, box, outgoingvarboxes, memo): + if self.fz_partialcontent is None: + return FrozenPtrVar.exactmatch(self, box, outgoingvarboxes, memo) + assert isinstance(box, PtrRedBox) + partialdatamatch = self.fz_partialcontent.match(box, + memo.partialdatamatch) + # skip the parent's exactmatch()! + exact = FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) + return exact and partialdatamatch + + class FrozenPtrVirtual(FrozenValue): def exactmatch(self, box, outgoingvarboxes, memo): Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_portal.py Thu Nov 23 12:28:43 2006 @@ -3,6 +3,7 @@ from pypy.jit.timeshifter.test.test_timeshift import hannotate, getargtypes from pypy.jit.timeshifter.hrtyper import HintRTyper from pypy.jit.timeshifter.test.test_timeshift import P_NOVIRTUAL +from pypy.jit.timeshifter.test.test_vlist import P_OOPSPEC from pypy.rpython.llinterp import LLInterpreter from pypy.objspace.flow.model import checkgraph, summary from pypy.rlib.objectmodel import hint @@ -12,6 +13,8 @@ class PortalTest(object): from pypy.jit.codegen.llgraph.rgenop import RGenOp + small = True + def setup_class(cls): cls._cache = {} cls._cache_order = [] @@ -52,13 +55,13 @@ self.hrtyper = HintRTyper(ha, self.rtyper, self.RGenOp) origportalgraph = graphof(t, portal) self.hrtyper.specialize(origportalgraph=origportalgraph, - view = conftest.option.view) + view = conftest.option.view and self.small) for graph in ha.translator.graphs: checkgraph(graph) t.graphs.append(graph) - if conftest.option.view: + if conftest.option.view and self.small: t.view() self.postprocess_timeshifting() self.readportalgraph = self.hrtyper.readportalgraph @@ -171,6 +174,21 @@ res = self.timeshift_from_portal(main, recognizeparts, [1, 0], policy=P_NOVIRTUAL) assert not res + def test_dfa_compile3(self): + from pypy.lang.automata.dfa import getautomaton, recognize3 + def main(gets): + auto = getautomaton() + s = ["aaaaaaaaaab", "aaaa"][gets] + return recognize3(auto, s) + + res = self.timeshift_from_portal(main, recognize3, [0], + policy=P_OOPSPEC) + assert res + + res = self.timeshift_from_portal(main, recognize3, [1], + policy=P_OOPSPEC) + assert not res + def test_method_call_promote(self): class Base(object): pass Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_promotion.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_promotion.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_promotion.py Thu Nov 23 12:28:43 2006 @@ -263,3 +263,28 @@ res = self.timeshift(ll_function, [5, 100], [0], policy=P_NOVIRTUAL) assert res == 115 + + def test_remembers_across_mp(self): + def ll_function(x, flag): + hint(None, global_merge_point=True) + hint(x.field, promote=True) + m = x.field + if flag: + m += 1 * flag + else: + m += 2 + flag + hint(x.field, promote=True) + return m + x.field + + S = lltype.GcStruct('S', ('field', lltype.Signed), + hints={'immutable': True}) + + def struct_S(string): + s = lltype.malloc(S) + s.field = int(string) + return s + ll_function.convert_arguments = [struct_S, int] + + res = self.timeshift(ll_function, ["20", 0], [], policy=P_NOVIRTUAL) + assert res == 42 + self.check_flexswitches(1) Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_timeshift.py Thu Nov 23 12:28:43 2006 @@ -5,7 +5,7 @@ from pypy.jit.hintannotator.model import * from pypy.jit.timeshifter.hrtyper import HintRTyper, originalconcretetype from pypy.jit.timeshifter import rtimeshift, rvalue -from pypy.objspace.flow.model import summary +from pypy.objspace.flow.model import summary, Variable from pypy.rpython.lltypesystem import lltype, llmemory, rstr from pypy.rlib.objectmodel import hint, keepalive_until_here from pypy.rlib.unroll import unrolling_iterable @@ -63,6 +63,8 @@ class TimeshiftingTests(object): from pypy.jit.codegen.llgraph.rgenop import RGenOp + small = True + def setup_class(cls): cls._cache = {} cls._cache_order = [] @@ -98,7 +100,7 @@ # make the timeshifted graphs hrtyper = HintRTyper(ha, rtyper, self.RGenOp) - hrtyper.specialize(view = conftest.option.view) + hrtyper.specialize(view = conftest.option.view and self.small) fresh_jitstate = hrtyper.ll_fresh_jitstate finish_jitstate = hrtyper.ll_finish_jitstate @@ -218,7 +220,7 @@ self.rtyper = rtyper self.hrtyper = hrtyper self.annotate_interface_functions() - if conftest.option.view: + if conftest.option.view and self.small: from pypy.translator.tool.graphpage import FlowGraphPage FlowGraphPage(t, ha.translator.graphs).display() @@ -320,6 +322,14 @@ for opname, count in counts.items(): assert self.insns.get(opname, 0) == count + def check_flexswitches(self, expected_count): + count = 0 + for block in self.residual_graph.iterblocks(): + if (isinstance(block.exitswitch, Variable) and + block.exitswitch.concretetype is lltype.Signed): + count += 1 + assert count == expected_count + class TestTimeshift(TimeshiftingTests): @@ -739,6 +749,32 @@ 'setarrayitem': 2, 'getarrayitem': 1, 'getarraysize': 1, 'int_mul': 1}) + def test_red_struct_array(self): + S = lltype.Struct('s', ('x', lltype.Signed)) + A = lltype.GcArray(S) + def ll_function(x, y, n): + a = lltype.malloc(A, 2) + a[0].x = x + a[1].x = y + return a[n].x*len(a) + + res = self.timeshift(ll_function, [21, -21, 0], [], + policy=P_NOVIRTUAL) + assert res == 42 + self.check_insns({'malloc_varsize': 1, 'ptr_iszero': 1, + 'getarraysubstruct': 3, + 'setfield': 2, 'getfield': 1, + 'getarraysize': 1, 'int_mul': 1}) + + res = self.timeshift(ll_function, [21, -21, 1], [], + policy=P_NOVIRTUAL) + assert res == -42 + self.check_insns({'malloc_varsize': 1, 'ptr_iszero': 1, + 'getarraysubstruct': 3, + 'setfield': 2, 'getfield': 1, + 'getarraysize': 1, 'int_mul': 1}) + + def test_red_varsized_struct(self): A = lltype.Array(lltype.Signed) S = lltype.GcStruct('S', ('foo', lltype.Signed), ('a', A)) @@ -1042,3 +1078,13 @@ res = self.timeshift(f, [0], [0], policy=P_NOVIRTUAL) assert res == 42 self.check_insns({}) + + def test_compile_time_const_tuple(self): + d = {(4, 5): 42, (6, 7): 12} + def f(a, b): + d1 = hint(d, deepfreeze=True) + return d1[a, b] + + res = self.timeshift(f, [4, 5], [0, 1], policy=P_NOVIRTUAL) + assert res == 42 + self.check_insns({}) Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_tlc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_tlc.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/test/test_tlc.py Thu Nov 23 12:28:43 2006 @@ -21,6 +21,7 @@ class TestTLC(PortalTest): + small = False def test_factorial(self): code = tlc.compile(FACTORIAL_SOURCE) @@ -36,7 +37,6 @@ assert res == expected def test_nth_item(self): - py.test.skip("in-progress") # get the nth item of a chained list code = tlc.compile(""" NIL @@ -50,6 +50,8 @@ DIV """) bytecode = ','.join([str(ord(c)) for c in code]) - res = self.timeshift(tlc_interp_without_call, [bytecode, 0, 1], - [0, 1], policy=P_OOPSPEC)#, backendoptimize=True) + res = self.timeshift_from_portal(tlc_interp_without_call, + tlc_interp_eval_without_call, + [bytecode, 0, 1], + policy=P_OOPSPEC)#, backendoptimize=True) assert res == 20 Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/transform.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/transform.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/transform.py Thu Nov 23 12:28:43 2006 @@ -442,7 +442,8 @@ if spaceop.opname == 'direct_call': c_func = spaceop.args[0] fnobj = c_func.value._obj - if hasattr(fnobj._callable, 'oopspec'): + if (hasattr(fnobj._callable, 'oopspec') and + getattr(self.hannotator.policy, 'oopspec', False)): return 'oopspec' for v in spaceop.args: Modified: pypy/branch/mininal-c-backend/pypy/jit/timeshifter/vlist.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/timeshifter/vlist.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/timeshifter/vlist.py Thu Nov 23 12:28:43 2006 @@ -1,5 +1,6 @@ from pypy.rpython.lltypesystem import lltype -from pypy.jit.timeshifter.rcontainer import AbstractContainer, cachedtype +from pypy.jit.timeshifter.rcontainer import VirtualContainer, FrozenContainer +from pypy.jit.timeshifter.rcontainer import cachedtype from pypy.jit.timeshifter import rvalue @@ -26,6 +27,9 @@ self.tok_ll_setitem_fast = RGenOp.sigToken( lltype.typeOf(ll_setitem_fast).TO) + def _freeze_(self): + return True + def factory(self, length, itembox): vlist = VirtualList(self, length, itembox) box = rvalue.PtrRedBox(self.ptrkind) @@ -36,7 +40,7 @@ TypeDesc = ListTypeDesc -class FrozenVirtualList(AbstractContainer): +class FrozenVirtualList(FrozenContainer): def __init__(self, typedesc): self.typedesc = typedesc @@ -70,8 +74,26 @@ fullmatch = False return fullmatch + def unfreeze(self, incomingvarboxes, memo): + contmemo = memo.containers + if self in contmemo: + return contmemo[self] + typedesc = self.typedesc + self_boxes = self.fz_item_boxes + length = len(self_boxes) + ownbox = typedesc.factory(length, None) + contmemo[self] = ownbox + vlist = ownbox.content + assert isinstance(vlist, VirtualList) + for i in range(length): + fz_box = self_boxes[i] + vlist.item_boxes[i] = fz_box.unfreeze(incomingvarboxes, + memo) + return ownbox + + -class VirtualList(AbstractContainer): +class VirtualList(VirtualContainer): def __init__(self, typedesc, length=0, itembox=None): self.typedesc = typedesc Modified: pypy/branch/mininal-c-backend/pypy/jit/tl/tlc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/jit/tl/tlc.py (original) +++ pypy/branch/mininal-c-backend/pypy/jit/tl/tlc.py Thu Nov 23 12:28:43 2006 @@ -184,10 +184,14 @@ elif opcode == SUB: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(b.sub(a)) elif opcode == MUL: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(b.mul(a)) elif opcode == DIV: @@ -208,6 +212,8 @@ elif opcode == LE: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(IntObj(not a.lt(b))) elif opcode == GT: @@ -219,7 +225,9 @@ stack.append(IntObj(not b.lt(a))) elif opcode == BR_COND: - if stack.pop().t(): + cond = stack.pop() + hint(cond.__class__, promote=True) + if cond.t(): pc += char2int(code[pc]) pc += 1 Modified: pypy/branch/mininal-c-backend/pypy/lang/automata/dfa.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/lang/automata/dfa.py (original) +++ pypy/branch/mininal-c-backend/pypy/lang/automata/dfa.py Thu Nov 23 12:28:43 2006 @@ -31,7 +31,7 @@ def __repr__(self): from pprint import pformat return "DFA%s" % (pformat( - self.num_states, self.transitions, self.final_states)) + (self.num_states, self.transitions, self.final_states))) def getautomaton(): " simple example of handcrafted dfa " @@ -130,3 +130,24 @@ res = hint(res, concrete=True) res = hint(res, variable=True) return res + +# a version of recognize() full of hints, but otherwise not too modified + +def recognize3(automaton, s): + automaton = hint(automaton, deepfreeze=True) + hint(automaton, concrete=True) + state = 0 + + index = 0 + while index < len(s): + hint(None, global_merge_point=True) + char = s[index] + index += 1 + char = hint(char, promote=True) + try: + state = automaton.get_transition(state, char) + except KeyError: + return False + state = hint(state, promote=True) + + return state in automaton.final_states Modified: pypy/branch/mininal-c-backend/pypy/lib/pyontology/constraint_classes.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/lib/pyontology/constraint_classes.py (original) +++ pypy/branch/mininal-c-backend/pypy/lib/pyontology/constraint_classes.py Thu Nov 23 12:28:43 2006 @@ -1,11 +1,115 @@ from logilab.constraint.propagation import AbstractDomain, AbstractConstraint,\ - ConsistencyFailure + ConsistencyFailure, Solver +from logilab.constraint.distributors import DichotomyDistributor, SplitDistributor +from logilab.constraint.fd import Expression from rdflib import URIRef import autopath import py from pypy.tool.ansi_print import ansi_log log = py.log.Producer("Constraint") py.log.setconsumer("Constraint", None) +import math + +class MySolver(Solver): + + def _solve(self, repository, recursion_level=0): + """main generator""" + solve = self._solve + verbose = self.verbose + if recursion_level > self.max_depth: + self.max_depth = recursion_level + if verbose: + print strftime('%H:%M:%S'), + print '*** [%d] Solve called with repository' % recursion_level, + print repository + try: + foundSolution = repository.consistency(verbose) + except ConsistencyFailure, exc: + if verbose: + print strftime('%H:%M:%S'), exc + pass + else: + if foundSolution: + solution = {} + for variable, domain in repository.getDomains().items(): + solution[variable] = list(domain.getValues())[0] + if verbose: + print strftime('%H:%M:%S'), '### Found Solution', solution + print '-'*80 + yield solution + else: + for repo in repository.distribute(self._distributor, + verbose): + for solution in solve(repo, recursion_level+1): + if solution is not None: + yield solution + + if recursion_level == 0 and self.verbose: + print strftime('%H:%M:%S'),'Finished search' + print strftime('%H:%M:%S'), + print 'Maximum recursion depth = ', self.max_depth + +class MyExpression(Expression): + + def _assign_values(self, domains): + variables = [] + kwargs = {} + for variable in self._variables: + domain = domains[variable] + values = list(domain.getValues()) + variables.append((domain.size(), [variable, values, 0, len(values)])) + kwargs[variable] = values[0] + # sort variables to instanciate those with fewer possible values first + variables.sort() + + go_on = 1 + while go_on: + yield kwargs + # try to instanciate the next variable + for size, curr in variables: + if (curr[2] + 1) < curr[-1]: + curr[2] += 1 + kwargs[curr[0]] = curr[1][curr[2]] + break + else: + curr[2] = 0 + kwargs[curr[0]] = curr[1][0] + else: + # it's over + go_on = 0 + + +class MyDistributor(SplitDistributor): + + def __init__(self): + SplitDistributor.__init__(self,2) + self.to_split = None + + def nb_subdomains(self, domains): + """See AbstractDistributor""" + self.to_split = self.findSmallestDomain(domains) + if self.nb_subspaces: + return min(self.nb_subspaces, domains[self.to_split].size()) + else: + return domains[self.to_split].size() + + def _distribute(self, *args): + """See AbstractDistributor""" + variable = self.to_split + nb_subspaces = len(args) + values = list(args[0][variable].getValues()) + nb_elts = max(1, len(values)*1./nb_subspaces) + slices = [(int(math.floor(index * nb_elts)), + int(math.floor((index + 1) * nb_elts))) + for index in range(nb_subspaces)] + if self.verbose: + print 'Distributing domain for variable', variable + modified = [] + for (dom, (end, start)) in zip(args, slices) : + dom[variable].removeValues(values[:end]) + dom[variable].removeValues(values[start:]) + modified.append(dom[variable]) + return modified class OwlConstraint(AbstractConstraint): @@ -115,7 +219,7 @@ # Narrow the list of properties (instances of some property type) # to those who has a pair (self.variable, self.object) dom = domains[self.prop] - vals = list(dom.getValues()) + vals = dom.getValues() for p in vals: if not ((self.variable, self.object) in domains[p]): dom.removeValue(p) @@ -133,7 +237,7 @@ # to those who has a pair (self.variable, self.object) dom = domains[self.prop] sub = domains[self.variable] - vals = list(dom.getValues()) + vals = dom.getValues() keep = [] for p in vals: items = domains[p].getValuesPrKey() @@ -144,6 +248,36 @@ keep.append(key) sub.removeValues([v for v in sub.getValues() if not v in keep]) +import time +class PropertyConstrain3(AbstractConstraint): + cost = 1 + def __init__(self, prop, variable, cls_or_restriction): + AbstractConstraint.__init__(self, [ prop]) + self.object = cls_or_restriction + self.variable = variable + self.prop = prop + + def narrow(self, domains): + # Narrow the domains of object and variable to those values + # that are connected by self.prop + dom = domains[self.prop] + sub = domains[self.variable] + obj = domains[self.object] + vals_dict = dom._dict + + keep = set() + sub_rem = [] + for v in sub.getValues(): + if not v in vals_dict: + sub_rem.append(v) + #sub.removeValue(v) + else: + for o in dom.getValuesPrKey(v): + keep.add(o) + remove = [x for x in obj.getValues() if not x in keep] + sub.removeValues(sub_rem) + obj.removeValues(remove) + class MemberConstraint(AbstractConstraint): cost = 1 @@ -485,12 +619,13 @@ remove = [] for v in indi: if not v in prop: - dom.removeValue(v) + remove.append(v) else: prop_val = prop[v] for p in prop_val: if not p in val: - dom.removeValue(v) + remove.append(v) + dom.removeValues(remove) class HasvalueConstraint(OneofPropertyConstraint): @@ -502,11 +637,14 @@ property = dom.property indi = dom.getValues() prop = Linkeddict(domains[property].getValues()) + remove = [] for v in indi: if not v in prop: - dom.removeValue(v) + remove.append(v) else: prop_val = prop[v] if not val in prop_val: - dom.removeValue(v) + remove.append(v) + dom.removeValues(remove) + Modified: pypy/branch/mininal-c-backend/pypy/lib/pyontology/pyontology.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/lib/pyontology/pyontology.py (original) +++ pypy/branch/mininal-c-backend/pypy/lib/pyontology/pyontology.py Thu Nov 23 12:28:43 2006 @@ -1,11 +1,13 @@ import autopath from rdflib import Graph, URIRef, BNode, Literal as rdflib_literal -from logilab.constraint import Repository, Solver -from logilab.constraint.fd import Expression, FiniteDomain as fd +from logilab.constraint import Repository +from logilab.constraint.fd import FiniteDomain as fd from logilab.constraint.propagation import AbstractDomain, AbstractConstraint,\ ConsistencyFailure from pypy.lib.pyontology.sparql_grammar import SPARQLGrammar as SP from constraint_classes import * +Solver = MySolver +Expression = MyExpression import sys, py import datetime, time from urllib2 import URLError @@ -170,9 +172,9 @@ self.values[value] = True def getValues(self): - #for key in self.values: - # yield key - return self.values.keys() + for key in self.values: + yield key + #return self.values.keys() def __iter__(self): return iter(self.values.keys()) @@ -228,9 +230,13 @@ def __eq__(self, other): #log("CMP %r,%r %i"%(self.name,other, len(self.differentfrom))) #assert isinstance(other, ClassDomain) - if ((hasattr(other,'uri') and self.uri == other.uri) or - (not hasattr(other,'uri') and self.uri == other) or - other in self.sameas): + if hasattr(other,'uri'): + if self.uri == other.uri: + return True + elif not hasattr(other,'uri'): + if self.uri == other: + return True + elif other in self.sameas: return True if not other or other in self.differentfrom: return False @@ -278,9 +284,7 @@ res = [] for k,vals in items: for v in vals: - #yield (k,v) - res.append((k,v)) - return res + yield (k,v) def getValuesPrKey(self, key= None): if key: @@ -516,8 +520,8 @@ constraint.narrow(self.variables) # except ConsistencyFailure, e: # print "FAilure", e - things = self.variables['owl_Thing'].getValues() - things += self.variables['owl_Literal'].getValues() + things = list(self.variables['owl_Thing'].getValues()) + things += list(self.variables['owl_Literal'].getValues()) self.variables['owl_Thing'].setValues(things) def _sparql(self, query): @@ -648,14 +652,23 @@ query_constr.append(PropertyConstrain2(prop_name, sub_name, obj)) elif case == 5: # return the values of p + #import pdb + ##pdb.set_trace() prop = self.make_var(Property, URIRef(trip[1])) query_dom[prop] = self.variables[prop] - p_vals = self.variables[prop].getValues() + p_vals = list(self.variables[prop].getValues()) sub = self.make_var(Thing, trip[0]) - self.variables[sub].setValues([v[0] for v in p_vals]) + vals = set([v[0] for v in p_vals]) + if self.variables[sub].size(): + vals &= set(self.variables[sub].getValues()) + self.variables[sub].setValues(vals) obj = self.make_var(Thing, trip[2]) - self.variables[obj].setValues([v[1] for v in p_vals]) - con = Expression([sub,prop,obj], "%s == (%s, %s)" %(prop, sub, obj)) + vals = set([v[1] for v in p_vals]) + if self.variables[obj].size(): + vals &= set(self.variables[obj].getValues()) + self.variables[obj].setValues(vals) + con = PropertyConstrain3(prop, sub, obj) +# con = Expression([sub,prop,obj], "%s == (%s, %s)" %(prop, sub, obj)) query_constr.append(con) elif case == 6: @@ -674,9 +687,6 @@ self.variables[prop].setValues(p_vals) sub = self.make_var(Thing, trip[0]) obj = self.make_var(Thing, trip[2]) - things = self.variables['owl_Thing'].getValues() - things += self.variables['owl_Literal'].getValues() - self.variables[obj].setValues(things) con = Expression([sub,prop,obj], "%s[0] == %s and %s[1] == %s" %(prop, sub, prop, obj)) query_constr.append(con) # call finish on the variables in the query @@ -688,20 +698,22 @@ for v in vars]) dom.update(query_dom) - print dom # solve the repository and return the solution rep = Repository(dom.keys(), dom, query_constr) - res_s = Solver().solve(rep, 3) - #res_s = self.solve() + res_s = Solver(MyDistributor()).solve(rep, verbose=0) res = [] + query_vars = dict([('query_%s_'%name,name) for name in resvars]) for d in res_s: + res_dict = {} for k,v in d.items(): if hasattr(v,'uri'): val = v.uri else: val = v d[k] = unicode(val) - res.append(d) + if k in query_vars: + res_dict[query_vars[k]] = unicode(val) + res.append(res_dict) return res def consider_triple(self,(s, p, o)): Modified: pypy/branch/mininal-c-backend/pypy/lib/pyontology/test/test_ontology.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/lib/pyontology/test/test_ontology.py (original) +++ pypy/branch/mininal-c-backend/pypy/lib/pyontology/test/test_ontology.py Thu Nov 23 12:28:43 2006 @@ -173,7 +173,7 @@ O.type(sub, obj) O.type(obj, namespaces['owl']+"#Class") - assert O.variables[O.make_var(None, obj)].getValues()[0].__class__ == Individual + assert list(O.variables[O.make_var(None, obj)].getValues())[0].__class__ == Individual # test for multiple types # test for type hierarchy Modified: pypy/branch/mininal-c-backend/pypy/lib/pyontology/test/test_sparql.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/lib/pyontology/test/test_sparql.py (original) +++ pypy/branch/mininal-c-backend/pypy/lib/pyontology/test/test_sparql.py Thu Nov 23 12:28:43 2006 @@ -91,8 +91,9 @@ O = Ontology() O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' def test_case_2(): "for all p's return p if p[0]==s and p[1]==o """ @@ -102,9 +103,10 @@ O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) assert list(O.variables['query_x_'].getValues())[0] == 'ns_p' - assert res[0]['query_x_'] == 'ns_p' + assert res[0]['x'] == 'ns_p' def test_case_3(): """search for s in p""" @@ -114,11 +116,9 @@ O.add_file("testont.rdf") O.attach_fd() -# import pdb -# pdb.set_trace() + O.finish() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0] == '123' - assert res[0]['query_x_'] == '123' + assert res[0]['x'] == '123' def test_case_4(): """ search for s in p """ @@ -127,11 +127,12 @@ O = Ontology() O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' - assert list(O.variables['query_y_'].getValues())[0] == 'ns_p' #u'http://example.org/ns#p' - assert res[0]['query_x_'] == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' + assert res[0]['y'] == 'ns_p' #u'http://example.org/ns#p' + assert res[0]['x'] == u'http://example.org/ns#sub' def test_case_5(): """ for all p's return p[0] if p[1]==o """ @@ -140,11 +141,12 @@ O = Ontology() O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' - assert list(O.variables['query_y_'].getValues())[0] == u'123' - assert res[0]['query_x_'] == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' + assert res[0]['y'] == u'123' + assert res[0]['x'] == u'http://example.org/ns#sub' def test_case_6(): """ return the values of p """ @@ -154,22 +156,24 @@ O = Ontology() O.add_file("testont.rdf") O.attach_fd() + O.finish() res = O.sparql(query) - assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' - assert res[0]['query_x_'] == u'http://example.org/ns#sub' + assert list(O.variables['x'].getValues())[0].uri == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' def test_case_7(): """ for all p's return p[1] if p[0]==s """ + #py.test.skip("Doesn't work yet due to changed generatorinterface") query = qt_proto % ('?x ?y ?z', '?x ?y ?z .') O = Ontology() O.add_file("testont.rdf") O.attach_fd() - + O.finish() res = O.sparql(query) assert list(O.variables['query_x_'].getValues())[0].uri == u'http://example.org/ns#sub' - assert res[0]['query_x_'] == u'http://example.org/ns#sub' + assert res[0]['x'] == u'http://example.org/ns#sub' query1 = """ PREFIX ltw : @@ -189,9 +193,9 @@ SELECT ?project WHERE { ?project ltw:funded_by ltw:BMBF . - ?project ltw:date_begin ?date_begin . - ?project ltw:date_end ?date_end . - FILTER ( ?date_begin < 2007 ) . + ?project ltw:dateStart ?date_begin . + ?project ltw:dateEnd ?date_end . + FILTER ( ?date_begin < 2007 ) . FILTER ( ?date_end >= 2006) . }""" #which project is funded in a technological area (i.e. Semantic web), @@ -212,8 +216,19 @@ res = O.sparql(query1) assert len(res) == 1 - assert res[0]['query_activity_'] == u'http://www.lt-world.org/ltw.owl#obj_59754' - assert res[0]['query_person_'] == u'\nKlara Vicsi' + assert res[0]['activity'] == u'http://www.lt-world.org/ltw.owl#obj_59754' + assert res[0]['person'] == u'\nKlara Vicsi' + +def test_query2(): + py.test.skip("Doesn't work yet") + O = Ontology() + O.add_file("testont2.rdf") + O.attach_fd() + + res = O.sparql(query2) + assert len(res) == 1 + assert res[0]['activity'] == u'http://www.lt-world.org/ltw.owl#obj_59754' + assert res[0]['person'] == u'\nKlara Vicsi' import xmlrpclib, socket, os, signal @@ -243,4 +258,4 @@ print "test_xmlrpc" server = xmlrpclib.ServerProxy("http://localhost:9000", allow_none=True) result = server.sparql(qt_proto % ('?x', 'ns:sub ns:p ?x .')) - assert result[0]['query_x_'] == '123' + assert result[0]['x'] == '123' Modified: pypy/branch/mininal-c-backend/pypy/lib/stackless.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/lib/stackless.py (original) +++ pypy/branch/mininal-c-backend/pypy/lib/stackless.py Thu Nov 23 12:28:43 2006 @@ -57,7 +57,8 @@ def restore_exception(etype, value, stack): """until I find out how to restore an exception on python level""" #sys.excepthook(etype, value, stack) - raise etype(value) + raise etype, value, stack + #raise etype(value) class TaskletProxy(object): """TaskletProxy is needed to give the main_coroutine tasklet behaviour""" Modified: pypy/branch/mininal-c-backend/pypy/lib/test2/test_distributed.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/lib/test2/test_distributed.py (original) +++ pypy/branch/mininal-c-backend/pypy/lib/test2/test_distributed.py Thu Nov 23 12:28:43 2006 @@ -11,14 +11,14 @@ class AppTestDistributed(object): def setup_class(cls): - cls.space = gettestobjspace(**{"objspace.std.withtproxy": True}) + cls.space = gettestobjspace(**{"objspace.std.withtproxy": True, + "usemodules":("_stackless",)}) def test_init(self): import distributed - distributed.proxy def test_protocol(self): - from distributed import AbstractProtocol + from distributed.protocol import AbstractProtocol protocol = AbstractProtocol() for item in ("aaa", 3, u"aa", 344444444444444444L, 1.2, (1, "aa")): assert protocol.unwrap(protocol.wrap(item)) == item @@ -32,7 +32,7 @@ def test_protocol_run(self): l = [1,2,3] - from distributed import LocalProtocol + from distributed.protocol import LocalProtocol protocol = LocalProtocol() wrap = protocol.wrap unwrap = protocol.unwrap @@ -46,9 +46,137 @@ def f(x, y): return x + y - from distributed import LocalProtocol + from distributed.protocol import LocalProtocol protocol = LocalProtocol() wrap = protocol.wrap unwrap = protocol.unwrap item = unwrap(wrap(f)) assert item(3, 2) == 5 + + def test_simulation_call(self): + def f(x, y): + return x + y + + import types + from distributed import RemoteProtocol + import sys + + data = [] + result = [] + protocol = RemoteProtocol(result.append, data.pop) + data += [("finished", protocol.wrap(5)), ("finished", protocol.wrap(f))] + fun = protocol.get_remote("f") + assert isinstance(fun, types.FunctionType) + assert fun(2, 3) == 5 + + def test_remote_protocol_call(self): + def f(x, y): + return x + y + + from distributed import test_env + protocol = test_env({"f": f}) + fun = protocol.get_remote("f") + assert fun(2, 3) == 5 + + def test_callback(self): + def g(): + return 8 + + def f(x): + return x + g() + + from distributed import test_env + protocol = test_env({"f":f}) + fun = protocol.get_remote("f") + assert fun(8) == 16 + + def test_remote_dict(self): + #skip("Land of infinite recursion") + from distributed import test_env + d = {'a':3} + protocol = test_env({'d':d}) + xd = protocol.get_remote('d') + #assert d['a'] == xd['a'] + assert d.keys() == xd.keys() + assert d.values() == xd.values() + assert d == xd + + def test_local_obj(self): + class A: + def __init__(self, x): + self.x = x + + def __len__(self): + return self.x + 8 + + from distributed.protocol import LocalProtocol + protocol = LocalProtocol() + wrap = protocol.wrap + unwrap = protocol.unwrap + item = unwrap(wrap(A(3))) + assert item.x == 3 + assert len(item) == 11 + + def test_remote_obj(self): + class A: + def __init__(self, x): + self.x = x + + def __len__(self): + return self.x + 8 + a = A(3) + + from distributed import test_env + protocol = test_env({'a':a}) + xa = protocol.get_remote("a") + assert xa.x == 3 + assert len(xa) == 11 + + def test_remote_doc_and_callback(self): + class A: + """xxx""" + def __init__(self): + pass + + def meth(self, x): + return x() + 3 + + def x(): + return 1 + + a = A() + + from distributed import test_env + protocol = test_env({'a':a}) + xa = protocol.get_remote('a') + assert xa.__class__.__doc__ == 'xxx' + assert xa.meth(x) == 4 + + def test_double_reference(self): + class A: + def meth(self, one): + self.one = one + + def perform(self): + return 1 + len(self.one()) + + class B: + def __call__(self): + return [1,2,3] + + from distributed import test_env + a = A() + protocol = test_env({'a': a}) + xa = protocol.get_remote('a') + xa.meth(B()) + assert xa.perform() == 4 + + def test_frame(self): + #skip("Land of infinite recursion") + import sys + from distributed import test_env + f = sys._getframe() + protocol = test_env({'f':f}) + xf = protocol.get_remote('f') + assert f.f_globals.keys() == xf.f_globals.keys() + assert f.f_locals.keys() == xf.f_locals.keys() Modified: pypy/branch/mininal-c-backend/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/__builtin__/__init__.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/__builtin__/__init__.py Thu Nov 23 12:28:43 2006 @@ -80,8 +80,6 @@ '_instance' : 'space.w_instance', # default __metaclass__ '__metaclass__' : '(space.w_type)', - '_isfake' : 'special._isfake', - '_pdb' : 'special._pdb', # interp-level function definitions 'abs' : 'operation.abs', @@ -103,7 +101,6 @@ 'setattr' : 'operation.setattr', 'delattr' : 'operation.delattr', 'iter' : 'operation.iter', - 'hash' : 'operation.hash', 'id' : 'operation.id', '_seqiter' : 'operation._seqiter', 'intern' : 'operation.intern', Modified: pypy/branch/mininal-c-backend/pypy/module/__builtin__/importing.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/__builtin__/importing.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/__builtin__/importing.py Thu Nov 23 12:28:43 2006 @@ -9,31 +9,14 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root, ObjSpace from pypy.interpreter.eval import Code -from pypy.lib._osfilewrapper import OsFileWrapper +from pypy.rlib import streamio from pypy.rlib.rarithmetic import intmask -# XXX this uses the os.path module at interp-level, which means -# XXX that translate_pypy will produce a translated version of -# XXX PyPy that will only run on the same platform, as it contains -# XXX a frozen version of some routines of only one of the -# XXX posixpath/ntpath/macpath modules. - -try: - BIN_READMASK = os.O_BINARY | os.O_RDONLY - BIN_WRITEMASK = os.O_BINARY | os.O_RDWR | os.O_CREAT -except AttributeError: - BIN_READMASK = os.O_RDONLY - BIN_WRITEMASK = os.O_RDWR | os.O_CREAT - NOFILE = 0 PYFILE = 1 PYCFILE = 2 -import stat - -PYC_ONOFF = True - -def info_modtype(space ,filepart): +def info_modtype(space, filepart): """ calculate whether the .py file exists, the .pyc file exists and whether the .pyc file has the correct mtime entry. @@ -51,7 +34,7 @@ pyfile_exist = False pycfile = filepart + ".pyc" - if PYC_ONOFF and os.path.exists(pycfile): + if space.config.objspace.usepycfiles and os.path.exists(pycfile): pyc_state = check_compiled_module(space, pyfile, pyfile_ts, pycfile) pycfile_exists = pyc_state >= 0 pycfile_ts_valid = pyc_state > 0 or (pyc_state == 0 and not pyfile_exist) @@ -99,11 +82,11 @@ e = None if modtype == PYFILE: filename = filepart + ".py" - fd = os.open(filename, os.O_RDONLY, 0666) + stream = streamio.open_file_as_stream(filename, "r") else: assert modtype == PYCFILE filename = filepart + ".pyc" - fd = os.open(filename, BIN_READMASK, 0666) + stream = streamio.open_file_as_stream(filename, "rb") space.sys.setmodule(w_mod) space.setattr(w_mod, w('__file__'), space.wrap(filename)) @@ -112,14 +95,13 @@ space.setattr(w_mod, w('__path__'), space.newlist([w(pkgdir)])) try: - osfile = OsFileWrapper(fd) try: if modtype == PYFILE: - load_source_module(space, w_modulename, w_mod, filename, osfile) + load_source_module(space, w_modulename, w_mod, filename, stream) else: - load_compiled_module(space, w_modulename, w_mod, filename, osfile) + load_compiled_module(space, w_modulename, w_mod, filename, stream) finally: - osfile.close() + stream.close() except OperationError, e: w_mods = space.sys.get('modules') @@ -130,7 +112,7 @@ if w_mod is not None and w_parent is not None: space.setattr(w_parent, w_name, w_mod) if e: - raise e + raise e return w_mod def try_getattr(space, w_obj, w_name): @@ -349,34 +331,33 @@ pyc_magic = MAGIC -def parse_source_module(space, pathname, osfile): +def parse_source_module(space, pathname, stream): """ Parse a source file and return the corresponding code object """ w = space.wrap - size = os.fstat(osfile.fd)[stat.ST_SIZE] - source = osfile.read(size) + source = stream.readall() w_source = w(source) w_mode = w("exec") w_pathname = w(pathname) - w_code = space.builtin.call('compile', w_source, w_pathname, w_mode) + w_code = space.builtin.call('compile', w_source, w_pathname, w_mode) pycode = space.interp_w(Code, w_code) return pycode -def load_source_module(space, w_modulename, w_mod, pathname, osfile): +def load_source_module(space, w_modulename, w_mod, pathname, stream): """ Load a source module from a given file and return its module object. """ w = space.wrap - pycode = parse_source_module(space, pathname, osfile) + pycode = parse_source_module(space, pathname, stream) w_dict = space.getattr(w_mod, w('__dict__')) - space.call_method(w_dict, 'setdefault', - w('__builtins__'), + space.call_method(w_dict, 'setdefault', + w('__builtins__'), w(space.builtin)) - pycode.exec_code(space, w_dict, w_dict) + pycode.exec_code(space, w_dict, w_dict) - if PYC_ONOFF: - mtime = os.fstat(osfile.fd)[stat.ST_MTIME] + if space.config.objspace.usepycfiles: + mtime = os.stat(pathname)[stat.ST_MTIME] cpathname = pathname + 'c' write_compiled_module(space, pycode, cpathname, mtime) @@ -385,8 +366,8 @@ # helper, to avoid exposing internals of marshal and the # difficulties of using it though applevel. _r_correction = intmask(1L<<32) # == 0 on 32-bit machines -def _r_long(osfile): - s = osfile.read(4) +def _r_long(stream): + s = stream.read(4) # XXX XXX could return smaller string if len(s) < 4: return -1 # good enough for our purposes a = ord(s[0]) @@ -398,7 +379,7 @@ x -= _r_correction return int(x) -def _w_long(osfile, x): +def _w_long(stream, x): a = x & 0xff x >>= 8 b = x & 0xff @@ -406,7 +387,7 @@ c = x & 0xff x >>= 8 d = x & 0xff - osfile.write(chr(a) + chr(b) + chr(c) + chr(d)) + stream.write(chr(a) + chr(b) + chr(c) + chr(d)) def check_compiled_module(space, pathname, mtime, cpathname): """ @@ -423,31 +404,28 @@ #XXX debug #print "skipped checking of", cpathname return -1 - fd = os.open(cpathname, BIN_READMASK, 0666) # using no defaults - osfile = OsFileWrapper(fd) - magic = _r_long(osfile) + stream = streamio.open_file_as_stream(cpathname, "rb") + magic = _r_long(stream) try: if magic != pyc_magic: # XXX what to do about Py_VerboseFlag ? # PySys_WriteStderr("# %s has bad magic\n", cpathname); return -1 - pyc_mtime = _r_long(osfile) + pyc_mtime = _r_long(stream) if pyc_mtime != mtime: # PySys_WriteStderr("# %s has bad mtime\n", cpathname); return 0 # if (Py_VerboseFlag) # PySys_WriteStderr("# %s matches %s\n", cpathname, pathname); finally: - os.close(fd) + stream.close() return 1 -def read_compiled_module(space, cpathname, osfile): +def read_compiled_module(space, cpathname, stream): """ Read a code object from a file and check it for validity """ w_marshal = space.getbuiltinmodule('marshal') - fd = osfile.fd - size = os.fstat(fd)[stat.ST_SIZE] - os.lseek(fd, 0, 1) - strbuf = osfile.read(size) + strbuf = stream.readall() w_code = space.call_method(w_marshal, 'loads', space.wrap(strbuf)) pycode = space.interpclass_w(w_code) if pycode is None or not isinstance(pycode, Code): @@ -455,19 +433,19 @@ "Non-code object in %s" % cpathname)) return pycode -def load_compiled_module(space, w_modulename, w_mod, cpathname, osfile): +def load_compiled_module(space, w_modulename, w_mod, cpathname, stream): """ Load a module from a compiled file, execute it, and return its module object. """ w = space.wrap - magic = _r_long(osfile) + magic = _r_long(stream) if magic != pyc_magic: raise OperationError(space.w_ImportError, w( "Bad magic number in %s" % cpathname)) - _r_long(osfile) # skip time stamp + _r_long(stream) # skip time stamp #print "loading pyc file:", cpathname - code_w = read_compiled_module(space, cpathname, osfile) + code_w = read_compiled_module(space, cpathname, stream) #if (Py_VerboseFlag) # PySys_WriteStderr("import %s # precompiled from %s\n", # name, cpathname); @@ -509,24 +487,23 @@ # too much like a valid pyc file but really isn't one. # try: - fd = os.open(cpathname, BIN_WRITEMASK, 0666) + stream = streamio.open_file_as_stream(cpathname, "wb") except OSError: return # cannot create file try: - osfile = OsFileWrapper(fd) try: # will patch the header later; write zeroes until we are sure that # the rest of the file is valid - _w_long(osfile, 0) # pyc_magic - _w_long(osfile, 0) # mtime - osfile.write(strbuf) + _w_long(stream, 0) # pyc_magic + _w_long(stream, 0) # mtime + stream.write(strbuf) # should be ok (XXX or should call os.fsync() to be sure?) - osfile.seek(0) - _w_long(osfile, pyc_magic) - _w_long(osfile, mtime) + stream.seek(0, 0) + _w_long(stream, pyc_magic) + _w_long(stream, mtime) finally: - osfile.close() + stream.close() except OSError: try: os.unlink(cpathname) Modified: pypy/branch/mininal-c-backend/pypy/module/__builtin__/special.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/__builtin__/special.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/__builtin__/special.py Thu Nov 23 12:28:43 2006 @@ -2,11 +2,6 @@ from pypy.interpreter.error import OperationError from pypy.rlib import rarithmetic -def _isfake(space, w_obj): - return space.wrap(bool(w_obj.typedef.fakedcpytype)) - #return space.wrap(bool(getattr(w_obj.typedef, 'fakedcpytype', None))) - - def _formatd(space, alt, prec, kind, x): formatd_max_length = rarithmetic.formatd_max_length if ((kind == 'g' and formatd_max_length <= 10+prec) or @@ -23,14 +18,4 @@ return space.wrap(rarithmetic.formatd(fmt, x)) _formatd.unwrap_spec = [gateway.ObjSpace, int, int, str, float] -def _pdb(space): - """Run an interp-level pdb. - This is not available in translated versions of PyPy.""" - from pypy.rlib.objectmodel import we_are_translated - if we_are_translated(): - raise OperationError(space.w_NotImplementedError, - space.wrap("Cannot use interp-level pdb in translated pypy")) - else: - import pdb - pdb.set_trace() Modified: pypy/branch/mininal-c-backend/pypy/module/_file/app_file.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/_file/app_file.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/_file/app_file.py Thu Nov 23 12:28:43 2006 @@ -50,10 +50,25 @@ def getnewlines(self): "end-of-line convention used in this file" - if isinstance(self.stream, _sio.TextInputFilter): - return self.stream.getnewlines() - else: + + newlines = self.stream.getnewlines() + if newlines == 0: return None + if newlines in [1, 2, 4]: + if newlines == 1: + return "\r" + elif newlines == 2: + return "\n" + else: + return "\r\n" + result = [] + if newlines & 1: + result.append('\r') + if newlines & 2: + result.append('\n') + if newlines & 4: + result.append('\r\n') + return tuple(result) mode = property(lambda self: self._mode, doc = "file mode ('r', 'U', 'w', 'a', " Modified: pypy/branch/mininal-c-backend/pypy/module/_file/test/test_file.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/_file/test/test_file.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/_file/test/test_file.py Thu Nov 23 12:28:43 2006 @@ -61,3 +61,13 @@ f.close() assert oct(os.stat(self.temppath).st_mode & 0777 | umask) == oct(0666) + def test_newlines(self): + import _file, os + f = _file.file(self.temppath, "wb") + f.write("\r\n") + assert f.newlines is None + f.close() + f = _file.file(self.temppath, "rU") + res = f.read() + assert res == "\n" + assert f.newlines == "\r\n" Modified: pypy/branch/mininal-c-backend/pypy/module/_stackless/__init__.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/_stackless/__init__.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/_stackless/__init__.py Thu Nov 23 12:28:43 2006 @@ -14,7 +14,6 @@ interpleveldefs = { 'tasklet' : 'interp_stackless.tasklet', 'coroutine' : 'coroutine.AppCoroutine', - 'clonable' : 'clonable.ClonableCoroutine', 'greenlet' : 'interp_greenlet.AppGreenlet', 'usercostate': 'composable_coroutine.W_UserCoState', } @@ -24,8 +23,11 @@ # are not yet directly supported from pypy.module._stackless.coroutine import post_install as post_install_coro post_install_coro(self) - from pypy.module._stackless.clonable import post_install as post_install_clonable - post_install_clonable(self) from pypy.module._stackless.interp_greenlet import post_install as post_install_greenlet post_install_greenlet(self) + if self.space.config.translation.gc in ('framework', 'stacklessgc'): + from pypy.module._stackless.clonable import post_install as post_install_clonable + self.extra_interpdef('clonable', 'clonable.AppClonableCoroutine') + self.extra_interpdef('fork', 'clonable.fork') + post_install_clonable(self) Modified: pypy/branch/mininal-c-backend/pypy/module/_stackless/coroutine.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/_stackless/coroutine.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/_stackless/coroutine.py Thu Nov 23 12:28:43 2006 @@ -45,22 +45,23 @@ def call(self): costate = self.costate w_result = self.space.call_args(self.w_func, self.args) - #XXX: unreachable code ? rstack.resume_point("appthunk", costate, returns=w_result) costate.w_tempval = w_result class AppCoroutine(Coroutine): # XXX, StacklessFlags): - def __init__(self, space, is_main=False, state=None): + def __init__(self, space, state=None): self.space = space if state is None: - state = self._get_state(space) + state = AppCoroutine._get_state(space) Coroutine.__init__(self, state) self.flags = 0 - self.framestack = None - if not is_main: - space.getexecutioncontext().subcontext_new(self) + self.newsubctx() + + def newsubctx(self): + ec = self.space.getexecutioncontext() + self.subctx = ec.Subcontext() def descr_method__new__(space, w_subtype): co = space.allocate_instance(AppCoroutine, w_subtype) @@ -109,11 +110,11 @@ def hello(self): ec = self.space.getexecutioncontext() - ec.subcontext_enter(self) + self.subctx.enter(ec) def goodbye(self): ec = self.space.getexecutioncontext() - ec.subcontext_leave(self) + self.subctx.leave(ec) def w_kill(self): self.kill() @@ -160,7 +161,7 @@ ] tup_state = [ w(self.flags), - ec.subcontext_getstate(self), + self.subctx.getstate(space), w_thunk, w(self.parent), ] @@ -176,7 +177,7 @@ self.flags = space.int_w(w_flags) self.parent = space.interp_w(AppCoroutine, w_parent, can_be_None=True) ec = self.space.getexecutioncontext() - ec.subcontext_setstate(self, w_state) + self.subctx.setstate(self.space, w_state) self.reconstruct_framechain() if space.is_w(w_thunk, space.w_None): self.thunk = None @@ -192,7 +193,7 @@ def reconstruct_framechain(self): from pypy.interpreter.pyframe import PyFrame from pypy.rlib.rstack import resume_state_create - if self.framestack.empty(): + if self.subctx.framestack.empty(): self.frame = None return @@ -206,7 +207,7 @@ # rstack.resume_point("appthunk", costate, returns=w_result) appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate) chain = appthunk_frame - for frame in self.framestack.items: + for frame in self.subctx.framestack.items: assert isinstance(frame, PyFrame) # rstack.resume_point("evalframe", self, executioncontext, returns=result) evalframe_frame = resume_state_create(chain, "evalframe", frame, ec) @@ -253,8 +254,8 @@ def w_descr__framestack(space, self): assert isinstance(self, AppCoroutine) - if self.framestack: - items = [space.wrap(item) for item in self.framestack.items] + if self.subctx.framestack is not None: + items = [space.wrap(item) for item in self.subctx.framestack.items] return space.newtuple(items) else: return space.newtuple([]) @@ -305,5 +306,5 @@ self.space = space def post_install(self): - self.current = self.main = AppCoroutine(self.space, is_main=True, - state=self) + self.current = self.main = AppCoroutine(self.space, state=self) + self.main.subctx.framestack = None # wack Modified: pypy/branch/mininal-c-backend/pypy/module/_stackless/interp_clonable.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/_stackless/interp_clonable.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/_stackless/interp_clonable.py Thu Nov 23 12:28:43 2006 @@ -6,31 +6,54 @@ from pypy.tool import stdlib_opcode as pythonopcode -class InterpClonableCoroutine(Coroutine): + +class InterpClonableMixin: local_pool = None + _mixin_ = True - def hello(self): + def hello_local_pool(self): if we_are_translated(): self.saved_pool = gc_swap_pool(self.local_pool) - def goodbye(self): + def goodbye_local_pool(self): if we_are_translated(): self.local_pool = gc_swap_pool(self.saved_pool) + self.saved_pool = None - def clone(self): + def clone_into(self, copy, extradata=None): if not we_are_translated(): raise NotImplementedError - if self.getcurrent() is self: - raise RuntimeError("clone() cannot clone the current coroutine; " - "use fork() instead") - if self.local_pool is None: # force it now - self.local_pool = gc_swap_pool(gc_swap_pool(None)) # cannot gc_clone() directly self, because it is not in its own # local_pool. Moreover, it has a __del__, which cloning doesn't # support properly at the moment. - copy = InterpClonableCoroutine(self.costate) copy.parent = self.parent - copy.frame, copy.local_pool = gc_clone(self.frame, self.local_pool) + # the hello/goodbye pair has two purposes: it forces + # self.local_pool to be computed even if it was None up to now, + # and it puts the 'data' tuple in the correct pool to be cloned. + self.hello_local_pool() + data = (self.frame, extradata) + self.goodbye_local_pool() + # clone! + data, copy.local_pool = gc_clone(data, self.local_pool) + copy.frame, extradata = data + return extradata + + +class InterpClonableCoroutine(Coroutine, InterpClonableMixin): + + def hello(self): + self.hello_local_pool() + + def goodbye(self): + self.goodbye_local_pool() + + def clone(self): + # hack, this is overridden in AppClonableCoroutine + if self.getcurrent() is self: + raise RuntimeError("clone() cannot clone the current coroutine; " + "use fork() instead") + copy = InterpClonableCoroutine(self.costate) + self.clone_into(copy) return copy Modified: pypy/branch/mininal-c-backend/pypy/module/_stackless/interp_greenlet.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/_stackless/interp_greenlet.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/_stackless/interp_greenlet.py Thu Nov 23 12:28:43 2006 @@ -60,8 +60,10 @@ assert isinstance(w_parent, AppGreenlet) self.w_parent = w_parent Coroutine.__init__(self, state) - if not is_main: - space.getexecutioncontext().subcontext_new(self) + self.subctx = space.getexecutioncontext().Subcontext() + if is_main: + self.subctx.framestack = None # wack + else: self.bind(GreenletThunk(space, state, self)) def descr_method__new__(space, w_subtype, w_callable): @@ -75,11 +77,11 @@ def hello(self): ec = self.space.getexecutioncontext() - ec.subcontext_enter(self) + self.subctx.enter(ec) def goodbye(self): ec = self.space.getexecutioncontext() - ec.subcontext_leave(self) + self.subctx.leave(ec) def w_getcurrent(space): return space.wrap(AppGreenlet._get_state(space).current) @@ -143,10 +145,11 @@ def w_get_frame(space, w_self): self = space.interp_w(AppGreenlet, w_self) - if not self.has_ever_run or space.is_true(self.w_dead): + if (not self.has_ever_run or space.is_true(self.w_dead) or + self.costate.current is self): return space.w_None try: - return self.framestack.top(0) + return self.subctx.framestack.top(0) except IndexError: return space.w_None Modified: pypy/branch/mininal-c-backend/pypy/module/pypymagic/__init__.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/pypymagic/__init__.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/pypymagic/__init__.py Thu Nov 23 12:28:43 2006 @@ -8,4 +8,6 @@ interpleveldefs = { 'pypy_repr' : 'interp_magic.pypy_repr', + 'isfake' : 'interp_magic.isfake', + 'interp_pdb' : 'interp_magic.interp_pdb', } Modified: pypy/branch/mininal-c-backend/pypy/module/pypymagic/interp_magic.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/pypymagic/interp_magic.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/pypymagic/interp_magic.py Thu Nov 23 12:28:43 2006 @@ -1,3 +1,21 @@ +from pypy.interpreter.error import OperationError +from pypy.rlib.objectmodel import we_are_translated def pypy_repr(space, w_object): return space.wrap('%r' % (w_object,)) + +def isfake(space, w_obj): + if we_are_translated(): + return space.w_False + return space.wrap(bool(w_obj.typedef.fakedcpytype)) + #return space.wrap(bool(getattr(w_obj.typedef, 'fakedcpytype', None))) + +def interp_pdb(space): + """Run an interp-level pdb. + This is not available in translated versions of PyPy.""" + if we_are_translated(): + raise OperationError(space.w_NotImplementedError, + space.wrap("Cannot use interp-level pdb in translated pypy")) + else: + import pdb + pdb.set_trace() Modified: pypy/branch/mininal-c-backend/pypy/module/rctime/test/test_rctime.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/module/rctime/test/test_rctime.py (original) +++ pypy/branch/mininal-c-backend/pypy/module/rctime/test/test_rctime.py Thu Nov 23 12:28:43 2006 @@ -55,7 +55,7 @@ assert res[-1] == 0 # DST is always zero in gmtime() t0 = rctime.mktime(rctime.gmtime()) t1 = rctime.mktime(rctime.gmtime(None)) - assert 0 <= (t1 - t0) < 0.2 + assert 0 <= (t1 - t0) < 1.2 t = rctime.time() assert rctime.gmtime(t) == rctime.gmtime(t) @@ -69,7 +69,7 @@ assert isinstance(res, rctime.struct_time) t0 = rctime.mktime(rctime.localtime()) t1 = rctime.mktime(rctime.localtime(None)) - assert 0 <= (t1 - t0) < 0.2 + assert 0 <= (t1 - t0) < 1.2 t = rctime.time() assert rctime.localtime(t) == rctime.localtime(t) Modified: pypy/branch/mininal-c-backend/pypy/objspace/cclp/misc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/cclp/misc.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/cclp/misc.py Thu Nov 23 12:28:43 2006 @@ -2,7 +2,6 @@ from pypy.rlib.objectmodel import we_are_translated # commonly imported there, used from types, variable, thread -from pypy.module._stackless.clonable import ClonableCoroutine from pypy.module._stackless.coroutine import AppCoroutine import os Modified: pypy/branch/mininal-c-backend/pypy/objspace/logic.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/logic.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/logic.py Thu Nov 23 12:28:43 2006 @@ -187,13 +187,10 @@ # multimethods hack space.model.typeorder[W_Var] = [(W_Var, None), (W_Root, None)] # None means no conversion - space.model.typeorder[W_Future] = [(W_Future, None), (W_Var, None)] - space.model.typeorder[W_CVar] = [(W_CVar, None), (W_Var, None)] - space.model.typeorder[W_CSpace] = [(W_CSpace, None), (baseobjspace.Wrappable, None)] - space.model.typeorder[W_ThreadGroupScheduler] = [(W_ThreadGroupScheduler, None), (W_CSpace, None)] + space.model.typeorder[W_Future] = [(W_Future, None), (W_Var, None), (W_Root, None)] + space.model.typeorder[W_CVar] = [(W_CVar, None), (W_Var, None), (W_Root, None)] space.model.typeorder[W_FiniteDomain] = [(W_FiniteDomain, None), (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)) Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/multimethod.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/multimethod.py Thu Nov 23 12:28:43 2006 @@ -459,6 +459,13 @@ for t1, num in self.typenum.items(): setattr(t1, self.attrname, num) self.indexarray = CompressedArray(0) + self.strict_subclasses = {} + for cls1 in list_of_types: + lst = [] + for cls2 in list_of_types: + if cls1 is not cls2 and issubclass(cls2, cls1): + lst.append(cls2) + self.strict_subclasses[cls1] = lst def normalize_length(self, next_array): # make sure that the indexarray is not smaller than any funcarray @@ -504,8 +511,9 @@ checklines.append(self.body) body = '\n '.join(checklines) source = 'def %s(%s):\n %s\n' % (name, ', '.join(fnargs), body) - #print '_' * 60 - #print source + #f = open('/tmp/mm-source/%s' % name, 'a') + #print >> f, source + #f.close() exec compile2(source) in self.miniglobals self._function = self.miniglobals[name] return self._function @@ -534,6 +542,27 @@ fulls += 1 if fulls == types_total: return 1 + + # a word about subclasses: we are using isinstance() to do + # the checks in generate_typechecks(), which is a + # compromize. In theory we should check the type ids + # instead. But using isinstance() is better because the + # annotator can deduce information from that. It is still + # correct to use isinstance() instead of type ids in + # "reasonable" cases, though -- where "reasonable" means + # that classes always have a delegate to their superclasses, + # e.g. W_IntObject delegates to W_Root. If this is true + # then both kind of checks are good enough to spot + # mismatches caused by the compression table. + + # Based on this reasoning, we can compress the typechecks a + # bit more - if we accept W_Root, for example, then we + # don't have to specifically accept W_IntObject too. + for cls, subnode in node.items(): + for cls2 in mrdtable.strict_subclasses[cls]: + if cls2 in node and node[cls2] == subnode: + del node[cls2] + return 0 types_total = len(mrdtable.list_of_types) Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/objspace.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/objspace.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/objspace.py Thu Nov 23 12:28:43 2006 @@ -135,10 +135,12 @@ # Adding transparent proxy call if self.config.objspace.std.withtproxy: w_pypymagic = self.getbuiltinmodule("pypymagic") - from pypy.objspace.std.transparent import app_proxy + from pypy.objspace.std.transparent import app_proxy, app_proxy_controller self.setattr(w_pypymagic, self.wrap('transparent_proxy'), self.wrap(app_proxy)) + self.setattr(w_pypymagic, self.wrap('get_transparent_controller'), + self.wrap(app_proxy_controller)) def enable_old_style_classes_as_default_metaclass(self): self.setitem(self.builtin.w_dict, self.wrap('__metaclass__'), self.w_classobj) Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/proxyobject.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/proxyobject.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/proxyobject.py Thu Nov 23 12:28:43 2006 @@ -68,7 +68,7 @@ def setdict(self, space, w_dict): if not self.setdictvalue(space, space.wrap('__dict__'), w_dict): baseobjspace.W_Root.setdict(self, space, w_dict) - + W_Transparent.__name__ = name return W_Transparent Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_multimethod.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_multimethod.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_multimethod.py Thu Nov 23 12:28:43 2006 @@ -1,7 +1,8 @@ import autopath from py.test import raises -from pypy.objspace.std.multimethod import * +from pypy.objspace.std import multimethod +from pypy.objspace.std.multimethod import FailedToImplement class W_Root(object): @@ -20,90 +21,169 @@ assert isinstance(w_x, W_BoolObject) return W_IntObject() -add = MultiMethodTable(2, root_class=W_Root, argnames_before=['space']) - def add__Int_Int(space, w_x, w_y): assert space == 'space' assert isinstance(w_x, W_IntObject) assert isinstance(w_y, W_IntObject) return 'fine' -add.register(add__Int_Int, W_IntObject, W_IntObject) + +class TestMultiMethod1: + Installer = multimethod.InstallerVersion1 + + def setup_class(cls): + cls.prev_installer = multimethod.Installer + multimethod.Installer = cls.Installer + add = multimethod.MultiMethodTable(2, root_class=W_Root, + argnames_before=['space']) + add.register(add__Int_Int, W_IntObject, W_IntObject) + typeorder = { + W_IntObject: [(W_IntObject, None), (W_Root, None)], + W_BoolObject: [(W_BoolObject, None), (W_IntObject, delegate_b2i), + (W_Root, None)], + W_StringObject: [(W_StringObject, None), (W_Root, None)], + } + cls.typeorder = typeorder + cls.add = add + cls.add1 = staticmethod(add.install('__add', [typeorder, typeorder])) + + def teardown_class(cls): + multimethod.Installer = cls.prev_installer + + def test_simple(self): + space = 'space' + w_x = W_IntObject() + w_y = W_IntObject() + assert self.add1(space, w_x, w_y) == 'fine' + + def test_failtoimplement(self): + space = 'space' + w_x = W_IntObject() + w_s = W_StringObject() + raises(FailedToImplement, "self.add1(space, w_x, w_s)") + raises(FailedToImplement, "self.add1(space, w_s, w_x)") + + def test_delegate(self): + space = 'space' + w_x = W_IntObject() + w_s = W_StringObject() + w_b = W_BoolObject() + assert self.add1(space, w_x, w_b) == 'fine' + assert self.add1(space, w_b, w_x) == 'fine' + assert self.add1(space, w_b, w_b) == 'fine' + raises(FailedToImplement, "self.add1(space, w_b, w_s)") + raises(FailedToImplement, "self.add1(space, w_s, w_b)") + + def test_not_baked(self): + typeorder = self.typeorder + add2 = self.add.install('__add2', [typeorder, typeorder], + baked_perform_call=False) + assert add2[0] == ['space', 'arg0', 'arg1'] + if multimethod.Installer is multimethod.InstallerVersion1: + assert add2[1] == 'arg0.__add2(space, arg1)' + assert isinstance(add2[2], dict) + assert not add2[3] + + def test_empty(self): + add3_installer = multimethod.Installer(self.add, '__add3', [{},{}]) + assert add3_installer.is_empty() + if multimethod.Installer is multimethod.InstallerVersion1: + assert len(add3_installer.to_install) == 1 + assert add3_installer.to_install[0][0] is None + + def test_empty_direct(self): + assert not self.add.install_if_not_empty('__add4', [{},{}]) + + def test_empty_not_baked(self): + add5_installer = multimethod.Installer(self.add, '__add5', [{},{}], + baked_perform_call=False) + assert add5_installer.is_empty() + if multimethod.Installer is multimethod.InstallerVersion1: + assert len(add5_installer.to_install) == 0 + add5 = add5_installer.install() + assert add5[0] == ['space', 'arg0', 'arg1'] + assert add5[1] == 'raiseFailedToImplement()' + assert isinstance(add5[2], dict) + assert add5[3] + + def test_mmdispatcher(self): + typeorder = self.typeorder + add2 = multimethod.MMDispatcher(self.add, [typeorder, typeorder]) + space = 'space' + w_x = W_IntObject() + w_s = W_StringObject() + w_b1 = W_BoolObject() + w_b2 = W_BoolObject() + assert add2(space, w_x, w_b1) == 'fine' + assert add2(space, w_b2, w_x) == 'fine' + assert add2(space, w_b1, w_b2) == 'fine' + raises(FailedToImplement, "add2(space, w_b2, w_s)") + raises(FailedToImplement, "add2(space, w_s, w_b1)") + + def test_all_cases(self): + import random + space = 'space' + w_x = W_IntObject() + w_x.expected = [W_IntObject, W_Root] + w_s = W_StringObject() + w_s.expected = [W_StringObject, W_Root] + w_b = W_BoolObject() + w_b.expected = [W_BoolObject, W_IntObject, W_Root] + + def test(indices): + sub = multimethod.MultiMethodTable(2, root_class=W_Root, + argnames_before=['space']) + def addimpl(cls1, cls2): + token = random.random() + def sub__cls1_cls2(space, w_x, w_y): + assert space == 'space' + assert isinstance(w_x, cls1) + assert isinstance(w_y, cls2) + return token + sub.register(sub__cls1_cls2, cls1, cls2) + return token + + def check(w1, w2): + try: + res = sub1(space, w1, w2) + except FailedToImplement: + res = FailedToImplement + for cls1 in w1.expected: + for cls2 in w2.expected: + if (cls1, cls2) in expected: + assert res == expected[cls1, cls2] + return + else: + assert res is FailedToImplement + + random.shuffle(indices) + expected = {} + for index in indices: + cls1, cls2 = choices[index] + token = addimpl(cls1, cls2) + expected[cls1, cls2] = token + + typeorder = self.typeorder + sub1 = sub.install('__sub', [typeorder, typeorder]) + for w1 in [w_x, w_s, w_b]: + for w2 in [w_x, w_s, w_b]: + check(w1, w2) + + classes = [W_Root, W_StringObject, W_IntObject, W_BoolObject] + choices = [(cls1, cls2) for cls1 in classes + for cls2 in classes] + # each choice is a pair of classes which can be implemented or + # not by the multimethod 'sub'. Test all combinations that + # involve at most three implemented choices. + for i in range(len(choices)): + test([i]) + for j in range(i+1, len(choices)): + test([i, j]) + for k in range(j+1, len(choices)): + test([i, j, k]) + #for l in range(k+1, len(choices)): -- for a 4th choice + # test([i, j, k, l]) -- (takes a while) -def setup_module(mod): - typeorder = { - W_IntObject: [(W_IntObject, None)], - W_BoolObject: [(W_BoolObject, None), (W_IntObject, delegate_b2i)], - W_StringObject: [(W_StringObject, None)], - } - mod.typeorder = typeorder - mod.add1 = add.install('__add', [typeorder, typeorder]) - - -def test_simple(): - space = 'space' - w_x = W_IntObject() - w_y = W_IntObject() - assert add1(space, w_x, w_y) == 'fine' - -def test_failtoimplement(): - space = 'space' - w_x = W_IntObject() - w_s = W_StringObject() - raises(FailedToImplement, "add1(space, w_x, w_s)") - raises(FailedToImplement, "add1(space, w_s, w_x)") - -def test_delegate(): - space = 'space' - w_x = W_IntObject() - w_s = W_StringObject() - w_b = W_BoolObject() - assert add1(space, w_x, w_b) == 'fine' - assert add1(space, w_b, w_x) == 'fine' - assert add1(space, w_b, w_b) == 'fine' - raises(FailedToImplement, "add1(space, w_b, w_s)") - raises(FailedToImplement, "add1(space, w_s, w_b)") - -def test_not_baked(): - add2 = add.install('__add2', [typeorder, typeorder],baked_perform_call=False) - assert add2[0] == ['space', 'arg0', 'arg1'] - if Installer is InstallerVersion1: - assert add2[1] == 'arg0.__add2(space, arg1)' - assert isinstance(add2[2], dict) - assert not add2[3] - -def test_empty(): - add3_installer = Installer(add, '__add3', [{},{}]) - assert add3_installer.is_empty() - if Installer is InstallerVersion1: - assert len(add3_installer.to_install) == 1 - assert add3_installer.to_install[0][0] is None - -def test_empty_direct(): - assert not add.install_if_not_empty('__add4', [{},{}]) - - -def test_empty_not_baked(): - add5_installer = Installer(add, '__add5', [{},{}], baked_perform_call=False) - assert add5_installer.is_empty() - if Installer is InstallerVersion1: - assert len(add5_installer.to_install) == 0 - add5 = add5_installer.install() - assert add5[0] == ['space', 'arg0', 'arg1'] - assert add5[1] == 'raiseFailedToImplement()' - assert isinstance(add5[2], dict) - assert add5[3] - -def test_mmdispatcher(): - add2 = MMDispatcher(add, [typeorder, typeorder]) - space = 'space' - w_x = W_IntObject() - w_s = W_StringObject() - w_b1 = W_BoolObject() - w_b2 = W_BoolObject() - assert add2(space, w_x, w_b1) == 'fine' - assert add2(space, w_b2, w_x) == 'fine' - assert add2(space, w_b1, w_b2) == 'fine' - raises(FailedToImplement, "add2(space, w_b2, w_s)") - raises(FailedToImplement, "add2(space, w_s, w_b1)") +class TestMultiMethod2(TestMultiMethod1): + Installer = multimethod.InstallerVersion2 Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy.py Thu Nov 23 12:28:43 2006 @@ -88,6 +88,12 @@ lst = self.proxy(list, c.perform) lst += [1,2,3] assert len(lst) == 6 + + def test_list_reverse_add(self): + c = self.Controller([1,2,3]) + lst = self.proxy(list, c.perform) + l = [1] + lst + assert l == [1,1,2,3] class AppTestDictProxy(AppProxyBasic): def test_dict(self): Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy_function.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy_function.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy_function.py Thu Nov 23 12:28:43 2006 @@ -80,3 +80,25 @@ del fun.__doc__ assert f.__doc__ is None + def test_proxy_bind_method(self): + class A: + pass + + def f(self): + return 3 + + class AA: + pass + + from pypymagic import transparent_proxy as proxy + a = A() + class X: + def __init__(self, x): + self.x = x + def f(self, name, *args, **kwargs): + return getattr(self.x, name)(*args, **kwargs) + + y = proxy(type(f), X(f).f) + x = proxy(AA, X(a).f) + AA.f = y + assert x.f() == 3 Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy_internals.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy_internals.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_proxy_internals.py Thu Nov 23 12:28:43 2006 @@ -101,6 +101,14 @@ e = sys.exc_info() assert traceback.format_tb(last_tb) == traceback.format_tb(e[2]) + + def test_proxy_get(self): + from pypymagic import transparent_proxy, get_transparent_controller + l = [1,2,3] + def f(name, *args, **kwargs): + return getattr(l, name)(*args, **kwargs) + lst = transparent_proxy(list, f) + assert get_transparent_controller(lst) is f class DONTAppTestProxyType(AppProxy): def test_filetype(self): Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_strjoinobject.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_strjoinobject.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/test/test_strjoinobject.py Thu Nov 23 12:28:43 2006 @@ -15,7 +15,6 @@ assert 'W_StringJoinObject' in pypymagic.pypy_repr(s) def test_add_twice(self): - skip("minimal failing test") x = "a" + "" y = x + "b" c = x + "b" Modified: pypy/branch/mininal-c-backend/pypy/objspace/std/transparent.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/objspace/std/transparent.py (original) +++ pypy/branch/mininal-c-backend/pypy/objspace/std/transparent.py Thu Nov 23 12:28:43 2006 @@ -35,5 +35,13 @@ raise OperationError(space.w_TypeError, space.wrap("Object type %s could not "\ "be wrapped (YET)" % w_type.getname(space, "?"))) +def proxy_controller(space, w_object): + if isinstance(w_object, W_Transparent): + return w_object.w_controller + if isinstance(w_object, W_TransparentObject): + return w_object.w_controller + return None + app_proxy = gateway.interp2app(proxy, unwrap_spec=[gateway.ObjSpace, gateway.W_Root, \ gateway.W_Root]) +app_proxy_controller = gateway.interp2app(proxy_controller, unwrap_spec=[gateway.ObjSpace, gateway.W_Root]) Modified: pypy/branch/mininal-c-backend/pypy/rlib/objectmodel.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rlib/objectmodel.py (original) +++ pypy/branch/mininal-c-backend/pypy/rlib/objectmodel.py Thu Nov 23 12:28:43 2006 @@ -190,8 +190,23 @@ resulttype = hop.r_result.lowleveltype) - -# __ hlinvoke XXX this doesn't seem completely the right place for this +def debug_assert(x, msg): + """After translation to C, this becomes an RPyAssert.""" + assert x, msg + +class Entry(ExtRegistryEntry): + _about_ = debug_assert + + def compute_result_annotation(self, s_x, s_msg): + assert s_msg.is_constant(), ("debug_assert(x, msg): " + "the msg must be constant") + return None + + def specialize_call(self, hop): + from pypy.rpython.lltypesystem import lltype + vlist = hop.inputargs(lltype.Bool, lltype.Void) + hop.genop('debug_assert', vlist) + def hlinvoke(repr, llcallable, *args): raise TypeError, "hlinvoke is meant to be rtyped and not called direclty" Modified: pypy/branch/mininal-c-backend/pypy/rlib/parsing/test/test_ebnfparse.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rlib/parsing/test/test_ebnfparse.py (original) +++ pypy/branch/mininal-c-backend/pypy/rlib/parsing/test/test_ebnfparse.py Thu Nov 23 12:28:43 2006 @@ -55,7 +55,9 @@ """) parse = make_parse_function(regexs, rules) print transformer - exec py.code.Source(transformer).compile() + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(transformer).compile() in ns + ToAST = ns["ToAST"] tree = parse("(0 +! 10) *! (999 +! 10) +! 1") print transformer tree = tree.visit(ToAST()) @@ -127,7 +129,9 @@ parse = make_parse_function(regexs, rules) tree = parse("x * floor + 1") print transformer - exec py.code.Source(transformer).compile() + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(transformer).compile() in ns + ToAST = ns["ToAST"] tree = tree.visit(ToAST()) assert tree.children[2].symbol == "NUMBER" @@ -238,7 +242,9 @@ 'tokenizer': '[object Object]', 'varDecls': '' }""") - exec py.code.Source(transformer).compile() + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(transformer).compile() in ns + ToAST = ns["ToAST"] print transformer t = t.visit(ToAST()) @@ -260,6 +266,29 @@ assert [c.symbol for c in t.children[0].children] == ["QUOTED_STRING"] * 2 t = parse("['a']") +def test_transform_star(): + py.test.skip("This needs to be fixed - generated transformer is buggy") + regexs, rules, transformer = parse_ebnf(""" + IGNORE: " "; + ATOM: "[\+a-zA-Z_][a-zA-Z0-9_]*"; + + sexpr: ATOM | list; + list: "(" sexpr* ")"; +""") + parse = make_parse_function(regexs, rules) + tree = parse("()") + print transformer + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(transformer).compile() in ns + ToAST = ns["ToAST"] + list_expr = tree.visit(ToAST()).children[0] + assert list_expr.symbol == 'list' + # should have two children, "(" and ")" + assert len(list_expr.children) == 2 + assert list_expr.children[0].symbol == '(' + assert list_expr.children[1].symbol == ')' + + def test_quoting(): regexs, rules, transformer = parse_ebnf(""" ATOM: "[a-z]*"; Modified: pypy/branch/mininal-c-backend/pypy/rlib/streamio.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rlib/streamio.py (original) +++ pypy/branch/mininal-c-backend/pypy/rlib/streamio.py Thu Nov 23 12:28:43 2006 @@ -206,6 +206,9 @@ def try_to_find_file_descriptor(self): return -1 + def getnewlines(self): + return 0 + class DiskFile(Stream): @@ -352,6 +355,7 @@ ("close", []), ("peek", []), ("try_to_find_file_descriptor", []), + ("getnewlines", []), ]) def PassThrough(meth_name, flush_buffers): @@ -735,25 +739,7 @@ self.CRLF = False def getnewlines(self): - foundchars = self.CR * 1 + self.NL * 2 + self.CRLF * 4 - if not foundchars: - return None - if foundchars in [1, 2, 4]: - if self.CR: - return '\r' - elif self.NL: - return '\n' - else: - return '\r\n' - else: - result = [] - if self.CR: - result.append('\r') - if self.NL: - result.append('\n') - if self.CRLF: - result.append('\r\n') - return tuple(result) + return self.CR * 1 + self.NL * 2 + self.CRLF * 4 def read(self, n): """Read up to n bytes.""" Modified: pypy/branch/mininal-c-backend/pypy/rlib/test/test_streamio.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rlib/test/test_streamio.py (original) +++ pypy/branch/mininal-c-backend/pypy/rlib/test/test_streamio.py Thu Nov 23 12:28:43 2006 @@ -354,7 +354,7 @@ for seekto in range(0, end+1) for whence in [0, 1, 2]] random.shuffle(cases) - if isinstance(self, LLRtypeMixin): + if isinstance(self, (LLRtypeMixin, OORtypeMixin)): cases = cases[:7] # pick some cases at random - too slow! def f(): all = file.readall() @@ -387,7 +387,7 @@ for seekto in range(readto, end+1) for whence in [1, 2]] random.shuffle(cases) - if isinstance(self, LLRtypeMixin): + if isinstance(self, (LLRtypeMixin, OORtypeMixin)): cases = cases[:7] # pick some cases at random - too slow! def f(): for readto, seekto, whence in cases: @@ -415,6 +415,10 @@ LLRtypeMixin): pass +class TestBufferingInputStreamTestsOOinterp(BaseTestBufferingInputStreamTests, + OORtypeMixin): + pass + class TestBufferedRead: packets = ["a", "b", "\n", "def", "\nxy\npq\nuv", "wx"] lines = ["ab\n", "def\n", "xy\n", "pq\n", "uvwx"] @@ -509,7 +513,11 @@ class TestBufferingOutputStreamLLinterp(BaseTestBufferingOutputStream, LLRtypeMixin): pass - + +class TestBufferingOutputStreamOOinterp(BaseTestBufferingOutputStream, + OORtypeMixin): + pass + class BaseTestLineBufferingOutputStream(BaseRtypingTest): @@ -550,7 +558,11 @@ class TestLineBufferingOutputStreamLLinterp(BaseTestLineBufferingOutputStream, LLRtypeMixin): pass - + +class TestLineBufferingOutputStreamOOinterp(BaseTestLineBufferingOutputStream, + OORtypeMixin): + pass + class BaseTestCRLFFilter(BaseRtypingTest): @@ -575,6 +587,8 @@ class TestCRLFFilterLLinterp(BaseTestCRLFFilter, LLRtypeMixin): pass +class TestCRLFFilterOOinterp(BaseTestCRLFFilter, OORtypeMixin): + pass class TestMMapFile(BaseTestBufferingInputStreamTests): tfn = None @@ -678,6 +692,10 @@ BaseTestBufferingInputOutputStreamTests, LLRtypeMixin): pass +class TestBufferingInputOutputStreamTestsOOinterp( + BaseTestBufferingInputOutputStreamTests, OORtypeMixin): + pass + class BaseTestTextInputFilter(BaseRtypingTest): @@ -717,15 +735,13 @@ ] expected_newlines = [ - (["abcd"], [None]), - (["abcd\n"], ["\n"]), - (["abcd\r\n"],["\r\n"]), - (["abcd\r"],[None]), # wrong, but requires precognition to fix - (["abcd\r", "\nefgh"], [None, "\r\n"]), - (["abcd", "\nefg\r", "hij", "k\r\n"], [None, "\n", ("\r", "\n"), - ("\r", "\n", "\r\n")]), - (["abcd", "\refg\r", "\nhij", "k\n"], [None, "\r", ("\r", "\r\n"), - ("\r", "\n", "\r\n")]) + (["abcd"], [0]), + (["abcd\n"], [2]), + (["abcd\r\n"],[4]), + (["abcd\r"],[0]), # wrong, but requires precognition to fix + (["abcd\r", "\nefgh"], [0, 4]), + (["abcd", "\nefg\r", "hij", "k\r\n"], [0, 2, 3, 7]), + (["abcd", "\refg\r", "\nhij", "k\n"], [0, 1, 5, 7]) ] def test_read(self): @@ -774,7 +790,18 @@ bufs.append(data) assert "".join(bufs) == all self.interpret(f, []) - + + def test_newlines_attribute(self): + for packets, expected in self.expected_newlines: + base = TReader(packets) + filter = streamio.TextInputFilter(base) + def f(): + for e in expected: + filter.read(100) + assert filter.getnewlines() == e + self.interpret(f, []) + + class TestTextInputFilter(BaseTestTextInputFilter): def interpret(self, func, args): return func(*args) @@ -782,6 +809,9 @@ class TestTextInputFilterLLinterp(BaseTestTextInputFilter, LLRtypeMixin): pass +class TestTextInputFilterOOinterp(BaseTestTextInputFilter, OORtypeMixin): + pass + class BaseTestTextOutputFilter(BaseRtypingTest): @@ -862,6 +892,9 @@ class TestTextOutputFilterLLinterp(BaseTestTextOutputFilter, LLRtypeMixin): pass +class TestTextOutputFilterOOinterp(BaseTestTextOutputFilter, OORtypeMixin): + pass + class TestDecodingInputFilter: @@ -897,22 +930,6 @@ filter.write(c) assert base.buf == data -class OldDisabledTests: - def test_readlines(self): - # This also tests next() and __iter__() - file = self.makeStream() - assert file.readlines() == self.lines - - - def test_newlines_attribute(self): - - for packets, expected in self.expected_newlines: - base = TReader(packets) - filter = streamio.TextInputFilter(base) - for e in expected: - filter.read(100) - assert filter.newlines == e - # Speed test Modified: pypy/branch/mininal-c-backend/pypy/rpython/annlowlevel.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/annlowlevel.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/annlowlevel.py Thu Nov 23 12:28:43 2006 @@ -10,16 +10,6 @@ from pypy.rpython import extfunctable, extregistry from pypy.objspace.flow.model import Constant -def not_const(s_obj): # xxx move it somewhere else - if s_obj.is_constant(): - new_s_obj = annmodel.SomeObject() - new_s_obj.__class__ = s_obj.__class__ - new_s_obj.__dict__ = s_obj.__dict__.copy() - del new_s_obj.const - s_obj = new_s_obj - return s_obj - - class KeyComp(object): def __init__(self, val): self.val = val @@ -59,7 +49,7 @@ key.append(KeyComp(s_obj.const)) new_args_s.append(s_obj) else: - new_args_s.append(not_const(s_obj)) + new_args_s.append(annmodel.not_const(s_obj)) try: key.append(annmodel.annotation_to_lltype(s_obj)) except ValueError: @@ -290,7 +280,7 @@ translator = self.rtyper.annotator.translator newgraphs = translator.graphs[self.original_graph_count:] self.original_graph_count = len(translator.graphs) - backend_optimizations(translator, newgraphs, **flags) + backend_optimizations(translator, newgraphs, secondary=True, **flags) # ____________________________________________________________ @@ -359,6 +349,7 @@ def cast_instance_to_base_ptr(instance): return cast_object_to_ptr(base_ptr_lltype(), instance) +cast_instance_to_base_ptr._annspecialcase_ = 'specialize:argtype(0)' def base_ptr_lltype(): from pypy.rpython.lltypesystem.rclass import OBJECTPTR Modified: pypy/branch/mininal-c-backend/pypy/rpython/callparse.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/callparse.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/callparse.py Thu Nov 23 12:28:43 2006 @@ -1,6 +1,6 @@ from pypy.interpreter.argument import Arguments, ArgErr from pypy.annotation import model as annmodel -from pypy.rpython.lltypesystem import rtuple # XXX not independent of type system! +from pypy.rpython import rtuple from pypy.rpython.error import TyperError from pypy.rpython.lltypesystem import lltype @@ -137,12 +137,12 @@ return self.holders def _emit(self, repr, hop): - assert isinstance(repr, rtuple.TupleRepr) + assert isinstance(repr, rtuple.AbstractTupleRepr) tupleitems_v = [] for h in self.holders: v = h.emit(repr.items_r[len(tupleitems_v)], hop) tupleitems_v.append(v) - vtuple = rtuple.newtuple(hop.llops, repr, tupleitems_v) + vtuple = repr.newtuple(hop.llops, repr, tupleitems_v) return vtuple Modified: pypy/branch/mininal-c-backend/pypy/rpython/llinterp.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/llinterp.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/llinterp.py Thu Nov 23 12:28:43 2006 @@ -448,9 +448,8 @@ import pdb pdb.set_trace() - def op_debug_log_exc(self, exc_type): - # do nothing, this is useful in compiled code - pass + def op_debug_assert(self, x, msg): + assert x, msg def op_debug_fatalerror(self, ll_msg, ll_exc=None): msg = ''.join(ll_msg.chars) @@ -460,6 +459,9 @@ ll_exc_type = lltype.cast_pointer(rclass.OBJECTPTR, ll_exc).typeptr raise LLFatalError(msg, LLException(ll_exc_type, ll_exc)) + def op_instrument_count(self, ll_tag, ll_label): + pass # xxx for now + def op_keepalive(self, value): pass @@ -556,8 +558,6 @@ return exceptiontransform.error_value(FTYPE.RESULT) raise - op_safe_call = op_direct_call - def op_indirect_call(self, f, *args): graphs = args[-1] args = args[:-1] Modified: pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/lloperation.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/lloperation.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/lloperation.py Thu Nov 23 12:28:43 2006 @@ -123,7 +123,7 @@ 'direct_call': LLOp(canraise=(Exception,)), 'indirect_call': LLOp(canraise=(Exception,)), - 'safe_call': LLOp(), + #'safe_call': LLOp(), 'unsafe_call': LLOp(canraise=(Exception,)), # __________ numeric operations __________ @@ -399,9 +399,11 @@ 'debug_view': LLOp(), 'debug_print': LLOp(), 'debug_pdb': LLOp(), - 'debug_log_exc': LLOp(), - 'debug_assert': LLOp(canfold=True), + 'debug_assert': LLOp(), 'debug_fatalerror': LLOp(), + + # __________ instrumentation _________ + 'instrument_count': LLOp(), } # __________ operations on PyObjects __________ Modified: pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/opimpl.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/opimpl.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/opimpl.py Thu Nov 23 12:28:43 2006 @@ -359,20 +359,6 @@ raise TypeError("cannot fold getfield on mutable array") return p[index] - -def op_debug_assert(expr, *ll_args): - if not isinstance(expr, str): - if hasattr(expr, 'chars'): # for lltypesystem - expr = ''.join(expr.chars) - elif hasattr(expr, '_str'): # for ootypesystem - expr = expr._str - else: - raise TypeError("what is %r??" % (expr,)) - names = ['v%d' % i for i in range(len(ll_args))] - d = dict(zip(names, ll_args)) - names = tuple(names) - assert eval(expr % names, d) - # ____________________________________________________________ def get_op_impl(opname): Modified: pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rdict.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rdict.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rdict.py Thu Nov 23 12:28:43 2006 @@ -170,6 +170,8 @@ 'keyeq': ll_keyeq, 'paranoia': False, } + adtmeths['KEY'] = self.DICTKEY + adtmeths['VALUE'] = self.DICTVALUE self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths, *fields)) @@ -394,6 +396,7 @@ return entry.value else: raise KeyError +ll_dict_getitem.oopspec = 'dict.getitem(d, key)' def ll_dict_setitem(d, key, value): hash = d.keyhash(key) @@ -414,6 +417,7 @@ d.num_pristine_entries -= 1 if d.num_pristine_entries <= len(d.entries) / 3: ll_dict_resize(d) +ll_dict_setitem.oopspec = 'dict.setitem(d, key, value)' def ll_dict_insertclean(d, key, value, hash): # Internal routine used by ll_dict_resize() to insert an item which is @@ -554,6 +558,7 @@ d.num_items = 0 d.num_pristine_entries = DICT_INITSIZE return d +ll_newdict.oopspec = 'newdict()' def ll_newdict_size(DICT, length_estimate): length_estimate = (length_estimate // 2) * 3 @@ -565,6 +570,7 @@ d.num_items = 0 d.num_pristine_entries = DICT_INITSIZE return d +ll_newdict_size.oopspec = 'newdict()' def rtype_r_dict(hop): @@ -729,3 +735,4 @@ def ll_contains(d, key): entry = ll_dict_lookup(d, key, d.keyhash(key)) return entry.valid() +ll_contains.oopspec = 'dict.contains(d, key)' Modified: pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rlist.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rlist.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rlist.py Thu Nov 23 12:28:43 2006 @@ -16,6 +16,7 @@ Bool, nullptr, typeMethod from pypy.rpython.lltypesystem import rstr from pypy.rpython import robject +from pypy.rlib.objectmodel import debug_assert # ____________________________________________________________ # @@ -374,6 +375,7 @@ # Accessor methods def ll_newlist(LIST, length): + debug_assert(length >= 0, "negative list length") l = malloc(LIST) l.length = length l.items = malloc(LIST.items.TO, length) @@ -387,19 +389,18 @@ def ll_items(l): return l.items -from pypy.rpython.lltypesystem.lloperation import llop - def ll_getitem_fast(l, index): - llop.debug_assert(Void, "%s < %s.length # getitem out of bounds", index, l) + debug_assert(index < l.length, "getitem out of bounds") return l.ll_items()[index] def ll_setitem_fast(l, index, item): - llop.debug_assert(Void, "%s < %s.length # setitem out of bounds", index, l) + debug_assert(index < l.length, "setitem out of bounds") l.ll_items()[index] = item # fixed size versions def ll_fixed_newlist(LIST, length): + debug_assert(length >= 0, "negative fixed list length") l = malloc(LIST, length) return l ll_fixed_newlist = typeMethod(ll_fixed_newlist) @@ -412,9 +413,11 @@ return l def ll_fixed_getitem_fast(l, index): + debug_assert(index < len(l), "fixed getitem out of bounds") return l[index] def ll_fixed_setitem_fast(l, index, item): + debug_assert(index < len(l), "fixed setitem out of bounds") l[index] = item def newlist(llops, r_list, items_v): Modified: pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rstr.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rstr.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rstr.py Thu Nov 23 12:28:43 2006 @@ -2,6 +2,7 @@ from pypy.annotation.pairtype import pairtype from pypy.rpython.error import TyperError from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated +from pypy.rlib.objectmodel import debug_assert from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rlib.rarithmetic import _hash_string from pypy.rpython.rmodel import inputconst, IntegerRepr @@ -109,10 +110,8 @@ resulttype=pyobj_repr, _callable= lambda chars, sz: pyobjectptr(''.join(chars))) -from pypy.rpython.lltypesystem.lloperation import llop - def mallocstr(length): - llop.debug_assert(Void, "%s >= 0 # negative string length", length) + debug_assert(length >= 0, "negative string length") r = malloc(STR, length) if not we_are_translated() or not malloc_zero_filled: r.hash = 0 Modified: pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rtupletype.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rtupletype.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/lltypesystem/rtupletype.py Thu Nov 23 12:28:43 2006 @@ -10,5 +10,6 @@ return Void # empty tuple else: fields = [('item%d' % i, TYPE) for i, TYPE in enumerate(field_lltypes)] - kwds = {'hints': {'immutable': True}} + kwds = {'hints': {'immutable': True, + 'noidentity': True}} return Ptr(GcStruct('tuple%d' % len(field_lltypes), *fields, **kwds)) Modified: pypy/branch/mininal-c-backend/pypy/rpython/memory/gctransform/framework.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/memory/gctransform/framework.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/memory/gctransform/framework.py Thu Nov 23 12:28:43 2006 @@ -443,6 +443,7 @@ self.default(hop) gct_indirect_call = gct_direct_call + gct_unsafe_call = gct_direct_call def gct_malloc(self, hop): op = hop.spaceop Modified: pypy/branch/mininal-c-backend/pypy/rpython/memory/gctransform/transform.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/memory/gctransform/transform.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/memory/gctransform/transform.py Thu Nov 23 12:28:43 2006 @@ -313,8 +313,8 @@ hop.rename('bare_' + hop.spaceop.opname) gct_setarrayitem = gct_setfield - def gct_safe_call(self, hop): - hop.rename("direct_call") + #def gct_safe_call(self, hop): + # hop.rename("direct_call") def gct_zero_gc_pointers_inside(self, hop): pass Modified: pypy/branch/mininal-c-backend/pypy/rpython/rbuiltin.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/rbuiltin.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/rbuiltin.py Thu Nov 23 12:28:43 2006 @@ -624,6 +624,7 @@ hints[key[2:]] = s_value.const v = hop.inputarg(hop.args_r[0], arg=0) c_hint = hop.inputconst(lltype.Void, hints) + hop.exception_cannot_occur() return hop.genop('hint', [v, c_hint], resulttype=v.concretetype) BUILTIN_TYPER[objectmodel.hint] = rtype_hint Modified: pypy/branch/mininal-c-backend/pypy/rpython/rint.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/rint.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/rint.py Thu Nov 23 12:28:43 2006 @@ -174,10 +174,16 @@ appendix = op_appendices[implicit_exc] func += '_' + appendix - repr = hop.rtyper.makerepr(hop.s_result) + r_result = hop.rtyper.makerepr(hop.s_result) + if r_result.lowleveltype == Bool: + repr = signed_repr + else: + repr = r_result vlist = hop.inputargs(repr, repr) hop.exception_is_here() - return hop.genop(repr.opprefix+func, vlist, resulttype=repr) + v_res = hop.genop(repr.opprefix+func, vlist, resulttype=repr) + v_res = hop.llops.convertvar(v_res, repr, r_result) + return v_res #Helper functions for comparisons Modified: pypy/branch/mininal-c-backend/pypy/rpython/rlist.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/rlist.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/rlist.py Thu Nov 23 12:28:43 2006 @@ -6,9 +6,8 @@ from pypy.rpython.rslice import AbstractSliceRepr from pypy.rpython.lltypesystem.lltype import typeOf, Ptr, Void, Signed, Bool from pypy.rpython.lltypesystem.lltype import nullptr, Char, UniChar -from pypy.rpython.lltypesystem.lloperation import llop from pypy.rpython import robject -from pypy.rlib.objectmodel import malloc_zero_filled +from pypy.rlib.objectmodel import malloc_zero_filled, debug_assert from pypy.rpython.annlowlevel import ADTInterface ADTIFixedList = ADTInterface(None, { @@ -474,6 +473,8 @@ def ll_insert_nonneg(l, index, newitem): length = l.ll_length() + debug_assert(0 <= index, "negative list insertion index") + debug_assert(index <= length, "list insertion index out of bound") l._ll_resize_ge(length+1) dst = length while dst > index: @@ -484,8 +485,12 @@ ll_insert_nonneg.oopspec = 'list.insert(l, index, newitem)' def ll_pop_nonneg(func, l, index): - if func is dum_checkidx and (index >= l.ll_length()): - raise IndexError + debug_assert(index >= 0, "unexpectedly negative list pop index") + if func is dum_checkidx: + if index >= l.ll_length(): + raise IndexError + else: + debug_assert(index < l.ll_length(), "list pop index out of bound") res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res @@ -495,6 +500,7 @@ length = l.ll_length() if func is dum_checkidx and (length == 0): raise IndexError + debug_assert(length > 0, "pop from empty list") index = length - 1 newlength = index res = l.ll_getitem_fast(index) @@ -509,6 +515,7 @@ length = l.ll_length() if func is dum_checkidx and (length == 0): raise IndexError + debug_assert(length > 0, "pop(0) from empty list") newlength = length - 1 res = l.ll_getitem_fast(0) j = 0 @@ -528,8 +535,12 @@ length = l.ll_length() if index < 0: index += length - if func is dum_checkidx and (index < 0 or index >= length): - raise IndexError + if func is dum_checkidx: + if index < 0 or index >= length: + raise IndexError + else: + debug_assert(index >= 0, "negative list pop index out of bound") + debug_assert(index < length, "list pop index out of bound") res = l.ll_getitem_fast(index) ll_delitem_nonneg(dum_nocheck, l, index) return res @@ -548,8 +559,12 @@ ll_reverse.oopspec = 'list.reverse(l)' def ll_getitem_nonneg(func, l, index): - if func is dum_checkidx and (index >= l.ll_length()): - raise IndexError + debug_assert(index >= 0, "unexpectedly negative list getitem index") + if func is dum_checkidx: + if index >= l.ll_length(): + raise IndexError + else: + debug_assert(index < l.ll_length(), "list getitem index out of bound") return l.ll_getitem_fast(index) ll_getitem_nonneg.oopspec = 'list.getitem(l, index)' @@ -557,14 +572,22 @@ length = l.ll_length() if index < 0: index += length - if func is dum_checkidx and (index < 0 or index >= length): - raise IndexError + if func is dum_checkidx: + if index < 0 or index >= length: + raise IndexError + else: + debug_assert(index >= 0, "negative list getitem index out of bound") + debug_assert(index < length, "list getitem index out of bound") return l.ll_getitem_fast(index) ll_getitem.oopspec = 'list.getitem(l, index)' def ll_setitem_nonneg(func, l, index, newitem): - if func is dum_checkidx and (index >= l.ll_length()): - raise IndexError + debug_assert(index >= 0, "unexpectedly negative list setitem index") + if func is dum_checkidx: + if index >= l.ll_length(): + raise IndexError + else: + debug_assert(index < l.ll_length(), "list setitem index out of bound") l.ll_setitem_fast(index, newitem) ll_setitem_nonneg.oopspec = 'list.setitem(l, index, newitem)' @@ -572,15 +595,23 @@ length = l.ll_length() if index < 0: index += length - if func is dum_checkidx and (index < 0 or index >= length): - raise IndexError + if func is dum_checkidx: + if index < 0 or index >= length: + raise IndexError + else: + debug_assert(index >= 0, "negative list setitem index out of bound") + debug_assert(index < length, "list setitem index out of bound") l.ll_setitem_fast(index, newitem) ll_setitem.oopspec = 'list.setitem(l, index, newitem)' def ll_delitem_nonneg(func, l, index): + debug_assert(index >= 0, "unexpectedly negative list delitem index") length = l.ll_length() - if func is dum_checkidx and (index >= length): - raise IndexError + if func is dum_checkidx: + if index >= length: + raise IndexError + else: + debug_assert(index < length, "list delitem index out of bound") newlength = length - 1 j = index j1 = j+1 @@ -599,8 +630,12 @@ length = l.ll_length() if i < 0: i += length - if func is dum_checkidx and (i < 0 or i >= length): - raise IndexError + if func is dum_checkidx: + if i < 0 or i >= length: + raise IndexError + else: + debug_assert(i >= 0, "negative list delitem index out of bound") + debug_assert(i < length, "list delitem index out of bound") ll_delitem_nonneg(dum_nocheck, l, i) ll_delitem.oopspec = 'list.delitem(l, i)' @@ -619,6 +654,8 @@ def ll_listslice_startonly(RESLIST, l1, start): len1 = l1.ll_length() + debug_assert(start >= 0, "unexpectedly negative list slice start") + debug_assert(start <= len1, "list slice start larger than list length") newlength = len1 - start l = RESLIST.ll_newlist(newlength) j = 0 @@ -633,6 +670,9 @@ start = slice.start stop = slice.stop length = l1.ll_length() + debug_assert(start >= 0, "unexpectedly negative list slice start") + debug_assert(start <= length, "list slice start larger than list length") + debug_assert(stop >= start, "list slice stop smaller than start") if stop > length: stop = length newlength = stop - start @@ -647,8 +687,7 @@ def ll_listslice_minusone(RESLIST, l1): newlength = l1.ll_length() - 1 - llop.debug_assert(Void, "%s >= 0 # empty list is sliced with [:-1]", - newlength) + debug_assert(newlength >= 0, "empty list is sliced with [:-1]") l = RESLIST.ll_newlist(newlength) j = 0 while j < newlength: @@ -657,6 +696,8 @@ return l def ll_listdelslice_startonly(l, start): + debug_assert(start >= 0, "del l[start:] with unexpectedly negative start") + debug_assert(start <= l.ll_length(), "del l[start:] with start > len(l)") newlength = start null = ll_null_item(l) if null is not None: @@ -670,6 +711,9 @@ start = slice.start stop = slice.stop length = l.ll_length() + debug_assert(start >= 0, "del l[start:x] with unexpectedly negative start") + debug_assert(start <= length, "del l[start:x] with start > len(l)") + debug_assert(stop >= start, "del l[x:y] with x > y") if stop > length: stop = length newlength = length - (stop-start) @@ -689,11 +733,12 @@ def ll_listsetslice(l1, slice, l2): count = l2.ll_length() - llop.debug_assert(Void, - "%s == %s - %s # setslice cannot resize lists in RPython", - count, slice.stop, slice.start) - # XXX but it should be easy enough to support, soon start = slice.start + debug_assert(start >= 0, "l[start:x] = l with unexpectedly negative start") + debug_assert(start <= l1.ll_length(), "l[start:x] = l with start > len(l)") + debug_assert(count == slice.stop - start, + "setslice cannot resize lists in RPython") + # XXX but it should be easy enough to support, soon j = start i = 0 while i < count: Modified: pypy/branch/mininal-c-backend/pypy/rpython/rpbc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/rpbc.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/rpbc.py Thu Nov 23 12:28:43 2006 @@ -567,6 +567,12 @@ def rtype_is_true(self, hop): return Constant(False, Bool) + def none_call(self, hop): + raise TyperError("attempt to call constant None") + + rtype_simple_call = none_call + rtype_call_args = none_call + none_frozen_pbc_repr = NoneFrozenPBCRepr() @@ -744,6 +750,8 @@ return v if r_clspbc1.lowleveltype is Void: return inputconst(r_clspbc2, r_clspbc1.s_pbc.const) + if r_clspbc2.lowleveltype is Void: + return inputconst(Void, r_clspbc2.s_pbc.const) return NotImplemented def adjust_shape(hop2, s_shape): Modified: pypy/branch/mininal-c-backend/pypy/rpython/rtuple.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/rtuple.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/rtuple.py Thu Nov 23 12:28:43 2006 @@ -124,6 +124,9 @@ def rtype_len(self, hop): return hop.inputconst(Signed, len(self.items_r)) + def rtype_id(self, hop): + raise TyperError("cannot ask for the id() of a tuple") + def get_ll_eq_function(self): return gen_eq_function(self.items_r) @@ -218,7 +221,10 @@ items_v.append(item_v) return r_from.newtuple(llops, r_to, items_v) return NotImplemented - + + def rtype_is_((robj1, robj2), hop): + raise TyperError("cannot compare tuples with 'is'") + class AbstractTupleIteratorRepr(IteratorRepr): Modified: pypy/branch/mininal-c-backend/pypy/rpython/test/test_rpbc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/test/test_rpbc.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/test/test_rpbc.py Thu Nov 23 12:28:43 2006 @@ -1458,6 +1458,25 @@ res = self.interpret(call_functionarg, []) assert res == 2 * 42 + 4 + def test_convert_multiple_classes_to_single(self): + class A: + result = 321 + def meth(self, n): + if n: + return A + else: + return B + class B(A): + result = 123 + def meth(self, n): + return B + def f(n): + A().meth(n) + cls = B().meth(n) + return cls().result + res = self.interpret(f, [5]) + assert res == 123 + # We don't care about the following test_hlinvoke tests working on # ootype. Maybe later. This kind of thing is only used in rdict Modified: pypy/branch/mininal-c-backend/pypy/rpython/test/test_rtuple.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/rpython/test/test_rtuple.py (original) +++ pypy/branch/mininal-c-backend/pypy/rpython/test/test_rtuple.py Thu Nov 23 12:28:43 2006 @@ -106,11 +106,11 @@ 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) + return x, y, z def f(): return g(5) res = self.interpret(f, []) - assert res is True + assert res.item0 == res.item1 == res.item2 def test_inst_tuple_getitem(self): class A: Modified: pypy/branch/mininal-c-backend/pypy/tool/build/README.txt ============================================================================== --- pypy/branch/mininal-c-backend/pypy/tool/build/README.txt (original) +++ pypy/branch/mininal-c-backend/pypy/tool/build/README.txt Thu Nov 23 12:28:43 2006 @@ -35,7 +35,8 @@ If there isn't one, the server walks through a list of connected participating clients to see if one of them can handle the job, and if so dispatches the compilation. If there's no participating client to handle the job, it gets -queued until there is. +queued until there is. Also, if a client crashes during compilation, the job +gets re-queued. This process will continue until a suitable build is available. Once a build is available, the server will send an email to all email addresses (it could be that more than one person asked for some build at the same time!) Modified: pypy/branch/mininal-c-backend/pypy/translator/asm/ppcgen/ppc_assembler.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/asm/ppcgen/ppc_assembler.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/asm/ppcgen/ppc_assembler.py Thu Nov 23 12:28:43 2006 @@ -19,7 +19,7 @@ X = Form("XO1") XS = Form("rA", "rS", "rB", "XO1", "Rc") -XS0 = Form("rS", "rA", "rB", "XO1") +XSO = Form("rS", "rA", "rB", "XO1") XD = Form("rD", "rA", "rB", "XO1") XO = Form("rD", "rA", "rB", "OE", "XO2", "Rc") XO0 = Form("rD", "rA", "OE", "XO2", "Rc") @@ -405,22 +405,22 @@ srw = XS(31, XO1=536, Rc=0) srwx = XS(31, XO1=536, Rc=1) - stbux = XS0(31, XO1=247) - stbx = XS0(31, XO1=215) - stfdux = XS0(31, XO1=759) - stfdx = XS0(31, XO1=727) - stfiwx = XS0(31, XO1=983) - stfsux = XS0(31, XO1=695) - stfsx = XS0(31, XO1=663) - sthbrx = XS0(31, XO1=918) - sthux = XS0(31, XO1=439) - sthx = XS0(31, XO1=407) + stbux = XSO(31, XO1=247) + stbx = XSO(31, XO1=215) + stfdux = XSO(31, XO1=759) + stfdx = XSO(31, XO1=727) + stfiwx = XSO(31, XO1=983) + stfsux = XSO(31, XO1=695) + stfsx = XSO(31, XO1=663) + sthbrx = XSO(31, XO1=918) + sthux = XSO(31, XO1=439) + sthx = XSO(31, XO1=407) stswi = Form("rS", "rA", "NB", "XO1")(31, XO1=725) - stswx = XS0(31, XO1=661) - stwbrx = XS0(31, XO1=662) + stswx = XSO(31, XO1=661) + stwbrx = XSO(31, XO1=662) stwcxx = Form("rS", "rA", "rB", "XO1", "Rc")(31, XO1=150, Rc=1) - stwux = XS0(31, XO1=183) - stwx = XS0(31, XO1=151) + stwux = XSO(31, XO1=183) + stwx = XSO(31, XO1=151) subf = XO(31, XO2=40, OE=0, Rc=0) subfx = XO(31, XO2=40, OE=0, Rc=1) Modified: pypy/branch/mininal-c-backend/pypy/translator/backendopt/all.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/backendopt/all.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/backendopt/all.py Thu Nov 23 12:28:43 2006 @@ -12,7 +12,7 @@ from pypy.translator.backendopt.support import log from pypy.objspace.flow.model import checkgraph -def backend_optimizations(translator, graphs=None, **kwds): +def backend_optimizations(translator, graphs=None, secondary=False, **kwds): # sensible keywords are # raisingop2direct_call, inline_threshold, mallocs # merge_if_blocks, constfold, heap2stack @@ -43,35 +43,22 @@ print_statistics(translator.graphs[0], translator) if not config.clever_malloc_removal: - # inline functions in each other - if config.inline_threshold: - callgraph = inline.inlinable_static_callers(graphs) - inline.auto_inlining(translator, config.inline_threshold, - callgraph=callgraph) - for graph in graphs: - removenoops.remove_superfluous_keep_alive(graph) - removenoops.remove_duplicate_casts(graph, translator) - - if config.print_statistics: - print "after inlining:" - print_statistics(translator.graphs[0], translator) - - # vaporize mallocs - if config.mallocs: - tot = 0 - for graph in graphs: - count = remove_simple_mallocs(graph) - if count: - # remove typical leftovers from malloc removal - removenoops.remove_same_as(graph) - simplify.eliminate_empty_blocks(graph) - simplify.transform_dead_op_vars(graph, translator) - tot += count - log.malloc("removed %d simple mallocs in total" % tot) - - if config.print_statistics: - print "after malloc removal:" - print_statistics(translator.graphs[0], translator) + if config.profile_based_inline and not secondary: + inline_malloc_removal_phase(config, translator, graphs, + config.inline_threshold*.5) # xxx tune! + inline.instrument_inline_candidates(graphs, config.inline_threshold) + counters = translator.driver_instrument_result( + config.profile_based_inline) + n = len(counters) + def call_count_pred(label): + if label >= n: + return False + return counters[label] > 250 # xxx tune! + else: + call_count_pred = None + inline_malloc_removal_phase(config, translator, graphs, + config.inline_threshold, + call_count_pred=call_count_pred) else: assert graphs is translator.graphs # XXX for now clever_inlining_and_malloc_removal(translator) @@ -101,3 +88,45 @@ for graph in graphs: checkgraph(graph) + +def inline_malloc_removal_phase(config, translator, graphs, inline_threshold, + call_count_pred=None): + + log.inlining("phase with threshold factor: %s" % inline_threshold) + + # inline functions in each other + if inline_threshold: + callgraph = inline.inlinable_static_callers(graphs) + count = inline.auto_inlining(translator, inline_threshold, + callgraph=callgraph, + call_count_pred=call_count_pred) + log.inlining('inlined %d callsites.'% (count,)) + for graph in graphs: + removenoops.remove_superfluous_keep_alive(graph) + removenoops.remove_duplicate_casts(graph, translator) + + if config.print_statistics: + print "after inlining:" + print_statistics(translator.graphs[0], translator) + + # vaporize mallocs + if config.mallocs: + tot = 0 + for graph in graphs: + count = remove_simple_mallocs(graph) + if count: + # remove typical leftovers from malloc removal + removenoops.remove_same_as(graph) + simplify.eliminate_empty_blocks(graph) + simplify.transform_dead_op_vars(graph, translator) + tot += count + log.malloc("removed %d simple mallocs in total" % tot) + + if config.print_statistics: + print "after malloc removal:" + print_statistics(translator.graphs[0], translator) + + if config.constfold: + for graph in graphs: + constant_fold_graph(graph) + Modified: pypy/branch/mininal-c-backend/pypy/translator/backendopt/graphanalyze.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/backendopt/graphanalyze.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/backendopt/graphanalyze.py Thu Nov 23 12:28:43 2006 @@ -38,6 +38,8 @@ if op.args[-1].value is None: return True return self.analyze_indirect_call(op.args[-1].value, seen) + elif op.opname == "unsafe_call": + return True if self.operation_is_true(op): return True Modified: pypy/branch/mininal-c-backend/pypy/translator/backendopt/inline.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/backendopt/inline.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/backendopt/inline.py Thu Nov 23 12:28:43 2006 @@ -7,7 +7,7 @@ from pypy.objspace.flow.model import FunctionGraph from pypy.objspace.flow.model import traverse, mkentrymap, checkgraph from pypy.annotation import model as annmodel -from pypy.rpython.lltypesystem.lltype import Bool, typeOf, Void, Ptr +from pypy.rpython.lltypesystem.lltype import Bool, Signed, typeOf, Void, Ptr from pypy.rpython.lltypesystem.lltype import normalizeptr from pypy.rpython import rmodel from pypy.tool.algo import sparsemat @@ -72,9 +72,10 @@ return False def inline_function(translator, inline_func, graph, lltype_to_classdef, - raise_analyzer): + raise_analyzer, call_count_pred=None): inliner = Inliner(translator, graph, inline_func, lltype_to_classdef, - raise_analyzer = raise_analyzer) + raise_analyzer = raise_analyzer, + call_count_pred=call_count_pred) return inliner.inline_all() def simple_inline_function(translator, inline_func, graph): @@ -128,7 +129,9 @@ class BaseInliner(object): def __init__(self, translator, graph, lltype_to_classdef, inline_guarded_calls=False, - inline_guarded_calls_no_matter_what=False, raise_analyzer=None): + inline_guarded_calls_no_matter_what=False, + raise_analyzer=None, + call_count_pred=None): self.translator = translator self.graph = graph self.inline_guarded_calls = inline_guarded_calls @@ -138,10 +141,12 @@ assert raise_analyzer is not None self.raise_analyzer = raise_analyzer self.lltype_to_classdef = lltype_to_classdef + self.call_count_pred = call_count_pred def inline_all(self): count = 0 non_recursive = {} + call_count_pred = self.call_count_pred while self.block_to_index: block, d = self.block_to_index.popitem() index_operation, subgraph = d.popitem() @@ -151,6 +156,13 @@ raise CannotInline("inlining a recursive function") else: non_recursive[subgraph] = True + if call_count_pred: + countop = block.operations[index_operation-1] + assert countop.opname == 'instrument_count' + assert countop.args[0].value == 'inline' + label = countop.args[1].value + if not call_count_pred(label): + continue operation = block.operations[index_operation] self.inline_once(block, index_operation) count += 1 @@ -417,12 +429,16 @@ class Inliner(BaseInliner): - def __init__(self, translator, graph, inline_func, lltype_to_classdef, inline_guarded_calls=False, - inline_guarded_calls_no_matter_what=False, raise_analyzer=None): + def __init__(self, translator, graph, inline_func, lltype_to_classdef, + inline_guarded_calls=False, + inline_guarded_calls_no_matter_what=False, + raise_analyzer=None, + call_count_pred=None): BaseInliner.__init__(self, translator, graph, lltype_to_classdef, inline_guarded_calls, inline_guarded_calls_no_matter_what, - raise_analyzer) + raise_analyzer, + call_count_pred) self.inline_func = inline_func # to simplify exception matching join_blocks(graph) @@ -447,6 +463,8 @@ 'malloc': 2, 'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme 'resume_point': sys.maxint, # XXX bit extreme + 'instrument_count': 0, + 'debug_assert': -1, } def block_weight(block, weights=OP_WEIGHTS): @@ -459,7 +477,7 @@ total += weights.get(op.opname, 1) if block.exitswitch is not None: total += 1 - return total + return max(0, total) def measure_median_execution_cost(graph): @@ -535,8 +553,48 @@ return result +def instrument_inline_candidates(graphs, multiplier): + threshold = BASE_INLINE_THRESHOLD * multiplier + cache = {None: False} + def candidate(graph): + try: + return cache[graph] + except KeyError: + res = static_instruction_count(graph) <= threshold + cache[graph] = res + return res + n = 0 + for parentgraph in graphs: + for block in parentgraph.iterblocks(): + ops = block.operations + i = len(ops)-1 + while i >= 0: + op = ops[i] + i -= 1 + if op.opname == "direct_call": + funcobj = op.args[0].value._obj + graph = getattr(funcobj, 'graph', None) + if graph is not None: + if getattr(getattr(funcobj, '_callable', None), + 'suggested_primitive', False): + continue + if getattr(getattr(funcobj, '_callable', None), + 'dont_inline', False): + continue + if candidate(graph): + tag = Constant('inline', Void) + label = Constant(n, Signed) + dummy = Variable() + dummy.concretetype = Void + count = SpaceOperation('instrument_count', + [tag, label], dummy) + ops.insert(i+1, count) + n += 1 + log.inlining("%d call sites instrumented" % n) + def auto_inlining(translator, multiplier=1, callgraph=None, - threshold=BASE_INLINE_THRESHOLD): + threshold=BASE_INLINE_THRESHOLD, + call_count_pred=None): from heapq import heappush, heappop, heapreplace, heapify threshold = threshold * multiplier callers = {} # {graph: {graphs-that-call-it}} @@ -585,14 +643,17 @@ for parentgraph in callers[graph]: if parentgraph == graph: continue + subcount = 0 try: - res = bool(inline_function(translator, graph, parentgraph, - lltype_to_classdef, raise_analyzer)) + subcount = inline_function(translator, graph, parentgraph, + lltype_to_classdef, raise_analyzer, + call_count_pred) + res = bool(subcount) except CannotInline: couldnt_inline[graph] = True res = CannotInline if res is True: - count += 1 + count += subcount # the parentgraph should now contain all calls that were # done by 'graph' for graph2 in callees.get(graph, {}): Modified: pypy/branch/mininal-c-backend/pypy/translator/backendopt/test/test_inline.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/backendopt/test/test_inline.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/backendopt/test/test_inline.py Thu Nov 23 12:28:43 2006 @@ -8,6 +8,7 @@ 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.backendopt.inline import instrument_inline_candidates from pypy.translator.translator import TranslationContext, graphof from pypy.rpython.llinterp import LLInterpreter from pypy.rlib.rarithmetic import ovfcheck @@ -66,16 +67,25 @@ return interp.eval_graph(graphof(t, entry), args) return eval_func -def check_auto_inlining(func, sig, multiplier=None): +def check_auto_inlining(func, sig, multiplier=None, call_count_check=False): t = translate(func, sig) if option.view: t.view() # inline! sanity_check(t) # also check before inlining (so we don't blame it) - if multiplier is None: - auto_inlining(t) + + if multiplier is not None: + multiplier = {'multiplier': multiplier} else: - auto_inlining(t, multiplier=multiplier) + multiplier = {} + + call_count_pred = None + if call_count_check: + call_count_pred = lambda lbl: True + instrument_inline_candidates(t.graphs, **multiplier) + + auto_inlining(t, call_count_pred=call_count_pred, **multiplier) + sanity_check(t) if option.view: t.view() @@ -364,6 +374,33 @@ result = eval_func([15]) assert result == -1 +def test_auto_inlining_small_call_big_call_count(): + def leaf(n): + total = 0 + i = 0 + while i < n: + total += i + if total > 100: + raise OverflowError + i += 1 + return total + def g(n): + return leaf(n) + def f(n): + try: + return g(n) + except OverflowError: + return -1 + eval_func, t = check_auto_inlining(f, [int], multiplier=10, + call_count_check=True) + f_graph = graphof(t, f) + assert len(collect_called_graphs(f_graph, t)) == 0 + + result = eval_func([10]) + assert result == 45 + result = eval_func([15]) + assert result == -1 + def test_inline_exception_catching(): def f3(): raise CustomError1 Modified: pypy/branch/mininal-c-backend/pypy/translator/cl/opformatter.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cl/opformatter.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cl/opformatter.py Thu Nov 23 12:28:43 2006 @@ -21,6 +21,10 @@ def nop(self, result, arg): yield "(setf %s %s)" % (result, arg) + + def op_debug_assert(self, result, *args): + return [] + op_same_as = nop op_ooupcast = nop op_oodowncast = nop Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/constant.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/constant.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/constant.py Thu Nov 23 12:28:43 2006 @@ -41,7 +41,6 @@ DEBUG_CONST_INIT = False DEBUG_CONST_INIT_VERBOSE = False -MAX_CONST_PER_STEP = 100 SERIALIZE = False # ______________________________________________________________________ Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/database.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/database.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/database.py Thu Nov 23 12:28:43 2006 @@ -127,7 +127,11 @@ return name def class_name(self, INSTANCE): - return self.classes[INSTANCE] + try: + NATIVE_INSTANCE = INSTANCE._hints['NATIVE_INSTANCE'] + return NATIVE_INSTANCE._name + except KeyError: + return self.classes[INSTANCE] def get_record_name(self, RECORD): try: Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/dotnet.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/dotnet.py Thu Nov 23 12:28:43 2006 @@ -50,7 +50,15 @@ if ooinst.ootype._isArray: return SomeOOInstance(ooinst.ootype._ELEMENT) return s_ImpossibleValue - + + def setitem((ooinst, index), s_value): + if ooinst.ootype._isArray: + ELEMENT = ooinst.ootype._ELEMENT + VALUE = s_value.ootype + assert ootype.isSubclass(VALUE, ELEMENT) + return s_None + return s_ImpossibleValue + ## Rtyper model @@ -100,6 +108,13 @@ hop.exception_is_here() return hop.genop('cli_getelem', [v_array, v_index], hop.r_result.lowleveltype) + def rtype_setitem((r_inst, r_int), hop): + if not r_inst.lowleveltype._isArray: + raise TyperError("setitem() on a non-array instance") + vlist = hop.inputargs(*hop.args_r) + hop.exception_is_here() + return hop.genop('cli_setelem', vlist, hop.r_result.lowleveltype) + ## OOType model @@ -344,12 +359,32 @@ v_obj, = hop.inputargs(*hop.args_r) return hop.genop('same_as', [v_obj], hop.r_result.lowleveltype) +def new_array(type, length): + return [None] * length def init_array(type, *args): # PythonNet doesn't provide a straightforward way to create arrays... fake it with a list return args class Entry(ExtRegistryEntry): + _about_ = new_array + + def compute_result_annotation(self, type_s, length_s): + from pypy.translator.cli.query import load_class_maybe + assert type_s.is_constant() + assert isinstance(length_s, SomeInteger) + TYPE = type_s.const._INSTANCE + fullname = '%s.%s[]' % (TYPE._namespace, TYPE._classname) + cliArray = load_class_maybe(fullname) + return SomeOOInstance(cliArray._INSTANCE) + + def specialize_call(self, hop): + c_type, v_length = hop.inputargs(*hop.args_r) + hop.exception_cannot_occur() + return hop.genop('cli_newarray', [c_type, v_length], hop.r_result.lowleveltype) + + +class Entry(ExtRegistryEntry): _about_ = init_array def compute_result_annotation(self, type_s, *args_s): Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/function.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/function.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/function.py Thu Nov 23 12:28:43 2006 @@ -60,7 +60,7 @@ if isinstance(link.last_exception, flowmodel.Variable): self.ilasm.opcode('dup') self.store(link.last_exc_value) - self.ilasm.get_field(('Object_meta', 'Object', 'meta')) + self.ilasm.get_field(('class Object_meta', 'Object', 'meta')) self.store(link.last_exception) else: self.store(link.last_exc_value) Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/ilgenerator.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/ilgenerator.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/ilgenerator.py Thu Nov 23 12:28:43 2006 @@ -252,7 +252,7 @@ self.call_method('void class [mscorlib]System.IO.TextWriter::WriteLine(string)', virtual=True) def add_comment(self, text): - self.out.write('// %s\n' % text) + self.code.writeline('// %s' % text) def flush(self): pass Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/src/pypylib.cs ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/src/pypylib.cs (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/src/pypylib.cs Thu Nov 23 12:28:43 2006 @@ -273,7 +273,7 @@ if (stop > s.Length) stop = s.Length; int count=stop-start; - if (start > s.Length) + if (start > s.Length || stop == 0) return -1; return s.LastIndexOf(ch, stop-1, count); } Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_constant.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_constant.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_constant.py Thu Nov 23 12:28:43 2006 @@ -119,3 +119,12 @@ s = A('bar') return a.dict[s] assert self.interpret(fn, [True]) == 42 + + def test_multiple_step(self): + from pypy.translator.oosupport import constant + constant.MAX_CONST_PER_STEP = 2 + c1 = [1] + c2 = [2] + def fn(x, y): + return c1[x] + c2[y] + assert self.interpret(fn, [0, 0]) == 3 Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_dict.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_dict.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_dict.py Thu Nov 23 12:28:43 2006 @@ -35,3 +35,9 @@ class TestCliConstantDict(CliTest, BaseTestRconstantdict): def test_constant_r_dict(self): py.test.skip('r_dict is not supported, yet') + + def test_tuple_as_key(self): + mydict = {('r',): 42} + def fn(ch): + return mydict[(ch,)] + assert self.interpret(fn, ['r']) == 42 Modified: pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/cli/test/test_dotnet.py Thu Nov 23 12:28:43 2006 @@ -7,7 +7,7 @@ from pypy.translator.cli.test.runtest import CliTest from pypy.translator.cli.dotnet import SomeCliClass, SomeCliStaticMethod,\ NativeInstance, CLR, box, unbox, OverloadingResolver, NativeException,\ - native_exc, init_array + native_exc, new_array, init_array System = CLR.System Math = CLR.System.Math @@ -111,7 +111,7 @@ a = RPythonAnnotator() s = a.build_types(fn, []) assert isinstance(s, annmodel.SomeOOInstance) - assert s.ootype._name == '[mscorlib]System.Object' + assert s.ootype._name == '[mscorlib]System.Object' class TestDotnetRtyping(CliTest): def _skip_pythonnet(self, msg): @@ -188,10 +188,18 @@ return unbox(array[0], ootype.Signed) assert self.interpret(fn, []) == 42 + def test_new_array(self): + def fn(): + x = new_array(System.Object, 2) + x[0] = box(42) + x[1] = box(43) + return unbox(x[0], ootype.Signed) + unbox(x[1], ootype.Signed) + assert self.interpret(fn, []) == 42+43 + def test_init_array(self): def fn(): - array = init_array(System.Object, box(42), box(43)) - return unbox(array[0], ootype.Signed) + unbox(array[1], ootype.Signed) + x = init_array([box(42), box(43)]) + return unbox(x[0], ootype.Signed) + unbox(x[1], ootype.Signed) assert self.interpret(fn, []) == 42+43 def test_null(self): @@ -241,6 +249,22 @@ res = self.ll_to_string(self.interpret(fn, [])) assert res.startswith("Index is less than 0") + def test_native_exception_invoke(self): + TargetInvocationException = NativeException(CLR.System.Reflection.TargetInvocationException) + def fn(): + x = ArrayList() + t = x.GetType() + meth = t.GetMethod('get_Item') + args = init_array(System.Object, box(0)) + try: + meth.Invoke(x, args) + return "Impossible!" + except TargetInvocationException, e: + inner = native_exc(e).get_InnerException() + message = str(inner.get_Message()) + return message + res = self.ll_to_string(self.interpret(fn, [])) + assert res.startswith("Index is less than 0") class TestPythonnet(TestDotnetRtyping): # don't interpreter functions but execute them directly through pythonnet Modified: pypy/branch/mininal-c-backend/pypy/translator/interactive.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/interactive.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/interactive.py Thu Nov 23 12:28:43 2006 @@ -14,15 +14,15 @@ class Translation(object): def __init__(self, entry_point, argtypes=None, **kwds): + self.driver = driver.TranslationDriver(overrides=DEFAULTS) + self.config = self.driver.config + self.entry_point = entry_point - self.context = TranslationContext() + self.context = TranslationContext(config=self.config) # for t.view() to work just after construction graph = self.context.buildflowgraph(entry_point) self.context._prebuilt_graphs[entry_point] = graph - self.driver = driver.TranslationDriver(overrides=DEFAULTS) - self.config = self.driver.config - # hook into driver events driver_own_event = self.driver._event def _event(kind, goal, func): @@ -53,7 +53,8 @@ else: if argtypes is None: argtypes = [] - self.driver.setup(self.entry_point, argtypes, policy, empty_translator=self.context) + self.driver.setup(self.entry_point, argtypes, policy, + empty_translator=self.context) self.ann_argtypes = argtypes self.ann_policy = policy self.driver_setup = True Modified: pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/example.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/example.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/example.py Thu Nov 23 12:28:43 2006 @@ -4,7 +4,8 @@ import autopath -from pypy.translator.js.test.runtest import compile_function +from pypy.translator.js.demo.jsdemo import support + from pypy.translator.js.modules.dom import setTimeout, get_document from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy @@ -81,10 +82,8 @@ if self.server.source: source = self.server.source else: - fn = compile_function(runjs, []) - source = fn.source() + source = support.js_source([runjs]) self.server.source = source - self.serve_data("text/javascript", source) def serve_data(self, content_type, data): @@ -94,12 +93,13 @@ self.end_headers() self.wfile.write(data) -def _main(server_class=Server, - handler_class=RequestHandler): +def build_http_server(server_address=('', 8000)): global httpd + httpd = Server(server_address, RequestHandler) - server_address = ('', 8000) - httpd = server_class(server_address, handler_class) +def _main(server_class=Server, + handler_class=RequestHandler): + build_http_server() httpd.serve_forever() if __name__ == '__main__': Modified: pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/pythonconsole.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/pythonconsole.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/js/demo/jsdemo/pythonconsole.py Thu Nov 23 12:28:43 2006 @@ -10,36 +10,20 @@ import autopath -import new, sys, os, cStringIO +import sys, os, cStringIO from cgi import parse_qs from pypy.translator.js.modules.dom import setTimeout, get_document -from pypy.translator.js.main import rpython2javascript from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal from pypy.translator.js import commproxy from pypy.translator.js.modules.mochikit import escapeHTML +from pypy.translator.js.demo.jsdemo import support + commproxy.USE_MOCHIKIT = True from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler #from SimpleHTTPServer import SimpleHTTPRequestHandler -def js_source(functions): - mod = new.module('_js_src') - function_names = [] - for func in functions: - name = func.__name__ - if hasattr(mod, name): - raise ValueError("exported function name %r is duplicated" - % (name,)) - mod.__dict__[name] = func - function_names.append(name) - sys.modules['_js_src'] = mod - try: - return rpython2javascript(mod, function_names) - finally: - del sys.modules['_js_src'] - -# ____________________________________________________________ HTML_PAGE = """ @@ -181,7 +165,7 @@ if self.server.source: source = self.server.source else: - source = js_source([setup_page]) + source = support.js_source([setup_page]) self.server.source = source self.serve_data("text/javascript", source) @@ -192,13 +176,14 @@ self.end_headers() self.wfile.write(data) -def _main(server_class=Server, - handler_class=RequestHandler): - global httpd - server_address = ('127.0.0.1', 8000) - httpd = server_class(server_address, handler_class) +def build_http_server(server_address=('', 8000)): + global httpd + httpd = Server(server_address, RequestHandler) print 'http://127.0.0.1:%d' % (server_address[1],) + +def _main(): + build_http_server() httpd.serve_forever() if __name__ == '__main__': Modified: pypy/branch/mininal-c-backend/pypy/translator/js/doc/dom.txt ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/js/doc/dom.txt (original) +++ pypy/branch/mininal-c-backend/pypy/translator/js/doc/dom.txt Thu Nov 23 12:28:43 2006 @@ -49,12 +49,14 @@ Currently events aren't fired automatically, to test event handling an event must be explicitly instantiated and dispatched:: - >>> from pypy.translator.js.modules.dom import get_window - >>> window = get_window() - >>> document = window.document + >>> def handler(e): + ... e.foo = 'bar' + >>> body.addEventListener('click', handler, False) >>> e = document.createEvent('group is ignored') >>> e.initEvent('click', True, True) >>> document.getElementsByTagName('body')[0].dispatchEvent(e) + >>> e.foo + 'bar' (This would result in all handlers for the 'click' event registered on body (and if not cancelled, bubbling up to the document node) getting @@ -68,12 +70,10 @@ Example:: - >>> from pypy.translator.js.modules.dom import get_window >>> window.location 'about:blank' >>> window.self is window True - >>> document = window.document * Additional HTML functionality on Element and Document @@ -84,9 +84,22 @@ Example:: - >>> from pypy.translator.js.modules.dom import get_window - >>> document = get_window().document >>> body = document.getElementsByTagName('body')[0] >>> body.nodeName u'BODY' + * CSS support + + There is support for inline style tags, not for stylesheets. Style + attributes are read on accessing the style property, and the style property + is used on HTML serialization (using .innerHTML). + + Example:: + + >>> body.innerHTML = '
foo
' + >>> body.firstChild.style.backgroundColor + u'green' + >>> body.firstChild.style.backgroundColor = 'black' + >>> body.innerHTML + u'
foo
' + Modified: pypy/branch/mininal-c-backend/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/js/modules/dom.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/js/modules/dom.py Thu Nov 23 12:28:43 2006 @@ -14,6 +14,7 @@ import time import re +import urllib from pypy.rpython.ootypesystem.bltregistry import BasicExternal, MethodDesc from pypy.rlib.nonconst import NonConstant @@ -87,6 +88,10 @@ original = getattr(other, '_original', other) return original is self._original + def __ne__(self, other): + original = getattr(other, '_original', other) + return original is not self._original + def getElementsByTagName(self, name): name = name.lower() return self.__getattr__('getElementsByTagName')(name) @@ -161,6 +166,9 @@ class Text(Node): nodeType = 3 +class Comment(Node): + nodeType = 8 + class Document(Node): nodeType = 9 @@ -394,6 +402,8 @@ # HTML specific 'style' : Style(), 'tabIndex' : 12, + # XXX: From HTMLInputElement to make pythonconsole work. + 'value': 'aa', }) Element._methods = Node._methods.copy() @@ -704,6 +714,7 @@ 1: Element, 2: Attribute, 3: Text, + 8: Comment, 9: Document, } def _wrap(value): @@ -729,7 +740,9 @@ _singletons = ['link', 'meta'] def _serialize_html(node): ret = [] - if node.nodeType == 1: + if node.nodeType in [3, 8]: + return node.nodeValue + elif node.nodeType == 1: original = getattr(node, '_original', node) nodeName = original.nodeName ret += ['<', nodeName] @@ -753,6 +766,8 @@ ret += [''] else: ret.append(' />') + else: + raise ValueError('unsupported node type %s' % (node.nodeType,)) return ''.join(ret) # initialization Modified: pypy/branch/mininal-c-backend/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/js/modules/test/test_dom.py Thu Nov 23 12:28:43 2006 @@ -188,6 +188,21 @@ body = code_set_innerHTML() assert body.innerHTML == '
some content
' assert body.childNodes[0].nodeName == 'DIV' + div = body.childNodes[0] + html = div.innerHTML + assert html == 'some content' + +def code_set_innerHTML_empty(): + window = get_window() + body = window.document.getElementsByTagName('body')[0] + body.innerHTML = '' + body.appendChild(window.document.createTextNode('foobar')) + return body + +def test_set_innerHTML_empty(): + body = code_set_innerHTML_empty() + html = body.innerHTML + assert html == 'foobar' def code_event_init_1(): window = get_window() @@ -344,6 +359,6 @@ if var.startswith('code_'): # just build it #def f(): - assert rpython2javascript(sys.modules[__name__], [var]) - + assert rpython2javascript(sys.modules[__name__], [var], use_pdb=False) + TRANSLATING = False Modified: pypy/branch/mininal-c-backend/pypy/translator/js/opcodes.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/js/opcodes.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/js/opcodes.py Thu Nov 23 12:28:43 2006 @@ -145,6 +145,8 @@ 'cast_float_to_int': [PushAllArgs,_CastFun("Math.floor",1)], 'cast_float_to_uint': [PushAllArgs,_CastFun("Math.floor",1)], 'truncate_longlong_to_int': CopyName, + + 'debug_assert' : DoNothing, } for key, value in opcodes.iteritems(): Modified: pypy/branch/mininal-c-backend/pypy/translator/llvm/opwriter.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/llvm/opwriter.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/llvm/opwriter.py Thu Nov 23 12:28:43 2006 @@ -172,11 +172,8 @@ float_abs = int_abs llong_abs = int_abs - def debug_log_exc(self, opr): - # XXX tmp - pass - def debug_assert(self, opr): + # XXX could do something about assertions pass def int_pow(self, opr): Modified: pypy/branch/mininal-c-backend/pypy/translator/oosupport/constant.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/oosupport/constant.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/oosupport/constant.py Thu Nov 23 12:28:43 2006 @@ -29,6 +29,8 @@ from pypy.rpython.ootypesystem import ootype import operator +MAX_CONST_PER_STEP = 100 + PRIMITIVE_TYPES = set([ootype.Void, ootype.Bool, ootype.Char, ootype.UniChar, ootype.Float, ootype.Signed, ootype.Unsigned, ootype.String, ootype.SignedLongLong, @@ -255,9 +257,9 @@ """ Iterates through each constant, initializing its data. """ gen.add_section("Initialize Data Phase") for const in all_constants: + self._consider_step(gen) gen.add_comment("Constant: %s" % const.name) self._push_constant_during_init(gen, const) - self._consider_step(gen) if not const.initialize_data(gen): gen.pop(const.OOTYPE()) @@ -266,7 +268,7 @@ start a new step every so often to ensure the initialization functions don't get too large and upset mono or the JVM or what have you. """ - if (self._all_counter % 100) == 0: + if (self._all_counter % MAX_CONST_PER_STEP) == 0: self._end_step(gen) self._declare_step(gen, self._step_counter) # open the next step self._all_counter += 1 @@ -595,6 +597,8 @@ # Dictionary constants class DictConst(AbstractConst): + PRIORITY = 90 + def __init__(self, db, dict, count): AbstractConst.__init__(self, db, dict, count) self.name = 'DICT__%d' % count Modified: pypy/branch/mininal-c-backend/pypy/translator/test/test_interactive.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/test/test_interactive.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/test/test_interactive.py Thu Nov 23 12:28:43 2006 @@ -8,6 +8,7 @@ t = Translation(f, [int, int]) assert t.context is t.driver.translator + assert t.config is t.driver.config is t.context.config s = t.annotate([int, int]) assert s.knowntype == int Modified: pypy/branch/mininal-c-backend/pypy/translator/tool/cbuild.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/tool/cbuild.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/tool/cbuild.py Thu Nov 23 12:28:43 2006 @@ -259,11 +259,38 @@ return spawn_and_log +class ProfOpt(object): + #XXX assuming gcc style flags for now + name = "profopt" + + def __init__(self, compiler): + self.compiler = compiler + + def first(self): + self.build('-fprofile-generate') + + def probe(self, exe, args): + from py.compat import subprocess + subprocess.call([exe, args]) + + def after(self): + self.build('-fprofile-use') + + def build(self, option): + compiler = self.compiler + compiler.compile_extra.append(option) + compiler.link_extra.append(option) + try: + compiler._build() + finally: + compiler.compile_extra.pop() + compiler.link_extra.pop() + class CCompiler: def __init__(self, cfilenames, outputfilename=None, include_dirs=[], libraries=[], library_dirs=[], compiler_exe=None, - profopt=None): + profbased=None): self.cfilenames = cfilenames ext = '' self.compile_extra = [] @@ -272,7 +299,7 @@ self.include_dirs = list(include_dirs) self.library_dirs = list(library_dirs) self.compiler_exe = compiler_exe - self.profopt = profopt + self.profbased = profbased if not sys.platform in ('win32', 'darwin'): # xxx if 'm' not in self.libraries: self.libraries.append('m') @@ -303,26 +330,18 @@ try: try: c = stdoutcapture.Capture(mixed_out_err = True) - log.profopt(str(self.profopt)) - if self.profopt is None: - self._build() - else: #XXX assuming gcc style flags for now - self.compile_extra.append('-fprofile-generate') - self.link_extra.append('-fprofile-generate') - self._build() - self.compile_extra.pop() - self.link_extra.pop() - - log.profopt('Gathering profile data from: %s %s' % ( - str(self.outputfilename), self.profopt)) - import subprocess - subprocess.call([str(self.outputfilename), self.profopt]) - - self.compile_extra.append('-fprofile-use') - self.link_extra.append('-fprofile-use') + if self.profbased is None: self._build() - self.compile_extra.pop() - self.link_extra.pop() + else: + ProfDriver, args = self.profbased + profdrv = ProfDriver(self) + dolog = getattr(log, profdrv.name) + dolog(args) + profdrv.first() + dolog('Gathering profile data from: %s %s' % ( + str(self.outputfilename), args)) + profdrv.probe(str(self.outputfilename),args) + profdrv.after() finally: foutput, foutput = c.done() data = foutput.read() Modified: pypy/branch/mininal-c-backend/pypy/translator/tool/pdbplus.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/tool/pdbplus.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/tool/pdbplus.py Thu Nov 23 12:28:43 2006 @@ -1,12 +1,16 @@ import pdb import types import code +import sys from pypy.objspace.flow.model import FunctionGraph class _EnableGraphic: def __init__(self, port=None): self.port = port +class NoTTY(Exception): + pass + class PdbPlusShow(pdb.Pdb): def __init__(self, translator): @@ -20,6 +24,11 @@ t = t.tb_next self.interaction(t.tb_frame, t) + def preloop(self): + if not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty(): + raise NoTTY("Cannot start the debugger when stdout is captured.") + pdb.Pdb.preloop(self) + def expose(self, d): self.exposed.update(d) From ericvrp at codespeak.net Thu Nov 23 14:42:29 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Thu, 23 Nov 2006 14:42:29 +0100 (CET) Subject: [pypy-svn] r34894 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061123134229.6013910063@code0.codespeak.net> Author: ericvrp Date: Thu Nov 23 14:42:27 2006 New Revision: 34894 Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: Working on interface to llvm jit codegen optimizations/transformation. The testcase for this is some dead-code elimination. Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Thu Nov 23 14:42:27 2006 @@ -6,6 +6,7 @@ #include "llvm/Assembly/Parser.h" #include "llvm/Bytecode/Writer.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Target/TargetData.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/SystemUtils.h" #include "llvm/System/Signals.h" @@ -13,6 +14,15 @@ #include "llvm/ExecutionEngine/JIT.h" #include "llvm/ExecutionEngine/Interpreter.h" #include "llvm/ExecutionEngine/GenericValue.h" + +#include "llvm/PassManager.h" +#include "llvm/Support/PassNameParser.h" +#include "llvm/Assembly/PrintModulePass.h" //for PrintModulePass +#include "llvm/Analysis/Verifier.h" //for createVerifierPass +#include "llvm/Transforms/Scalar.h" //for createInstructionCombiningPass... + +#include "llvm/Target/TargetOptions.h" //for PrintMachineCode + #include #include #include @@ -24,12 +34,40 @@ ExecutionEngine* gp_execution_engine = ExecutionEngine::create( new ExistingModuleProvider(gp_module), false); +//all optimization/transform passes +static cl::list + PassList(cl::desc("Optimizations available:")); + +// +//code... +// void restart() { delete gp_execution_engine; //XXX test if this correctly cleans up including generated code gp_module = new Module("llvmjit"); gp_execution_engine = ExecutionEngine::create(new ExistingModuleProvider(gp_module), false); + + //PrintMachineCode = 1; +} + + +int transform(const char* passnames) { + if (!gp_module) { + return -1; + } + + PassManager passes; //XXX: note: if passnames is the same as last time we can reuse passes + passes.add(new TargetData(gp_module)); + + //XXX next couple of passes should be dependent on passnames! + passes.add(new PrintModulePass()); + passes.add(createInstructionCombiningPass()); + passes.add(createCFGSimplificationPass()); + passes.add(new PrintModulePass()); + passes.add(createVerifierPass()); + + return passes.run(*gp_module); } Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h Thu Nov 23 14:42:27 2006 @@ -5,6 +5,7 @@ #endif void restart(); +int transform(const char* passnames); int compile(const char* llsource); void* find_function(const char* funcname); int execute(const void* function, int param); Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Thu Nov 23 14:42:27 2006 @@ -45,6 +45,10 @@ #exposed functions... restart = llvmjit.restart +transform = llvmjit.transform +transform.restype = c_int +transform.argtypes = [c_char_p] + compile = llvmjit.compile compile.restype = c_int compile.argtypes = [c_char_p] Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Thu Nov 23 14:42:27 2006 @@ -12,8 +12,6 @@ #helper data curdir = dirname(__file__) -square = join(curdir, 'square') -mul2 = join(curdir, 'mul2') llsquare = '''int %square(int %n) { block0: @@ -27,6 +25,19 @@ ret int %n2 }''' +lldeadcode = '''int %deadcode(int %n) { +Test: + %cond = seteq int %n, %n + br bool %cond, label %IfEqual, label %IfUnequal + +IfEqual: + %n2 = mul int %n, 2 + ret int %n2 + +IfUnequal: + ret int -1 +}''' + llacross1 = '''declare int %across2(int) implementation @@ -107,16 +118,6 @@ assert llvmjit.execute(square, i) == i * i assert llvmjit.execute(mul2 , i) == i * 2 -def test_call_found_function(): - llvmjit.restart() - llvmjit.compile(llsquare) - llvmjit.compile(llmul2) - square = llvmjit.find_function('square') - mul2 = llvmjit.find_function('mul2') - for i in range(5): - assert llvmjit.execute(square, i) == i * i - assert llvmjit.execute(mul2 , i) == i * 2 - def test_execute_across_module(): def my_across1(n): return n * 3 @@ -139,6 +140,18 @@ assert llvmjit.execute(across1to2, i) == my_across1to2(i) assert llvmjit.execute(across2to1, i) == my_across2to1(i) +def test_transform(): #XXX This uses Module transforms, think about Function transforms too. + llvmjit.restart() + llvmjit.compile(lldeadcode) + deadcode = llvmjit.find_function('deadcode') + assert llvmjit.execute(deadcode, 10) == 10 * 2 + + #XXX enable this part of the test asap + #assert not llvmjit.transform("instcombine printm verify") + assert llvmjit.execute(deadcode, 20) == 20 * 2 + + assert llvmjit.transform("instcombine simplifycfg printm verify") + assert llvmjit.execute(deadcode, 30) == 30 * 2 def DONTtest_modify_global_data(): pass @@ -152,9 +165,6 @@ def DONTtest_functions_with_different_signatures(): pass -def DONTtest_llvm_transformations(): - pass - def DONTtest_layers_of_codegenerators(): #e.g. i386 code until function stabilizes then llvm pass From mwh at codespeak.net Thu Nov 23 15:22:39 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Nov 2006 15:22:39 +0100 (CET) Subject: [pypy-svn] r34897 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20061123142239.40A1010061@code0.codespeak.net> Author: mwh Date: Thu Nov 23 15:22:36 2006 New Revision: 34897 Modified: pypy/dist/pypy/objspace/std/test/test_typeobject.py pypy/dist/pypy/objspace/std/typeobject.py pypy/dist/pypy/objspace/std/typetype.py Log: issue204 testing implement assignment to __bases__ introduces some amount of code duplication which could or should be reduced. Modified: pypy/dist/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_typeobject.py Thu Nov 23 15:22:36 2006 @@ -88,7 +88,205 @@ assert Y.__bases__ == (X,) class Z(Y,X): pass assert Z.__bases__ == (Y, X) - + + Z.__bases__ = (X,) + #print Z.__bases__ + assert Z.__bases__ == (X,) + + def test_mutable_bases(self): + # from CPython's test_descr + class C(object): + pass + class C2(object): + def __getattribute__(self, attr): + if attr == 'a': + return 2 + else: + return super(C2, self).__getattribute__(attr) + def meth(self): + return 1 + class D(C): + pass + class E(D): + pass + d = D() + e = E() + D.__bases__ = (C,) + D.__bases__ = (C2,) + #import pdb; pdb.set_trace() + assert d.meth() == 1 + assert e.meth() == 1 + assert d.a == 2 + assert e.a == 2 + assert C2.__subclasses__() == [D] + + # stuff that shouldn't: + class L(list): + pass + + try: + L.__bases__ = (dict,) + except TypeError: + pass + else: + assert 0, "shouldn't turn list subclass into dict subclass" + + try: + list.__bases__ = (dict,) + except TypeError: + pass + else: + assert 0, "shouldn't be able to assign to list.__bases__" + + try: + D.__bases__ = (C2, list) + except TypeError: + pass + else: + assert 0, "best_base calculation found wanting" + + try: + del D.__bases__ + except (TypeError, AttributeError): + pass + else: + assert 0, "shouldn't be able to delete .__bases__" + + try: + D.__bases__ = () + except TypeError, msg: + if str(msg) == "a new-style class can't have only classic bases": + assert 0, "wrong error message for .__bases__ = ()" + else: + assert 0, "shouldn't be able to set .__bases__ to ()" + + try: + D.__bases__ = (D,) + except TypeError: + pass + else: + # actually, we'll have crashed by here... + assert 0, "shouldn't be able to create inheritance cycles" + + try: + D.__bases__ = (C, C) + except TypeError: + pass + else: + assert 0, "didn't detect repeated base classes" + + try: + D.__bases__ = (E,) + except TypeError: + pass + else: + assert 0, "shouldn't be able to create inheritance cycles" + + # let's throw a classic class into the mix: + try: + class Classic: + __metaclass__ = _classobj + def meth2(self): + return 3 + except NameError: + class Classic: + def meth2(self): + return 3 + + D.__bases__ = (C, Classic) + + assert d.meth2() == 3 + assert e.meth2() == 3 + try: + d.a + except AttributeError: + pass + else: + assert 0, "attribute should have vanished" + + try: + D.__bases__ = (Classic,) + except TypeError: + pass + else: + assert 0, "new-style class must have a new-style base" + + def test_mutable_bases_with_failing_mro(self): + class WorkOnce(type): + def __new__(self, name, bases, ns): + self.flag = 0 + return super(WorkOnce, self).__new__(WorkOnce, name, bases, ns) + def mro(instance): + if instance.flag > 0: + raise RuntimeError, "bozo" + else: + instance.flag += 1 + return type.mro(instance) + + class WorkAlways(type): + def mro(self): + # this is here to make sure that .mro()s aren't called + # with an exception set (which was possible at one point). + # An error message will be printed in a debug build. + # What's a good way to test for this? + return type.mro(self) + + class C(object): + pass + + class C2(object): + pass + + class D(C): + pass + + class E(D): + pass + + class F(D): + __metaclass__ = WorkOnce + + class G(D): + __metaclass__ = WorkAlways + + # Immediate subclasses have their mro's adjusted in alphabetical + # order, so E's will get adjusted before adjusting F's fails. We + # check here that E's gets restored. + + E_mro_before = E.__mro__ + D_mro_before = D.__mro__ + + try: + D.__bases__ = (C2,) + except RuntimeError: + assert D.__mro__ == D_mro_before + assert E.__mro__ == E_mro_before + else: + assert 0, "exception not propagated" + + def test_mutable_bases_catch_mro_conflict(self): + class A(object): + pass + + class B(object): + pass + + class C(A, B): + pass + + class D(A, B): + pass + + class E(C, D): + pass + + try: + C.__bases__ = (B, A) + except TypeError: + pass + else: + raise TestFailed, "didn't catch MRO conflict" + def test_builtin_add(self): x = 5 assert x.__add__(6) == 11 Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Thu Nov 23 15:22:36 2006 @@ -342,6 +342,16 @@ else: w_self.weak_subclasses_w.append(w_newref) + def remove_subclass(w_self, w_subclass): + space = w_self.space + + for i in range(len(w_self.weak_subclasses_w)): + w_ref = w_self.weak_subclasses_w[i] + ob = space.call_function(w_ref) + if space.is_w(ob, w_subclass): + del w_self.weak_subclasses_w[i] + return + # for now, weakref support for W_TypeObject is hard to get automatically _lifeline_ = None def getweakref(self): Modified: pypy/dist/pypy/objspace/std/typetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/typetype.py (original) +++ pypy/dist/pypy/objspace/std/typetype.py Thu Nov 23 15:22:36 2006 @@ -1,5 +1,6 @@ from pypy.interpreter.error import OperationError from pypy.interpreter import gateway +from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import weakref_descr from pypy.objspace.std.stdtypedef import * @@ -84,14 +85,118 @@ w_type = _check(space, w_type,"expected type") return space.newlist(w_type.compute_mro()) -def descr__bases(space, w_type): +def descr_get__bases__(space, w_type): w_type = _check(space, w_type) - from pypy.objspace.std.typeobject import W_TypeObject - if not isinstance(w_type, W_TypeObject): - raise OperationError(space.w_TypeError, - space.wrap("descriptor is for 'type'")) return space.newtuple(w_type.bases_w) +def mro_subclasses(space, w_type, temp): + from pypy.objspace.std.typeobject import W_TypeObject + if not w_type.weak_subclasses_w: + return + for w_ref in w_type.weak_subclasses_w: + w_sc = space.call_function(w_ref) + if not space.is_w(w_sc, space.w_None): + assert isinstance(w_sc, W_TypeObject) + temp.append((w_sc, w_sc.mro_w)) + mro_internal(space, w_sc) + mro_subclasses(space, w_sc, temp) + +# should be a W_TypeObject method i guess +def mro_internal(space, w_type): + if not space.is_w(space.type(w_type), space.w_type): + #w_type.mro_w = [] + mro_func = space.type(w_type).lookup('mro') + mro_func_args = Arguments(space, [w_type]) + w_mro = space.call_args(mro_func, mro_func_args) + w_type.mro_w = space.unpackiterable(w_mro) + # do some checking here + else: + w_type.mro_w = w_type.compute_mro() + +def best_base(space, newstyle_bases_w): + if not newstyle_bases_w: + raise OperationError(space.w_TypeError, + space.wrap("a new-style class can't have only classic bases")) + w_bestbase = None + w_winner = None + for w_base in newstyle_bases_w: + w_candidate = w_base.get_layout() + if w_winner is None: + w_winner = w_candidate + w_bestbase = w_base + elif space.is_true(space.issubtype(w_winner, w_candidate)): + pass + elif space.is_true(space.issubtype(w_candidate, w_winner)): + w_winner = w_candidate + w_bestbase = w_base + else: + raise OperationError(space.w_TypeError, + space.wrap("multiple bases have instance lay-out conflict")) + return w_bestbase + +def descr_set__bases__(space, w_type, w_value): + from pypy.objspace.std.typeobject import W_TypeObject + # this assumes all app-level type objects are W_TypeObject + w_type = _check(space, w_type) + if not w_type.is_heaptype(): + raise OperationError(space.w_TypeError, + space.wrap("can't set %s.__bases__" % + w_type.name)) + if not space.is_true(space.isinstance(w_value, space.w_tuple)): + raise OperationError(space.w_TypeError, + space.wrap("can only assign tuple to %s.__bases__, not %s"% + (w_type.name, space.type(w_value).name))) + if space.int_w(space.len(w_value)) == 0: + raise OperationError(space.w_TypeError, + space.wrap("can only assign non-empty tuple to %s.__bases__, not ()"% + w_type.name)) + new_newstyle_bases = [] + for w_base in space.unpackiterable(w_value): + if not isinstance(w_base, W_TypeObject): + w_typ = space.type(w_base) + if not space.is_w(w_typ, space.w_classobj): + raise OperationError(space.w_TypeError, + space.wrap("%s.__bases__ must be tuple of old- or new-style classes, not '%s'"% + (w_type.name, w_typ.name))) + else: + new_newstyle_bases.append(w_base) + if space.is_true(space.issubtype(w_base, w_type)): + raise OperationError(space.w_TypeError, + space.wrap("a __bases__ item causes an inheritance cycle")) + + new_base = best_base(space, new_newstyle_bases) + + if w_type.w_bestbase.get_full_instance_layout() != new_base.get_full_instance_layout(): + raise OperationError(space.w_TypeError, + space.wrap("__bases__ assignment: '%s' object layout differs from '%s'" % + (w_type.getname(space, '?'), new_base.getname(space, '?')))) + + saved_bases = w_type.bases_w + saved_base = w_type.w_bestbase + saved_mro = w_type.mro_w + + w_type.bases_w = space.unpackiterable(w_value) + w_type.w_bestbase = new_base + + temp = [] + try: + mro_internal(space, w_type) + + mro_subclasses(space, w_type, temp) + + for old_base in saved_bases: + if isinstance(old_base, W_TypeObject): + old_base.remove_subclass(w_type) + for new_base in new_newstyle_bases: + new_base.add_subclass(w_type) + except: + for cls, old_mro in temp: + cls.mro_w = old_mro + w_type.bases_w = saved_bases + w_type.w_bestbase = saved_base + w_type.mro_w = saved_mro + raise + def descr__base(space, w_type): w_type = _check(space, w_type) if w_type.w_bestbase is not None: @@ -155,7 +260,7 @@ type_typedef = StdTypeDef("type", __new__ = newmethod(descr__new__), __name__ = GetSetProperty(descr_get__name__, descr_set__name__), - __bases__ = GetSetProperty(descr__bases), + __bases__ = GetSetProperty(descr_get__bases__, descr_set__bases__), __base__ = GetSetProperty(descr__base), __mro__ = GetSetProperty(descr_get__mro__), __dict__ = GetSetProperty(descr_get_dict), From mwh at codespeak.net Thu Nov 23 15:32:17 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Nov 2006 15:32:17 +0100 (CET) Subject: [pypy-svn] r34898 - pypy/dist/lib-python/modified-2.4.1/test Message-ID: <20061123143217.A045B1006C@code0.codespeak.net> Author: mwh Date: Thu Nov 23 15:32:15 2006 New Revision: 34898 Modified: pypy/dist/lib-python/modified-2.4.1/test/test_descr.py Log: i don't think we care if del C.__bases__ raises TypeError or AttributeError Modified: pypy/dist/lib-python/modified-2.4.1/test/test_descr.py ============================================================================== --- pypy/dist/lib-python/modified-2.4.1/test/test_descr.py (original) +++ pypy/dist/lib-python/modified-2.4.1/test/test_descr.py Thu Nov 23 15:32:15 2006 @@ -3456,7 +3456,7 @@ try: del D.__bases__ - except TypeError: + except (AttributeError, TypeError): pass else: raise TestFailed, "shouldn't be able to delete .__bases__" From ale at codespeak.net Thu Nov 23 15:34:39 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 23 Nov 2006 15:34:39 +0100 (CET) Subject: [pypy-svn] r34899 - pypy/branch/mininal-c-backend Message-ID: <20061123143439.A1D801006C@code0.codespeak.net> Author: ale Date: Thu Nov 23 15:34:38 2006 New Revision: 34899 Removed: pypy/branch/mininal-c-backend/ Log: Removing failed branch - and create a new one From mwh at codespeak.net Thu Nov 23 15:38:06 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Nov 2006 15:38:06 +0100 (CET) Subject: [pypy-svn] r34900 - pypy/dist/lib-python Message-ID: <20061123143806.6AD5E1006C@code0.codespeak.net> Author: mwh Date: Thu Nov 23 15:38:05 2006 New Revision: 34900 Modified: pypy/dist/lib-python/conftest.py Log: fix one last piece of fallout from the config branch merge. Modified: pypy/dist/lib-python/conftest.py ============================================================================== --- pypy/dist/lib-python/conftest.py (original) +++ pypy/dist/lib-python/conftest.py Thu Nov 23 15:38:05 2006 @@ -879,7 +879,7 @@ if regrtest.compiler: pypy_options.append('--compiler=%s' % regrtest.compiler) pypy_options.extend( - ['--usemodules=%s' % mod for mod in regrtest.usemodules]) + ['--withmod-%s' % mod for mod in regrtest.usemodules]) sopt = " ".join(pypy_options) # experimental: always use regrverbose script # previously we only did it if regrtest.outputpath() was True From ale at codespeak.net Thu Nov 23 15:41:47 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 23 Nov 2006 15:41:47 +0100 (CET) Subject: [pypy-svn] r34901 - pypy/branch/mininal-c-backend Message-ID: <20061123144147.C01AC10075@code0.codespeak.net> Author: ale Date: Thu Nov 23 15:41:46 2006 New Revision: 34901 Added: pypy/branch/mininal-c-backend/ - copied from r34900, pypy/dist/ Log: New branch From mwh at codespeak.net Thu Nov 23 15:57:44 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Nov 2006 15:57:44 +0100 (CET) Subject: [pypy-svn] r34903 - pypy/dist/pypy/objspace/std Message-ID: <20061123145744.3AC3210061@code0.codespeak.net> Author: mwh Date: Thu Nov 23 15:57:43 2006 New Revision: 34903 Modified: pypy/dist/pypy/objspace/std/typeobject.py Log: another test_descr bug: checking the return value of __init__() Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Thu Nov 23 15:57:43 2006 @@ -375,7 +375,10 @@ # maybe invoke the __init__ of the type if space.is_true(space.isinstance(w_newobject, w_type)): w_descr = space.lookup(w_newobject, '__init__') - space.get_and_call_args(w_descr, w_newobject, __args__) + w_result = space.get_and_call_args(w_descr, w_newobject, __args__) + if not space.is_w(w_result, space.w_None): + raise OperationError(space.w_TypeError, + space.wrap("__init__() should return None")) return w_newobject def issubtype__Type_Type(space, w_type1, w_type2): From mwh at codespeak.net Thu Nov 23 16:16:46 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 23 Nov 2006 16:16:46 +0100 (CET) Subject: [pypy-svn] r34906 - pypy/dist/pypy/objspace/std Message-ID: <20061123151646.2676310063@code0.codespeak.net> Author: mwh Date: Thu Nov 23 16:16:44 2006 New Revision: 34906 Modified: pypy/dist/pypy/objspace/std/typeobject.py Log: mostly revert 34903 -- 2.4 only warns when a new-style classes' __init__ returns non-None Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Thu Nov 23 16:16:44 2006 @@ -376,9 +376,9 @@ if space.is_true(space.isinstance(w_newobject, w_type)): w_descr = space.lookup(w_newobject, '__init__') w_result = space.get_and_call_args(w_descr, w_newobject, __args__) - if not space.is_w(w_result, space.w_None): - raise OperationError(space.w_TypeError, - space.wrap("__init__() should return None")) +## if not space.is_w(w_result, space.w_None): +## raise OperationError(space.w_TypeError, +## space.wrap("__init__() should return None")) return w_newobject def issubtype__Type_Type(space, w_type1, w_type2): From ale at codespeak.net Thu Nov 23 16:18:52 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 23 Nov 2006 16:18:52 +0100 (CET) Subject: [pypy-svn] r34907 - in pypy/branch/mininal-c-backend/pypy/translator: c c/src goal Message-ID: <20061123151852.5128D10063@code0.codespeak.net> Author: ale Date: Thu Nov 23 16:18:50 2006 New Revision: 34907 Added: pypy/branch/mininal-c-backend/pypy/translator/goal/targetreallynopstandalone.py - copied, changed from r34885, pypy/branch/mininal-c-backend/pypy/translator/goal/targetnopstandalone.py Modified: pypy/branch/mininal-c-backend/pypy/translator/c/genc.py pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h pypy/branch/mininal-c-backend/pypy/translator/c/src/g_prerequisite.h pypy/branch/mininal-c-backend/pypy/translator/c/src/ll_math.h pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h Log: to compile to avr architecture use python translate.py --batch --cc=avr-gcc --gc=none --vanilla targetreallynopstandalone.py Unfortunately this generates more code than avr accomodates - so it compiles but can't link :-( Modified: pypy/branch/mininal-c-backend/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/genc.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/genc.py Thu Nov 23 16:18:50 2006 @@ -275,6 +275,8 @@ if self.config.translation.cc: cc = self.config.translation.cc +# if cc == 'avr-gcc': +# compiler.compile_extra.append('-DAVR') else: cc = 'gcc' Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h Thu Nov 23 16:18:50 2006 @@ -16,8 +16,12 @@ #include "src/mem.h" #include "src/exception.h" -#include "src/trace.h" #include "src/support.h" +#ifndef AVR +#include "src/trace.h" +#else + #define PY_LONG_LONG long long +#endif #ifndef PYPY_STANDALONE # include "src/module.h" @@ -26,9 +30,11 @@ #include "src/int.h" #include "src/char.h" -#include "src/unichar.h" #include "src/float.h" +#ifndef AVR +#include "src/unichar.h" #include "src/address.h" +#endif #include "src/instrument.h" @@ -40,6 +46,7 @@ /*** modules ***/ #ifdef HAVE_RTYPER /* only if we have an RTyper */ # include "src/rtyper.h" +#ifndef AVR # include "src/ll_os.h" # include "src/ll_time.h" # include "src/ll_math.h" @@ -48,8 +55,11 @@ # include "src/ll_thread.h" # endif #endif +#endif +#ifndef AVR #include "src/stack.h" +#endif #ifdef PYPY_STANDALONE # include "src/main.h" Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/g_prerequisite.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/g_prerequisite.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/g_prerequisite.h Thu Nov 23 16:18:50 2006 @@ -6,10 +6,12 @@ * executables (which are *not* linked against CPython then), * to get the convenient macro definitions */ +#ifndef AVR #include "Python.h" #include "thread.h" /* needs to be included early to define the struct RPyOpaque_ThreadLock */ +#endif #include Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/ll_math.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/ll_math.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/ll_math.h Thu Nov 23 16:18:50 2006 @@ -9,6 +9,7 @@ /* xxx macro from pyport.h, at some point define our owns */ /* xxx this 2.3 name is later deprecated */ +#include #define LL_MATH_SET_ERANGE_IF_MATH_ERROR Py_SET_ERANGE_IF_OVERFLOW #define LL_MATH_ERROR_RESET errno = 0 Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h Thu Nov 23 16:18:50 2006 @@ -37,8 +37,10 @@ exitcode = STANDALONE_ENTRY_POINT(list); if (RPyExceptionOccurred()) { /* fish for the exception type, at least */ +#ifndef AVR fprintf(stderr, "Fatal PyPy error: %s\n", RPyFetchExceptionType()->ov_name->items); +#endif exitcode = 1; } return exitcode; @@ -46,7 +48,9 @@ memory_out: errmsg = "out of memory"; error: +#ifndef AVR fprintf(stderr, "Fatal error during initialization: %s\n", errmsg); +#endif return 1; } Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h Thu Nov 23 16:18:50 2006 @@ -5,7 +5,11 @@ #include #ifndef PYPY_NOT_MAIN_FILE - +#ifdef AVR + #ifndef NO_OBMALLOC + #define NO_OBMALLOC + #endif +#endif #ifdef NO_OBMALLOC void *PyObject_Malloc(size_t n) { return malloc(n); } void *PyObject_Realloc(void *p, size_t n) { return realloc(p, n); } From pedronis at codespeak.net Thu Nov 23 20:24:05 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 23 Nov 2006 20:24:05 +0100 (CET) Subject: [pypy-svn] r34914 - in pypy/dist/pypy/jit/timeshifter: . test Message-ID: <20061123192405.AD4CB10061@code0.codespeak.net> Author: pedronis Date: Thu Nov 23 20:24:01 2006 New Revision: 34914 Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/jit/timeshifter/rtimeshift.py pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py pypy/dist/pypy/jit/timeshifter/transform.py Log: (arre, pedronis) started working toward supporting returning more than one state out of red calls: introduce a collect_split after all of them like for yellow calls. For now it always receives just one state. Next step is to have merging that can keep more than one state for a key, then leave code for calls will need to be changed to cope with that. We will probably need to do something about portal calls which should not return more than one single state. Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Thu Nov 23 20:24:01 2006 @@ -827,14 +827,6 @@ [v_jitstate , c_index , c_TYPE], s_result) - def translate_op_fetch_return(self, hop): - ts = self - v_jitstate = hop.llops.getjitstate() - return hop.llops.genmixlevelhelpercall(rtimeshift.getreturnbox, - [ts.s_JITState], - [v_jitstate ], - ts.s_RedBox) - def translate_op_is_constant(self, hop): hs = hop.args_s[0] r_arg = self.getredrepr(originalconcretetype(hs)) Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py Thu Nov 23 20:24:01 2006 @@ -329,6 +329,8 @@ for i in range(node.n): pending = pending.next pending.greens.extend(greens_gv) + if pending.returnbox is not None: + pending.frame.local_boxes.insert(0, getreturnbox(pending)) pending.next = None return pending @@ -337,6 +339,8 @@ jitstate = pending pending = pending.next jitstate.greens.extend(greens_gv) # item 0 is the return value + if jitstate.returnbox is not None: + jitstate.frame.local_boxes.insert(0, getreturnbox(jitstate)) jitstate.resumepoint = resumepoint if resuming is None: node = jitstate.promotion_path @@ -399,7 +403,9 @@ return jitstate.greens[i].revealconst(T) def getreturnbox(jitstate): - return jitstate.returnbox + retbox = jitstate.returnbox + jitstate.returnbox = None + return retbox def getexctypebox(jitstate): return jitstate.exc_type_box @@ -916,6 +922,8 @@ if jitstate is not None: myframe = jitstate.frame leave_frame(jitstate) + jitstate.greens = [] + jitstate.next = None jitstate.returnbox = myframe.local_boxes[0] # ^^^ fetched by a 'fetch_return' operation return jitstate @@ -924,6 +932,9 @@ jitstate = merge_returning_jitstates(jitstate, dispatchqueue) if jitstate is not None: leave_frame(jitstate) + jitstate.greens = [] + jitstate.next = None + jitstate.returnbox = None return jitstate def leave_frame(jitstate): Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Thu Nov 23 20:24:01 2006 @@ -221,8 +221,8 @@ res = self.timeshift_from_portal(ll_function, ll_function, [5], policy=P_NOVIRTUAL) assert res == 10 - self.check_insns(indirect_call=0) + self.check_insns(indirect_call=0) #, malloc=0) res = self.timeshift_from_portal(ll_function, ll_function, [0], policy=P_NOVIRTUAL) assert res == ord('2') - self.check_insns(indirect_call=0) + self.check_insns(indirect_call=0) #, malloc=0) Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Thu Nov 23 20:24:01 2006 @@ -1079,6 +1079,28 @@ assert res == 42 self.check_insns({}) + def test_simple_red_meth(self): + class Base(object): + def m(self, n): + raise NotImplementedError + pass # for inspect.getsource() bugs + + class Concrete(Base): + def m(self, n): + return 21*n + pass # for inspect.getsource() bugs + + def f(flag, x): + if flag: + o = Base() + else: + o = Concrete() + return o.m(x) + + res = self.timeshift(f, [0, 2], [0], policy=P_NOVIRTUAL) + assert res == 42 + self.check_insns({'int_mul': 1}) + def test_compile_time_const_tuple(self): d = {(4, 5): 42, (6, 7): 12} def f(a, b): Modified: pypy/dist/pypy/jit/timeshifter/transform.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/transform.py (original) +++ pypy/dist/pypy/jit/timeshifter/transform.py Thu Nov 23 20:24:01 2006 @@ -9,7 +9,7 @@ from pypy.translator.unsimplify import split_block, split_block_at_start from pypy.translator.simplify import rec_op_has_side_effects from pypy.translator.backendopt.ssa import SSA_to_SSI -from pypy.translator.backendopt import support +from pypy.translator.unsimplify import split_block class MergePointFamily(object): @@ -512,16 +512,25 @@ self.go_to_dispatcher_if(block, v_finished) def handle_red_call(self, block, pos, color='red'): - varsalive = self.variables_alive(block, pos+1) + link = split_block(self.hannotator, block, pos+1) op = block.operations.pop(pos) + assert len(block.operations) == pos + nextblock = link.target + linkargs = link.args + varsalive = list(linkargs) + try: - varsalive.remove(op.result) - uses_retval = True # it will be restored by 'fetch_return' + index = varsalive.index(op.result) + uses_retval = True # it will be restored by a restore_local + del varsalive[index] + old_v_result = linkargs.pop(index) + linkargs.insert(0, old_v_result) + v_result = nextblock.inputargs.pop(index) + nextblock.inputargs.insert(0, v_result) except ValueError: uses_retval = False - reds, greens = self.sort_by_color(varsalive) - nextblock = self.naive_split_block(block, pos) + reds, greens = self.sort_by_color(varsalive) v_func = op.args[0] hs_func = self.hannotator.binding(v_func) @@ -538,29 +547,17 @@ resulttype = lltype.Bool) self.genswitch(block, v_is_constant, true = constantblock, false = nonconstantblock) - constantblock.closeblock(Link([], nextblock)) - nonconstantblock.closeblock(Link([], nextblock)) postconstantblock = self.naive_split_block(constantblock, len(constantblock.operations)) blockset[postconstantblock] = False self.make_call(constantblock, op, reds, color) - mapping = {} - for i, var in enumerate(reds): - c_index = Constant(i, concretetype=lltype.Signed) - newvar = self.genop(postconstantblock, 'restore_local', [c_index], - result_like = var) - mapping[var] = newvar - - if uses_retval: - assert not self.hannotator.binding(op.result).is_green() - var = op.result - newvar = self.genop(postconstantblock, 'fetch_return', [], - result_like = var) - mapping[var] = newvar - - nextblock.renamevariables(mapping) + resumepoint = self.get_resume_point(nextblock) + c_resumepoint = inputconst(lltype.Signed, resumepoint) + self.genop(postconstantblock, 'collect_split', [c_resumepoint] + greens) + resumeblock = self.get_resume_point_link(nextblock).target + postconstantblock.recloseblock(Link([], resumeblock)) if nonconstantblock is not None: args_v = op.args[1:] @@ -571,21 +568,13 @@ v_res = self.genop(nonconstantblock, 'residual_%s_call' % (color,), [op.args[0]], result_like = op.result) - oldvars = mapping.keys() - newvars = [mapping[v] for v in oldvars] - postconstantblock.exits[0].args = newvars - nextblock.inputargs = newvars - - mapping2 = dict([(v, copyvar(self.hannotator, v)) - for v in newvars]) - nextblock.renamevariables(mapping2) - - mapping3 = {op.result: v_res} - nonconstantblock.exits[0].args = [mapping3.get(v, v) - for v in oldvars] + if uses_retval: + linkargs[0] = v_res + + nonconstantblock.closeblock(Link(linkargs, nextblock)) - blockset[block] = True # reachable from outside - blockset[nextblock] = False + blockset[block] = True # reachable from outside + blockset[nextblock] = True # reachable from outside SSA_to_SSI(blockset, self.hannotator) def handle_gray_call(self, block, pos): @@ -619,8 +608,7 @@ newop = SpaceOperation('same_as', [v_tmp], v_real_result) block.operations.insert(pos+1, newop) - link = support.split_block_with_keepalive(block, pos+1, - annotator=self.hannotator) + link = split_block(self.hannotator, block, pos+1) op1 = block.operations.pop(pos) assert op1 is op assert len(block.operations) == pos @@ -694,8 +682,7 @@ newop = SpaceOperation('revealconst', [v_promote], op.result) block.operations[i] = newop - link = support.split_block_with_keepalive(block, i, - annotator=self.hannotator) + link = split_block(self.hannotator, block, i) nextblock = link.target reds, greens = self.sort_by_color(link.args) From antocuni at codespeak.net Thu Nov 23 21:43:56 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 23 Nov 2006 21:43:56 +0100 (CET) Subject: [pypy-svn] r34915 - in pypy/dist/pypy/module/_dotnet: . test Message-ID: <20061123204356.205FB10068@code0.codespeak.net> Author: antocuni Date: Thu Nov 23 21:43:55 2006 New Revision: 34915 Added: pypy/dist/pypy/module/_dotnet/ pypy/dist/pypy/module/_dotnet/__init__.py (contents, props changed) pypy/dist/pypy/module/_dotnet/app_dotnet.py (contents, props changed) pypy/dist/pypy/module/_dotnet/interp_dotnet.py (contents, props changed) pypy/dist/pypy/module/_dotnet/test/ pypy/dist/pypy/module/_dotnet/test/test_dotnet.py (contents, props changed) pypy/dist/pypy/module/_dotnet/test/test_dotnet.pyc (contents, props changed) Log: Very first implementation of .NET integration at applevel: this is more a proof of concept than a real implementation. The idea is to have a thin layer at interp-level doing the dispatching to the .NET code, and implementing all the types at application level. This should make very easy to dynamically add new .NET wrappers, because we just need to dynamically create applevel classes. Added: pypy/dist/pypy/module/_dotnet/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_dotnet/__init__.py Thu Nov 23 21:43:55 2006 @@ -0,0 +1,13 @@ +# Package initialisation +from pypy.interpreter.mixedmodule import MixedModule + +class Module(MixedModule): + """CLR module""" + + appleveldefs = { + 'ArrayList': 'app_dotnet.ArrayList', + } + + interpleveldefs = { + '_CliObject_internal': 'interp_dotnet.W_CliObject', + } Added: pypy/dist/pypy/module/_dotnet/app_dotnet.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_dotnet/app_dotnet.py Thu Nov 23 21:43:55 2006 @@ -0,0 +1,15 @@ +# NOT_RPYTHON + +class ArrayList(object): + __cliname__ = 'System.Collections.ArrayList' + ATTRS = ['Add'] + + def __init__(self): + import _dotnet + self.obj = _dotnet._CliObject_internal(self.__cliname__) + + def Add(self, x): + return self.obj.call_method('Add', [x]) + + def get_Item(self, idx): + return self.obj.call_method('get_Item', [idx]) Added: pypy/dist/pypy/module/_dotnet/interp_dotnet.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_dotnet/interp_dotnet.py Thu Nov 23 21:43:55 2006 @@ -0,0 +1,66 @@ +from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import interp2app +from pypy.interpreter.typedef import TypeDef +from pypy.rpython.ootypesystem import ootype +from pypy.translator.cli.dotnet import CLR, box, unbox, NativeException, native_exc, new_array, init_array + +# TODO: this code is not translatable + +Type = CLR.System.Type +Object = CLR.System.Object +TargetInvocationException = NativeException(CLR.System.Reflection.TargetInvocationException) + +import sys + +class W_CliObject(Wrappable): + def __init__(self, space, obj): + self.space = space + self.obj = obj + + def call_method(self, name, w_args): + t = self.obj.GetType() + meth = t.GetMethod(name) # TODO: overloading! + args = self.rewrap_args(w_args) + try: + res = meth.Invoke(self.obj, args) + except TargetInvocationException, e: + inner = native_exc(e).get_InnerException() + message = str(inner.get_Message()) + # TODO: use the appropriate exception, not StandardError + raise OperationError(self.space.w_StandardError, self.space.wrap(message)) + return self.cli2py(res) + call_method.unwrap_spec = ['self', str, W_Root] + + def rewrap_args(self, w_args): + py_args = self.space.unpackiterable(w_args) + res = new_array(Object, len(py_args)) + for i in range(len(py_args)): + res[i] = self.py2cli(py_args[i]) + return res + + def py2cli(self, w_obj): + space = self.space + if space.is_true(space.isinstance(w_obj, self.space.w_int)): + return box(space.int_w(w_obj)) + else: + assert False + + def cli2py(self, obj): + intval = unbox(obj, ootype.Signed) # TODO: support other types + return self.space.wrap(intval) + + +def cli_object_new(space, w_subtype, typename): + t = Type.GetType(typename) + ctor = t.GetConstructor(init_array(Type)) + obj = ctor.Invoke(init_array(Object)) + return space.wrap(W_CliObject(space, obj)) +cli_object_new.unwrap_spec = [ObjSpace, W_Root, str] + + +W_CliObject.typedef = TypeDef( + '_CliObject_internal', + __new__ = interp2app(cli_object_new), + call_method = interp2app(W_CliObject.call_method), + ) Added: pypy/dist/pypy/module/_dotnet/test/test_dotnet.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/_dotnet/test/test_dotnet.py Thu Nov 23 21:43:55 2006 @@ -0,0 +1,26 @@ +from pypy.conftest import gettestobjspace +import os + +class AppTestDotnet: + def setup_class(cls): + space = gettestobjspace(usemodules=('_dotnet',)) + cls.space = space + + def test_cliobject(self): + import _dotnet + obj = _dotnet._CliObject_internal('System.Collections.ArrayList') + max_index = obj.call_method('Add', [42]) + assert max_index == 0 + + def test_ArrayList(self): + import _dotnet + obj = _dotnet.ArrayList() + obj.Add(42) + obj.Add(43) + total = obj.get_Item(0) + obj.get_Item(1) + assert total == 42+43 + + def test_ArrayList_error(self): + import _dotnet + obj = _dotnet.ArrayList() + raises(StandardError, obj.get_Item, 0) Added: pypy/dist/pypy/module/_dotnet/test/test_dotnet.pyc ============================================================================== Binary file. No diff available. From antocuni at codespeak.net Thu Nov 23 21:45:08 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 23 Nov 2006 21:45:08 +0100 (CET) Subject: [pypy-svn] r34916 - pypy/dist/pypy/module/_dotnet/test Message-ID: <20061123204508.D213110068@code0.codespeak.net> Author: antocuni Date: Thu Nov 23 21:45:06 2006 New Revision: 34916 Removed: pypy/dist/pypy/module/_dotnet/test/test_dotnet.pyc Log: oops, this file shoud not be under svn From fijal at codespeak.net Thu Nov 23 21:49:48 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 23 Nov 2006 21:49:48 +0100 (CET) Subject: [pypy-svn] r34917 - in pypy/dist/pypy/module/_dotnet: . test Message-ID: <20061123204948.EC3DF10068@code0.codespeak.net> Author: fijal Date: Thu Nov 23 21:49:44 2006 New Revision: 34917 Modified: pypy/dist/pypy/module/_dotnet/ (props changed) pypy/dist/pypy/module/_dotnet/test/ (props changed) Log: fixeol From arigo at codespeak.net Thu Nov 23 22:08:16 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 23 Nov 2006 22:08:16 +0100 (CET) Subject: [pypy-svn] r34921 - pypy/dist/pypy/module/_stackless Message-ID: <20061123210816.7277B10061@code0.codespeak.net> Author: arigo Date: Thu Nov 23 22:08:14 2006 New Revision: 34921 Modified: pypy/dist/pypy/module/_stackless/clonable.py Log: (untested...) a fix in w_clone that was not propagated to fork(). Modified: pypy/dist/pypy/module/_stackless/clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/clonable.py (original) +++ pypy/dist/pypy/module/_stackless/clonable.py Thu Nov 23 22:08:14 2006 @@ -82,7 +82,7 @@ oldcoro = self.coroutine self.coroutine = None newcoro = AppClonableCoroutine(oldcoro.space, state=oldcoro.costate) - oldcoro.clone_into(newcoro) + newcoro.subctx = oldcoro.clone_into(newcoro, oldcoro.subctx) self.newcoroutine = newcoro def fork(space): From ale at codespeak.net Fri Nov 24 12:27:24 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Fri, 24 Nov 2006 12:27:24 +0100 (CET) Subject: [pypy-svn] r34929 - in pypy/branch/mininal-c-backend/pypy: config translator/c Message-ID: <20061124112724.992B210075@code0.codespeak.net> Author: ale Date: Fri Nov 24 12:27:21 2006 New Revision: 34929 Modified: pypy/branch/mininal-c-backend/pypy/config/pypyoption.py pypy/branch/mininal-c-backend/pypy/translator/c/genc.py Log: Added options to pass compiler and linker flags from the commandline to the c compiler. Now : python translate.py --cc=avr-gcc --gc=none --vanilla --cflags="-mmcu=atmega16" --ldflags="-mmcu=atmega16" targetreallynopstandalone.py compiles and links to 32kbyte ELF file Modified: pypy/branch/mininal-c-backend/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/config/pypyoption.py (original) +++ pypy/branch/mininal-c-backend/pypy/config/pypyoption.py Fri Nov 24 12:27:21 2006 @@ -177,6 +177,10 @@ BoolOption("no__thread", "don't use __thread for implementing TLS", default=False, cmdline="--no__thread", negation=False), + StrOption("compilerflags", "Specify flags for the compiler", + cmdline="--cflags"), + StrOption("linkerflags", "Specify flags for the linker", + cmdline="--ldflags"), # Flags of the TranslationContext: BoolOption("simplifying", "Simplify flow graphs", default=True), Modified: pypy/branch/mininal-c-backend/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/genc.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/genc.py Fri Nov 24 12:27:21 2006 @@ -245,6 +245,10 @@ assert self.c_source_filename assert not self._compiled compiler = self.getccompiler(extra_includes=[str(self.targetdir)]) + if self.config.translation.compilerflags: + compiler.compile_extra.append(self.config.translation.compilerflags) + if self.config.translation.linkerflags: + compiler.link_extra.append(self.config.translation.compilerflags) compiler.build() self.executable_name = str(compiler.outputfilename) self._compiled = True @@ -279,7 +283,6 @@ # compiler.compile_extra.append('-DAVR') else: cc = 'gcc' - if self.config.translation.profopt: profopt = self.config.translation.profopt else: From fijal at codespeak.net Fri Nov 24 12:33:59 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 24 Nov 2006 12:33:59 +0100 (CET) Subject: [pypy-svn] r34930 - pypy/dist/pypy/translator/goal Message-ID: <20061124113359.C77EE10075@code0.codespeak.net> Author: fijal Date: Fri Nov 24 12:33:47 2006 New Revision: 34930 Modified: pypy/dist/pypy/translator/goal/app_main.py Log: (mwh, fijal) - added ignoring of sigpipe. Otherwise program got killed by it. Modified: pypy/dist/pypy/translator/goal/app_main.py ============================================================================== --- pypy/dist/pypy/translator/goal/app_main.py (original) +++ pypy/dist/pypy/translator/goal/app_main.py Fri Nov 24 12:33:47 2006 @@ -15,6 +15,13 @@ originalexcepthook = sys.__excepthook__ +try: + from signal import signal, SIG_IGN, SIGPIPE + signal(SIGPIPE, SIG_IGN) +except ImportError: + # XXX: we should do it on c-level anyway + pass + def run_toplevel(f, *fargs, **fkwds): """Calls f() and handle all OperationErrors. Intended use is to run the main program or one interactive statement. From arigo at codespeak.net Fri Nov 24 14:00:41 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 24 Nov 2006 14:00:41 +0100 (CET) Subject: [pypy-svn] r34932 - in pypy/dist/pypy/module/_stackless: . test Message-ID: <20061124130041.4DF3B10075@code0.codespeak.net> Author: arigo Date: Fri Nov 24 14:00:39 2006 New Revision: 34932 Modified: pypy/dist/pypy/module/_stackless/coroutine.py pypy/dist/pypy/module/_stackless/interp_coroutine.py pypy/dist/pypy/module/_stackless/test/test_clonable.py Log: (pedronis, arigo) Test and bug fix for an obscure problem in _execute(), where the local 'self' is not correct if the coroutine is a clone -- it still points to the original. Reload it from costate.current instead. Sidenotedly, 'ddd' is slightly less pain than 'gdb' to debug compiled pypy-c's. Modified: pypy/dist/pypy/module/_stackless/coroutine.py ============================================================================== --- pypy/dist/pypy/module/_stackless/coroutine.py (original) +++ pypy/dist/pypy/module/_stackless/coroutine.py Fri Nov 24 14:00:39 2006 @@ -86,9 +86,9 @@ if self.frame is None: raise OperationError(space.w_ValueError, space.wrap( "cannot switch to an unbound Coroutine")) - self.switch() - rstack.resume_point("w_switch", self, space) state = self.costate + self.switch() + rstack.resume_point("w_switch", state, space) w_ret, state.w_tempval = state.w_tempval, space.w_None return w_ret @@ -202,8 +202,8 @@ costate = self.costate # now the big fun of recreating tiny things... bottom = resume_state_create(None, "yield_current_frame_to_caller_1") - # resume_point("coroutine__bind", self, state) - _bind_frame = resume_state_create(bottom, "coroutine__bind", self, costate) + # resume_point("coroutine__bind", state) + _bind_frame = resume_state_create(bottom, "coroutine__bind", costate) # rstack.resume_point("appthunk", costate, returns=w_result) appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate) chain = appthunk_frame @@ -231,10 +231,10 @@ call_frame = resume_state_create(dispatch_call_frame, 'call_function', frame) chain = call_frame - # rstack.resume_point("w_switch", self, space) - w_switch_frame = resume_state_create(chain, 'w_switch', self, space) - # resume_point("coroutine_switch", self, state, returns=incoming_frame) - switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", self, costate) + # rstack.resume_point("w_switch", state, space) + w_switch_frame = resume_state_create(chain, 'w_switch', costate, space) + # resume_point("coroutine_switch", state, returns=incoming_frame) + switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", costate) self.frame = switch_frame # _mixin_ did not work 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 Nov 24 14:00:39 2006 @@ -217,11 +217,15 @@ thunk = self.thunk self.thunk = None thunk.call() - resume_point("coroutine__bind", self, state) + resume_point("coroutine__bind", state) except Exception, e: exc = e raise finally: + # warning! we must reload the 'self' from the costate, + # because after a clone() the 'self' of both copies + # point to the original! + self = state.current self.finish(exc) except CoroutineExit: # ignore a shutdown exception @@ -242,7 +246,7 @@ raise CoroutineDamage state = self.costate incoming_frame = state.update(self).switch() - resume_point("coroutine_switch", self, state, returns=incoming_frame) + resume_point("coroutine_switch", state, returns=incoming_frame) syncstate.switched(incoming_frame) def kill(self): Modified: pypy/dist/pypy/module/_stackless/test/test_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_clonable.py Fri Nov 24 14:00:39 2006 @@ -17,67 +17,96 @@ def test_solver(self): - import new, sys + import _stackless - mod = new.module('mod') - sys.modules['mod'] = mod - try: - exec ''' -import _stackless - -class Fail(Exception): - pass - -class Success(Exception): - pass - -def first_solution(func): - global next_answer - co = _stackless.clonable() - co.bind(func) - pending = [(co, None)] - while pending: - co, next_answer = pending.pop() - try: - co.switch() - except Fail: + class Fail(Exception): pass - except Success, e: - return e.args[0] - else: - # zero_or_one() called, clone the coroutine - co2 = co.clone() - pending.append((co2, 1)) - pending.append((co, 0)) - raise Fail("no solution") - -pending = [] -main = _stackless.clonable.getcurrent() - -def zero_or_one(): - main.switch() - return next_answer - -# ____________________________________________________________ - -invalid_prefixes = { - (0, 0): True, - (0, 1, 0): True, - (0, 1, 1): True, - (1, 0): True, - (1, 1, 0, 0): True, - } - -def example(): - test = [] - for n in range(5): - test.append(zero_or_one()) - if tuple(test) in invalid_prefixes: - raise Fail - raise Success(test) - -res = first_solution(example) -assert res == [1, 1, 0, 1, 0] -''' in mod.__dict__ - finally: - del sys.modules['mod'] + + class Success(Exception): + pass + + def first_solution(func): + global next_answer + co = _stackless.clonable() + co.bind(func) + pending = [(co, None)] + while pending: + co, next_answer = pending.pop() + try: + co.switch() + except Fail: + pass + except Success, e: + return e.args[0] + else: + # zero_or_one() called, clone the coroutine + co2 = co.clone() + pending.append((co2, 1)) + pending.append((co, 0)) + raise Fail("no solution") + + pending = [] + main = _stackless.clonable.getcurrent() + + def zero_or_one(): + main.switch() + return next_answer + + # ____________________________________________________________ + + invalid_prefixes = { + (0, 0): True, + (0, 1, 0): True, + (0, 1, 1): True, + (1, 0): True, + (1, 1, 0, 0): True, + } + + def example(): + test = [] + for n in range(5): + test.append(zero_or_one()) + if tuple(test) in invalid_prefixes: + raise Fail + raise Success(test) + + res = first_solution(example) + assert res == [1, 1, 0, 1, 0] + + + def test_myself_may_not_be_me_any_more(self): + import gc + from _stackless import clonable + + counter = [0] + + def runner(): + while 1: + assert clonable.getcurrent() is coro + counter[0] += 1 + main.switch() + + main = clonable.getcurrent() + coro = clonable() + coro.bind(runner) + + coro.switch() + assert counter == [1] + + assert clonable.getcurrent() is main + coro1 = coro.clone() + assert counter == [1] + assert clonable.getcurrent() is main + coro.switch() + assert counter == [2] + coro.switch() + assert counter == [3] + assert clonable.getcurrent() is main + del coro1 + gc.collect() + #print "collected!" + assert clonable.getcurrent() is main + assert counter == [3] + coro.switch() + assert clonable.getcurrent() is main + assert counter == [4] From ale at codespeak.net Fri Nov 24 14:29:26 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Fri, 24 Nov 2006 14:29:26 +0100 (CET) Subject: [pypy-svn] r34933 - pypy/branch/mininal-c-backend/pypy/translator/c Message-ID: <20061124132926.5FF8810077@code0.codespeak.net> Author: ale Date: Fri Nov 24 14:29:24 2006 New Revision: 34933 Modified: pypy/branch/mininal-c-backend/pypy/translator/c/genc.py Log: The flags should go into the makefile as well. Modified: pypy/branch/mininal-c-backend/pypy/translator/c/genc.py ============================================================================== --- pypy/branch/mininal-c-backend/pypy/translator/c/genc.py (original) +++ pypy/branch/mininal-c-backend/pypy/translator/c/genc.py Fri Nov 24 14:29:24 2006 @@ -269,6 +269,10 @@ prefix = ' ' * len(prefix) compiler = self.getccompiler(extra_includes=['.']) + if self.config.translation.compilerflags: + compiler.compile_extra.append(self.config.translation.compilerflags) + if self.config.translation.linkerflags: + compiler.link_extra.append(self.config.translation.compilerflags) cfiles = [] ofiles = [] for fn in compiler.cfilenames: From fijal at codespeak.net Fri Nov 24 16:30:58 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 24 Nov 2006 16:30:58 +0100 (CET) Subject: [pypy-svn] r34937 - pypy/dist/pypy/translator/goal Message-ID: <20061124153058.DDE541007B@code0.codespeak.net> Author: fijal Date: Fri Nov 24 16:30:57 2006 New Revision: 34937 Modified: pypy/dist/pypy/translator/goal/app_main.py Log: Stupid commit Modified: pypy/dist/pypy/translator/goal/app_main.py ============================================================================== --- pypy/dist/pypy/translator/goal/app_main.py (original) +++ pypy/dist/pypy/translator/goal/app_main.py Fri Nov 24 16:30:57 2006 @@ -15,13 +15,6 @@ originalexcepthook = sys.__excepthook__ -try: - from signal import signal, SIG_IGN, SIGPIPE - signal(SIGPIPE, SIG_IGN) -except ImportError: - # XXX: we should do it on c-level anyway - pass - def run_toplevel(f, *fargs, **fkwds): """Calls f() and handle all OperationErrors. Intended use is to run the main program or one interactive statement. From fijal at codespeak.net Fri Nov 24 16:36:57 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Fri, 24 Nov 2006 16:36:57 +0100 (CET) Subject: [pypy-svn] r34938 - pypy/dist/pypy/translator/goal Message-ID: <20061124153657.0E2221007C@code0.codespeak.net> Author: fijal Date: Fri Nov 24 16:36:53 2006 New Revision: 34938 Modified: pypy/dist/pypy/translator/goal/app_main.py Log: (fijal, arigo) - Now this should help with signal and SIG_PIPE Modified: pypy/dist/pypy/translator/goal/app_main.py ============================================================================== --- pypy/dist/pypy/translator/goal/app_main.py (original) +++ pypy/dist/pypy/translator/goal/app_main.py Fri Nov 24 16:36:53 2006 @@ -208,6 +208,7 @@ def keyboard_interrupt_handler(*args): raise KeyboardInterrupt signal.signal(signal.SIGINT, keyboard_interrupt_handler) + signal.signal(signal.SIGPIPE, signal.SIG_IGN) try: if sys.argv: From mwh at codespeak.net Fri Nov 24 17:48:48 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 24 Nov 2006 17:48:48 +0100 (CET) Subject: [pypy-svn] r34940 - pypy/dist/pypy/rlib/parsing Message-ID: <20061124164848.AE5D81007C@code0.codespeak.net> Author: mwh Date: Fri Nov 24 17:48:47 2006 New Revision: 34940 Modified: pypy/dist/pypy/rlib/parsing/tree.py Log: avoiding reusing the 'name' argument to a metaclass's __new__ in a for loop -- led to classes with ridiculous __names__s like '__doc__' Modified: pypy/dist/pypy/rlib/parsing/tree.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/tree.py (original) +++ pypy/dist/pypy/rlib/parsing/tree.py Fri Nov 24 17:48:47 2006 @@ -106,7 +106,7 @@ return dispatch class CreateDispatchDictionaryMetaclass(type): - def __new__(cls, name, bases, dct): + def __new__(cls, name_, bases, dct): dispatch_table = {} for name, value in dct.iteritems(): if name.startswith("visit_"): @@ -118,7 +118,7 @@ dispatch_table["__" + special] = dct[special] dct["dispatch_table"] = dispatch_table dct["dispatch"] = make_dispatch_function(dispatch_table) - return type.__new__(cls, name, bases, dct) + return type.__new__(cls, name_, bases, dct) class RPythonVisitor(object): __metaclass__ = CreateDispatchDictionaryMetaclass From arigo at codespeak.net Fri Nov 24 18:07:58 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 24 Nov 2006 18:07:58 +0100 (CET) Subject: [pypy-svn] r34941 - pypy/dist/pypy/doc Message-ID: <20061124170758.E33F11007D@code0.codespeak.net> Author: arigo Date: Fri Nov 24 18:07:55 2006 New Revision: 34941 Modified: pypy/dist/pypy/doc/_ref.txt pypy/dist/pypy/doc/constraints-and-logic.txt pypy/dist/pypy/doc/index.txt pypy/dist/pypy/doc/jit.txt pypy/dist/pypy/doc/rtyper.txt pypy/dist/pypy/doc/translation.txt Log: issue248 resolved PyPy directory cross-reference updated. Modified: pypy/dist/pypy/doc/_ref.txt ============================================================================== --- pypy/dist/pypy/doc/_ref.txt (original) +++ pypy/dist/pypy/doc/_ref.txt Fri Nov 24 18:07:55 2006 @@ -8,7 +8,10 @@ .. _`annotation/binaryop.py`: ../../pypy/annotation/binaryop.py .. _`pypy/annotation/builtin.py`: ../../pypy/annotation/builtin.py .. _`pypy/annotation/model.py`: ../../pypy/annotation/model.py +.. _`bin/`: ../../pypy/bin +.. _`config/`: ../../pypy/config .. _`doc/`: ../../pypy/doc +.. _`doc/discussion/`: ../../pypy/doc/discussion .. _`interpreter/`: .. _`pypy/interpreter`: ../../pypy/interpreter .. _`pypy/interpreter/argument.py`: ../../pypy/interpreter/argument.py @@ -21,8 +24,18 @@ .. _`pypy/interpreter/mixedmodule.py`: ../../pypy/interpreter/mixedmodule.py .. _`pypy/interpreter/nestedscope.py`: ../../pypy/interpreter/nestedscope.py .. _`pypy/interpreter/pyopcode.py`: ../../pypy/interpreter/pyopcode.py +.. _`interpreter/pyparser/`: .. _`pypy/interpreter/pyparser`: ../../pypy/interpreter/pyparser .. _`pypy/interpreter/typedef.py`: ../../pypy/interpreter/typedef.py +.. _`jit/`: ../../pypy/jit +.. _`jit/codegen/`: ../../pypy/jit/codegen +.. _`pypy/jit/codegen/model.py`: ../../pypy/jit/codegen/model.py +.. _`jit/hintannotator/`: ../../pypy/jit/hintannotator +.. _`jit/timeshifter/`: ../../pypy/jit/timeshifter +.. _`jit/tl/`: ../../pypy/jit/tl +.. _`lang/`: ../../pypy/lang +.. _`lang/js/`: ../../pypy/lang/js +.. _`lang/prolog/`: ../../pypy/lang/prolog .. _`lib/`: .. _`pypy/lib/`: ../../pypy/lib .. _`pypy/lib/stackless.py`: ../../pypy/lib/stackless.py @@ -31,25 +44,24 @@ .. _`module/`: .. _`pypy/module`: .. _`pypy/module/`: ../../pypy/module -.. _`module/__builtin__/`: ../../pypy/module/__builtin__ .. _`pypy/module/__builtin__/__init__.py`: ../../pypy/module/__builtin__/__init__.py .. _`pypy/module/_demo`: ../../pypy/module/_demo -.. _`module/_sre/`: .. _`pypy/module/_sre`: ../../pypy/module/_sre .. _`pypy/module/_sre/interp_sre.py`: ../../pypy/module/_sre/interp_sre.py .. _`pypy/module/_stackless/test/test_composable_coroutine.py`: ../../pypy/module/_stackless/test/test_composable_coroutine.py .. _`pypy/module/readline`: ../../pypy/module/readline -.. _`module/recparser/`: ../../pypy/module/recparser -.. _`module/sys/`: ../../pypy/module/sys .. _`objspace/`: .. _`pypy/objspace`: ../../pypy/objspace +.. _`objspace/dump.py`: ../../pypy/objspace/dump.py .. _`objspace/flow/`: ../../pypy/objspace/flow +.. _`objspace/logic.py`: ../../pypy/objspace/logic.py .. _`objspace/std/`: .. _`pypy/objspace/std`: ../../pypy/objspace/std .. _`objspace/thunk.py`: ../../pypy/objspace/thunk.py .. _`objspace/trace.py`: .. _`pypy/objspace/trace.py`: ../../pypy/objspace/trace.py -.. _`pypy/rlib`: ../../pypy/rlib +.. _`pypy/rlib`: +.. _`rlib/`: ../../pypy/rlib .. _`pypy/rlib/objectmodel.py`: ../../pypy/rlib/objectmodel.py .. _`pypy/rlib/rarithmetic.py`: ../../pypy/rlib/rarithmetic.py .. _`pypy/rlib/test`: ../../pypy/rlib/test @@ -57,6 +69,7 @@ .. _`pypy/rpython/`: .. _`rpython/`: ../../pypy/rpython .. _`pypy/rpython/extfunctable.py`: ../../pypy/rpython/extfunctable.py +.. _`rpython/lltypesystem/`: ../../pypy/rpython/lltypesystem .. _`pypy/rpython/lltypesystem/lltype.py`: .. _`rpython/lltypesystem/lltype.py`: ../../pypy/rpython/lltypesystem/lltype.py .. _`rpython/memory/`: ../../pypy/rpython/memory @@ -67,6 +80,7 @@ .. _`pypy/rpython/module/`: ../../pypy/rpython/module .. _`pypy/rpython/module/ll_os.py`: ../../pypy/rpython/module/ll_os.py .. _`pypy/rpython/module/test`: ../../pypy/rpython/module/test +.. _`rpython/ootypesystem/`: ../../pypy/rpython/ootypesystem .. _`rpython/ootypesystem/ootype.py`: ../../pypy/rpython/ootypesystem/ootype.py .. _`pypy/rpython/rctypes/test/test_ctypes.py`: ../../pypy/rpython/rctypes/test/test_ctypes.py .. _`rpython/rint.py`: ../../pypy/rpython/rint.py @@ -81,12 +95,19 @@ .. _`tool/tb_server/`: ../../pypy/tool/tb_server .. _`pypy/translator`: .. _`translator/`: ../../pypy/translator +.. _`translator/backendopt/`: ../../pypy/translator/backendopt .. _`translator/c/`: ../../pypy/translator/c .. _`pypy/translator/c/extfunc.py`: ../../pypy/translator/c/extfunc.py .. _`pypy/translator/c/src/`: ../../pypy/translator/c/src .. _`pypy/translator/c/src/ll_os.h`: ../../pypy/translator/c/src/ll_os.h .. _`pypy/translator/c/test/test_extfunc.py`: ../../pypy/translator/c/test/test_extfunc.py +.. _`translator/cl/`: ../../pypy/translator/cl +.. _`translator/cli/`: ../../pypy/translator/cli .. _`translator/goal/`: ../../pypy/translator/goal .. _`pypy/translator/goal/targetnopstandalone.py`: ../../pypy/translator/goal/targetnopstandalone.py +.. _`translator/js/`: ../../pypy/translator/js +.. _`translator/jvm/`: ../../pypy/translator/jvm .. _`translator/llvm/`: ../../pypy/translator/llvm +.. _`translator/squeak/`: ../../pypy/translator/squeak +.. _`translator/stackless/`: ../../pypy/translator/stackless .. _`translator/tool/`: ../../pypy/translator/tool \ No newline at end of file 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 Fri Nov 24 18:07:55 2006 @@ -214,6 +214,8 @@ other hand, the lexically bounded mini-language proposed above helps solve this more uniformly. +.. _`logic programming`: + Logic Programming, Prolog and Oz-style ====================================== Modified: pypy/dist/pypy/doc/index.txt ============================================================================== --- pypy/dist/pypy/doc/index.txt (original) +++ pypy/dist/pypy/doc/index.txt Fri Nov 24 18:07:55 2006 @@ -164,40 +164,72 @@ ============================ =========================================== `annotation/`_ `type inferencing code`_ for `RPython`_ programs +`bin/`_ command-line scripts, mainly `py.py`_ and `translatorshell.py`_ + +`config/`_ handles the numerous options for building and running PyPy + `doc/`_ text versions of PyPy developer documentation -`interpreter/`_ `bytecode interpreter`_ and related objects (frames, functions, modules,...) +`doc/discussion/`_ drafts of ideas and documentation + +`interpreter/`_ `bytecode interpreter`_ and related objects + (frames, functions, modules,...) + +`interpreter/pyparser/`_ interpreter-level Python source parser `interpreter/astcompiler/`_ interpreter-level bytecode compiler, via an AST representation -`lib/`_ PyPy's wholesale reimplementations of CPython modules_ +`jit/`_ the `just-in-time compiler generator`_ -`lib/test2/`_ tests running at interp-level against the reimplementations +`jit/codegen/`_ `jit backends`_ for different architectures -`module/`_ contains `mixed modules`_ implementing core modules with - both application and interpreter level code +`jit/hintannotator/`_ the `hint-annotator`_ that analyzes an interpreter + +`jit/timeshifter/`_ the `timeshifter`_ that turns an interpreter into a JIT compiler -`module/_sre/`_ full regular expression implementation +`jit/tl/`_ interpreters for toy languages, with which we test the + JIT generator -`module/__builtin__/`_ full implementation of CPython's ``__builtin__`` module. +`lang/`_ interpreters for non-Python languages, written in RPython_ -`module/recparser/`_ parser_ package from Logilab +`lang/js/`_ a JavaScript interpreter (in-progress) -`module/sys/`_ implementation of CPython's ``sys`` module. +`lang/prolog/`_ a Prolog interpreter + +`lib/`_ PyPy's wholesale reimplementations of CPython modules_ + and experimental new application-level modules + +`lib/test2/`_ tests running at interp-level against the reimplementations + +`module/`_ contains `mixed modules`_ implementing core modules with + both application and interpreter level code. + Not all are finished and working. Use the ``--withmod-xxx`` + options of `translate.py`_. `objspace/`_ `object space`_ implementations `objspace/trace.py`_ the `trace object space`_ monitoring bytecode and space operations +`objspace/dump.py`_ the dump object space saves a large, searchable log file + with all operations + `objspace/thunk.py`_ the `thunk object space`_, providing unique object features +`objspace/logic.py`_ the `logic object space`_, providing Prolog-like logic variables + `objspace/flow/`_ the FlowObjSpace_ implementing `abstract interpretation` `objspace/std/`_ the StdObjSpace_ implementing CPython's objects and types +`rlib/`_ a "standard library" for RPython_ programs + `rpython/`_ the `RPython Typer`_ +`rpython/lltypesystem/`_ the `low-level type system`_ for C-like backends + +`rpython/ootypesystem/`_ the `object-oriented type system`_ for OO backends + `rpython/memory/`_ experimental `garbage collector`_ construction framework @@ -213,16 +245,29 @@ `translator/`_ translation_ backends and support code +`translator/backendopt/`_ general optimizations that run before a backend generates code + `translator/c/`_ the `GenC backend`_, producing C code from an RPython program (generally via the RTyper) +`translator/cl/`_ the `Common Lisp backend`_ (incomplete) + +`translator/cli/`_ the `CLI backend`_ for `.NET`_ (Microsoft CLR or Mono_) + +`translator/goal/`_ our `main PyPy-translation scripts`_ live here + +`translator/js/`_ the `JavaScript backend`_ + +`translator/jvm/`_ the Java backend (in-progress) + `translator/llvm/`_ contains the `LLVM backend`_ producing LLVM assembler from fully annotated RPython programs -`translator/tool/`_ helper tools for translation +`translator/squeak/`_ the `Squeak backend`_ (very incomplete) -`translator/goal/`_ currently our main PyPy-translation scripts - live here +`translator/stackless/`_ the `Stackless Transform`_ + +`translator/tool/`_ helper tools for translation ``*/test/`` many directories have a test subdirectory containing test modules (see `Testing in PyPy`_) @@ -232,7 +277,7 @@ ============================ =========================================== .. _`bytecode interpreter`: interpreter.html -.. _`translating application level to interpreterlevel`: translation.html#python-back-end +.. _`translating application level to interpreterlevel`: geninterp.html .. _documentation: index.html .. _`Testing in PyPy`: coding-guide.html#testing-in-pypy .. _`mixed modules`: coding-guide.html#mixed-modules @@ -241,7 +286,8 @@ .. _`object space`: objspace.html .. _FlowObjSpace: objspace.html#the-flow-object-space .. _`trace object space`: objspace.html#the-trace-object-space -.. _`thunk object space`: objspace.html#the-thunk-object-space +.. _`thunk object space`: objspace.html#the-thunk-object-space +.. _`logic object space`: constraints-and-logic.html#logic-programming .. _StdObjSpace: objspace.html#the-standard-object-space .. _`abstract interpretation`: theory.html#abstract-interpretation .. _`rpython`: coding-guide.html#rpython @@ -250,10 +296,25 @@ .. _`testing methods`: coding-guide.html#testing-in-pypy .. _`translation`: translation.html .. _`GenC backend`: translation.html#genc -.. _`LLVM backend`: translation.html#llvm +.. _`LLVM backend`: translation.html#llvm +.. _`CLI backend`: translation.html#gencli +.. _`Common Lisp backend`: translation.html#gencl +.. _`Squeak backend`: translation.html#gensqueak .. _`revision report`: http://codespeak.net/pypy/rev/current .. _`garbage collector`: garbage_collection.html .. _`extension compiler`: extcompiler.html - +.. _`py.py`: getting-started.html#main-entry-point +.. _`translatorshell.py`: getting-started.html#try-out-the-translator +.. _`just-in-time compiler generator`: jit.html +.. _`jit backends`: jit.html#backends +.. _`hint-annotator`: jit.html#hint-annotator +.. _`timeshifter`: jit.html#timeshifter +.. _`low-level type system`: rtyper.html#low-level-type +.. _`object-oriented type system`: rtyper.html#oo-type +.. _`Stackless Transform`: translation.html#the-stackless-transform +.. _`main PyPy-translation scripts`: getting-started.html#translating-the-pypy-interpreter +.. _`translate.py`: getting-started.html#translating-the-pypy-interpreter +.. _`.NET`: http://www.microsoft.com/net/ +.. _Mono: http://www.mono-project.com/ .. include:: _ref.txt Modified: pypy/dist/pypy/doc/jit.txt ============================================================================== --- pypy/dist/pypy/doc/jit.txt (original) +++ pypy/dist/pypy/doc/jit.txt Fri Nov 24 18:07:55 2006 @@ -85,11 +85,11 @@ over-allocation, which causes several identical RPython lists to look different when represented as low-level structs and arrays. -Hint-RTyper +Timeshifter ----------- -Once the graph has been colored, enters the hint-rtyper. This tool -- -again loosely based on the normal RTyper -- transforms the colored +Once the graph has been colored, enters the "timeshifter". This +tool -- 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 @@ -183,7 +183,7 @@ 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 +The current preliminary work on the timeshifter turns the interpreter 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 @@ -220,7 +220,7 @@ 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 +timeshifter 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. @@ -235,3 +235,16 @@ 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. + +Backends +---------------- + +The compilers produced by the timeshifter are linked with one of our +backends, which are written by hand in RPython. We currently have a +backend for producing IA32/i386 machine code in memory, PowerPC machine +code in memory, or (for testing) further low-level control flow graphs. + +The interface is documented in `pypy/jit/codegen/model.py`_. + + +.. include:: _ref.txt Modified: pypy/dist/pypy/doc/rtyper.txt ============================================================================== --- pypy/dist/pypy/doc/rtyper.txt (original) +++ pypy/dist/pypy/doc/rtyper.txt Fri Nov 24 18:07:55 2006 @@ -431,6 +431,8 @@ See for example `rpython/rlist.py`_. +.. _`oo type`: + Object Oriented Types --------------------- Modified: pypy/dist/pypy/doc/translation.txt ============================================================================== --- pypy/dist/pypy/doc/translation.txt (original) +++ pypy/dist/pypy/doc/translation.txt Fri Nov 24 18:07:55 2006 @@ -617,9 +617,6 @@ .. _`here`: getting-started.html#translating-the-flow-graph-to-llvm-code -.. _`Python again`: -.. _`Python back-end`: - The Object-Oriented Backends ---------------------------- @@ -702,6 +699,10 @@ GenCL has seen work from many people, but the driving force has mostly been Seo Sanghyeon. + +.. _`Python again`: +.. _`Python back-end`: + The Interpreter-Level backend ----------------------------- From arigo at codespeak.net Fri Nov 24 18:15:04 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 24 Nov 2006 18:15:04 +0100 (CET) Subject: [pypy-svn] r34942 - pypy/dist/pypy/doc/js Message-ID: <20061124171504.DFA9110076@code0.codespeak.net> Author: arigo Date: Fri Nov 24 18:15:02 2006 New Revision: 34942 Modified: pypy/dist/pypy/doc/js/using.txt Log: Fix links. Modified: pypy/dist/pypy/doc/js/using.txt ============================================================================== --- pypy/dist/pypy/doc/js/using.txt (original) +++ pypy/dist/pypy/doc/js/using.txt Fri Nov 24 18:15:02 2006 @@ -171,6 +171,6 @@ working copy on-line right now, sorry) and a simple example of JS a `console`_. There is also a simple `django ping example`_. -.. _`here`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/tools/start_bnb.py -.. _`console`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/tools/console.py +.. _`here`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/examples/start_bnb.py +.. _`console`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/examples/console.py .. _`django ping example`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/demo/jsdemo/djangoping From arigo at codespeak.net Fri Nov 24 18:23:23 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 24 Nov 2006 18:23:23 +0100 (CET) Subject: [pypy-svn] r34943 - in pypy/dist/pypy/module/_stackless: . test Message-ID: <20061124172323.982F51007C@code0.codespeak.net> Author: arigo Date: Fri Nov 24 18:23:21 2006 New Revision: 34943 Modified: pypy/dist/pypy/module/_stackless/clonable.py pypy/dist/pypy/module/_stackless/interp_clonable.py pypy/dist/pypy/module/_stackless/test/test_clonable.py pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py Log: Change the parent of a freshly cloned coroutine, to be its original. This allows much more natural code to be written, as seen in the new test_fork(). Modified: pypy/dist/pypy/module/_stackless/clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/clonable.py (original) +++ pypy/dist/pypy/module/_stackless/clonable.py Fri Nov 24 18:23:21 2006 @@ -83,6 +83,7 @@ self.coroutine = None newcoro = AppClonableCoroutine(oldcoro.space, state=oldcoro.costate) newcoro.subctx = oldcoro.clone_into(newcoro, oldcoro.subctx) + newcoro.parent = oldcoro self.newcoroutine = newcoro def fork(space): Modified: pypy/dist/pypy/module/_stackless/interp_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/interp_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/interp_clonable.py Fri Nov 24 18:23:21 2006 @@ -64,7 +64,9 @@ def call(self): oldcoro = self.coroutine self.coroutine = None - self.newcoroutine = oldcoro.clone() + newcoro = oldcoro.clone() + newcoro.parent = oldcoro + self.newcoroutine = newcoro def fork(): """Fork, as in the Unix fork(): the call returns twice, and the return Modified: pypy/dist/pypy/module/_stackless/test/test_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_clonable.py Fri Nov 24 18:23:21 2006 @@ -110,3 +110,58 @@ coro.switch() assert clonable.getcurrent() is main assert counter == [4] + + + def test_fork(self): + import _stackless + + class Fail(Exception): + pass + + class Success(Exception): + pass + + def first_solution(func): + global next_answer + co = _stackless.clonable() + co.bind(func) + try: + co.switch() + except Success, e: + return e.args[0] + + def zero_or_one(): + sub = _stackless.fork() + if sub is not None: + # in the parent: run the child first + try: + sub.switch() + except Fail: + pass + # then proceed with answer '1' + return 1 + else: + # in the child: answer '0' + return 0 + + # ____________________________________________________________ + + invalid_prefixes = { + (0, 0): True, + (0, 1, 0): True, + (0, 1, 1): True, + (1, 0): True, + (1, 1, 0, 0): True, + } + + def example(): + test = [] + for n in range(5): + test.append(zero_or_one()) + if tuple(test) in invalid_prefixes: + raise Fail + raise Success(test) + + res = first_solution(example) + assert res == [1, 1, 0, 1, 0] + Modified: pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py ============================================================================== --- pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py (original) +++ pypy/dist/pypy/module/_stackless/test/test_interp_clonable.py Fri Nov 24 18:23:21 2006 @@ -92,6 +92,7 @@ # in the parent self.result.append(3) newcoro.switch() + self.result.append(5) else: # in the child self.result.append(4) @@ -103,8 +104,6 @@ coro.bind(T(result)) result.append(1) coro.switch() - result.append(5) - coro.switch() # resume after newcoro.switch() result.append(6) n = 0 for i in result: From ac at codespeak.net Fri Nov 24 19:17:18 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Fri, 24 Nov 2006 19:17:18 +0100 (CET) Subject: [pypy-svn] r34944 - in pypy/dist/pypy/jit/timeshifter: . test Message-ID: <20061124181718.C1BED10079@code0.codespeak.net> Author: ac Date: Fri Nov 24 19:17:06 2006 New Revision: 34944 Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/jit/timeshifter/rtimeshift.py pypy/dist/pypy/jit/timeshifter/rvalue.py pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/jit/timeshifter/transform.py Log: (pedronis, arre, arigo around) Make check_insns() work for tests with portals != entrypoint. Add support for less aggressive merging (not used yet). Support red and grey calls returning more than one jitstate. Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Fri Nov 24 19:17:06 2006 @@ -3,6 +3,7 @@ from pypy.translator.unsimplify import varoftype from pypy.translator.backendopt.ssa import SSA_to_SSI from pypy.annotation import model as annmodel +from pypy.annotation import listdef from pypy.annotation.pairtype import pair, pairtype from pypy.rpython.annlowlevel import PseudoHighLevelCallable from pypy.rlib.unroll import unrolling_iterable @@ -152,11 +153,16 @@ bk = self.annotator.bookkeeper bk.compute_after_normalization() entrygraph = self.annotator.translator.graphs[0] + if origportalgraph: + portalgraph = bk.get_graph_by_key(origportalgraph, None) + else: + portalgraph = None pending = [entrygraph] seen = {entrygraph: True} while pending: graph = pending.pop() - for nextgraph in self.transform_graph(graph): + for nextgraph in self.transform_graph(graph, + is_portal=graph is portalgraph): if nextgraph not in seen: pending.append(nextgraph) seen[nextgraph] = True @@ -170,7 +176,6 @@ self.timeshift_graph(graph) if origportalgraph: - portalgraph = bk.get_graph_by_key(origportalgraph, None) self.rewire_portal(origportalgraph, portalgraph) def rewire_portal(self, origportalgraph, portalgraph): @@ -222,6 +227,9 @@ return cache[key] except KeyError: return lltype.nullptr(FUNC) + + def readallportals(): + return state.cache.values() def portalentry(*args): i = 0 @@ -280,8 +288,13 @@ portalentrygraph = annhelper.getgraph(portalentry, args_s, s_result) portalentrygraph.tag = "portal_entry" + s_funcptr = annmodel.SomePtr(lltype.Ptr(FUNC)) self.readportalgraph = annhelper.getgraph(readportal, args_s, - annmodel.SomePtr(lltype.Ptr(FUNC))) + s_funcptr) + + s_funcptrlist = annmodel.SomeList(listdef.ListDef(None, s_funcptr)) + self.readallportalsgraph = annhelper.getgraph(readallportals, [], + s_funcptrlist) annhelper.finish() @@ -290,11 +303,12 @@ origportalgraph.exceptblock = portalentrygraph.exceptblock # name, func? - def transform_graph(self, graph): + def transform_graph(self, graph, is_portal=False): # prepare the graphs by inserting all bookkeeping/dispatching logic # as special operations assert graph.startblock in self.annotator.annotated - transformer = HintGraphTransformer(self.annotator, graph) + transformer = HintGraphTransformer(self.annotator, graph, + is_portal=is_portal) transformer.transform() flowmodel.checkgraph(graph) # for now return transformer.tsgraphs_seen @@ -752,14 +766,18 @@ [v_jitstate , self.v_queue], annmodel.s_None) - def translate_op_leave_graph_red(self, hop): + def translate_op_leave_graph_red(self, hop, is_portal=False): v_jitstate = hop.llops.getjitstate() + c_is_portal = inputconst(lltype.Bool, is_portal) v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_red, - [self.s_JITState, self.s_Queue], - [v_jitstate , self.v_queue], + [self.s_JITState, self.s_Queue, annmodel.s_Bool], + [v_jitstate , self.v_queue, c_is_portal], self.s_JITState) hop.llops.setjitstate(v_newjs) + def translate_op_leave_graph_portal(self, hop): + self.translate_op_leave_graph_red(hop, is_portal=True) + def translate_op_leave_graph_gray(self, hop): v_jitstate = hop.llops.getjitstate() v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_gray, Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py Fri Nov 24 19:17:06 2006 @@ -212,7 +212,7 @@ def return_marker(jitstate): raise AssertionError("shouldn't get here") -def start_new_block(states_dic, jitstate, key, global_resumer): +def start_new_block(states_dic, jitstate, key, global_resumer, index=-1): memo = rvalue.freeze_memo() frozen = jitstate.freeze(memo) memo = rvalue.exactmatch_memo() @@ -221,7 +221,11 @@ assert res, "exactmatch() failed" cleanup_partial_data(memo.partialdatamatch) newblock = enter_next_block(jitstate, outgoingvarboxes) - states_dic[key] = frozen, newblock + if index == -1: + states_dic[key].append((frozen, newblock)) + else: + states_dic[key][index] = (frozen, newblock) + if global_resumer is not None and global_resumer is not return_marker: greens_gv = jitstate.greens rgenop = jitstate.curbuilder.rgenop @@ -233,35 +237,51 @@ #debug_print(lltype.Void, "PROMOTION ROOT") start_new_block._annspecialcase_ = "specialize:arglltype(2)" -def retrieve_jitstate_for_merge(states_dic, jitstate, key, global_resumer): +class DontMerge(Exception): + pass + +def retrieve_jitstate_for_merge(states_dic, jitstate, key, global_resumer, + force_merge=False): if key not in states_dic: + states_dic[key] = [] start_new_block(states_dic, jitstate, key, global_resumer) return False # continue - frozen, oldblock = states_dic[key] - memo = rvalue.exactmatch_memo() - outgoingvarboxes = [] - - if frozen.exactmatch(jitstate, outgoingvarboxes, memo): - linkargs = [] + states = states_dic[key] + for i in range(len(states) -1, -1, -1): + frozen, oldblock = states[i] + memo = rvalue.exactmatch_memo(force_merge) + outgoingvarboxes = [] + + try: + match = frozen.exactmatch(jitstate, outgoingvarboxes, memo) + except DontMerge: + continue + if match: + linkargs = [] + for box in outgoingvarboxes: + linkargs.append(box.getgenvar(jitstate.curbuilder)) + jitstate.curbuilder.finish_and_goto(linkargs, oldblock) + return True # finished + # A mergable blook found + # We need a more general block. Do it by generalizing all the + # redboxes from outgoingvarboxes, by making them variables. + # Then we make a new block based on this new state. + cleanup_partial_data(memo.partialdatamatch) + replace_memo = rvalue.copy_memo() for box in outgoingvarboxes: - linkargs.append(box.getgenvar(jitstate.curbuilder)) - jitstate.curbuilder.finish_and_goto(linkargs, oldblock) - return True # finished - - # We need a more general block. Do it by generalizing all the - # redboxes from outgoingvarboxes, by making them variables. - # Then we make a new block based on this new state. - cleanup_partial_data(memo.partialdatamatch) - replace_memo = rvalue.copy_memo() - for box in outgoingvarboxes: - box.forcevar(jitstate.curbuilder, replace_memo) - if replace_memo.boxes: - jitstate.replace(replace_memo) + box.forcevar(jitstate.curbuilder, replace_memo) + if replace_memo.boxes: + jitstate.replace(replace_memo) + start_new_block(states_dic, jitstate, key, global_resumer, index=i) + if global_resumer is None: + merge_generalized(jitstate) + return False # continue + + # No mergable states found, make a new. start_new_block(states_dic, jitstate, key, global_resumer) - if global_resumer is None: - merge_generalized(jitstate) - return False # continue + return False + retrieve_jitstate_for_merge._annspecialcase_ = "specialize:arglltype(2)" def cleanup_partial_data(partialdatamatch): @@ -888,54 +908,64 @@ parent_mergesleft = MC_CALL_NOT_TAKEN dispatchqueue.mergecounter = parent_mergesleft -def merge_returning_jitstates(jitstate, dispatchqueue): +def merge_returning_jitstates(jitstate, dispatchqueue, force_merge=False): return_chain = dispatchqueue.return_chain - resuming = jitstate.resuming return_cache = {} still_pending = None while return_chain is not None: jitstate = return_chain return_chain = return_chain.next res = retrieve_jitstate_for_merge(return_cache, jitstate, (), - return_marker) + return_marker, + force_merge=force_merge) if res is False: # not finished jitstate.next = still_pending still_pending = jitstate - most_general_jitstate = still_pending - # if there are more than one jitstate still left, merge them forcefully - if still_pending is not None: - still_pending = still_pending.next - while still_pending is not None: - jitstate = still_pending - still_pending = still_pending.next + + # Of the jitstates we have left some may be mergable to a later + # more general one. + return_chain = still_pending + if return_chain is not None: + return_cache = {} + still_pending = None + while return_chain is not None: + jitstate = return_chain + return_chain = return_chain.next res = retrieve_jitstate_for_merge(return_cache, jitstate, (), - return_marker) - assert res is True # finished + return_marker, + force_merge=force_merge) + if res is False: # not finished + jitstate.next = still_pending + still_pending = jitstate + return still_pending +def leave_graph_red(jitstate, dispatchqueue, is_portal): + resuming = jitstate.resuming + return_chain = merge_returning_jitstates(jitstate, dispatchqueue, + force_merge=is_portal) if resuming is not None: resuming.leave_call(dispatchqueue) - - return most_general_jitstate - -def leave_graph_red(jitstate, dispatchqueue): - jitstate = merge_returning_jitstates(jitstate, dispatchqueue) - if jitstate is not None: + jitstate = return_chain + while jitstate is not None: myframe = jitstate.frame leave_frame(jitstate) jitstate.greens = [] - jitstate.next = None jitstate.returnbox = myframe.local_boxes[0] - # ^^^ fetched by a 'fetch_return' operation - return jitstate + jitstate = jitstate.next + return return_chain def leave_graph_gray(jitstate, dispatchqueue): - jitstate = merge_returning_jitstates(jitstate, dispatchqueue) - if jitstate is not None: + resuming = jitstate.resuming + return_chain = merge_returning_jitstates(jitstate, dispatchqueue) + if resuming is not None: + resuming.leave_call(dispatchqueue) + jitstate = return_chain + while jitstate is not None: leave_frame(jitstate) jitstate.greens = [] - jitstate.next = None jitstate.returnbox = None - return jitstate + jitstate = jitstate.next + return return_chain def leave_frame(jitstate): myframe = jitstate.frame Modified: pypy/dist/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/dist/pypy/jit/timeshifter/rvalue.py Fri Nov 24 19:17:06 2006 @@ -13,9 +13,10 @@ def freeze_memo(): return Memo() -def exactmatch_memo(): +def exactmatch_memo(force_merge=False): memo = Memo() memo.partialdatamatch = {} + memo.force_merge=force_merge return memo def copy_memo(): Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Fri Nov 24 19:17:06 2006 @@ -25,6 +25,7 @@ def postprocess_timeshifting(self): self.readportalgraph = self.hrtyper.readportalgraph + self.readallportalsgraph = self.hrtyper.readallportalsgraph def _timeshift_from_portal(self, main, portal, main_args, inline=None, policy=None, @@ -82,6 +83,7 @@ inline=inline, policy=policy, backendoptimize=backendoptimize) self.main_args = main_args + self.main_is_portal = main is portal llinterp = LLInterpreter(self.rtyper) res = llinterp.eval_graph(self.maingraph, main_args) return res @@ -89,8 +91,14 @@ def check_insns(self, expected=None, **counts): # XXX only works if the portal is the same as the main llinterp = LLInterpreter(self.rtyper) - residual_graph = llinterp.eval_graph(self.readportalgraph, - self.main_args)._obj.graph + if self.main_is_portal: + residual_graph = llinterp.eval_graph(self.readportalgraph, + self.main_args)._obj.graph + else: + residual_graphs = llinterp.eval_graph(self.readallportalsgraph, []) + assert residual_graphs.ll_length() == 1 + residual_graph = residual_graphs.ll_getitem_fast(0)._obj.graph + self.insns = summary(residual_graph) if expected is not None: assert self.insns == expected @@ -207,6 +215,45 @@ def get(self): return ord(self.s[4]) + def ll_main(n): + if n > 0: + o = Int(n) + else: + o = Str('123') + return ll_function(o) + + def ll_function(o): + hint(None, global_merge_point=True) + hint(o.__class__, promote=True) + return o.double().get() + + res = self.timeshift_from_portal(ll_main, ll_function, [5], policy=P_NOVIRTUAL) + assert res == 10 + self.check_insns(indirect_call=0) + + res = self.timeshift_from_portal(ll_main, ll_function, [0], policy=P_NOVIRTUAL) + assert res == ord('2') + self.check_insns(indirect_call=0) + + def test_virt_obj_method_call_promote(self): + py.test.skip('WIP') + class Base(object): + pass + class Int(Base): + def __init__(self, n): + self.n = n + def double(self): + return Int(self.n * 2) + def get(self): + return self.n + class Str(Base): + def __init__(self, s): + self.s = s + def double(self): + return Str(self.s + self.s) + def get(self): + return ord(self.s[4]) + def ll_make(n): if n > 0: return Int(n) @@ -221,8 +268,8 @@ res = self.timeshift_from_portal(ll_function, ll_function, [5], policy=P_NOVIRTUAL) assert res == 10 - self.check_insns(indirect_call=0) #, malloc=0) + self.check_insns(indirect_call=0, malloc=0) res = self.timeshift_from_portal(ll_function, ll_function, [0], policy=P_NOVIRTUAL) assert res == ord('2') - self.check_insns(indirect_call=0) #, malloc=0) + self.check_insns(indirect_call=0, malloc=0) Modified: pypy/dist/pypy/jit/timeshifter/transform.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/transform.py (original) +++ pypy/dist/pypy/jit/timeshifter/transform.py Fri Nov 24 19:17:06 2006 @@ -37,9 +37,10 @@ class HintGraphTransformer(object): c_dummy = inputconst(lltype.Void, None) - def __init__(self, hannotator, graph): + def __init__(self, hannotator, graph, is_portal=False): self.hannotator = hannotator self.graph = graph + self.is_portal = is_portal self.graphcolor = self.graph_calling_color(graph) self.resumepoints = {} self.mergepoint_set = {} # set of blocks @@ -399,7 +400,6 @@ elif self.graphcolor == 'yellow': self.genop(block, 'save_greens', [v_retbox]) elif self.graphcolor == 'red': - self.leave_graph_opname = 'leave_graph_red' self.genop(block, 'save_locals', [v_retbox]) else: raise AssertionError(self.graph, self.graphcolor) @@ -419,7 +419,11 @@ def insert_leave_graph(self): block = self.before_return_block() - self.genop(block, 'leave_graph_%s' % (self.graphcolor,), []) + if self.is_portal: + assert self.graphcolor == 'red' + self.genop(block, 'leave_graph_portal', []) + else: + self.genop(block, 'leave_graph_%s' % (self.graphcolor,), []) # __________ handling of the various kinds of calls __________ From arigo at codespeak.net Fri Nov 24 20:20:56 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 24 Nov 2006 20:20:56 +0100 (CET) Subject: [pypy-svn] r34946 - pypy/dist/pypy/rlib/parsing Message-ID: <20061124192056.A0F7D1007A@code0.codespeak.net> Author: arigo Date: Fri Nov 24 20:20:54 2006 New Revision: 34946 Modified: pypy/dist/pypy/rlib/parsing/tree.py Log: Trying to get rid of the 'exec' here. A closure works just as nicely. This fixes a problem where multiple 'self.dispatch_table' get merged between multiple subclasses of RPythonVisitor. Modified: pypy/dist/pypy/rlib/parsing/tree.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/tree.py (original) +++ pypy/dist/pypy/rlib/parsing/tree.py Fri Nov 24 20:20:54 2006 @@ -26,6 +26,7 @@ id(self), self.symbol, addinfo)).replace("\\", "\\\\") def visit(self, visitor): + "NOT_RPYTHON" if isinstance(visitor, RPythonVisitor): visitor.dispatch(self) method = getattr(visitor, "visit_" + self.symbol, None) @@ -52,6 +53,7 @@ yield line def visit(self, visitor): + "NOT_RPYTHON" if isinstance(visitor, RPythonVisitor): visitor.dispatch(self) general = getattr(visitor, "visit", None) @@ -75,34 +77,32 @@ def __str__(self): return "could not visit %s" % (self.node, ) -def make_dispatch_function(dispatch_table): - code = ["def dispatch(self, node):"] - code.append(" if isinstance(node, Nonterminal):") - code.append(" if node.symbol not in self.dispatch_table:") - if "__general_nonterminal_visit" in dispatch_table: - code.append( - " return self.dispatch_table['__general_nonterminal_visit'](self, node)") - elif "__general_visit" in dispatch_table: - code.append( - " return self.dispatch_table['__general_visit'](self, node)") - else: - code.append(" raise VisitError(node)") - code.append(" else:") - code.append(" return self.dispatch_table[node.symbol](self, node)") - code.append(" if isinstance(node, Symbol):") - code.append(" if node.symbol not in self.dispatch_table:") - if "__general_symbol_visit" in dispatch_table: - code.append( - " return self.dispatch_table['__general_symbol_visit'](self, node)") - elif "__general_visit" in dispatch_table: - code.append( - " return self.dispatch_table['__general_visit'](self, node)") - else: - code.append(" raise VisitError(node)") - code.append(" else:") - code.append(" return self.dispatch_table[node.symbol](self, node)") - code.append(" raise VisitError(node)") - exec py.code.Source("\n".join(code)).compile() +def make_dispatch_function(__general_nonterminal_visit=None, + __general_symbol_visit=None, + __general_visit=None, + **dispatch_table): + def dispatch(self, node): + if isinstance(node, Nonterminal): + if node.symbol not in dispatch_table: + if __general_nonterminal_visit: + return __general_nonterminal_visit(self, node) + elif __general_visit: + return __general_visit(self, node) + else: + raise VisitError(node) + else: + return dispatch_table[node.symbol](self, node) + if isinstance(node, Symbol): + if node.symbol not in dispatch_table: + if __general_symbol_visit: + return __general_symbol_visit(self, node) + elif __general_visit: + return __general_visit(self, node) + else: + raise VisitError(node) + else: + return dispatch_table[node.symbol](self, node) + raise VisitError(node) return dispatch class CreateDispatchDictionaryMetaclass(type): @@ -116,26 +116,8 @@ "general_visit"]: if special in dct: dispatch_table["__" + special] = dct[special] - dct["dispatch_table"] = dispatch_table - dct["dispatch"] = make_dispatch_function(dispatch_table) + dct["dispatch"] = make_dispatch_function(**dispatch_table) return type.__new__(cls, name_, bases, dct) class RPythonVisitor(object): __metaclass__ = CreateDispatchDictionaryMetaclass - - def dispatch(self, node): - if isinstance(node, Nonterminal): - if node.symbol not in self.dispatch_table: - raise VisitError(node) - else: - return self.dispatch_table[node.symbol](self, node) - elif isinstance(node, Symbol): - if node.symbol not in self.dispatch_table: - if "__general_symbol" in self.dispatch_table: - return self.dispatch_table["__general_symbol"](self, node) - raise VisitError(node) - else: - return self.dispatch_table[node.symbol](self, node) - - else: - raise VisitError(node) From pedronis at codespeak.net Sat Nov 25 00:37:36 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Nov 2006 00:37:36 +0100 (CET) Subject: [pypy-svn] r34947 - pypy/extradoc/talk/dls2006 Message-ID: <20061124233736.6EE7910079@code0.codespeak.net> Author: pedronis Date: Sat Nov 25 00:37:33 2006 New Revision: 34947 Modified: pypy/extradoc/talk/dls2006/talk.txt Log: locations of this talk Modified: pypy/extradoc/talk/dls2006/talk.txt ============================================================================== --- pypy/extradoc/talk/dls2006/talk.txt (original) +++ pypy/extradoc/talk/dls2006/talk.txt Sat Nov 25 00:37:33 2006 @@ -5,8 +5,8 @@ ================================================= :Authors: Armin Rigo, Samuele Pedroni -:Date: 23 October 2006 -:Location: DLS'06 +:Date: 23 October 2006 / 24 Octorber 2006 +:Location: DLS'06 OOPSLA Portland OR / Intel Hillsboro OR PyPy ======================== @@ -356,5 +356,4 @@ and memory management very much needed. .. |bullet| unicode:: U+02022 -.. footer:: DLS'06 - +.. footer:: DLS'06 / Intel From pedronis at codespeak.net Sat Nov 25 01:00:36 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Nov 2006 01:00:36 +0100 (CET) Subject: [pypy-svn] r34948 - pypy/dist/pypy/doc Message-ID: <20061125000036.6481B10079@code0.codespeak.net> Author: pedronis Date: Sat Nov 25 01:00:34 2006 New Revision: 34948 Modified: pypy/dist/pypy/doc/extradoc.txt Log: our OOPSLA and Intel presentations. Modified: pypy/dist/pypy/doc/extradoc.txt ============================================================================== --- pypy/dist/pypy/doc/extradoc.txt (original) +++ pypy/dist/pypy/doc/extradoc.txt Sat Nov 25 01:00:34 2006 @@ -8,6 +8,12 @@ Talks in 2006 +++++++++++++ +* 'PyPy's VM Approach'_ talk, given by Armin Rigo at the Dynamic Languages + Symposium at OOPSLA'06 (Portland OR), and by Samuele Pedroni at Intel + Hillsboro (OR) (October). The talk presents the paper + `PyPy's approach to virtual machine construction`_ accepted for + the symposium. + * `PyPy Status`_ talk, given by Samuele Pedroni at the Vancouner Python Workshop 2006 (August). @@ -88,6 +94,9 @@ .. _`Open Source, EU-Funding and Agile Methods`: http://codespeak.net/pypy/extradoc/talk/22c3/agility.pdf .. _`PyPy Status`: http://codespeak.net/pypy/extradoc/talk/vancouver/talk.html .. _`Sprinting the PyPy way`: http://codespeak.net/svn/pypy/extradoc/talk/ep2005/pypy_sprinttalk_ep2005bd.pdf +.. _`PyPy's VM Approach`: http://codespeak.net/pypy/extradoc/talk/dls2006/talk.html +.. _`PyPy's approach to virtual machine construction`: http://codespeak.net/svn/pypy/extradoc/talk/dls2006/pypy-vm-construction.pdf + Related projects ---------------------------------- From pedronis at codespeak.net Sat Nov 25 01:03:40 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Nov 2006 01:03:40 +0100 (CET) Subject: [pypy-svn] r34949 - pypy/dist/pypy/doc Message-ID: <20061125000340.D4F7010079@code0.codespeak.net> Author: pedronis Date: Sat Nov 25 01:03:38 2006 New Revision: 34949 Modified: pypy/dist/pypy/doc/extradoc.txt Log: oops, wrong quotes Modified: pypy/dist/pypy/doc/extradoc.txt ============================================================================== --- pypy/dist/pypy/doc/extradoc.txt (original) +++ pypy/dist/pypy/doc/extradoc.txt Sat Nov 25 01:03:38 2006 @@ -8,7 +8,7 @@ Talks in 2006 +++++++++++++ -* 'PyPy's VM Approach'_ talk, given by Armin Rigo at the Dynamic Languages +* `PyPy's VM Approach`_ talk, given by Armin Rigo at the Dynamic Languages Symposium at OOPSLA'06 (Portland OR), and by Samuele Pedroni at Intel Hillsboro (OR) (October). The talk presents the paper `PyPy's approach to virtual machine construction`_ accepted for From arigo at codespeak.net Sat Nov 25 03:45:55 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Nov 2006 03:45:55 +0100 (CET) Subject: [pypy-svn] r34950 - pypy/dist/pypy/doc Message-ID: <20061125024555.742211007E@code0.codespeak.net> Author: arigo Date: Sat Nov 25 03:45:41 2006 New Revision: 34950 Modified: pypy/dist/pypy/doc/_ref.txt pypy/dist/pypy/doc/stackless.txt Log: Added the last missing example to doc/stackless.txt. Modified: pypy/dist/pypy/doc/_ref.txt ============================================================================== --- pypy/dist/pypy/doc/_ref.txt (original) +++ pypy/dist/pypy/doc/_ref.txt Sat Nov 25 03:45:41 2006 @@ -48,6 +48,7 @@ .. _`pypy/module/_demo`: ../../pypy/module/_demo .. _`pypy/module/_sre`: ../../pypy/module/_sre .. _`pypy/module/_sre/interp_sre.py`: ../../pypy/module/_sre/interp_sre.py +.. _`pypy/module/_stackless/test/test_clonable.py`: ../../pypy/module/_stackless/test/test_clonable.py .. _`pypy/module/_stackless/test/test_composable_coroutine.py`: ../../pypy/module/_stackless/test/test_composable_coroutine.py .. _`pypy/module/readline`: ../../pypy/module/readline .. _`objspace/`: Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Sat Nov 25 03:45:41 2006 @@ -448,7 +448,56 @@ current pool cause the target objects to be recursively copied; pointers outside the current pool are simply shared. -XXX examples? might be hard... +Two interfaces are available to clone a coroutine: + +* ``coro.clone()`` + + Clones a suspended coroutine, returning the new copy. + +* ``fork()`` + + This global function (from the ``_stackless`` module) clones the + currently running coroutine, returning the new copy - which, in this + case, is a children of the original coroutine (i.e. its parent is + the original coroutine). When the parent or any other coroutine + eventually switches to the child, execution appears to return from + the same ``fork()`` call, this time with a ``None`` return value. + + +Example +~~~~~~~ + +Forking is a natural way to implement backtracking. Consider a +coroutine other than the main one (the main coroutine cannot be cloned +or forked) which issues a call to the following function:: + + def zero_or_one(): + subcoro = fork() + if subcoro is not None: + try: + subcoro.switch() # in the parent: run the child first + except Fail: + pass + return 1 # then proceed with answer 1 + else: + return 0 # in the child: answer 0 + +It clones the current coroutine, and switches to the new child. In the +latter, ``zero_or_one()`` returns 0, so the caller sees the value 0 +first. But at any later point in time (even from a completely unrelated +place, as long as it is still in the same coroutine) the caller may +decide that 0 is not a suitable value, and backtrack and try again with +the value 1. To do so, it simply raises a Fail exception. The +exception stops the child coroutine, which comes back to the parent, +where the Fail is caught and the value 1 is returned from +``zero_or_one()``. + +The tests in `pypy/module/_stackless/test/test_clonable.py`_ contain an +example using exactly the above function to search for a sequence of +zeroes and ones that has a specific property, by trial-and-error. This +allow a style that looks similar to what is traditionally reserved to +logic programming languages. + Composability +++++++++++++ From arigo at codespeak.net Sat Nov 25 13:49:54 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Nov 2006 13:49:54 +0100 (CET) Subject: [pypy-svn] r34956 - pypy/dist/pypy/translator/goal Message-ID: <20061125124954.0386210077@code0.codespeak.net> Author: arigo Date: Sat Nov 25 13:49:53 2006 New Revision: 34956 Modified: pypy/dist/pypy/translator/goal/translate.py Log: Import the translation target properly, instead of execfile()ing it. Eases debugging. Modified: pypy/dist/pypy/translator/goal/translate.py ============================================================================== --- pypy/dist/pypy/translator/goal/translate.py (original) +++ pypy/dist/pypy/translator/goal/translate.py Sat Nov 25 13:49:53 2006 @@ -4,7 +4,7 @@ See below """ -import sys, os +import sys, os, new import autopath @@ -93,12 +93,10 @@ targetspec += '.py' thismod = sys.modules[__name__] sys.modules['translate'] = thismod - targetspec_dic = { - '__name__': os.path.splitext(os.path.basename(targetspec))[0], - '__file__': targetspec} + specname = os.path.splitext(os.path.basename(targetspec))[0] sys.path.insert(0, os.path.dirname(targetspec)) - execfile(targetspec, targetspec_dic) - return targetspec_dic + mod = __import__(specname) + return mod.__dict__ def parse_options_and_load_target(): opt_parser = optparse.OptionParser(usage="%prog [options] [target] [target-specific-options]", From arigo at codespeak.net Sat Nov 25 13:57:13 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Nov 2006 13:57:13 +0100 (CET) Subject: [pypy-svn] r34957 - in pypy/dist/pypy: interpreter interpreter/test module/__builtin__ Message-ID: <20061125125713.ED5371007E@code0.codespeak.net> Author: arigo Date: Sat Nov 25 13:57:11 2006 New Revision: 34957 Modified: pypy/dist/pypy/interpreter/mixedmodule.py pypy/dist/pypy/interpreter/test/test_py.py pypy/dist/pypy/module/__builtin__/__init__.py Log: Don't put a __file__ attribute in the __builtin__ module. This causes all modules that don't otherwise have a __file__ (like __main__) to believe their file is pypy/module/__builtin__/*.py. Modified: pypy/dist/pypy/interpreter/mixedmodule.py ============================================================================== --- pypy/dist/pypy/interpreter/mixedmodule.py (original) +++ pypy/dist/pypy/interpreter/mixedmodule.py Sat Nov 25 13:57:11 2006 @@ -12,6 +12,7 @@ NOT_RPYTHON_ATTRIBUTES = ['loaders'] applevel_name = None + expose__file__attribute = True def __init__(self, space, w_name): """ NOT_RPYTHON """ @@ -84,7 +85,8 @@ for name, spec in cls.appleveldefs.items(): loaders[name] = getappfileloader(pkgroot, spec) assert '__file__' not in loaders - loaders['__file__'] = cls.get__file__ + if cls.expose__file__attribute: + loaders['__file__'] = cls.get__file__ if '__doc__' not in loaders: loaders['__doc__'] = cls.get__doc__ Modified: pypy/dist/pypy/interpreter/test/test_py.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_py.py (original) +++ pypy/dist/pypy/interpreter/test/test_py.py Sat Nov 25 13:57:11 2006 @@ -91,3 +91,16 @@ pass assert e," expected failure" assert e.err.splitlines()[-1] == 'KeyError: ' + + +def test_no__file__in_main(): + tmpfilepath = udir.join("test_py_script.py") + tmpfilepath.write(str(py.code.Source(""" + try: + print __file__ + except NameError: + print 'no __file__.' + """))) + output = py.process.cmdexec( '''"%s" "%s" "%s" ''' % + (sys.executable, pypypath, tmpfilepath) ) + assert 'no __file__.\n' in output Modified: pypy/dist/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/__init__.py (original) +++ pypy/dist/pypy/module/__builtin__/__init__.py Sat Nov 25 13:57:11 2006 @@ -4,6 +4,7 @@ class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" + expose__file__attribute = False appleveldefs = { 'quit' : 'app_help.exit', From arigo at codespeak.net Sat Nov 25 17:38:25 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Nov 2006 17:38:25 +0100 (CET) Subject: [pypy-svn] r34966 - pypy/dist/pypy/rpython Message-ID: <20061125163825.B4F5A1008F@code0.codespeak.net> Author: arigo Date: Sat Nov 25 17:38:23 2006 New Revision: 34966 Modified: pypy/dist/pypy/rpython/rmodel.py Log: Fix missing_rtype_operation()'s error message. The 'hop.spaceop.opname' may differ from the name under which the missing_rtype_operation was looked up; see e.g. the error message that was given by float("3.14") . Modified: pypy/dist/pypy/rpython/rmodel.py ============================================================================== --- pypy/dist/pypy/rpython/rmodel.py (original) +++ pypy/dist/pypy/rpython/rmodel.py Sat Nov 25 17:38:23 2006 @@ -299,24 +299,22 @@ # ____________________________________________________________ -def missing_rtype_operation(self, hop): - raise MissingRTypeOperation("unimplemented operation: '%s' on %r" % ( - hop.spaceop.opname, self)) - -def setattr_default(obj, attr, value): - if not hasattr(obj, attr): - setattr(obj, attr, value) +def make_missing_op(rcls, opname): + attr = 'rtype_' + opname + if not hasattr(rcls, attr): + def missing_rtype_operation(self, hop): + raise MissingRTypeOperation("unimplemented operation: " + "'%s' on %r" % (opname, self)) + setattr(rcls, attr, missing_rtype_operation) for opname in annmodel.UNARY_OPERATIONS: - setattr_default(Repr, 'rtype_' + opname, missing_rtype_operation) + make_missing_op(Repr, opname) for opname in annmodel.BINARY_OPERATIONS: - setattr_default(pairtype(Repr, Repr), - 'rtype_' + opname, missing_rtype_operation) + make_missing_op(pairtype(Repr, Repr), opname) # not in BINARY_OPERATIONS -setattr_default(pairtype(Repr, Repr), - 'rtype_contains', missing_rtype_operation) +make_missing_op(pairtype(Repr, Repr), 'contains') class __extend__(pairtype(Repr, Repr)): def convert_from_to((r_from, r_to), v, llops): From arigo at codespeak.net Sat Nov 25 17:56:32 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 25 Nov 2006 17:56:32 +0100 (CET) Subject: [pypy-svn] r34967 - pypy/dist/pypy/rpython Message-ID: <20061125165632.892C010094@code0.codespeak.net> Author: arigo Date: Sat Nov 25 17:56:30 2006 New Revision: 34967 Modified: pypy/dist/pypy/rpython/rint.py Log: Another small error reporting improvement. Modified: pypy/dist/pypy/rpython/rint.py ============================================================================== --- pypy/dist/pypy/rpython/rint.py (original) +++ pypy/dist/pypy/rpython/rint.py Sat Nov 25 17:56:30 2006 @@ -8,7 +8,7 @@ from pypy.rpython.rmodel import IntegerRepr, inputconst from pypy.rpython.robject import PyObjRepr, pyobj_repr from pypy.rlib.rarithmetic import intmask, r_int, r_uint, r_ulonglong, r_longlong -from pypy.rpython.error import TyperError +from pypy.rpython.error import TyperError, MissingRTypeOperation from pypy.rpython.rmodel import log from pypy.rlib import objectmodel @@ -117,6 +117,15 @@ return _rtype_template(hop, 'rshift', [ValueError]) rtype_inplace_rshift = rtype_rshift + def rtype_pow(_, hop): + raise MissingRTypeOperation("pow(int, int)" + " (use float**float instead; it is too" + " easy to overlook the overflow" + " issues of int**int)") + + rtype_pow_ovf = rtype_pow + rtype_inplace_pow = rtype_pow + ## def rtype_pow(_, hop, suffix=''): ## if hop.has_implicit_exception(ZeroDivisionError): ## suffix += '_zer' From pedronis at codespeak.net Sat Nov 25 18:25:18 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Nov 2006 18:25:18 +0100 (CET) Subject: [pypy-svn] r34968 - pypy/dist/pypy/jit/tl Message-ID: <20061125172518.50AD410092@code0.codespeak.net> Author: pedronis Date: Sat Nov 25 18:25:17 2006 New Revision: 34968 Modified: pypy/dist/pypy/jit/tl/tlc.py Log: more promotes in the tlc. Modified: pypy/dist/pypy/jit/tl/tlc.py ============================================================================== --- pypy/dist/pypy/jit/tl/tlc.py (original) +++ pypy/dist/pypy/jit/tl/tlc.py Sat Nov 25 18:25:17 2006 @@ -180,6 +180,8 @@ elif opcode == ADD: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(b.add(a)) elif opcode == SUB: @@ -196,18 +198,26 @@ elif opcode == DIV: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(b.div(a)) elif opcode == EQ: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(IntObj(b.eq(a))) elif opcode == NE: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(IntObj(not b.eq(a))) elif opcode == LT: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(IntObj(b.lt(a))) elif opcode == LE: @@ -218,10 +228,14 @@ elif opcode == GT: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(IntObj(a.lt(b))) elif opcode == GE: a, b = stack.pop(), stack.pop() + hint(a.__class__, promote=True) + hint(b.__class__, promote=True) stack.append(IntObj(not b.lt(a))) elif opcode == BR_COND: From pedronis at codespeak.net Sat Nov 25 18:27:56 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Nov 2006 18:27:56 +0100 (CET) Subject: [pypy-svn] r34969 - in pypy/dist/pypy/jit/timeshifter: . test Message-ID: <20061125172756.F29DF10092@code0.codespeak.net> Author: pedronis Date: Sat Nov 25 18:27:54 2006 New Revision: 34969 Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/jit/timeshifter/rcontainer.py pypy/dist/pypy/jit/timeshifter/rtimeshift.py pypy/dist/pypy/jit/timeshifter/rvalue.py pypy/dist/pypy/jit/timeshifter/test/test_portal.py pypy/dist/pypy/jit/timeshifter/test/test_promotion.py Log: (arre, arigo around, pedronis) now that we can return multiple states from a function, try to avoid forcing virtual structs at merge points. Still force merges when returning from the portal. Now test_virt_obj_method_call_promote passes, als test_factorial for the tlc only promotes once and produces a box at the end for the result, which is good. Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Sat Nov 25 18:27:54 2006 @@ -155,14 +155,20 @@ entrygraph = self.annotator.translator.graphs[0] if origportalgraph: portalgraph = bk.get_graph_by_key(origportalgraph, None) + leaveportalgraph = portalgraph else: portalgraph = None + # in the case of tests not specifying a portal + # we still need to force merges when entry + # returns + leaveportalgraph = entrygraph + pending = [entrygraph] seen = {entrygraph: True} while pending: graph = pending.pop() for nextgraph in self.transform_graph(graph, - is_portal=graph is portalgraph): + is_portal=graph is leaveportalgraph): if nextgraph not in seen: pending.append(nextgraph) seen[nextgraph] = True Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rcontainer.py (original) +++ pypy/dist/pypy/jit/timeshifter/rcontainer.py Sat Nov 25 18:27:54 2006 @@ -1,3 +1,4 @@ + import operator from pypy.rpython.lltypesystem import lltype from pypy.rpython.annlowlevel import cachedtype @@ -192,6 +193,8 @@ outgoingvarboxes.append(vstruct.ownbox) return False if self.typedesc is not vstruct.typedesc: + if not memo.force_merge: + raise rvalue.DontMerge outgoingvarboxes.append(vstruct.ownbox) return False contmemo[self] = vstruct Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rtimeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py Sat Nov 25 18:27:54 2006 @@ -237,9 +237,6 @@ #debug_print(lltype.Void, "PROMOTION ROOT") start_new_block._annspecialcase_ = "specialize:arglltype(2)" -class DontMerge(Exception): - pass - def retrieve_jitstate_for_merge(states_dic, jitstate, key, global_resumer, force_merge=False): if key not in states_dic: @@ -255,7 +252,7 @@ try: match = frozen.exactmatch(jitstate, outgoingvarboxes, memo) - except DontMerge: + except rvalue.DontMerge: continue if match: linkargs = [] Modified: pypy/dist/pypy/jit/timeshifter/rvalue.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/rvalue.py (original) +++ pypy/dist/pypy/jit/timeshifter/rvalue.py Sat Nov 25 18:27:54 2006 @@ -25,6 +25,8 @@ def unfreeze_memo(): return Memo() +class DontMerge(Exception): + pass class RedBox(object): __slots__ = ['kind', 'genvar'] @@ -397,7 +399,12 @@ def exactmatch(self, box, outgoingvarboxes, memo): assert isinstance(box, PtrRedBox) memo.partialdatamatch[box] = None # could do better - return FrozenConst.exactmatch(self, box, outgoingvarboxes, memo) + match = FrozenConst.exactmatch(self, box, outgoingvarboxes, memo) + if not memo.force_merge and not match: + from pypy.jit.timeshifter.rcontainer import VirtualContainer + if isinstance(box.content, VirtualContainer): + raise DontMerge + return match def unfreeze(self, incomingvarboxes, memo): return PtrRedBox(self.kind, self.gv_const) @@ -408,7 +415,12 @@ def exactmatch(self, box, outgoingvarboxes, memo): assert isinstance(box, PtrRedBox) memo.partialdatamatch[box] = None - return FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) + match = FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) + if not memo.force_merge and not match: + from pypy.jit.timeshifter.rcontainer import VirtualContainer + if isinstance(box.content, VirtualContainer): + raise DontMerge + return match def unfreeze(self, incomingvarboxes, memo): memo = memo.boxes @@ -431,7 +443,12 @@ memo.partialdatamatch) # skip the parent's exactmatch()! exact = FrozenVar.exactmatch(self, box, outgoingvarboxes, memo) - return exact and partialdatamatch + match = exact and partialdatamatch + if not memo.force_merge and not match: + from pypy.jit.timeshifter.rcontainer import VirtualContainer + if isinstance(box.content, VirtualContainer): + raise DontMerge + return match class FrozenPtrVirtual(FrozenValue): @@ -440,12 +457,13 @@ assert isinstance(box, PtrRedBox) if box.genvar: outgoingvarboxes.append(box) - return False + match = False else: assert box.content is not None - return self.fz_content.exactmatch(box.content, outgoingvarboxes, + match = self.fz_content.exactmatch(box.content, outgoingvarboxes, memo) - + return match + def unfreeze(self, incomingvarboxes, memo): return self.fz_content.unfreeze(incomingvarboxes, memo) Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Sat Nov 25 18:27:54 2006 @@ -197,6 +197,43 @@ policy=P_OOPSPEC) assert not res + def test_method_call_nonpromote(self): + class Base(object): + pass + class Int(Base): + def __init__(self, n): + self.n = n + def double(self): + return Int(self.n * 2) + def get(self): + return self.n + class Str(Base): + def __init__(self, s): + self.s = s + def double(self): + return Str(self.s + self.s) + def get(self): + return ord(self.s[4]) + + def ll_main(n): + if n > 0: + o = Int(n) + else: + o = Str('123') + return ll_function(o) + + def ll_function(o): + hint(None, global_merge_point=True) + return o.double().get() + + res = self.timeshift_from_portal(ll_main, ll_function, [5], policy=P_NOVIRTUAL) + assert res == 10 + self.check_insns(indirect_call=2) + + res = self.timeshift_from_portal(ll_main, ll_function, [0], policy=P_NOVIRTUAL) + assert res == ord('2') + self.check_insns(indirect_call=2) + def test_method_call_promote(self): class Base(object): pass @@ -236,7 +273,6 @@ self.check_insns(indirect_call=0) def test_virt_obj_method_call_promote(self): - py.test.skip('WIP') class Base(object): pass class Int(Base): Modified: pypy/dist/pypy/jit/timeshifter/test/test_promotion.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_promotion.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_promotion.py Sat Nov 25 18:27:54 2006 @@ -185,44 +185,6 @@ res = self.timeshift(ll_function, [100, 2], [], policy=P_NOVIRTUAL) assert res == ll_function(100, 2) - - def test_method_call_nonpromote(self): - class Base(object): - pass - class Int(Base): - def __init__(self, n): - self.n = n - def double(self): - return Int(self.n * 2) - def get(self): - return self.n - class Str(Base): - def __init__(self, s): - self.s = s - def double(self): - return Str(self.s + self.s) - def get(self): - return int(self.s) - - def ll_make(n): - if n > 0: - return Int(n) - else: - return Str('123') - - def ll_function(n): - o = ll_make(n) - return o.double().get() - - res = self.timeshift(ll_function, [5], [], policy=P_NOVIRTUAL) - assert res == 10 - self.check_insns(indirect_call=2) - - res = self.timeshift(ll_function, [0], [], policy=P_NOVIRTUAL) - assert res == 123123 - self.check_insns(indirect_call=2) - - def test_mixed_merges(self): def ll_function(x, y, z, k): if x: From pedronis at codespeak.net Sat Nov 25 19:12:40 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 25 Nov 2006 19:12:40 +0100 (CET) Subject: [pypy-svn] r34970 - pypy/dist/pypy/translator/stackless/test Message-ID: <20061125181240.58BFE10086@code0.codespeak.net> Author: pedronis Date: Sat Nov 25 19:12:38 2006 New Revision: 34970 Modified: pypy/dist/pypy/translator/stackless/test/test_coroutine_reconstruction.py Log: match the changed resume_points Modified: pypy/dist/pypy/translator/stackless/test/test_coroutine_reconstruction.py ============================================================================== --- pypy/dist/pypy/translator/stackless/test/test_coroutine_reconstruction.py (original) +++ pypy/dist/pypy/translator/stackless/test/test_coroutine_reconstruction.py Sat Nov 25 19:12:38 2006 @@ -43,14 +43,14 @@ costate = interp_coroutine.Coroutine._get_default_costate() bottom = resume_state_create(None, "yield_current_frame_to_caller_1") - _bind_frame = resume_state_create(bottom, "coroutine__bind", new_coro, costate) + _bind_frame = resume_state_create(bottom, "coroutine__bind", costate) f_frame_1 = resume_state_create(_bind_frame, "f_1", main_coro, 5, 1) f_frame_2 = resume_state_create(f_frame_1, "f_1", main_coro, 4, 2) f_frame_3 = resume_state_create(f_frame_2, "f_1", main_coro, 3, 4) f_frame_4 = resume_state_create(f_frame_3, "f_1", main_coro, 2, 8) f_frame_5 = resume_state_create(f_frame_4, "f_1", main_coro, 1, 16) f_frame_0 = resume_state_create(f_frame_5, "f_0") - switch_frame = resume_state_create(f_frame_0, "coroutine_switch", new_coro, costate) + switch_frame = resume_state_create(f_frame_0, "coroutine_switch", costate) new_coro.frame = switch_frame From cfbolz at codespeak.net Sat Nov 25 22:21:47 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 25 Nov 2006 22:21:47 +0100 (CET) Subject: [pypy-svn] r34973 - pypy/dist/pypy/interpreter Message-ID: <20061125212147.59BA01007E@code0.codespeak.net> Author: cfbolz Date: Sat Nov 25 22:21:45 2006 New Revision: 34973 Modified: pypy/dist/pypy/interpreter/generator.py pypy/dist/pypy/interpreter/pycode.py Log: use _mixin_ instead of manually creating the effect. Modified: pypy/dist/pypy/interpreter/generator.py ============================================================================== --- pypy/dist/pypy/interpreter/generator.py (original) +++ pypy/dist/pypy/interpreter/generator.py Sat Nov 25 22:21:45 2006 @@ -12,8 +12,9 @@ # that return iterators). # -class GeneratorFrame(EvalFrame): +class GeneratorFrameMixin(object): "A frame attached to a generator." + _mixin_ = True def run(self): "Build a generator-iterator." Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Sat Nov 25 22:21:45 2006 @@ -58,26 +58,20 @@ "NOT_RPYTHON" from pypy.interpreter.pyopcode import PyInterpFrame from pypy.interpreter.nestedscope import PyNestedScopeFrame - from pypy.interpreter.generator import GeneratorFrame + from pypy.interpreter.generator import GeneratorFrameMixin - def fresh_GeneratorFrame_methods(): - from pypy.tool.sourcetools import func_with_new_name - dic = GeneratorFrame.__dict__.copy() - for n in dic: - x = dic[n] - if isinstance(x, types.FunctionType): - dic[n] = func_with_new_name(x, x.__name__) - return dic + class PyGeneratorFrame(GeneratorFrameMixin, PyInterpFrame): + pass + + class PyNestedScopeGeneratorFrame(GeneratorFrameMixin, PyNestedScopeFrame): + pass frame_classes.extend([None]*4) frame_classes[0] = PyInterpFrame frame_classes[NESTED] = PyNestedScopeFrame - frame_classes[GENERATOR] = type('PyGeneratorFrame', - (PyInterpFrame,), - fresh_GeneratorFrame_methods()) - frame_classes[NESTED|GENERATOR] = type('PyNestedScopeGeneratorFrame', - (PyNestedScopeFrame,), - fresh_GeneratorFrame_methods()) + frame_classes[GENERATOR] = PyGeneratorFrame + frame_classes[NESTED|GENERATOR] = PyNestedScopeGeneratorFrame + class PyCode(eval.Code): "CPython-style code objects." From cfbolz at codespeak.net Sat Nov 25 22:30:12 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 25 Nov 2006 22:30:12 +0100 (CET) Subject: [pypy-svn] r34974 - pypy/branch/builtin-call-speedup Message-ID: <20061125213012.5F6571007E@code0.codespeak.net> Author: cfbolz Date: Sat Nov 25 22:30:10 2006 New Revision: 34974 Added: pypy/branch/builtin-call-speedup/ - copied from r34973, pypy/dist/ Log: a branch to experiment with the speedup to calls of unshadowed builtins From cfbolz at codespeak.net Sat Nov 25 23:39:04 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Sat, 25 Nov 2006 23:39:04 +0100 (CET) Subject: [pypy-svn] r34975 - in pypy/branch/builtin-call-speedup: lib-python/modified-2.4.1 pypy/config pypy/interpreter pypy/interpreter/astcompiler pypy/module/__builtin__ pypy/module/__builtin__/test pypy/objspace/std Message-ID: <20061125223904.342BF1007E@code0.codespeak.net> Author: cfbolz Date: Sat Nov 25 23:38:59 2006 New Revision: 34975 Added: pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py Modified: pypy/branch/builtin-call-speedup/lib-python/modified-2.4.1/opcode.py pypy/branch/builtin-call-speedup/pypy/config/pypyoption.py pypy/branch/builtin-call-speedup/pypy/interpreter/astcompiler/pycodegen.py pypy/branch/builtin-call-speedup/pypy/interpreter/module.py pypy/branch/builtin-call-speedup/pypy/interpreter/pycode.py pypy/branch/builtin-call-speedup/pypy/module/__builtin__/__init__.py pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py pypy/branch/builtin-call-speedup/pypy/objspace/std/objspace.py Log: first round of trying to make builtin lookups faster (nearly as fast as a local lookup) while still behaving correctly when builtins are shadowed. Modified: pypy/branch/builtin-call-speedup/lib-python/modified-2.4.1/opcode.py ============================================================================== --- pypy/branch/builtin-call-speedup/lib-python/modified-2.4.1/opcode.py (original) +++ pypy/branch/builtin-call-speedup/lib-python/modified-2.4.1/opcode.py Sat Nov 25 23:38:59 2006 @@ -187,4 +187,7 @@ def_op('EXTENDED_ARG', 143) EXTENDED_ARG = 143 +# pypy modification, experimental bytecode +def_op('CALL_LIKELY_BUILTIN', 144) # #args + (#kwargs << 8) + del def_op, name_op, jrel_op, jabs_op Modified: pypy/branch/builtin-call-speedup/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/config/pypyoption.py (original) +++ pypy/branch/builtin-call-speedup/pypy/config/pypyoption.py Sat Nov 25 23:38:59 2006 @@ -59,6 +59,9 @@ "keep track of bytecode usage", default=False), + BoolOption("withfastbuiltins", "speed up calls to builtin functions", + default=False, requires=[("objspace.usepycfiles", False)]), + BoolOption("usepycfiles", "Write and read pyc files when importing", default=True), Modified: pypy/branch/builtin-call-speedup/pypy/interpreter/astcompiler/pycodegen.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/interpreter/astcompiler/pycodegen.py (original) +++ pypy/branch/builtin-call-speedup/pypy/interpreter/astcompiler/pycodegen.py Sat Nov 25 23:38:59 2006 @@ -30,6 +30,8 @@ TRY_FINALLY = 3 END_FINALLY = 4 +from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX + def compileFile(filename, display=0): f = open(filename, 'U') buf = f.read() @@ -1005,6 +1007,8 @@ self.emit('EXEC_STMT') def visitCallFunc(self, node): + if self.emit_builtin_call(node): + return pos = 0 kw = 0 self.set_lineno(node) @@ -1024,6 +1028,35 @@ opcode = callfunc_opcode_info[ have_star*2 + have_dstar] self.emitop_int(opcode, kw << 8 | pos) + def emit_builtin_call(self, node): + if not self.space.config.objspace.withfastbuiltins: + return False + if node.star_args is not None or node.dstar_args is not None: + return False + pos = 0 + # check for kw args + for arg in node.args: + if isinstance(arg, ast.Keyword): + return False + else: + pos = pos + 1 + func = node.node + if not isinstance(func, ast.Name): + return False + + name = func.varname + scope = self.scope.check_name(name) + # YYY + index = BUILTIN_TO_INDEX.get(name, -1) + if ((scope == SC_GLOBAL or + (scope == SC_DEFAULT and self.optimized and self.localsfullyknown)) + and index != -1): + for arg in node.args: + arg.accept(self) + self.emitop_int("CALL_LIKELY_BUILTIN", index << 8 | pos) + return True + return False + def visitPrint(self, node): self.set_lineno(node) if node.dest: Modified: pypy/branch/builtin-call-speedup/pypy/interpreter/module.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/interpreter/module.py (original) +++ pypy/branch/builtin-call-speedup/pypy/interpreter/module.py Sat Nov 25 23:38:59 2006 @@ -10,7 +10,7 @@ def __init__(self, space, w_name, w_dict=None): self.space = space if w_dict is None: - w_dict = space.newdict() + w_dict = space.newdict(track_builtin_shadowing=True) self.w_dict = w_dict self.w_name = w_name if w_name is not None: Modified: pypy/branch/builtin-call-speedup/pypy/interpreter/pycode.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/interpreter/pycode.py (original) +++ pypy/branch/builtin-call-speedup/pypy/interpreter/pycode.py Sat Nov 25 23:38:59 2006 @@ -51,6 +51,7 @@ NESTED = 1 GENERATOR = 2 +CALLSPECIAL = 4 frame_classes = [] @@ -59,6 +60,8 @@ from pypy.interpreter.pyopcode import PyInterpFrame from pypy.interpreter.nestedscope import PyNestedScopeFrame from pypy.interpreter.generator import GeneratorFrameMixin + from pypy.interpreter.generator import GeneratorFrameMixin + from pypy.interpreter.specialcode import CallLikelyBuiltinMixin class PyGeneratorFrame(GeneratorFrameMixin, PyInterpFrame): pass @@ -66,11 +69,30 @@ class PyNestedScopeGeneratorFrame(GeneratorFrameMixin, PyNestedScopeFrame): pass - frame_classes.extend([None]*4) + class PyCallSpecialInterpFrame(PyInterpFrame, CallLikelyBuiltinMixin): + pass + + class PyCallSpecialNestedScopeFrame( + PyNestedScopeFrame, CallLikelyBuiltinMixin): + pass + + class PyCallSpecialGeneratorFrame( + PyGeneratorFrame, CallLikelyBuiltinMixin): + pass + + class PyCallSpecialNestedScopeGeneratorFrame( + PyNestedScopeGeneratorFrame, CallLikelyBuiltinMixin): + pass + + frame_classes.extend([None] * 8) frame_classes[0] = PyInterpFrame frame_classes[NESTED] = PyNestedScopeFrame frame_classes[GENERATOR] = PyGeneratorFrame frame_classes[NESTED|GENERATOR] = PyNestedScopeGeneratorFrame + frame_classes[CALLSPECIAL] = PyCallSpecialInterpFrame + frame_classes[NESTED|CALLSPECIAL] = PyCallSpecialNestedScopeFrame + frame_classes[GENERATOR|CALLSPECIAL] = PyCallSpecialGeneratorFrame + frame_classes[NESTED|GENERATOR|CALLSPECIAL] = PyCallSpecialNestedScopeGeneratorFrame class PyCode(eval.Code): @@ -257,6 +279,8 @@ choose |= NESTED if self.co_flags & CO_GENERATOR: choose |= GENERATOR + if self.space.config.objspace.withfastbuiltins: + choose |= CALLSPECIAL Frame = frame_classes[choose] return Frame Modified: pypy/branch/builtin-call-speedup/pypy/module/__builtin__/__init__.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/module/__builtin__/__init__.py (original) +++ pypy/branch/builtin-call-speedup/pypy/module/__builtin__/__init__.py Sat Nov 25 23:38:59 2006 @@ -1,6 +1,22 @@ from pypy.interpreter.error import OperationError from pypy.interpreter import module -from pypy.interpreter.mixedmodule import MixedModule +from pypy.interpreter.mixedmodule import MixedModule + +# put builtins here that should be optimized somehow + +OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate", + "isinstance", "type", "zip", "file", "open", "abs", "chr", "unichr", + "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", "getattr", + "setattr", "delattr", "callable", "int", "str", "float"] + +assert len(OPTIMIZED_BUILTINS) <= 256 + +BUILTIN_TO_INDEX = {} + +for i, name in enumerate(OPTIMIZED_BUILTINS): + BUILTIN_TO_INDEX[name] = i + +assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX) class Module(MixedModule): """Built-in functions, exceptions, and other objects.""" @@ -141,6 +157,9 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" space = self.space + self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS) + for i, name in enumerate(OPTIMIZED_BUILTINS): + self.builtins_by_index[i] = space.getattr(self, space.wrap(name)) # call installations for pickle support for name in self.loaders.keys(): if name.startswith('_install_pickle_support_for_'): Modified: pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py (original) +++ pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py Sat Nov 25 23:38:59 2006 @@ -433,6 +433,38 @@ raises(TypeError, hasattr, x, None) raises(TypeError, hasattr, x, 42) +class AppTestBuiltinOptimized(object): + def setup_class(cls): + from pypy.conftest import gettestobjspace + cls.space = gettestobjspace(**{"objspace.withfastbuiltins": True}) + assert cls.space.config.objspace.withfastbuiltins + + # hum, we need to invoke the compiler explicitely + def test_xrange_len(self): + s = """def test(): + x = xrange(33) + assert len(x) == 33 + x = xrange(33.2) + assert len(x) == 33 + x = xrange(33,0,-1) + assert len(x) == 33 + x = xrange(33,0) + assert len(x) == 0 + x = xrange(33,0.2) + assert len(x) == 0 + x = xrange(0,33) + assert len(x) == 33 + x = xrange(0,33,-1) + assert len(x) == 0 + x = xrange(0,33,2) + assert len(x) == 17 + x = xrange(0,32,2) + assert len(x) == 16 + """ + ns = {} + exec s in ns + ns["test"]() + class TestInternal: def setup_method(self,method): Modified: pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py (original) +++ pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py Sat Nov 25 23:38:59 2006 @@ -65,6 +65,7 @@ from pypy.objspace.std import dictobject from pypy.objspace.std import dictstrobject from pypy.objspace.std import dictmultiobject + from pypy.objspace.std import warydictobject from pypy.objspace.std import stringobject from pypy.objspace.std import strsliceobject from pypy.objspace.std import strjoinobject @@ -109,8 +110,13 @@ self.typeorder[setobject.W_FrozensetObject] = [] self.typeorder[setobject.W_SetIterObject] = [] + # XXX add to option_to_typename somehow + if config.objspace.withfastbuiltins: + self.typeorder[warydictobject.W_WaryDictObject] = [] + imported_but_not_registered = { dictobject.W_DictObject: True, + warydictobject.W_WaryDictObject: True, dictobject.W_DictIterObject: True, } for option, value in config.objspace.std: Modified: pypy/branch/builtin-call-speedup/pypy/objspace/std/objspace.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/objspace/std/objspace.py (original) +++ pypy/branch/builtin-call-speedup/pypy/objspace/std/objspace.py Sat Nov 25 23:38:59 2006 @@ -363,7 +363,10 @@ def newlist(self, list_w): return W_ListObject(list_w) - def newdict(self): + def newdict(self, track_builtin_shadowing=False): + if self.config.objspace.withfastbuiltins and track_builtin_shadowing: + from pypy.objspace.std.warydictobject import W_WaryDictObject + return W_WaryDictObject(self) return self.DictObjectCls(self) def newslice(self, w_start, w_end, w_step): Added: pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py ============================================================================== --- (empty file) +++ pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py Sat Nov 25 23:38:59 2006 @@ -0,0 +1,43 @@ + +from pypy.objspace.std.objspace import * +from pypy.interpreter import gateway +from pypy.objspace.std.dictobject import W_DictObject +from pypy.objspace.std.stringobject import W_StringObject + +from pypy.rlib.objectmodel import r_dict + +class W_WaryDictObject(W_DictObject): + def __init__(w_self, space, wary_of=None, w_otherdict=None): + from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX + W_DictObject.__init__(w_self, space, w_otherdict) + if wary_of is None: + wary_of = BUILTIN_TO_INDEX + if w_otherdict is None: + w_self.shadowed = [False] * len(wary_of) + else: + w_self.shadowed = [True] * len(wary_of) + w_self.wary_of = wary_of + +registerimplementation(W_WaryDictObject) + +def setitem__WaryDict_ANY_ANY(space, w_dict, w_key, w_newvalue): + if space.is_true(space.isinstance(w_key, space.w_str)): + s = space.str_w(w_key) + i = w_dict.wary_of.get(s, -1) + if i != -1: + w_dict.shadowed[i] = True + w_dict.content[w_key] = w_newvalue + +def delitem__WaryDict_ANY(space, w_dict, w_lookup): + try: + if space.is_true(space.isinstance(w_lookup, space.w_str)): + s = space.str_w(w_lookup) + i = w_dict.wary_of.get(s, -1) + if i != -1: + w_dict.shadowed[i] = False + del w_dict.content[w_lookup] + except KeyError: + raise OperationError(space.w_KeyError, w_lookup) + +from pypy.objspace.std import dicttype +register_all(vars(), dicttype) From fijal at codespeak.net Sun Nov 26 14:02:39 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 26 Nov 2006 14:02:39 +0100 (CET) Subject: [pypy-svn] r35002 - pypy/extradoc/talk/warsaw2006 Message-ID: <20061126130239.C26FB1007E@code0.codespeak.net> Author: fijal Date: Sun Nov 26 14:02:20 2006 New Revision: 35002 Added: pypy/extradoc/talk/warsaw2006/ pypy/extradoc/talk/warsaw2006/fireworks-slides.txt (contents, props changed) pypy/extradoc/talk/warsaw2006/notes Log: Added some slides. Added: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt ============================================================================== --- (empty file) +++ pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Sun Nov 26 14:02:20 2006 @@ -0,0 +1,40 @@ +============== +PyPy fireworks +============== + +:Authors: Maciej Fijalkowski +:Location: Warsaw Univeristy +:Date: 1.XII.2006 + +What is PyPy? +============= + +* An implementation of Python written in Python + +* A very flexible compiler toolchain + +* An open source project (MIT License) + +* A STREP ("Specific Targeted REsearch Project"), partially funded by the EU + +* A lot of fun! + +Deterministic concurrency: +========================== + +* So called "stackless" features + +* Basically provides way of copying stack to heap and backwards + +* (demo) (in-browser) + +* pickling coroutines + +* cloning coroutines + +Composability problem: +====================== + +* (demo) + +* possible solution Added: pypy/extradoc/talk/warsaw2006/notes ============================================================================== --- (empty file) +++ pypy/extradoc/talk/warsaw2006/notes Sun Nov 26 14:02:20 2006 @@ -0,0 +1,28 @@ +I want to present some rough ideas where PyPy's flexible architecture +makes good usecase examples and some overview of that architecture. + +Details: + +1. Stackless features, composable deterministic concurrency, picklable + coroutines, an overview how this is implemented + +2. Transparent proxy, remote objects. Need to make examples work under + pypy-c (especially py.execnet) + +3. Digging deeper - compiler toolchain overview, what is RPython, why + C considered harmfull. + +4. Multiple backend choice, (in)flexibility of RPython, duality, CLI, + JVM etc. + +!!! 5. Extension compiler + +6. JavaScript backend, unittest under python run on browser (not-completed). + +7. (in)famous offline partial evaluation, JIT, some demos. + +8. Prolog interp as an example of using compiler toolchain? + +Method: + +Some RPython written - presentation viewer??? From arigo at codespeak.net Sun Nov 26 22:58:32 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 26 Nov 2006 22:58:32 +0100 (CET) Subject: [pypy-svn] r35008 - pypy/dist/pypy/doc Message-ID: <20061126215832.7F1621007B@code0.codespeak.net> Author: arigo Date: Sun Nov 26 22:58:30 2006 New Revision: 35008 Modified: pypy/dist/pypy/doc/stackless.txt Log: Typoi. Modified: pypy/dist/pypy/doc/stackless.txt ============================================================================== --- pypy/dist/pypy/doc/stackless.txt (original) +++ pypy/dist/pypy/doc/stackless.txt Sun Nov 26 22:58:30 2006 @@ -268,8 +268,9 @@ are not normally picklable in CPython. Here again, the `Stackless Python`_ implementation has paved the way, and we follow the same general design decisions: simple internal objects like bound method -objects and various kind of iterators are supported; frame objects can -be fully pickled and unpickled (by serializing the bytecode they are +objects and various kinds of iterators are supported; frame objects can +be fully pickled and unpickled +(by serializing a reference to the bytecode they are running in addition to all the local variables). References to globals and modules are pickled by name, similarly to references to functions and classes in the traditional CPython ``pickle``. @@ -504,7 +505,7 @@ Although the concept of coroutines is far from new, they have not been generally integrated into mainstream languages, or only in limited form -(like generators in Python and iterators C#). We can argue that a +(like generators in Python and iterators in C#). We can argue that a possible reason for that is that they do not scale well when a program's complexity increases: they look attractive in small examples, but the models that require explicit switching, by naming the target coroutine, From arigo at codespeak.net Mon Nov 27 00:06:31 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Nov 2006 00:06:31 +0100 (CET) Subject: [pypy-svn] r35009 - in pypy/dist/pypy: config objspace Message-ID: <20061126230631.D84B51006E@code0.codespeak.net> Author: arigo Date: Mon Nov 27 00:06:10 2006 New Revision: 35009 Added: pypy/dist/pypy/objspace/sand.py (contents, props changed) Modified: pypy/dist/pypy/config/pypyoption.py Log: Just an experiment. Not sure how useful this is, but it's fun and not many lines of code. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Mon Nov 27 00:06:10 2006 @@ -21,7 +21,8 @@ pypy_optiondescription = OptionDescription("pypy", "All PyPy Options", [ OptionDescription("objspace", "Object Space Option", [ ChoiceOption("name", "Object Space name", - ["std", "flow", "logic", "thunk", "cpy", "dump"], "std", + ["std", "flow", "logic", "thunk", "cpy", "dump", "sand"], + "std", requires = { "thunk": [("objspace.geninterp", False)], "logic": [("objspace.geninterp", False), Added: pypy/dist/pypy/objspace/sand.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/sand.py Mon Nov 27 00:06:10 2006 @@ -0,0 +1,145 @@ +""" +Just an experiment. +""" +from pypy.objspace.std.objspace import StdObjSpace +from pypy.objspace.proxy import patch_space_in_place +from pypy.objspace.thunk import nb_forcing_args +from pypy.interpreter.error import OperationError +from pypy.interpreter import baseobjspace, gateway +from pypy.tool.sourcetools import func_with_new_name +from pypy.rlib.unroll import unrolling_iterable + + +class W_Tainted(baseobjspace.W_Root): + def __init__(self, w_obj): + self.w_obj = w_obj + +## def getdict(self): +## return taint(self.w_obj.getdict()) + +## def getdictvalue_w(self, space, attr): +## return taint(self.w_obj.getdictvalue_w(space, attr)) + +## def getdictvalue(self, space, w_attr): +## return taint(self.w_obj.getdictvalue(space, w_attr)) + +## def setdictvalue(self, space, w_attr, w_value): +## return self.w_obj.setdictvalue(space, w_attr, w_value) + +## ... + +class W_TaintBomb(baseobjspace.W_Root): + def __init__(self, operr): + self.operr = operr + + def explode(self, space): + msg = self.operr.errorstr(space) + raise OperationError(space.w_TaintError, space.wrap(msg)) + + +def taint(w_obj): + if w_obj is None or isinstance(w_obj, W_Tainted): + return w_obj + else: + return W_Tainted(w_obj) +taint.unwrap_spec = [gateway.W_Root] +app_taint = gateway.interp2app(taint) + +def is_tainted(space, w_obj): + res = isinstance(w_obj, W_Tainted) + return space.wrap(res) +app_is_tainted = gateway.interp2app(is_tainted) + +def untaint(space, w_obj, w_expectedtype): + if isinstance(w_obj, W_Tainted): + w_obj = w_obj.w_obj + elif isinstance(w_obj, W_TaintBomb): + w_obj.explode(space) + #if isinstance(w_expectedtype, W_Tainted): + # w_expectedtype = w_expectedtype.w_obj + w_realtype = space.type(w_obj) + if not space.is_w(w_realtype, w_expectedtype): + msg = "expected an object of type '%s', got '%s'" % ( + w_expectedtype.getname(space, '?'), + w_realtype.getname(space, '?')) + raise OperationError(space.w_TaintError, + space.wrap(msg)) + return w_obj +app_untaint = gateway.interp2app(untaint) + +# ____________________________________________________________ + + +class SandSpace(StdObjSpace): + + def __init__(self, *args, **kwds): + StdObjSpace.__init__(self, *args, **kwds) + self.w_TaintError = self.call_function( + self.w_type, + self.wrap("TaintError"), + self.newtuple([self.w_Exception]), + self.newdict()) + w_pypymagic = self.getbuiltinmodule("pypymagic") + self.setattr(w_pypymagic, self.wrap('taint'), + self.wrap(app_taint)) + self.setattr(w_pypymagic, self.wrap('is_tainted'), + self.wrap(app_is_tainted)) + self.setattr(w_pypymagic, self.wrap('untaint'), + self.wrap(app_untaint)) + patch_space_in_place(self, 'sand', proxymaker) + + +Space = SandSpace + + +def tainted_error(space, name): + msg = "operation '%s' forbidden on tainted object" % (name,) + raise OperationError(space.w_TaintError, space.wrap(msg)) + + +RegularMethods = dict.fromkeys( + [name for name, _, _, _ in baseobjspace.ObjSpace.MethodTable]) + +def proxymaker(space, name, parentfn): + arity = nb_forcing_args[name] + indices = unrolling_iterable(range(arity)) + if name in RegularMethods: + + def proxy(*args_w): + newargs_w = () + tainted = False + for i in indices: + w_arg = args_w[i] + if isinstance(w_arg, W_Tainted): + tainted = True + w_arg = w_arg.w_obj + elif isinstance(w_arg, W_TaintBomb): + return w_arg + newargs_w += (w_arg,) + newargs_w += args_w[arity:] + try: + w_res = parentfn(*newargs_w) + except OperationError, e: + if not tainted: + raise + return W_TaintBomb(e) + if tainted: + w_res = taint(w_res) + return w_res + + elif arity == 0: + return None + + else: + + def proxy(*args_w): + for i in indices: + w_arg = args_w[i] + if isinstance(w_arg, W_Tainted): + tainted_error(space, name) + elif isinstance(w_arg, W_TaintBomb): + w_arg.explode(space) + return parentfn(*args_w) + + proxy = func_with_new_name(proxy, '%s_proxy' % name) + return proxy From arigo at codespeak.net Mon Nov 27 00:25:34 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 27 Nov 2006 00:25:34 +0100 (CET) Subject: [pypy-svn] r35010 - pypy/dist/pypy/config Message-ID: <20061126232534.AA0071006E@code0.codespeak.net> Author: arigo Date: Mon Nov 27 00:25:32 2006 New Revision: 35010 Modified: pypy/dist/pypy/config/pypyoption.py Log: Uh? In the config branch it was suddenly decided that the thunk objspace should not use geninterp. Is there a reason for that? The thunk did use geninterp before the config branch was merged, at least. Looks to me like an experiment with dependencies that was left behind by accident. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Mon Nov 27 00:25:32 2006 @@ -24,7 +24,7 @@ ["std", "flow", "logic", "thunk", "cpy", "dump", "sand"], "std", requires = { - "thunk": [("objspace.geninterp", False)], + #"thunk": [("objspace.geninterp", False)], uh? why? "logic": [("objspace.geninterp", False), ("objspace.usemodules._stackless", True)], }, From guido at codespeak.net Mon Nov 27 14:08:21 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 27 Nov 2006 14:08:21 +0100 (CET) Subject: [pypy-svn] r35027 - in pypy/dist/pypy/translator/js/modules: . test Message-ID: <20061127130821.6225310075@code0.codespeak.net> Author: guido Date: Mon Nov 27 14:08:19 2006 New Revision: 35027 Modified: pypy/dist/pypy/translator/js/modules/dom.py pypy/dist/pypy/translator/js/modules/test/test_dom.py Log: Added missing __setattr__ on Node... :| Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Mon Nov 27 14:08:19 2006 @@ -65,6 +65,7 @@ class Node(EventTarget): """base class of all node types""" + _original = None def __init__(self, node=None): self._original = node @@ -84,6 +85,14 @@ value = getattr(self._original, name) return _wrap(value) + def __setattr__(self, name, value): + """set an attribute on the wrapped node""" + if name in dir(self): + return super(Node, self).__setattr__(name, value) + if name not in self._fields: + raise NameError, name + setattr(self._original, name, value) + def __eq__(self, other): original = getattr(other, '_original', other) return original is self._original Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Mon Nov 27 14:08:19 2006 @@ -71,6 +71,18 @@ assert div.nodeType == 1 assert document.documentElement.childNodes[-1]._original is div._original +def code_nodeValue(): + window = get_window() + document = window.document + td = document.createElement('td') + td.appendChild(document.createTextNode('foo')) + td.childNodes[0].nodeValue = 'bar' + return td.childNodes[0].nodeValue + +def test_nodeValue(): + nodevalue = code_nodeValue() + assert nodevalue == 'bar' + def code_node_eq(): window = get_window() body = window.document.getElementsByTagName('body')[0] From cfbolz at codespeak.net Mon Nov 27 14:09:57 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 27 Nov 2006 14:09:57 +0100 (CET) Subject: [pypy-svn] r35029 - pypy/dist/pypy/module/__builtin__/test Message-ID: <20061127130957.6122B10080@code0.codespeak.net> Author: cfbolz Date: Mon Nov 27 14:09:55 2006 New Revision: 35029 Modified: pypy/dist/pypy/module/__builtin__/test/test_import.py Log: oops, rewrote the tests to use streamio instead of the removed osfilewrapper Modified: pypy/dist/pypy/module/__builtin__/test/test_import.py ============================================================================== --- pypy/dist/pypy/module/__builtin__/test/test_import.py (original) +++ pypy/dist/pypy/module/__builtin__/test/test_import.py Mon Nov 27 14:09:55 2006 @@ -2,10 +2,10 @@ from pypy.interpreter.module import Module from pypy.interpreter import gateway import pypy.interpreter.pycode -from pypy.tool.udir import udir +from pypy.tool.udir import udir +from pypy.rlib import streamio import sys, os import tempfile, marshal -from pypy.lib._osfilewrapper import OsFileWrapper from pypy.module.__builtin__ import importing @@ -64,16 +64,15 @@ w = space.wrap w_modname = w("compiled.x") filename = str(p.join("x.py")) - fd = os.open(filename, os.O_RDONLY, 0666) - osfile = importing.OsFileWrapper(fd) + stream = streamio.open_file_as_stream(filename, "r") try: importing.load_source_module(space, w_modname, w(importing.Module(space, w_modname)), filename, - osfile) + stream) finally: - osfile.close() + stream.close() return str(root) @@ -314,11 +313,14 @@ mtime = 12345 co = compile('x = 42', '?', 'exec') cpathname = _testfile(importing.pyc_magic, mtime, co) - fd = os.open(cpathname, importing.BIN_READMASK, 0777) - os.lseek(fd, 8, 0) - w_code = importing.read_compiled_module(space, cpathname, OsFileWrapper(fd)) - pycode = space.interpclass_w(w_code) - os.close(fd) + stream = streamio.open_file_as_stream(cpathname, "r") + try: + stream.seek(8, 0) + w_code = importing.read_compiled_module( + space, cpathname, stream) + pycode = space.interpclass_w(w_code) + finally: + stream.close() assert type(pycode) is pypy.interpreter.pycode.PyCode w_dic = space.newdict() pycode.exec_code(space, w_dic, w_dic) @@ -333,14 +335,16 @@ co = compile('x = 42', '?', 'exec') cpathname = _testfile(importing.pyc_magic, mtime, co) w_modulename = space.wrap('somemodule') - fd = os.open(cpathname, importing.BIN_READMASK, 0777) - w_mod = space.wrap(Module(space, w_modulename)) - w_ret = importing.load_compiled_module(space, - w_modulename, - w_mod, - cpathname, - OsFileWrapper(fd)) - os.close(fd) + stream = streamio.open_file_as_stream(cpathname, "r") + try: + w_mod = space.wrap(Module(space, w_modulename)) + w_ret = importing.load_compiled_module(space, + w_modulename, + w_mod, + cpathname, + stream) + finally: + stream.close() assert w_mod is w_ret w_ret = space.getattr(w_mod, space.wrap('x')) ret = space.int_w(w_ret) @@ -349,12 +353,13 @@ def test_parse_source_module(self): space = self.space pathname = _testfilesource() - fd = os.open(pathname, importing.BIN_READMASK, 0777) - osfile = OsFileWrapper(fd) - w_ret = importing.parse_source_module(space, - pathname, - osfile) - osfile.close() + stream = streamio.open_file_as_stream(pathname, "r") + try: + w_ret = importing.parse_source_module(space, + pathname, + stream) + finally: + stream.close() pycode = space.interpclass_w(w_ret) assert type(pycode) is pypy.interpreter.pycode.PyCode w_dic = space.newdict() @@ -365,31 +370,38 @@ def test_long_writes(self): pathname = str(udir.join('test.dat')) - f = file(pathname, "wb") - osfile = OsFileWrapper(f.fileno()) - importing._w_long(osfile, 42) - importing._w_long(osfile, 12312) - importing._w_long(osfile, 128397198) - f.close() - f = file(pathname, "r") - osfile = OsFileWrapper(f.fileno()) - assert importing._r_long(osfile) == 42 - assert importing._r_long(osfile) == 12312 - assert importing._r_long(osfile) == 128397198 + stream = streamio.open_file_as_stream(pathname, "wb") + try: + importing._w_long(stream, 42) + importing._w_long(stream, 12312) + importing._w_long(stream, 128397198) + finally: + stream.close() + stream = streamio.open_file_as_stream(pathname, "r") + try: + res = importing._r_long(stream) + assert res == 42 + res = importing._r_long(stream) + assert res == 12312 + res = importing._r_long(stream) + assert res == 128397198 + finally: + stream.close() def test_load_source_module(self): space = self.space w_modulename = space.wrap('somemodule') w_mod = space.wrap(Module(space, w_modulename)) pathname = _testfilesource() - fd = os.open(pathname, importing.BIN_READMASK, 0777) - osfile = OsFileWrapper(fd) - w_ret = importing.load_source_module(space, - w_modulename, - w_mod, - pathname, - osfile) - osfile.close() + stream = streamio.open_file_as_stream(pathname, "r") + try: + w_ret = importing.load_source_module(space, + w_modulename, + w_mod, + pathname, + stream) + finally: + stream.close() assert w_mod is w_ret w_ret = space.getattr(w_mod, space.wrap('x')) ret = space.int_w(w_ret) @@ -400,12 +412,13 @@ def test_write_compiled_module(self): space = self.space pathname = _testfilesource() - fd = os.open(pathname, importing.BIN_READMASK, 0777) - osfile = OsFileWrapper(fd) - w_ret = importing.parse_source_module(space, - pathname, - osfile) - osfile.close() + stream = streamio.open_file_as_stream(pathname, "r") + try: + w_ret = importing.parse_source_module(space, + pathname, + stream) + finally: + stream.close() pycode = space.interpclass_w(w_ret) assert type(pycode) is pypy.interpreter.pycode.PyCode @@ -425,12 +438,13 @@ assert ret == 1 # read compile module - fd = os.open(cpathname, importing.BIN_READMASK, 0777) - os.lseek(fd, 8, 0) - osfile = OsFileWrapper(fd) - w_code = importing.read_compiled_module(space, cpathname, osfile) - pycode = space.interpclass_w(w_code) - os.close(fd) + stream = streamio.open_file_as_stream(cpathname, "r") + try: + stream.seek(8, 0) + w_code = importing.read_compiled_module(space, cpathname, stream) + pycode = space.interpclass_w(w_code) + finally: + stream.close() # check value of load w_dic = space.newdict() From cfbolz at codespeak.net Mon Nov 27 16:55:08 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 27 Nov 2006 16:55:08 +0100 (CET) Subject: [pypy-svn] r35041 - in pypy/dist/pypy: doc/discussion tool/build Message-ID: <20061127155508.C00B21007B@code0.codespeak.net> Author: cfbolz Date: Mon Nov 27 16:55:05 2006 New Revision: 35041 Added: pypy/dist/pypy/doc/discussion/build-tool-description.txt - copied unchanged from r35025, pypy/dist/pypy/tool/build/README.txt Removed: pypy/dist/pypy/tool/build/README.txt Log: moved the readme to discussion (we try to keep all docs in the doc dir) From pedronis at codespeak.net Mon Nov 27 17:33:28 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 27 Nov 2006 17:33:28 +0100 (CET) Subject: [pypy-svn] r35045 - in pypy/dist/pypy/jit: codegen codegen/i386 codegen/llgraph codegen/llgraph/test codegen/ppc codegen/ppc/test codegen/test timeshifter timeshifter/test Message-ID: <20061127163328.13CB210077@code0.codespeak.net> Author: pedronis Date: Mon Nov 27 17:33:12 2006 New Revision: 35045 Modified: pypy/dist/pypy/jit/codegen/graph2rgenop.py pypy/dist/pypy/jit/codegen/i386/rgenop.py pypy/dist/pypy/jit/codegen/llgraph/llimpl.py pypy/dist/pypy/jit/codegen/llgraph/rgenop.py pypy/dist/pypy/jit/codegen/llgraph/test/test_rgenop.py pypy/dist/pypy/jit/codegen/model.py pypy/dist/pypy/jit/codegen/ppc/rgenop.py pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py pypy/dist/pypy/jit/codegen/test/rgenop_tests.py pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Log: (arre, pedronis) change the rgenop interface, newgraph returns directly a GenConst for the function pointer. There's no gencallableconst anymore. the change is on the path for supporting recursive portal calls. Modified: pypy/dist/pypy/jit/codegen/graph2rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/graph2rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/graph2rgenop.py Mon Nov 27 17:33:12 2006 @@ -10,7 +10,8 @@ FUNC = lltype.FuncType([v.concretetype for v in graph.getargs()], graph.getreturnvar().concretetype) sigtoken = rgenop.sigToken(FUNC) - builder, entrypoint, args_gv = rgenop.newgraph(sigtoken) + builder, gv_entrypoint, args_gv = rgenop.newgraph(sigtoken, + "compiled_%s" % (graph.name,)) pending_blocks = {graph.startblock: (builder, args_gv)} seen_blocks = {} @@ -73,5 +74,6 @@ args_gv = [var2gv(v) for v in link.args] pending_blocks[link.target] = builder, args_gv - return rgenop.gencallableconst(sigtoken, "compiled_%s" % (graph.name,), - entrypoint) + builder.end() + return gv_entrypoint + Modified: pypy/dist/pypy/jit/codegen/i386/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/i386/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/i386/rgenop.py Mon Nov 27 17:33:12 2006 @@ -218,11 +218,15 @@ class Builder(GenBuilder): + def __init__(self, rgenop, mc, stackdepth): self.rgenop = rgenop self.stackdepth = stackdepth self.mc = mc + def end(self): + pass + def _write_prologue(self, sigtoken): numargs = sigtoken # for now #self.mc.BREAKPOINT() @@ -799,6 +803,9 @@ def __init__(self, rgenop): self.rgenop = rgenop + def end(self): + pass + @specialize.arg(1) def genop1(self, opname, gv_arg): return dummy_var @@ -888,13 +895,13 @@ def openbuilder(self, stackdepth): return Builder(self, self.open_mc(), stackdepth) - def newgraph(self, sigtoken): + def newgraph(self, sigtoken, name): numargs = sigtoken # for now initialstackdepth = numargs+1 builder = self.openbuilder(initialstackdepth) entrypoint = builder.mc.tell() inputargs_gv = builder._write_prologue(sigtoken) - return builder, entrypoint, inputargs_gv + return builder, IntConst(entrypoint), inputargs_gv def replay(self, label, kinds): return ReplayBuilder(self), [dummy_var] * len(kinds) @@ -959,9 +966,6 @@ def sigToken(FUNCTYPE): return len(FUNCTYPE.ARGS) # for now - def gencallableconst(self, sigtoken, name, entrypointaddr): - return IntConst(entrypointaddr) - @staticmethod def erasedType(T): if T is llmemory.Address: Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llgraph/llimpl.py (original) +++ pypy/dist/pypy/jit/codegen/llgraph/llimpl.py Mon Nov 27 17:33:12 2006 @@ -28,8 +28,11 @@ block = flowmodel.Block([]) return to_opaque_object(block) -def newgraph(gv_FUNCTYPE): +def newgraph(gv_FUNCTYPE, name): FUNCTYPE = from_opaque_object(gv_FUNCTYPE).value + # 'name' is just a way to track things + if not isinstance(name, str): + name = LLSupport.from_rstr(name) inputargs = [] erasedinputargs = [] for ARG in FUNCTYPE.ARGS: @@ -42,17 +45,27 @@ startblock = flowmodel.Block(inputargs) return_var = flowmodel.Variable() return_var.concretetype = FUNCTYPE.RESULT - graph = flowmodel.FunctionGraph("in_progress", startblock, return_var) + graph = flowmodel.FunctionGraph(name, startblock, return_var) v1 = flowmodel.Variable() v1.concretetype = lltype.erasedType(FUNCTYPE.RESULT) graph.prereturnblock = flowmodel.Block([v1]) casting_link(graph.prereturnblock, [v1], graph.returnblock) substartblock = flowmodel.Block(erasedinputargs) casting_link(graph.startblock, inputargs, substartblock) - return to_opaque_object(graph) + fptr = lltype.functionptr(FUNCTYPE, name, + graph=graph) + return genconst(fptr) -def getstartblock(graph): - graph = from_opaque_object(graph) +def _getgraph(gv_func): + graph = from_opaque_object(gv_func).value._obj.graph + return graph + +def end(gv_func): + graph = _getgraph(gv_func) + _buildgraph(graph) + +def getstartblock(gv_func): + graph = _getgraph(gv_func) [link] = graph.startblock.exits substartblock = link.target return to_opaque_object(substartblock) @@ -161,17 +174,6 @@ assert 0, "failed to guess the type of %s: %s" % (opname, e) return lltype.typeOf(result) -def gencallableconst(name, graph, gv_FUNCTYPE): - # 'name' is just a way to track things - if not isinstance(name, str): - name = LLSupport.from_rstr(name) - graph = from_opaque_object(graph) - graph.name = name - FUNCTYPE = from_opaque_object(gv_FUNCTYPE).value - fptr = lltype.functionptr(FUNCTYPE, name, - graph=_buildgraph(graph, FUNCTYPE)) - return genconst(fptr) - def genconst(llvalue): T = lltype.typeOf(llvalue) T1 = lltype.erasedType(T) @@ -342,10 +344,10 @@ import pdb; pdb.post_mortem(tb) raise -def closereturnlink(link, returnvar, graph): +def closereturnlink(link, returnvar, gv_func): returnvar = from_opaque_object(returnvar) link = from_opaque_object(link) - graph = from_opaque_object(graph) + graph = _getgraph(gv_func) _closelink(link, [returnvar], graph.prereturnblock) def casting_link(source, sourcevars, target): @@ -370,7 +372,7 @@ from pypy.rpython.typesystem import LowLevelTypeSystem self.type_system = LowLevelTypeSystem.instance -def _buildgraph(graph, FUNCTYPE): +def _buildgraph(graph): flowmodel.checkgraph(graph) eliminate_empty_blocks(graph) join_blocks(graph) @@ -379,7 +381,7 @@ def buildgraph(graph, FUNCTYPE): graph = from_opaque_object(graph) - return _buildgraph(graph, FUNCTYPE) + return _buildgraph(graph) def testgengraph(gengraph, args, viewbefore=False, executor=LLInterpreter): if viewbefore: @@ -466,12 +468,12 @@ s_Graph = annmodel.SomePtr(GRAPH) setannotation(newblock, s_Block) -setannotation(newgraph, s_Graph) +setannotation(newgraph, s_ConstOrVar) setannotation(getstartblock, s_Block) setannotation(geninputarg, s_ConstOrVar) setannotation(getinputarg, s_ConstOrVar) setannotation(genop, s_ConstOrVar) -setannotation(gencallableconst, s_ConstOrVar) +setannotation(end, None) setannotation(genconst, s_ConstOrVar) setannotation(cast, s_ConstOrVar) setannotation(revealconst, lambda s_T, s_gv: annmodel.lltype_to_annotation( Modified: pypy/dist/pypy/jit/codegen/llgraph/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llgraph/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/llgraph/rgenop.py Mon Nov 27 17:33:12 2006 @@ -38,19 +38,19 @@ def __init__(self, b, g): self.b = b - self.g = g + self.gv_f = g self.cases_gv = [] def add_case(self, gv_case): self.cases_gv.append(gv_case) # not used so far, but keeps ptrs alive l_case = llimpl.add_case(self.b, gv_case.v) - builder = LLBuilder(self.g) + builder = LLBuilder(self.gv_f) builder.lnk = l_case return builder def add_default(self): l_default = llimpl.add_default(self.b) - builder = LLBuilder(self.g) + builder = LLBuilder(self.gv_f) builder.lnk = l_default return builder @@ -59,8 +59,11 @@ def __init__(self, g): self.rgenop = rgenop - self.g = g + self.gv_f = g + def end(self): + llimpl.end(self.gv_f) + @specialize.arg(1) def genop1(self, opname, gv_arg): return LLVar(llimpl.genop(self.b, opname, [gv_arg], llimpl.guess)) @@ -145,7 +148,7 @@ llimpl.closelink(lnk, args_gv, self.b) for i in range(len(args_gv)): args_gv[i] = newb_args_gv[i] - return LLLabel(self.b, self.g) + return LLLabel(self.b, self.gv_f) def finish_and_goto(self, args_gv, target): lnk = self.lnk or llimpl.closeblock1(self.b) @@ -156,12 +159,12 @@ gv_returnvar = gv_returnvar or gv_dummy_placeholder lnk = self.lnk or llimpl.closeblock1(self.b) self.lnk = llimpl.nulllink - llimpl.closereturnlink(lnk, gv_returnvar.v, self.g) + llimpl.closereturnlink(lnk, gv_returnvar.v, self.gv_f) def jump_if_true(self, gv_cond): l_false, l_true = llimpl.closeblock2(self.b, gv_cond.v) self.b = llimpl.nullblock - later_builder = LLBuilder(self.g) + later_builder = LLBuilder(self.gv_f) later_builder.lnk = l_true self.lnk = l_false return later_builder @@ -169,37 +172,33 @@ def jump_if_false(self, gv_cond): l_false, l_true = llimpl.closeblock2(self.b, gv_cond.v) self.b = llimpl.nullblock - later_builder = LLBuilder(self.g) + later_builder = LLBuilder(self.gv_f) later_builder.lnk = l_false self.lnk = l_true return later_builder def flexswitch(self, gv_switchvar): llimpl.closeblockswitch(self.b, gv_switchvar.v) - flexswitch = LLFlexSwitch(self.b, self.g) + flexswitch = LLFlexSwitch(self.b, self.gv_f) self.b = llimpl.nullblock self.lnk = llimpl.nulllink return flexswitch def show_incremental_progress(self): - llimpl.show_incremental_progress(self.g) + llimpl.show_incremental_progress(self.gv_f) class RGenOp(AbstractRGenOp): gv_Void = gv_Void - def newgraph(self, (ARGS_gv, gv_RESULT, gv_FUNCTYPE)): - graph = llimpl.newgraph(gv_FUNCTYPE.v) - builder = LLBuilder(graph) - builder.b = llimpl.getstartblock(graph) + def newgraph(self, (ARGS_gv, gv_RESULT, gv_FUNCTYPE), name): + gv_func = llimpl.newgraph(gv_FUNCTYPE.v, name) + builder = LLBuilder(gv_func) + builder.b = llimpl.getstartblock(gv_func) inputargs_gv = [LLVar(llimpl.getinputarg(builder.b, i)) for i in range(len(ARGS_gv))] - return builder, graph, inputargs_gv - - def gencallableconst(self, (ARGS_gv, gv_RESULT, gv_FUNCTYPE), name, graph): - return LLConst(llimpl.gencallableconst(name, graph, - gv_FUNCTYPE.v)) + return builder, LLConst(gv_func), inputargs_gv @staticmethod @specialize.genconst(0) Modified: pypy/dist/pypy/jit/codegen/llgraph/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llgraph/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/llgraph/test/test_rgenop.py Mon Nov 27 17:33:12 2006 @@ -38,10 +38,10 @@ def build_square(): """def square(v0): return v0*v0""" - builder, graph, (gv0,) = rgenop.newgraph(f1_token) + builder, gv_square, (gv0,) = rgenop.newgraph(f1_token, "square") gv1 = builder.genop2('int_mul', gv0, gv0) builder.finish_and_return(f1_token, gv1) - gv_square = rgenop.gencallableconst(f1_token, "square", graph) + builder.end() square_ptr = gv_square.revealconst(lltype.Ptr(F1)) return square_ptr @@ -63,14 +63,14 @@ else: return v0 """ - builder, graph, (gv0,) = rgenop.newgraph(f1_token) + builder, gv_if, (gv0,) = rgenop.newgraph(f1_token, "if") const0 = rgenop.genconst(0) gv1 = builder.genop2('int_lt', gv0, const0) false_builder = builder.jump_if_false(gv1) builder.finish_and_return(f1_token, const0) false_builder.finish_and_return(f1_token, gv0) - gv_if = rgenop.gencallableconst(f1_token, "if", graph) + builder.end() if_ptr = gv_if.revealconst(lltype.Ptr(F1)) return if_ptr @@ -100,7 +100,7 @@ if i > v0: break return result """ - builder, graph, (gv0,) = rgenop.newgraph(f1_token) + builder, gv_loop, (gv0,) = rgenop.newgraph(f1_token, "loop") const1 = rgenop.genconst(1) args_gv = [const1, const1, gv0] @@ -114,7 +114,7 @@ builder.finish_and_return(f1_token, gv_result1) loop_builder.finish_and_goto([gv_result1, gv_i1, gv1], loopblock) - gv_loop = rgenop.gencallableconst(f1_token, "loop", graph) + builder.end() loop_ptr = gv_loop.revealconst(lltype.Ptr(F1)) return loop_ptr @@ -165,7 +165,7 @@ else: return v1 """ - builder, graph, (gv0, gv1) = rgenop.newgraph(f2_token) + builder, gv_switch, (gv0, gv1) = rgenop.newgraph(f2_token, "switch") flexswitch = builder.flexswitch(gv0) const21 = rgenop.genconst(21) @@ -193,7 +193,7 @@ [gv1_default] = default_args_gv default_builder.finish_and_return(f2_token, gv1_default) - gv_switch = rgenop.gencallableconst(f2_token, "switch", graph) + builder.end() switch_ptr = gv_switch.revealconst(lltype.Ptr(F2)) return switch_ptr Modified: pypy/dist/pypy/jit/codegen/model.py ============================================================================== --- pypy/dist/pypy/jit/codegen/model.py (original) +++ pypy/dist/pypy/jit/codegen/model.py Mon Nov 27 17:33:12 2006 @@ -152,12 +152,13 @@ being written to. ''' - def newgraph(self, sigtoken): + def newgraph(self, sigtoken, name): """Begin code generation for a new function, which signature described by sigtoken. Returns a new builder, entrypoint, inputargs_gv where the new builder is for the startblock, - entrypoint is the address of the new function and inputargs_gv - is the location of each argument on entry to the function.""" + entrypoint is the address of the new function as GenConst and + inputargs_gv is the location of each argument on entry to the + function. name is for debugging purposes""" # all staticmethods commented out for the sake of the annotator @@ -178,16 +179,6 @@ # This is for immortal prebuilt data.""" # raise NotImplementedError - #def gencallableconst(self, sigtoken, name, entrypoint): - # """Returns a GenConst that contains a function pointer. This - # might be the time to do some further optimization of the - # generated code. - # - # sigtoken describes the signature, name is for debugging - # purposes and entrypoint is what was returned from - # newgraph.""" - # raise NotImplementedError - def replay(self, label, kinds): '''Return a builder that will "generate" exactly the same code as was already generated, starting from label. kinds is a Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py Mon Nov 27 17:33:12 2006 @@ -196,6 +196,9 @@ # ---------------------------------------------------------------- # the public Builder interface: + def end(self): + pass + @specialize.arg(1) def genop1(self, opname, gv_arg): genmethod = getattr(self, 'op_' + opname) @@ -688,7 +691,7 @@ builder = self.openbuilder() entrypoint = builder.asm.mc.tell() inputargs_gv = builder._write_prologue(sigtoken) - return builder, entrypoint, inputargs_gv + return builder, IntConst(entrypoint), inputargs_gv @specialize.genconst(1) def genconst(self, llvalue): @@ -709,9 +712,6 @@ ## @specialize.genconst(0) ## def constPrebuiltGlobal(llvalue): - def gencallableconst(self, sigtoken, name, entrypointaddr): - return IntConst(entrypointaddr) - ## def replay(self, label, kinds): ## @staticmethod Modified: pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py ============================================================================== --- pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py (original) +++ pypy/dist/pypy/jit/codegen/ppc/test/test_rgenop.py Mon Nov 27 17:33:12 2006 @@ -20,7 +20,8 @@ rgenop = self.RGenOp() signed_kind = rgenop.kindToken(lltype.Signed) sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) + builder, gv_callable, [gv_x, gv_y] = rgenop.newgraph(sigtoken, + "multicmp") args_gv = [gv_x, gv_y] builder.enter_next_block([signed_kind, signed_kind], args_gv) @@ -48,7 +49,7 @@ gv_r5 = builder.genop2("int_add", gv_r4, gv_ne2) builder.finish_and_return(sigtoken, gv_r5) - gv_callable = rgenop.gencallableconst(sigtoken, "multicmp", entrypoint) + builder.end() fnptr = cast(c_void_p(gv_callable.value), CFUNCTYPE(c_int, c_int)) res = fnptr(1, 2) assert res == 101010 Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py ============================================================================== --- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py (original) +++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py Mon Nov 27 17:33:12 2006 @@ -13,10 +13,10 @@ def make_adder(rgenop, n): # 'return x+n' sigtoken = rgenop.sigToken(FUNC) - builder, entrypoint, [gv_x] = rgenop.newgraph(sigtoken) + builder, gv_add_one, [gv_x] = rgenop.newgraph(sigtoken, "adder") gv_result = builder.genop2("int_add", gv_x, rgenop.genconst(n)) builder.finish_and_return(sigtoken, gv_result) - gv_add_one = rgenop.gencallableconst(sigtoken, "adder", entrypoint) + builder.end() return gv_add_one def get_adder_runner(RGenOp): @@ -35,7 +35,7 @@ # 'return x - (y - (x-1))' signed_kind = rgenop.kindToken(lltype.Signed) sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) + builder, gv_dummyfn, [gv_x, gv_y] = rgenop.newgraph(sigtoken, "dummy") gv_z = builder.genop2("int_sub", gv_x, rgenop.genconst(1)) args_gv = [gv_y, gv_z, gv_x] @@ -46,7 +46,7 @@ gv_t2 = builder.genop2("int_sub", gv_x2, gv_s2) builder.finish_and_return(sigtoken, gv_t2) - gv_dummyfn = rgenop.gencallableconst(sigtoken, "dummy", entrypoint) + builder.end() return gv_dummyfn def get_dummy_runner(RGenOp): @@ -64,7 +64,8 @@ # else: return y' signed_kind = rgenop.kindToken(lltype.Signed) sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) + builder, gv_branchingfn, [gv_x, gv_y] = rgenop.newgraph(sigtoken, + "branching") gv_cond = builder.genop2("int_gt", gv_x, rgenop.genconst(5)) false_builder = builder.jump_if_false(gv_cond) @@ -83,8 +84,7 @@ false_builder.finish_and_return(sigtoken, gv_y) # done - gv_branchingfn = rgenop.gencallableconst(sigtoken, - "branching", entrypoint) + builder.end() return gv_branchingfn def get_branching_runner(RGenOp): @@ -139,7 +139,7 @@ # return y signed_kind = rgenop.kindToken(lltype.Signed) sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken) + builder, gv_gotofn, [gv_x, gv_y] = rgenop.newgraph(sigtoken, "goto") [gv_x, gv_y, gv_z],loopblock,bodybuilder = loop_start( rgenop, builder, signed_kind, gv_x, gv_y) @@ -149,7 +149,7 @@ rgenop, loopblock, bodybuilder, signed_kind, gv_x, gv_y, gv_z) # done - gv_gotofn = rgenop.gencallableconst(sigtoken, "goto", entrypoint) + builder.end() return gv_gotofn def get_goto_runner(RGenOp): @@ -169,7 +169,7 @@ # return x + a signed_kind = rgenop.kindToken(lltype.Signed) sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv_x1, gv_unused] = rgenop.newgraph(sigtoken) + builder, gv_gotofn, [gv_x1, gv_unused] = rgenop.newgraph(sigtoken, "if") # check args_gv = [gv_x1, gv_unused] @@ -199,7 +199,7 @@ elsebuilder.finish_and_goto([gv_x3, gv_x3], label) # done - gv_gotofn = rgenop.gencallableconst(sigtoken, "goto", entrypoint) + builder.end() return gv_gotofn def get_if_runner(RGenOp): @@ -224,7 +224,7 @@ """ signed_kind = rgenop.kindToken(lltype.Signed) sigtoken = rgenop.sigToken(FUNC2) - builder, entrypoint, [gv0, gv1] = rgenop.newgraph(sigtoken) + builder, gv_switch, [gv0, gv1] = rgenop.newgraph(sigtoken, "switch") flexswitch = builder.flexswitch(gv0) const21 = rgenop.genconst(21) @@ -252,7 +252,7 @@ gv_res_case1 = case_builder.genop2('int_add', const21, gv1_case1) case_builder.finish_and_return(sigtoken, gv_res_case1) - gv_switch = rgenop.gencallableconst(sigtoken, "switch", entrypoint) + builder.end() return gv_switch def get_switch_runner(RGenOp): @@ -282,7 +282,7 @@ """ signed_tok = rgenop.kindToken(lltype.Signed) f2_token = rgenop.sigToken(FUNC2) - builder, graph, (gv0, gv1) = rgenop.newgraph(f2_token) + builder, gv_switch, (gv0, gv1) = rgenop.newgraph(f2_token, "large_switch") flexswitch = builder.flexswitch(gv0) const21 = rgenop.genconst(21) @@ -312,7 +312,7 @@ gv_res_casex = case_builder.genop2('int_add', const2px, gv1_casex) case_builder.finish_and_return(f2_token, gv_res_casex) - gv_switch = rgenop.gencallableconst(f2_token, "large_switch", graph) + builder.end() return gv_switch def get_large_switch_runner(RGenOp): @@ -335,9 +335,7 @@ # return 1 signed_kind = rgenop.kindToken(lltype.Signed) sigtoken = rgenop.sigToken(FUNC) - builder, entrypoint, [gv_x] = rgenop.newgraph(sigtoken) - - gv_fact = rgenop.gencallableconst(sigtoken, "fact", entrypoint) + builder, gv_fact, [gv_x] = rgenop.newgraph(sigtoken, "fact") gv_cond = builder.genop1("int_is_true", gv_x) @@ -356,6 +354,7 @@ builder.enter_next_block([], []) builder.finish_and_return(sigtoken, rgenop.genconst(1)) + builder.end() return gv_fact def get_fact_runner(RGenOp): Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Mon Nov 27 17:33:12 2006 @@ -256,7 +256,8 @@ except KeyError: portal_ts_args = () sigtoken = rgenop.sigToken(FUNC) - builder, entrypoint, inputargs_gv = rgenop.newgraph(sigtoken) + builder, gv_generated, inputargs_gv = rgenop.newgraph(sigtoken, + "generated") i = 0 for color in argcolors: if color == "green": @@ -279,9 +280,7 @@ if top_jitstate is not None: finish_jitstate(top_jitstate, sigtoken) - gv_generated = rgenop.gencallableconst(sigtoken, - "generated", - entrypoint) + builder.end() fn = gv_generated.revealconst(lltype.Ptr(FUNC)) builder.show_incremental_progress() cache[key] = fn Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py Mon Nov 27 17:33:12 2006 @@ -155,7 +155,8 @@ timeshifted_entrypoint_args = () sigtoken = rgenop.sigToken(FUNC) - builder, entrypoint, inputargs_gv = rgenop.newgraph(sigtoken) + builder, gv_generated, inputargs_gv = rgenop.newgraph(sigtoken, + "generated") i = 0 for color in argcolors: if color == "green": @@ -185,8 +186,7 @@ if top_jitstate is not None: finish_jitstate(top_jitstate, sigtoken) - gv_generated = rgenop.gencallableconst(sigtoken, "generated", - entrypoint) + builder.end() generated = gv_generated.revealconst(lltype.Ptr(FUNC)) return generated From ac at codespeak.net Mon Nov 27 17:46:29 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Mon, 27 Nov 2006 17:46:29 +0100 (CET) Subject: [pypy-svn] r35046 - pypy/dist/pypy/jit/codegen/llgraph Message-ID: <20061127164629.7716110082@code0.codespeak.net> Author: ac Date: Mon Nov 27 17:46:28 2006 New Revision: 35046 Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py Log: (pedronis, arre) Oops. Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llgraph/llimpl.py (original) +++ pypy/dist/pypy/jit/codegen/llgraph/llimpl.py Mon Nov 27 17:46:28 2006 @@ -394,10 +394,10 @@ graph = buildgraph(graph, FUNCTYPE) return testgengraph(graph, args, viewbefore, executor) -def show_incremental_progress(graph): +def show_incremental_progress(gv_func): from pypy import conftest if conftest.option.view: - graph = from_opaque_object(graph) + graph = _getgraph(gv_func) eliminate_empty_blocks(graph) graph.show() From cfbolz at codespeak.net Mon Nov 27 19:01:56 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 27 Nov 2006 19:01:56 +0100 (CET) Subject: [pypy-svn] r35048 - in pypy/dist/pypy/rlib/parsing: . test Message-ID: <20061127180156.2B67910087@code0.codespeak.net> Author: cfbolz Date: Mon Nov 27 19:01:48 2006 New Revision: 35048 Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py pypy/dist/pypy/rlib/parsing/parsing.py pypy/dist/pypy/rlib/parsing/regexparse.py pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py pypy/dist/pypy/rlib/parsing/test/test_regexparse.py pypy/dist/pypy/rlib/parsing/test/test_translate.py pypy/dist/pypy/rlib/parsing/tree.py Log: big checkin with all the changes to the parsing stuff, done during the various train-rides of the last days: - general refactoring of the ebnf parser to be much saner - add a new graph rewriting pattern to the automatically generated transformer (>...<) that replaces a node by its children - add support for +, which matches at least one occurence of a symbol - add support for ?, which matches at most one occurence of a symbol - fixed quite some corner cases in various places Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/ebnfparse.py Mon Nov 27 19:01:48 2006 @@ -20,17 +20,21 @@ StringExpression('\t')] rs, rules, transformer = parse_ebnf(r""" file: list EOF; - list: element*; - element: regex | production; + list: element+; + element: | ; regex: SYMBOLNAME ":" QUOTE ";"; production: NONTERMINALNAME ":" body ";"; - body: expansion "|" body | expansion; - expansion: enclosed expansion | enclosed; - enclosed: "[" primary "]" | + body: (expansion ["|"])* expansion; + expansion: decorated+; + decorated: enclosed "*" | + enclosed "+" | + enclosed "?" | + ; + enclosed: "[" expansion "]" | + ">" expansion "<" | "<" primary ">" | - primary_parens "*" | - primary; - primary_parens: "(" expansion ")" | primary; + "(" ")" | + ; primary: NONTERMINALNAME | SYMBOLNAME | QUOTE; """) names2, regexs2 = zip(*rs) @@ -46,11 +50,25 @@ print tokens s = parser.parse(tokens) s = s.visit(EBNFToAST()) + assert len(s) == 1 + s = s[0] s.visit(visitor) - visitor.fix_rule_order() - ToAstVisitor = make_transformer(visitor.rules, visitor.changes, - visitor.star_rules) - return zip(visitor.names, visitor.regexs), visitor.rules, ToAstVisitor + + rules, changes = visitor.get_rules_and_changes() + maker = TransformerMaker(rules, changes) + ToAstVisitor = maker.make_transformer() + return zip(visitor.names, visitor.regexs), rules, ToAstVisitor + +def check_for_missing_names(names, regexs, rules): + known_names = dict.fromkeys(names, True) + known_names["EOF"] = True + for rule in rules: + known_names[rule.nonterminal] = True + for rule in rules: + for expansion in rule.expansions: + for symbol in expansion: + if symbol not in known_names: + raise ValueError("symbol '%s' not known" % (symbol, )) def make_parse_function(regexs, rules, eof=False): from pypy.rlib.parsing.lexer import Lexer @@ -59,6 +77,7 @@ ignore = ["IGNORE"] else: ignore = [] + check_for_missing_names(names, regexs, rules) lexer = Lexer(list(regexs), list(names), ignore=ignore) parser = PackratParser(rules, rules[0].nonterminal) def parse(s): @@ -73,15 +92,18 @@ self.names = [] self.rules = [] self.changes = [] - self.star_rules = {} + self.maybe_rules = {} + self.num_plus_symbols = 0 self.first_rule = None + self.literals = {} + def visit_file(self, node): return node.children[0].visit(self) + def visit_list(self, node): - for child in node.children[0].children: + for child in node.children: child.visit(self) - def visit_element(self, node): - node.children[0].visit(self) + def visit_regex(self, node): regextext = node.children[2].additional_info[1:-1].replace('\\"', '"') regex = parse_regex(regextext) @@ -90,233 +112,456 @@ "%s is not a valid regular expression" % regextext) self.regexs.append(regex) self.names.append(node.children[0].additional_info) + def visit_production(self, node): - self.conditions = [] - self.returnvals = [] name = node.children[0].additional_info - expansions, changes = node.children[2].visit(self) - self.rules.append(Rule(name, expansions)) + expansions = node.children[2].visit(self) + changes = [] + rule_expansions = [] + for expansion in expansions: + expansion, change = zip(*expansion) + rule_expansions.append(list(expansion)) + changes.append("".join(change)) if self.first_rule is None: self.first_rule = name self.changes.append(changes) + self.rules.append(Rule(name, rule_expansions)) + def visit_body(self, node): - if len(node.children) == 1: - expansion, changes = node.children[0].visit(self) - return [expansion], [changes] - expansion, change = node.children[0].visit(self) - expansions, changes = node.children[2].visit(self) - expansions.insert(0, expansion) - changes.insert(0, change) - return expansions, changes + expansions = [] + for child in node.children: + expansion = child.visit(self) + expansions.append(expansion) + return expansions + def visit_expansion(self, node): - if len(node.children) == 1: - return node.children[0].visit(self) - expansion1, changes1 = node.children[0].visit(self) - expansion2, changes2 = node.children[1].visit(self) - return expansion1 + expansion2, changes1 + changes2 + expansions = [] + for child in node.children: + expansion = child.visit(self) + expansions += expansion + return expansions + def visit_enclosed(self, node): - if len(node.children) == 1: - return node.children[0].visit(self), " " - elif len(node.children) == 3: - return (node.children[1].visit(self), - node.children[0].additional_info) - elif len(node.children) == 2: - # XXX - expansions, changes = node.children[0].visit(self) - name = "_star_symbol%s" % (len(self.star_rules), ) - self.rules.append(Rule(name, [expansions + [name], []])) - self.changes.append([changes + " ", changes]) - self.star_rules[name] = self.rules[-1] - return [name], " " + result = [] + newchange = node.children[0].additional_info + for name, change in node.children[1].visit(self): + assert change == " " or change == newchange + result.append((name, newchange)) + return result + + def visit_decorated(self, node): + expansions = node.children[0].visit(self) + expansions, changes = zip(*expansions) + expansions, changes = list(expansions), "".join(changes) + if node.children[1].additional_info == "*": + name = "_star_symbol%s" % (len(self.maybe_rules), ) + maybe_rule = True + expansions = [expansions + [name], expansions] + changes = [changes + ">", changes] + elif node.children[1].additional_info == "+": + name = "_plus_symbol%s" % (self.num_plus_symbols, ) + self.num_plus_symbols += 1 + maybe_rule = False + expansions = [expansions + [name], expansions] + changes = [changes + ">", changes] + elif node.children[1].additional_info == "?": + name = "_maybe_symbol%s" % (len(self.maybe_rules), ) + maybe_rule = True + expansions = [expansions] + changes = [changes] + self.rules.append(Rule(name, expansions)) + self.changes.append(changes) + if maybe_rule: + self.maybe_rules[name] = self.rules[-1] + return [(name, ">")] + def visit_primary_parens(self, node): if len(node.children) == 1: - return node.children[0].visit(self), " " + return node.children[0].visit(self) else: return node.children[1].visit(self) + def visit_primary(self, node): - if len(node.children) == 3: - return node.children[1].visit(self) - elif node.children[0].symbol == "QUOTE": - # harmless, since the string starts and ends with quotes + if node.children[0].symbol == "QUOTE": + from pypy.rlib.parsing.regexparse import unescape content = node.children[0].additional_info[1:-1] - if content.endswith("'"): - e = '"""' + content + '"""' - else: - e = "'''" + content + "'''" - name = eval(e) - self.names.insert(0, name) - self.regexs.insert(0, StringExpression(name)) - return [name] + expression = unescape(content) + name = self.get_literal_name(expression) + return [(name, " ")] else: - return [node.children[0].additional_info] + return [(node.children[0].additional_info, " ")] + + def get_literal_name(self, expression): + if expression in self.literals: + return self.literals[expression] + name = "__%s_%s" % (len(self.literals), expression) + self.literals[expression] = name + self.regexs.insert(0, StringExpression(expression)) + self.names.insert(0, name) + return name + + def get_rules_and_changes(self): + self.fix_rule_order() + return self.add_all_possibilities() + def fix_rule_order(self): if self.rules[0].nonterminal != self.first_rule: - i = [r.nonterminal for r in self.rules].index(self.first_rule) + for i, r in enumerate(self.rules): + if r.nonterminal == self.first_rule: + break self.rules[i], self.rules[0] = self.rules[0], self.rules[i] self.changes[i], self.changes[0] = self.changes[0], self.changes[i] -def make_transformer(rules, changes, star_rules): - rulenames = dict.fromkeys([r.nonterminal for r in rules]) - result = ["class ToAST(RPythonVisitor):"] - result.append(" def general_visit(self, node):") - result.append(" return node") - for rule, change in zip(rules, changes): - lenchanges = [len(c) for c in change] - result.append(" def visit_%s(self, node):" % (rule.nonterminal, )) - if rule.nonterminal in star_rules: - subchange = change[0] - expansion = rule.expansions[0] - result.append(" children = []") - result.append(" while len(node.children) == %s:" % ( - len(expansion), )) - children = [] - for i, (n, c) in enumerate(zip(expansion[:-1], subchange[:-1])): - if c == " ": - children.append("self.dispatch(node.children[%s])" % (i, )) - result.append( - " children.extend([%s])" % ( - (",\n" + " " * 45).join(children))) - result.append(" node = node.children[-1]") - result.append( - " children.extend([%s])" % ( - (",\n" + " " * 45).join(children))) - result.append(" return Nonterminal('__list', children)") - continue - for j, (expansion, subchange) in enumerate( - zip(rule.expansions, change)): - if len(rule.expansions) == 1: - result.append(" if True:") - elif j == len(rule.expansions) - 1: - result.append(" else:") - elif lenchanges.count(len(expansion)) == 1: - result.append(" if len(node.children) == %s:" % - (len(expansion), )) - else: - conds = ["len(node.children) == %s" % (len(expansion), )] - for i, n in enumerate(expansion): - conds.append("node.children[%s].symbol == %r" % (i, n)) - result.append( - " if (%s):" % (" and \n ".join(conds), )) + def add_all_possibilities(self): + all_rules = [] + all_changes = [] + for rule, changes in zip(self.rules, self.changes): + real_changes = [] + real_expansions = [] + for expansion, change in zip(rule.expansions, changes): + maybe_pattern = [symbol in self.maybe_rules + for symbol in expansion] + n = maybe_pattern.count(True) + if n == 0: + real_expansions.append(expansion) + real_changes.append(change) + continue + assert n != len(expansion), ( + "currently an expansion needs at least one" + "symbol that always has to occur") + maybe_index = {} + for i, star in enumerate(maybe_pattern): + if star: + maybe_index[i] = len(maybe_index) + for i in range(2 ** n): + real_expansion = [] + real_change = [] + for j, (symbol, ch) in enumerate(zip(expansion, change)): + if (j not in maybe_index or + (i & (2 ** (n - 1) >> maybe_index[j])) == 0): + real_expansion.append(symbol) + real_change.append(ch) + real_expansions.append(real_expansion) + real_changes.append(real_change) + all_rules.append(Rule(rule.nonterminal, real_expansions)) + all_changes.append(real_changes) + return all_rules, all_changes + +class TransformerMaker(object): + def __init__(self, rules, changes): + self.rules = rules + self.changes = changes + self.nonterminals = dict.fromkeys([rule.nonterminal for rule in rules]) + self.code = [] + self.depth = 0 + self.blocks = [] + + def make_transformer(self, print_code=False): + self.start_block("class ToAST(object):") + for i in range(len(self.rules)): + self.create_visit_method(i) + self.start_block("def transform(self, tree):") + self.emit("assert isinstance(tree, Nonterminal)") + startsymbol = self.rules[0].nonterminal + self.emit("assert tree.symbol == %r" % (startsymbol, )) + self.emit("r = self.visit_%s(tree)" % (startsymbol, )) + self.emit("assert len(r) == 1") + self.emit("return r[0]") + self.end_block("transform") + self.end_block("ToAST") + assert not self.blocks + code = "\n".join(self.code) + if print_code: + print code + ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} + exec py.code.Source(code).compile() in ns + ToAST = ns["ToAST"] + ToAST.__module__ = "pypy.rlib.parsing.ebnfparse" + assert isinstance(ToAST, type) + assert ToAST.__name__ == "ToAST" + ToAST.source = code + return ToAST + + def emit(self, line): + for line in line.split("\n"): + self.code.append(" " * (4 * len(self.blocks)) + line) + + def start_block(self, blockstarter): + assert blockstarter.endswith(":") + self.emit(blockstarter) + self.blocks.append(blockstarter) + + def end_block(self, starterpart=""): + block = self.blocks.pop() + assert starterpart in block, "ended wrong block %s with %s" % ( + block, starterpart) + + def dispatch(self, symbol, expr): + if symbol in self.nonterminals: + return "self.visit_%s(%s)" % (symbol, expr) + return "[%s]" % (expr, ) + + def create_visit_method(self, index): + rule = self.rules[index] + change = self.changes[index] + self.start_block("def visit_%s(self, node):" % (rule.nonterminal, )) + for expansion, subchange in self.generate_conditions(index): if "<" in subchange: i = subchange.index("<") - assert subchange.count("<") == 1 - result.append(" return self.dispatch(node.children[%s])" % (i, )) + assert subchange.count("<") == 1, ( + "cannot expand more than one node in rule %s" % (rule, )) + i = subchange.index("<") + returnval = self.dispatch( + expansion[i], "node.children[%s]" % (i, )) + self.emit("return " + returnval) else: - children = [] - assert len(expansion) == len(subchange) - for i, (n, c) in enumerate(zip(expansion, subchange)): - if c == " ": - children.append("self.dispatch(node.children[%s])" % (i, )) - result.append( - " return Nonterminal(node.symbol, [%s])" % ( - (",\n" + " " * 45).join(children))) - result.append("") - return "\n".join(result) + self.create_returning_code(expansion, subchange) + self.end_block(rule.nonterminal) + + def create_returning_code(self, expansion, subchange): + assert len(expansion) == len(subchange) + children = [] + self.emit("children = []") + for i, (symbol, c) in enumerate(zip(expansion, subchange)): + if c == "[": + continue + expr = self.dispatch(symbol, "node.children[%s]" % (i, )) + if c == " ": + self.emit("children.extend(%s)" % (expr, )) + if c == ">": + self.emit("expr = %s" % (expr, )) + self.emit("assert len(expr) == 1") + self.emit("children.extend(expr[0].children)") + self.emit("return [Nonterminal(node.symbol, children)]") + + def generate_conditions(self, index): + rule = self.rules[index] + change = self.changes[index] + len_partition = {} + if len(rule.expansions) == 1: + yield rule.expansions[0], change[0] + return + for expansion, subchange in zip(rule.expansions, change): + len_partition.setdefault(len(expansion), []).append( + (expansion, subchange)) + len_partition = len_partition.items() + len_partition.sort() + last_length = len_partition[-1][0] + self.emit("length = len(node.children)") + for length, items in len_partition: + if length < last_length: + self.start_block("if length == %s:" % (length, )) + if len(items) == 1: + yield items[0] + if length < last_length: + self.end_block("if length ==") + continue + # XXX quite bad complexity, might be ok in practice + while items: + shorter = False + for i in range(length): + symbols = {} + for pos, item in enumerate(items): + expansion = item[0] + symbol = expansion[i] + symbols.setdefault(symbol, []).append((pos, item)) + symbols = symbols.items() + symbols.sort() + remove = [] + for symbol, subitems in symbols: + if (len(subitems) == 1 and + (len(items) - len(remove)) > 1): + self.start_block( + "if node.children[%s].symbol == %r:" % ( + i, symbol)) + pos, subitem = subitems[0] + yield subitem + remove.append(pos) + shorter = True + self.end_block("if node.children[") + remove.sort() + for pos in remove[::-1]: + items.pop(pos) + if shorter: + if len(items) == 1: + yield items[0] + items.pop(0) + else: + continue + break + # for the remaining items we do a brute force comparison + # could be even cleverer, but very unlikely to be useful + assert len(items) != 1 + for expansion, subchange in items: + conds = [] + for i, symbol in enumerate(expansion): + conds.append("node.children[%s].symbol == %r" % ( + i, symbol)) + self.start_block("if (%s):" % (" and ".join(conds), )) + yield expansion, subchange + self.end_block("if") + if length < last_length: + self.end_block("if length ==") + # generated code between this line and its other occurence class EBNFToAST(object): def visit_file(self, node): - if True: - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self)]) - - def visit__star_symbol0(self, node): children = [] - while len(node.children) == 2: - children.extend([node.children[0].visit(self)]) - node = node.children[-1] - children.extend([node.children[0].visit(self)]) - return Nonterminal('__list', children) + children.extend(self.visit_list(node.children[0])) + children.extend([node.children[1]]) + return [Nonterminal(node.symbol, children)] + def visit__plus_symbol0(self, node): + length = len(node.children) + if length == 1: + children = [] + children.extend(self.visit_element(node.children[0])) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_element(node.children[0])) + expr = self.visit__plus_symbol0(node.children[1]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] def visit_list(self, node): - if True: - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - + children = [] + expr = self.visit__plus_symbol0(node.children[0]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] def visit_element(self, node): - if (len(node.children) == 1 and - node.children[0].symbol == 'regex'): - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - else: - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - + length = len(node.children) + if node.children[0].symbol == 'production': + return self.visit_production(node.children[0]) + return self.visit_regex(node.children[0]) def visit_regex(self, node): - if True: - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self), - node.children[2].visit(self), - node.children[3].visit(self)]) - + children = [] + children.extend([node.children[0]]) + children.extend([node.children[1]]) + children.extend([node.children[2]]) + children.extend([node.children[3]]) + return [Nonterminal(node.symbol, children)] def visit_production(self, node): - if True: - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self), - node.children[2].visit(self), - node.children[3].visit(self)]) - + children = [] + children.extend([node.children[0]]) + children.extend([node.children[1]]) + children.extend(self.visit_body(node.children[2])) + children.extend([node.children[3]]) + return [Nonterminal(node.symbol, children)] + def visit__star_symbol0(self, node): + length = len(node.children) + if length == 2: + if (node.children[0].symbol == 'expansion' and node.children[1].symbol == '__2_|'): + children = [] + children.extend(self.visit_expansion(node.children[0])) + return [Nonterminal(node.symbol, children)] + if (node.children[0].symbol == 'expansion' and node.children[1].symbol == '__2_|'): + children = [] + children.extend(self.visit_expansion(node.children[0])) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_expansion(node.children[0])) + expr = self.visit__star_symbol0(node.children[2]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] def visit_body(self, node): - if len(node.children) == 3: - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self), - node.children[2].visit(self)]) - else: - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - + length = len(node.children) + if length == 1: + children = [] + children.extend(self.visit_expansion(node.children[0])) + return [Nonterminal(node.symbol, children)] + children = [] + expr = self.visit__star_symbol0(node.children[0]) + assert len(expr) == 1 + children.extend(expr[0].children) + children.extend(self.visit_expansion(node.children[1])) + return [Nonterminal(node.symbol, children)] + def visit__plus_symbol1(self, node): + length = len(node.children) + if length == 1: + children = [] + children.extend(self.visit_decorated(node.children[0])) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_decorated(node.children[0])) + expr = self.visit__plus_symbol1(node.children[1]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] def visit_expansion(self, node): - if len(node.children) == 2: - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self)]) - else: - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - + children = [] + expr = self.visit__plus_symbol1(node.children[0]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] + def visit_decorated(self, node): + length = len(node.children) + if length == 1: + return self.visit_enclosed(node.children[0]) + if node.children[1].symbol == '__3_*': + children = [] + children.extend(self.visit_enclosed(node.children[0])) + children.extend([node.children[1]]) + return [Nonterminal(node.symbol, children)] + if node.children[1].symbol == '__4_+': + children = [] + children.extend(self.visit_enclosed(node.children[0])) + children.extend([node.children[1]]) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_enclosed(node.children[0])) + children.extend([node.children[1]]) + return [Nonterminal(node.symbol, children)] def visit_enclosed(self, node): - if (len(node.children) == 3 and - node.children[0].symbol == '[' and - node.children[1].symbol == 'primary' and - node.children[2].symbol == ']'): - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self), - node.children[2].visit(self)]) - if (len(node.children) == 3 and - node.children[0].symbol == '<' and - node.children[1].symbol == 'primary' and - node.children[2].symbol == '>'): - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self), - node.children[2].visit(self)]) - if len(node.children) == 2: - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self)]) - else: - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - - def visit_primary_parens(self, node): - if len(node.children) == 3: - return Nonterminal(node.symbol, [node.children[0].visit(self), - node.children[1].visit(self), - node.children[2].visit(self)]) - else: - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - + length = len(node.children) + if length == 1: + return self.visit_primary(node.children[0]) + if node.children[0].symbol == '__10_(': + return self.visit_expansion(node.children[1]) + if node.children[0].symbol == '__6_[': + children = [] + children.extend([node.children[0]]) + children.extend(self.visit_expansion(node.children[1])) + children.extend([node.children[2]]) + return [Nonterminal(node.symbol, children)] + if node.children[0].symbol == '__8_>': + children = [] + children.extend([node.children[0]]) + children.extend(self.visit_expansion(node.children[1])) + children.extend([node.children[2]]) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend([node.children[0]]) + children.extend(self.visit_primary(node.children[1])) + children.extend([node.children[2]]) + return [Nonterminal(node.symbol, children)] def visit_primary(self, node): - if (len(node.children) == 1 and - node.children[0].symbol == 'NONTERMINALNAME'): - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - if (len(node.children) == 1 and - node.children[0].symbol == 'SYMBOLNAME'): - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - else: - return Nonterminal(node.symbol, [node.children[0].visit(self)]) - + length = len(node.children) + if node.children[0].symbol == 'NONTERMINALNAME': + children = [] + children.extend([node.children[0]]) + return [Nonterminal(node.symbol, children)] + if node.children[0].symbol == 'QUOTE': + children = [] + children.extend([node.children[0]]) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend([node.children[0]]) + return [Nonterminal(node.symbol, children)] parser = PackratParser([Rule('file', [['list', 'EOF']]), - Rule('_star_symbol0', [['element', '_star_symbol0'], ['element']]), - Rule('list', [['_star_symbol0']]), + Rule('_plus_symbol0', [['element', '_plus_symbol0'], ['element']]), + Rule('list', [['_plus_symbol0']]), Rule('element', [['regex'], ['production']]), - Rule('regex', [['SYMBOLNAME', ':', 'QUOTE', ';']]), - Rule('production', [['NONTERMINALNAME', ':', 'body', ';']]), - Rule('body', [['expansion', '|', 'body'], ['expansion']]), - Rule('expansion', [['enclosed', 'expansion'], ['enclosed']]), - Rule('enclosed', [['[', 'primary', ']'], ['<', 'primary', '>'], ['primary_parens', '*'], ['primary']]), - Rule('primary_parens', [['(', 'expansion', ')'], ['primary']]), + Rule('regex', [['SYMBOLNAME', '__0_:', 'QUOTE', '__1_;']]), + Rule('production', [['NONTERMINALNAME', '__0_:', 'body', '__1_;']]), + Rule('_star_symbol0', [['expansion', '__2_|', '_star_symbol0'], ['expansion', '__2_|'], ['expansion', '__2_|']]), + Rule('body', [['_star_symbol0', 'expansion'], ['expansion']]), + Rule('_plus_symbol1', [['decorated', '_plus_symbol1'], ['decorated']]), + Rule('expansion', [['_plus_symbol1']]), + Rule('decorated', [['enclosed', '__3_*'], ['enclosed', '__4_+'], ['enclosed', '__5_?'], ['enclosed']]), + Rule('enclosed', [['__6_[', 'expansion', '__7_]'], ['__8_>', 'expansion', '__9_<'], ['__9_<', 'primary', '__8_>'], ['__10_(', 'expansion', '__11_)'], ['primary']]), Rule('primary', [['NONTERMINALNAME'], ['SYMBOLNAME'], ['QUOTE']])], 'file') def recognize(runner, i): @@ -349,26 +594,30 @@ state = 8 elif char == '(': state = 9 - elif char == '*': + elif char == '+': state = 10 - elif char == ';': + elif char == '*': state = 11 - elif char == ':': + elif char == ';': state = 12 - elif char == '<': + elif char == ':': state = 13 - elif char == '>': + elif char == '<': state = 14 - elif char == '[': + elif char == '?': state = 15 - elif char == ']': + elif char == '>': state = 16 - elif char == '_': + elif char == '[': state = 17 - elif 'a' <= char <= 'z': + elif char == ']': state = 18 - elif char == '|': + elif char == '_': state = 19 + elif 'a' <= char <= 'z': + state = 20 + elif char == '|': + state = 21 else: break if state == 3: @@ -396,7 +645,7 @@ runner.state = 5 return ~i if char == '\n': - state = 25 + state = 27 elif '\x00' <= char <= '\t': state = 5 continue @@ -413,7 +662,9 @@ runner.state = 6 return ~i if char == '\\': - state = 22 + state = 24 + elif char == '"': + state = 25 elif '\x00' <= char <= '!': state = 6 continue @@ -423,8 +674,6 @@ elif ']' <= char <= '\xff': state = 6 continue - elif char == '"': - state = 23 else: break if state == 7: @@ -435,73 +684,73 @@ runner.state = 7 return ~i if char == '"': - state = 20 + state = 22 else: break - if state == 17: + if state == 19: runner.last_matched_index = i - 1 runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 17 + runner.state = 19 return i if char == '_': - state = 17 + state = 19 continue - elif '0' <= char <= '9': - state = 18 - elif 'a' <= char <= 'z': - state = 18 elif 'A' <= char <= 'Z': state = 3 continue + elif '0' <= char <= '9': + state = 20 + elif 'a' <= char <= 'z': + state = 20 else: break - if state == 18: + if state == 20: runner.last_matched_index = i - 1 runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 18 + runner.state = 20 return i if '0' <= char <= '9': - state = 18 + state = 20 continue elif char == '_': - state = 18 + state = 20 continue elif 'a' <= char <= 'z': - state = 18 + state = 20 continue else: break - if state == 20: + if state == 22: if i < len(input): char = input[i] i += 1 else: - runner.state = 20 + runner.state = 22 return ~i if char == "'": - state = 21 + state = 23 else: break - if state == 22: + if state == 24: if i < len(input): char = input[i] i += 1 else: - runner.state = 22 + runner.state = 24 return ~i - if char == '"': + if char == '\\': state = 24 - elif char == '\\': - state = 22 continue + elif char == '"': + state = 26 elif '\x00' <= char <= '!': state = 6 continue @@ -513,23 +762,23 @@ continue else: break - if state == 24: + if state == 26: runner.last_matched_index = i - 1 runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 24 + runner.state = 26 return i - if '\x00' <= char <= '!': + if char == '"': + state = 25 + elif '\x00' <= char <= '!': state = 6 continue elif '#' <= char <= '\xff': state = 6 continue - elif char == '"': - state = 23 else: break runner.last_matched_state = state @@ -542,7 +791,7 @@ break runner.state = state return ~i -lexer = DummyLexer(recognize, DFA(26, +lexer = DummyLexer(recognize, DFA(28, {(0, '\t'): 1, (0, '\n'): 2, (0, ' '): 4, @@ -551,11 +800,13 @@ (0, "'"): 7, (0, '('): 9, (0, ')'): 8, - (0, '*'): 10, - (0, ':'): 12, - (0, ';'): 11, - (0, '<'): 13, - (0, '>'): 14, + (0, '*'): 11, + (0, '+'): 10, + (0, ':'): 13, + (0, ';'): 12, + (0, '<'): 14, + (0, '>'): 16, + (0, '?'): 15, (0, 'A'): 3, (0, 'B'): 3, (0, 'C'): 3, @@ -582,36 +833,36 @@ (0, 'X'): 3, (0, 'Y'): 3, (0, 'Z'): 3, - (0, '['): 15, - (0, ']'): 16, - (0, '_'): 17, - (0, 'a'): 18, - (0, 'b'): 18, - (0, 'c'): 18, - (0, 'd'): 18, - (0, 'e'): 18, - (0, 'f'): 18, - (0, 'g'): 18, - (0, 'h'): 18, - (0, 'i'): 18, - (0, 'j'): 18, - (0, 'k'): 18, - (0, 'l'): 18, - (0, 'm'): 18, - (0, 'n'): 18, - (0, 'o'): 18, - (0, 'p'): 18, - (0, 'q'): 18, - (0, 'r'): 18, - (0, 's'): 18, - (0, 't'): 18, - (0, 'u'): 18, - (0, 'v'): 18, - (0, 'w'): 18, - (0, 'x'): 18, - (0, 'y'): 18, - (0, 'z'): 18, - (0, '|'): 19, + (0, '['): 17, + (0, ']'): 18, + (0, '_'): 19, + (0, 'a'): 20, + (0, 'b'): 20, + (0, 'c'): 20, + (0, 'd'): 20, + (0, 'e'): 20, + (0, 'f'): 20, + (0, 'g'): 20, + (0, 'h'): 20, + (0, 'i'): 20, + (0, 'j'): 20, + (0, 'k'): 20, + (0, 'l'): 20, + (0, 'm'): 20, + (0, 'n'): 20, + (0, 'o'): 20, + (0, 'p'): 20, + (0, 'q'): 20, + (0, 'r'): 20, + (0, 's'): 20, + (0, 't'): 20, + (0, 'u'): 20, + (0, 'v'): 20, + (0, 'w'): 20, + (0, 'x'): 20, + (0, 'y'): 20, + (0, 'z'): 20, + (0, '|'): 21, (3, 'A'): 3, (3, 'B'): 3, (3, 'C'): 3, @@ -649,7 +900,7 @@ (5, '\x07'): 5, (5, '\x08'): 5, (5, '\t'): 5, - (5, '\n'): 25, + (5, '\n'): 27, (5, '\x0b'): 5, (5, '\x0c'): 5, (5, '\r'): 5, @@ -929,7 +1180,7 @@ (6, '\x1f'): 6, (6, ' '): 6, (6, '!'): 6, - (6, '"'): 23, + (6, '"'): 25, (6, '#'): 6, (6, '$'): 6, (6, '%'): 6, @@ -987,7 +1238,7 @@ (6, 'Y'): 6, (6, 'Z'): 6, (6, '['): 6, - (6, '\\'): 22, + (6, '\\'): 24, (6, ']'): 6, (6, '^'): 6, (6, '_'): 6, @@ -1151,364 +1402,108 @@ (6, '\xfd'): 6, (6, '\xfe'): 6, (6, '\xff'): 6, - (7, '"'): 20, - (17, '0'): 18, - (17, '1'): 18, - (17, '2'): 18, - (17, '3'): 18, - (17, '4'): 18, - (17, '5'): 18, - (17, '6'): 18, - (17, '7'): 18, - (17, '8'): 18, - (17, '9'): 18, - (17, 'A'): 3, - (17, 'B'): 3, - (17, 'C'): 3, - (17, 'D'): 3, - (17, 'E'): 3, - (17, 'F'): 3, - (17, 'G'): 3, - (17, 'H'): 3, - (17, 'I'): 3, - (17, 'J'): 3, - (17, 'K'): 3, - (17, 'L'): 3, - (17, 'M'): 3, - (17, 'N'): 3, - (17, 'O'): 3, - (17, 'P'): 3, - (17, 'Q'): 3, - (17, 'R'): 3, - (17, 'S'): 3, - (17, 'T'): 3, - (17, 'U'): 3, - (17, 'V'): 3, - (17, 'W'): 3, - (17, 'X'): 3, - (17, 'Y'): 3, - (17, 'Z'): 3, - (17, '_'): 17, - (17, 'a'): 18, - (17, 'b'): 18, - (17, 'c'): 18, - (17, 'd'): 18, - (17, 'e'): 18, - (17, 'f'): 18, - (17, 'g'): 18, - (17, 'h'): 18, - (17, 'i'): 18, - (17, 'j'): 18, - (17, 'k'): 18, - (17, 'l'): 18, - (17, 'm'): 18, - (17, 'n'): 18, - (17, 'o'): 18, - (17, 'p'): 18, - (17, 'q'): 18, - (17, 'r'): 18, - (17, 's'): 18, - (17, 't'): 18, - (17, 'u'): 18, - (17, 'v'): 18, - (17, 'w'): 18, - (17, 'x'): 18, - (17, 'y'): 18, - (17, 'z'): 18, - (18, '0'): 18, - (18, '1'): 18, - (18, '2'): 18, - (18, '3'): 18, - (18, '4'): 18, - (18, '5'): 18, - (18, '6'): 18, - (18, '7'): 18, - (18, '8'): 18, - (18, '9'): 18, - (18, '_'): 18, - (18, 'a'): 18, - (18, 'b'): 18, - (18, 'c'): 18, - (18, 'd'): 18, - (18, 'e'): 18, - (18, 'f'): 18, - (18, 'g'): 18, - (18, 'h'): 18, - (18, 'i'): 18, - (18, 'j'): 18, - (18, 'k'): 18, - (18, 'l'): 18, - (18, 'm'): 18, - (18, 'n'): 18, - (18, 'o'): 18, - (18, 'p'): 18, - (18, 'q'): 18, - (18, 'r'): 18, - (18, 's'): 18, - (18, 't'): 18, - (18, 'u'): 18, - (18, 'v'): 18, - (18, 'w'): 18, - (18, 'x'): 18, - (18, 'y'): 18, - (18, 'z'): 18, - (20, "'"): 21, - (22, '\x00'): 6, - (22, '\x01'): 6, - (22, '\x02'): 6, - (22, '\x03'): 6, - (22, '\x04'): 6, - (22, '\x05'): 6, - (22, '\x06'): 6, - (22, '\x07'): 6, - (22, '\x08'): 6, - (22, '\t'): 6, - (22, '\n'): 6, - (22, '\x0b'): 6, - (22, '\x0c'): 6, - (22, '\r'): 6, - (22, '\x0e'): 6, - (22, '\x0f'): 6, - (22, '\x10'): 6, - (22, '\x11'): 6, - (22, '\x12'): 6, - (22, '\x13'): 6, - (22, '\x14'): 6, - (22, '\x15'): 6, - (22, '\x16'): 6, - (22, '\x17'): 6, - (22, '\x18'): 6, - (22, '\x19'): 6, - (22, '\x1a'): 6, - (22, '\x1b'): 6, - (22, '\x1c'): 6, - (22, '\x1d'): 6, - (22, '\x1e'): 6, - (22, '\x1f'): 6, - (22, ' '): 6, - (22, '!'): 6, - (22, '"'): 24, - (22, '#'): 6, - (22, '$'): 6, - (22, '%'): 6, - (22, '&'): 6, - (22, "'"): 6, - (22, '('): 6, - (22, ')'): 6, - (22, '*'): 6, - (22, '+'): 6, - (22, ','): 6, - (22, '-'): 6, - (22, '.'): 6, - (22, '/'): 6, - (22, '0'): 6, - (22, '1'): 6, - (22, '2'): 6, - (22, '3'): 6, - (22, '4'): 6, - (22, '5'): 6, - (22, '6'): 6, - (22, '7'): 6, - (22, '8'): 6, - (22, '9'): 6, - (22, ':'): 6, - (22, ';'): 6, - (22, '<'): 6, - (22, '='): 6, - (22, '>'): 6, - (22, '?'): 6, - (22, '@'): 6, - (22, 'A'): 6, - (22, 'B'): 6, - (22, 'C'): 6, - (22, 'D'): 6, - (22, 'E'): 6, - (22, 'F'): 6, - (22, 'G'): 6, - (22, 'H'): 6, - (22, 'I'): 6, - (22, 'J'): 6, - (22, 'K'): 6, - (22, 'L'): 6, - (22, 'M'): 6, - (22, 'N'): 6, - (22, 'O'): 6, - (22, 'P'): 6, - (22, 'Q'): 6, - (22, 'R'): 6, - (22, 'S'): 6, - (22, 'T'): 6, - (22, 'U'): 6, - (22, 'V'): 6, - (22, 'W'): 6, - (22, 'X'): 6, - (22, 'Y'): 6, - (22, 'Z'): 6, - (22, '['): 6, - (22, '\\'): 22, - (22, ']'): 6, - (22, '^'): 6, - (22, '_'): 6, - (22, '`'): 6, - (22, 'a'): 6, - (22, 'b'): 6, - (22, 'c'): 6, - (22, 'd'): 6, - (22, 'e'): 6, - (22, 'f'): 6, - (22, 'g'): 6, - (22, 'h'): 6, - (22, 'i'): 6, - (22, 'j'): 6, - (22, 'k'): 6, - (22, 'l'): 6, - (22, 'm'): 6, - (22, 'n'): 6, - (22, 'o'): 6, - (22, 'p'): 6, - (22, 'q'): 6, - (22, 'r'): 6, - (22, 's'): 6, - (22, 't'): 6, - (22, 'u'): 6, - (22, 'v'): 6, - (22, 'w'): 6, - (22, 'x'): 6, - (22, 'y'): 6, - (22, 'z'): 6, - (22, '{'): 6, - (22, '|'): 6, - (22, '}'): 6, - (22, '~'): 6, - (22, '\x7f'): 6, - (22, '\x80'): 6, - (22, '\x81'): 6, - (22, '\x82'): 6, - (22, '\x83'): 6, - (22, '\x84'): 6, - (22, '\x85'): 6, - (22, '\x86'): 6, - (22, '\x87'): 6, - (22, '\x88'): 6, - (22, '\x89'): 6, - (22, '\x8a'): 6, - (22, '\x8b'): 6, - (22, '\x8c'): 6, - (22, '\x8d'): 6, - (22, '\x8e'): 6, - (22, '\x8f'): 6, - (22, '\x90'): 6, - (22, '\x91'): 6, - (22, '\x92'): 6, - (22, '\x93'): 6, - (22, '\x94'): 6, - (22, '\x95'): 6, - (22, '\x96'): 6, - (22, '\x97'): 6, - (22, '\x98'): 6, - (22, '\x99'): 6, - (22, '\x9a'): 6, - (22, '\x9b'): 6, - (22, '\x9c'): 6, - (22, '\x9d'): 6, - (22, '\x9e'): 6, - (22, '\x9f'): 6, - (22, '\xa0'): 6, - (22, '\xa1'): 6, - (22, '\xa2'): 6, - (22, '\xa3'): 6, - (22, '\xa4'): 6, - (22, '\xa5'): 6, - (22, '\xa6'): 6, - (22, '\xa7'): 6, - (22, '\xa8'): 6, - (22, '\xa9'): 6, - (22, '\xaa'): 6, - (22, '\xab'): 6, - (22, '\xac'): 6, - (22, '\xad'): 6, - (22, '\xae'): 6, - (22, '\xaf'): 6, - (22, '\xb0'): 6, - (22, '\xb1'): 6, - (22, '\xb2'): 6, - (22, '\xb3'): 6, - (22, '\xb4'): 6, - (22, '\xb5'): 6, - (22, '\xb6'): 6, - (22, '\xb7'): 6, - (22, '\xb8'): 6, - (22, '\xb9'): 6, - (22, '\xba'): 6, - (22, '\xbb'): 6, - (22, '\xbc'): 6, - (22, '\xbd'): 6, - (22, '\xbe'): 6, - (22, '\xbf'): 6, - (22, '\xc0'): 6, - (22, '\xc1'): 6, - (22, '\xc2'): 6, - (22, '\xc3'): 6, - (22, '\xc4'): 6, - (22, '\xc5'): 6, - (22, '\xc6'): 6, - (22, '\xc7'): 6, - (22, '\xc8'): 6, - (22, '\xc9'): 6, - (22, '\xca'): 6, - (22, '\xcb'): 6, - (22, '\xcc'): 6, - (22, '\xcd'): 6, - (22, '\xce'): 6, - (22, '\xcf'): 6, - (22, '\xd0'): 6, - (22, '\xd1'): 6, - (22, '\xd2'): 6, - (22, '\xd3'): 6, - (22, '\xd4'): 6, - (22, '\xd5'): 6, - (22, '\xd6'): 6, - (22, '\xd7'): 6, - (22, '\xd8'): 6, - (22, '\xd9'): 6, - (22, '\xda'): 6, - (22, '\xdb'): 6, - (22, '\xdc'): 6, - (22, '\xdd'): 6, - (22, '\xde'): 6, - (22, '\xdf'): 6, - (22, '\xe0'): 6, - (22, '\xe1'): 6, - (22, '\xe2'): 6, - (22, '\xe3'): 6, - (22, '\xe4'): 6, - (22, '\xe5'): 6, - (22, '\xe6'): 6, - (22, '\xe7'): 6, - (22, '\xe8'): 6, - (22, '\xe9'): 6, - (22, '\xea'): 6, - (22, '\xeb'): 6, - (22, '\xec'): 6, - (22, '\xed'): 6, - (22, '\xee'): 6, - (22, '\xef'): 6, - (22, '\xf0'): 6, - (22, '\xf1'): 6, - (22, '\xf2'): 6, - (22, '\xf3'): 6, - (22, '\xf4'): 6, - (22, '\xf5'): 6, - (22, '\xf6'): 6, - (22, '\xf7'): 6, - (22, '\xf8'): 6, - (22, '\xf9'): 6, - (22, '\xfa'): 6, - (22, '\xfb'): 6, - (22, '\xfc'): 6, - (22, '\xfd'): 6, - (22, '\xfe'): 6, - (22, '\xff'): 6, + (7, '"'): 22, + (19, '0'): 20, + (19, '1'): 20, + (19, '2'): 20, + (19, '3'): 20, + (19, '4'): 20, + (19, '5'): 20, + (19, '6'): 20, + (19, '7'): 20, + (19, '8'): 20, + (19, '9'): 20, + (19, 'A'): 3, + (19, 'B'): 3, + (19, 'C'): 3, + (19, 'D'): 3, + (19, 'E'): 3, + (19, 'F'): 3, + (19, 'G'): 3, + (19, 'H'): 3, + (19, 'I'): 3, + (19, 'J'): 3, + (19, 'K'): 3, + (19, 'L'): 3, + (19, 'M'): 3, + (19, 'N'): 3, + (19, 'O'): 3, + (19, 'P'): 3, + (19, 'Q'): 3, + (19, 'R'): 3, + (19, 'S'): 3, + (19, 'T'): 3, + (19, 'U'): 3, + (19, 'V'): 3, + (19, 'W'): 3, + (19, 'X'): 3, + (19, 'Y'): 3, + (19, 'Z'): 3, + (19, '_'): 19, + (19, 'a'): 20, + (19, 'b'): 20, + (19, 'c'): 20, + (19, 'd'): 20, + (19, 'e'): 20, + (19, 'f'): 20, + (19, 'g'): 20, + (19, 'h'): 20, + (19, 'i'): 20, + (19, 'j'): 20, + (19, 'k'): 20, + (19, 'l'): 20, + (19, 'm'): 20, + (19, 'n'): 20, + (19, 'o'): 20, + (19, 'p'): 20, + (19, 'q'): 20, + (19, 'r'): 20, + (19, 's'): 20, + (19, 't'): 20, + (19, 'u'): 20, + (19, 'v'): 20, + (19, 'w'): 20, + (19, 'x'): 20, + (19, 'y'): 20, + (19, 'z'): 20, + (20, '0'): 20, + (20, '1'): 20, + (20, '2'): 20, + (20, '3'): 20, + (20, '4'): 20, + (20, '5'): 20, + (20, '6'): 20, + (20, '7'): 20, + (20, '8'): 20, + (20, '9'): 20, + (20, '_'): 20, + (20, 'a'): 20, + (20, 'b'): 20, + (20, 'c'): 20, + (20, 'd'): 20, + (20, 'e'): 20, + (20, 'f'): 20, + (20, 'g'): 20, + (20, 'h'): 20, + (20, 'i'): 20, + (20, 'j'): 20, + (20, 'k'): 20, + (20, 'l'): 20, + (20, 'm'): 20, + (20, 'n'): 20, + (20, 'o'): 20, + (20, 'p'): 20, + (20, 'q'): 20, + (20, 'r'): 20, + (20, 's'): 20, + (20, 't'): 20, + (20, 'u'): 20, + (20, 'v'): 20, + (20, 'w'): 20, + (20, 'x'): 20, + (20, 'y'): 20, + (20, 'z'): 20, + (22, "'"): 23, (24, '\x00'): 6, (24, '\x01'): 6, (24, '\x02'): 6, @@ -1543,7 +1538,7 @@ (24, '\x1f'): 6, (24, ' '): 6, (24, '!'): 6, - (24, '"'): 23, + (24, '"'): 26, (24, '#'): 6, (24, '$'): 6, (24, '%'): 6, @@ -1601,7 +1596,7 @@ (24, 'Y'): 6, (24, 'Z'): 6, (24, '['): 6, - (24, '\\'): 6, + (24, '\\'): 24, (24, ']'): 6, (24, '^'): 6, (24, '_'): 6, @@ -1764,9 +1759,265 @@ (24, '\xfc'): 6, (24, '\xfd'): 6, (24, '\xfe'): 6, - (24, '\xff'): 6}, - set([1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23, 24, 25]), - set([1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23, 24, 25]), + (24, '\xff'): 6, + (26, '\x00'): 6, + (26, '\x01'): 6, + (26, '\x02'): 6, + (26, '\x03'): 6, + (26, '\x04'): 6, + (26, '\x05'): 6, + (26, '\x06'): 6, + (26, '\x07'): 6, + (26, '\x08'): 6, + (26, '\t'): 6, + (26, '\n'): 6, + (26, '\x0b'): 6, + (26, '\x0c'): 6, + (26, '\r'): 6, + (26, '\x0e'): 6, + (26, '\x0f'): 6, + (26, '\x10'): 6, + (26, '\x11'): 6, + (26, '\x12'): 6, + (26, '\x13'): 6, + (26, '\x14'): 6, + (26, '\x15'): 6, + (26, '\x16'): 6, + (26, '\x17'): 6, + (26, '\x18'): 6, + (26, '\x19'): 6, + (26, '\x1a'): 6, + (26, '\x1b'): 6, + (26, '\x1c'): 6, + (26, '\x1d'): 6, + (26, '\x1e'): 6, + (26, '\x1f'): 6, + (26, ' '): 6, + (26, '!'): 6, + (26, '"'): 25, + (26, '#'): 6, + (26, '$'): 6, + (26, '%'): 6, + (26, '&'): 6, + (26, "'"): 6, + (26, '('): 6, + (26, ')'): 6, + (26, '*'): 6, + (26, '+'): 6, + (26, ','): 6, + (26, '-'): 6, + (26, '.'): 6, + (26, '/'): 6, + (26, '0'): 6, + (26, '1'): 6, + (26, '2'): 6, + (26, '3'): 6, + (26, '4'): 6, + (26, '5'): 6, + (26, '6'): 6, + (26, '7'): 6, + (26, '8'): 6, + (26, '9'): 6, + (26, ':'): 6, + (26, ';'): 6, + (26, '<'): 6, + (26, '='): 6, + (26, '>'): 6, + (26, '?'): 6, + (26, '@'): 6, + (26, 'A'): 6, + (26, 'B'): 6, + (26, 'C'): 6, + (26, 'D'): 6, + (26, 'E'): 6, + (26, 'F'): 6, + (26, 'G'): 6, + (26, 'H'): 6, + (26, 'I'): 6, + (26, 'J'): 6, + (26, 'K'): 6, + (26, 'L'): 6, + (26, 'M'): 6, + (26, 'N'): 6, + (26, 'O'): 6, + (26, 'P'): 6, + (26, 'Q'): 6, + (26, 'R'): 6, + (26, 'S'): 6, + (26, 'T'): 6, + (26, 'U'): 6, + (26, 'V'): 6, + (26, 'W'): 6, + (26, 'X'): 6, + (26, 'Y'): 6, + (26, 'Z'): 6, + (26, '['): 6, + (26, '\\'): 6, + (26, ']'): 6, + (26, '^'): 6, + (26, '_'): 6, + (26, '`'): 6, + (26, 'a'): 6, + (26, 'b'): 6, + (26, 'c'): 6, + (26, 'd'): 6, + (26, 'e'): 6, + (26, 'f'): 6, + (26, 'g'): 6, + (26, 'h'): 6, + (26, 'i'): 6, + (26, 'j'): 6, + (26, 'k'): 6, + (26, 'l'): 6, + (26, 'm'): 6, + (26, 'n'): 6, + (26, 'o'): 6, + (26, 'p'): 6, + (26, 'q'): 6, + (26, 'r'): 6, + (26, 's'): 6, + (26, 't'): 6, + (26, 'u'): 6, + (26, 'v'): 6, + (26, 'w'): 6, + (26, 'x'): 6, + (26, 'y'): 6, + (26, 'z'): 6, + (26, '{'): 6, + (26, '|'): 6, + (26, '}'): 6, + (26, '~'): 6, + (26, '\x7f'): 6, + (26, '\x80'): 6, + (26, '\x81'): 6, + (26, '\x82'): 6, + (26, '\x83'): 6, + (26, '\x84'): 6, + (26, '\x85'): 6, + (26, '\x86'): 6, + (26, '\x87'): 6, + (26, '\x88'): 6, + (26, '\x89'): 6, + (26, '\x8a'): 6, + (26, '\x8b'): 6, + (26, '\x8c'): 6, + (26, '\x8d'): 6, + (26, '\x8e'): 6, + (26, '\x8f'): 6, + (26, '\x90'): 6, + (26, '\x91'): 6, + (26, '\x92'): 6, + (26, '\x93'): 6, + (26, '\x94'): 6, + (26, '\x95'): 6, + (26, '\x96'): 6, + (26, '\x97'): 6, + (26, '\x98'): 6, + (26, '\x99'): 6, + (26, '\x9a'): 6, + (26, '\x9b'): 6, + (26, '\x9c'): 6, + (26, '\x9d'): 6, + (26, '\x9e'): 6, + (26, '\x9f'): 6, + (26, '\xa0'): 6, + (26, '\xa1'): 6, + (26, '\xa2'): 6, + (26, '\xa3'): 6, + (26, '\xa4'): 6, + (26, '\xa5'): 6, + (26, '\xa6'): 6, + (26, '\xa7'): 6, + (26, '\xa8'): 6, + (26, '\xa9'): 6, + (26, '\xaa'): 6, + (26, '\xab'): 6, + (26, '\xac'): 6, + (26, '\xad'): 6, + (26, '\xae'): 6, + (26, '\xaf'): 6, + (26, '\xb0'): 6, + (26, '\xb1'): 6, + (26, '\xb2'): 6, + (26, '\xb3'): 6, + (26, '\xb4'): 6, + (26, '\xb5'): 6, + (26, '\xb6'): 6, + (26, '\xb7'): 6, + (26, '\xb8'): 6, + (26, '\xb9'): 6, + (26, '\xba'): 6, + (26, '\xbb'): 6, + (26, '\xbc'): 6, + (26, '\xbd'): 6, + (26, '\xbe'): 6, + (26, '\xbf'): 6, + (26, '\xc0'): 6, + (26, '\xc1'): 6, + (26, '\xc2'): 6, + (26, '\xc3'): 6, + (26, '\xc4'): 6, + (26, '\xc5'): 6, + (26, '\xc6'): 6, + (26, '\xc7'): 6, + (26, '\xc8'): 6, + (26, '\xc9'): 6, + (26, '\xca'): 6, + (26, '\xcb'): 6, + (26, '\xcc'): 6, + (26, '\xcd'): 6, + (26, '\xce'): 6, + (26, '\xcf'): 6, + (26, '\xd0'): 6, + (26, '\xd1'): 6, + (26, '\xd2'): 6, + (26, '\xd3'): 6, + (26, '\xd4'): 6, + (26, '\xd5'): 6, + (26, '\xd6'): 6, + (26, '\xd7'): 6, + (26, '\xd8'): 6, + (26, '\xd9'): 6, + (26, '\xda'): 6, + (26, '\xdb'): 6, + (26, '\xdc'): 6, + (26, '\xdd'): 6, + (26, '\xde'): 6, + (26, '\xdf'): 6, + (26, '\xe0'): 6, + (26, '\xe1'): 6, + (26, '\xe2'): 6, + (26, '\xe3'): 6, + (26, '\xe4'): 6, + (26, '\xe5'): 6, + (26, '\xe6'): 6, + (26, '\xe7'): 6, + (26, '\xe8'): 6, + (26, '\xe9'): 6, + (26, '\xea'): 6, + (26, '\xeb'): 6, + (26, '\xec'): 6, + (26, '\xed'): 6, + (26, '\xee'): 6, + (26, '\xef'): 6, + (26, '\xf0'): 6, + (26, '\xf1'): 6, + (26, '\xf2'): 6, + (26, '\xf3'): 6, + (26, '\xf4'): 6, + (26, '\xf5'): 6, + (26, '\xf6'): 6, + (26, '\xf7'): 6, + (26, '\xf8'): 6, + (26, '\xf9'): 6, + (26, '\xfa'): 6, + (26, '\xfb'): 6, + (26, '\xfc'): 6, + (26, '\xfd'): 6, + (26, '\xfe'): 6, + (26, '\xff'): 6}, + set([1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 27]), + set([1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 25, 26, 27]), ['0, 0, 0, final*, start*, 0, 0, 1, final*, start*, 0, 0, 0, start|, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0', 'IGNORE', 'IGNORE', @@ -1775,18 +2026,20 @@ '1, 0, start|, 0, final*, start*, 0, 0, 1, final|, start|, 0, final*, start*, 0, 0, final|, start|, 0, 1, final*, start*, 0', '1, 0, final*, start*, start|, 0, final|, final*, start*, 0, 0, 0, start|, 0, 0, final*, final|, start|, 0, final|, final*, start*, 0, 0, 0, start|, 1, 0, start*, 0, final*, final|, start|, 0, 1, final*, start*, 0, 0, 0, final|, start|, 0, start*, 0, 1, final|, start|, 0, final*, start*, 0, final*, final*, 1, final|, final*, 0, start|, 0, final*, start*, final*, start*, 0, final|, start|, 0, 0, 0, final|, start|, 0, 1, final*, start*, 0, final*, final*, final|, 1, final*, 0, start|, 0, final*, start*, final*, start*, 0, final|, start|, 0, 0, 0, final*, start*, final*, start*, 0, final|, start|, 0, 0, final*, final*, 0, 1, final|, final*, 0, start|, 0, final*, start*, final*, start*, 0, final|, start|, 0, 0, final*, final*, 0, final|, 1, final*, 0, start|, 0, final*, start*, final*, start*, 0, final|, start|, 0, 0, final*, final*, 0, final*, 0, 1, final|, start|, 0, 1, final*, start*, final*, start*, 0, final|, start|, 0, 0, final*, final*, 0, final*, 0, final|, start|, 0, final*, start*, final*, start*, 0, final|, start|, 0, 0, final*, final*, 0, 1, final|, final*, 0, 1, final|, start|, 0, 1, final*, start*, final*, start*, 0, final|, start|, 0, 0, final*, final*, 0, final|, 1, final*, 0, final|, start|, 0, 1, final|, start|, 0, final*, start*, 0, final*, final*, 1, final|, final*, 0, 1, final|, start|, 0, final*, start*, final*, start*, 0, final|, start|, 0, 0, 0, final|, start|, 0, 1, final*, start*, 0, final*, final*, final|, 1, final*, 0, final|, start|, 0, 1, final*, start*, final*, start*, 0, final|, start|, 0, 0, 0, 1, final|, start|, 0, final*, start*, 0, final*, final*, final*, 0, 1, final|, start|, 0, final*, start*, final*, start*, 0, final|, start|, 0, 0, 0, final|, start|, 0, 1, final*, start*, 0, final*, final*, final*, 0, final|, start|, 0, 1, final*, start*, final*, start*, 0, final|, start|, 0, 0', '1', - ')', - '(', - '*', - ';', - ':', - '<', - '>', - '[', - ']', + '__11_)', + '__10_(', + '__4_+', + '__3_*', + '__1_;', + '__0_:', + '__9_<', + '__5_?', + '__8_>', + '__6_[', + '__7_]', 'NONTERMINALNAME', 'NONTERMINALNAME', - '|', + '__2_|', '2', 'QUOTE', '0, 1, final*, 0, final|, start|, 0, final*, 0, final|, start|, 0, 1, final*, 0, final|, start|, 0, 1, final*, start*, final*, start*, 0, final|, start|, 0, 1, 0, 0, final|, start|, 0, 1, final*, start*, 0, 1, 0, final|, start|, 0, 0, start|, 0, final*, start*, 0, final|, start|, 0, 1, 0, 0, final|, start|, 0, 1, final*, start*, 0, 1, final*, 0, final|, start|, 0, final*, 0, start|, 0, final*, 0, final|, start|, 0, 1, final*, start*, final*, start*, 0, final|, start|, 0, 1, 0, 0, final|, start|, 0, 1, final*, start*, 0, 1, final*, 0, final|, start|, 0, final*, 0, final|, start|, 0, 1, final*, 0, start|, 0, final*, start*, final*, start*, 0, final|, start|, 0, 1, 0, 0, final|, start|, 0, 1, final*, start*, 0, 1, final*, 0, final|, start|, 0, final*, 0, final|, start|, 0, 1, final*, 0, final|, start|, 0, 1, final*, start*, final*, start*, 0, final|, start|, 0, 1, 0, 0, 1, final*, 0, final|, start|, 0, final*, 0, start|, 0, final*, 0, final|, start|, 0, 1, final*, start*, final*, start*, 0, final|, start|, 0, 1, 0', @@ -1801,7 +2054,8 @@ s = "# GENERATED CODE BETWEEN THIS LINE AND ITS OTHER OCCURENCE\n".lower() pre, gen, after = oldcontent.split(s) - parser, lexer, transformer = make_ebnf_parser() + parser, lexer, ToAST = make_ebnf_parser() + transformer = ToAST.source newcontent = "%s%s%s\nparser = %r\n%s\n%s%s" % ( pre, s, transformer.replace("ToAST", "EBNFToAST"), parser, lexer.get_dummy_repr(), s, after) Modified: pypy/dist/pypy/rlib/parsing/parsing.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/parsing.py (original) +++ pypy/dist/pypy/rlib/parsing/parsing.py Mon Nov 27 19:01:48 2006 @@ -140,7 +140,14 @@ self.matched[i, symbol] = result return result else: - error = ErrorInformation(i, [symbol]) + # XXX hack unnice: handles the sort of token names that + # ebnfparse produces + if (symbol.startswith("__") and + symbol.split("_")[2][0] in "0123456789"): + expected = symbol.split("_")[-1] + else: + expected = symbol + error = ErrorInformation(i, [expected]) except IndexError: error = ErrorInformation(i) return None, 0, error Modified: pypy/dist/pypy/rlib/parsing/regexparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/regexparse.py (original) +++ pypy/dist/pypy/rlib/parsing/regexparse.py Mon Nov 27 19:01:48 2006 @@ -1,5 +1,6 @@ import py from pypy.rlib.parsing.parsing import PackratParser, Rule +from pypy.rlib.parsing.tree import Nonterminal from pypy.rlib.parsing.regex import StringExpression, RangeExpression from pypy.rlib.parsing.lexer import Lexer, DummyLexer from pypy.rlib.parsing.deterministic import compress_char_set, DFA @@ -16,6 +17,48 @@ "\\": "\\" } +for i in range(256): + # 'x' and numbers are reserved for hexadecimal/octal escapes + if chr(i) in 'x01234567': + continue + escaped = "\\" + chr(i) + if escaped not in ESCAPES: + ESCAPES[escaped] = chr(i) +for a in "0123456789ABCDEFabcdef": + for b in "0123456789ABCDEFabcdef": + escaped = "\\x%s%s" % (a, b) + if escaped not in ESCAPES: + ESCAPES[escaped] = chr(int("%s%s" % (a, b), 16)) +for a in "0123": + for b in "01234567": + for c in "01234567": + escaped = "\\x%s%s%s" % (a, b, c) + if escaped not in ESCAPES: + ESCAPES[escaped] = chr(int("%s%s%s" % (a, b, c), 8)) + +def unescape(s): + result = [] + i = 0 + while i < len(s): + if s[i] != "\\": + result.append(s[i]) + i += 1 + continue + if s[i + 1] == "x": + escaped = s[i: i + 4] + i += 4 + elif s[i + 1] in "01234567": + escaped = s[i: i + 4] + i += 4 + else: + escaped = s[i: i + 2] + i += 2 + if escaped not in ESCAPES: + raise ValueError("escape %r unknown" % (escaped, )) + else: + result.append(ESCAPES[escaped]) + return "".join(result) + def make_regex_parser(): from pypy.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function # construct regular expressions by hand, to not go completely insane @@ -23,13 +66,8 @@ special_chars = "*+()[]{}|.-?,^" # lexer QUOTES = [] - for i in range(256): - # 'x' is reserved for hexadecimal escapes - if chr(i) != 'x': - QUOTES.append(StringExpression("\\" + chr(i))) - for a in "0123456789ABCDEFabcdef": - for b in "0123456789ABCDEFabcdef": - QUOTES.append(StringExpression("\\x%s%s" % (a, b))) + for escaped in ESCAPES.iterkeys(): + QUOTES.append(StringExpression(escaped)) REST = StringExpression("a") for p in string.printable: if p not in special_chars: @@ -37,45 +75,45 @@ regexs1 = QUOTES + [REST] names1 = ['QUOTEDCHAR'] * len(QUOTES) + ['CHAR'] # parser - rs, rules, transformer = parse_ebnf(""" - regex: concatenation "|" regex | concatenation; - concatenation: repetition concatenation | repetition; + rs, rules, ToAST = parse_ebnf(""" + regex: concatenation "|" regex | ; + concatenation: repetition concatenation | ; repetition: primary "*" | primary "+" | primary "?" | primary "{" numrange "}" | - primary; - primary: "(" regex ")" | + ; + primary: "(" ")" | "[" range "]" | char | "."; char: QUOTEDCHAR | CHAR; range: "^" subrange | subrange; - subrange: char "-" char subrange | char "-" char | char subrange | char; - numrange: num "," num | num; - num: CHAR num | CHAR; + subrange: rangeelement+; + rangeelement: char "-" char | char; + numrange: num "," num | ; + num: CHAR+; """) names2, regexs2 = zip(*rs) lexer = Lexer(regexs1 + list(regexs2), names1 + list(names2)) parser = PackratParser(rules, "regex") - return parser, lexer + return parser, lexer, ToAST def parse_regex(s): tokens = lexer.tokenize(s) s = parser.parse(tokens) - return s.visit(RegexBuilder()) + s = s.visit(RegexToAST())[0] + res = s.visit(RegexBuilder()) + assert res is not None + return res class RegexBuilder(object): def visit_regex(self, node): - if len(node.children) == 1: - return node.children[0].visit(self) return node.children[0].visit(self) | node.children[2].visit(self) + def visit_concatenation(self, node): - if len(node.children) == 1: - return node.children[0].visit(self) return node.children[0].visit(self) + node.children[1].visit(self) + def visit_repetition(self, node): - if len(node.children) == 1: - return node.children[0].visit(self) if len(node.children) == 4: subregex = node.children[0].visit(self) r1, r2 = node.children[2].visit(self) @@ -90,33 +128,32 @@ rest = rest | curr curr += subregex return base + rest - if node.children[1].symbol == "*": + if node.children[1].additional_info == "*": return node.children[0].visit(self).kleene() - elif node.children[1].symbol == "+": + elif node.children[1].additional_info == "+": return + node.children[0].visit(self) - elif node.children[1].symbol == "?": + elif node.children[1].additional_info == "?": return StringExpression("") | node.children[0].visit(self) + def visit_primary(self, node): if len(node.children) == 1: if node.children[0].symbol == "char": return node.children[0].visit(self) - elif node.children[0].symbol == ".": + elif node.children[0].additional_info == ".": return RangeExpression(chr(0), chr(255)) raise ParserError - if node.children[0].symbol == "(": + if node.children[0].additional_info == "(": return node.children[1].visit(self) else: return node.children[1].visit(self) + def visit_char(self, node): if node.children[0].symbol == "QUOTEDCHAR": quote = node.children[0].additional_info - if quote in ESCAPES: - return StringExpression(ESCAPES[quote]) - if quote[1] == "x": - return StringExpression(chr(int(quote[2:], 16))) - return StringExpression(node.children[0].additional_info[-1]) + return StringExpression(unescape(quote)) else: return StringExpression(node.children[0].additional_info[-1]) + def visit_range(self, node): ranges = node.children[-1].visit(self) invert = len(node.children) == 2 @@ -130,43 +167,177 @@ return reduce(py.std.operator.or_, [RangeExpression(a, chr(ord(a) + b - 1)) for a, b in compressed]) + def visit_subrange(self, node): - if len(node.children) >= 3: + return [c.visit(self) for c in node.children] + + def visit_rangeelement(self, node): + if len(node.children) == 3: r = (node.children[0].visit(self).string, node.children[2].visit(self).string) else: char = node.children[0].visit(self).string r = (char, char) - if len(node.children) in (2, 4): - return [r] + node.children[-1].visit(self) - else: - return [r] + return r + def visit_numrange(self, node): - if len(node.children) == 3: - r1 = node.children[0].visit(self) - r2 = node.children[2].visit(self) + 1 - else: - r1 = node.children[0].visit(self) - r2 = r1 + 1 + r1 = node.children[0].visit(self)[0] + r2 = node.children[2].visit(self)[0] + 1 return r1, r2 - def visit_num(self, node): - if len(node.children) == 2: - return (int(node.children[0].additional_info) * 10 + - node.children[1].visit(self)) - return int(node.children[0].additional_info) + def visit_num(self, node): + r = int("".join([c.additional_info for c in node.children])) + return r, r + 1 # generated code between this line and its other occurence -parser = PackratParser([Rule('regex', [['concatenation', '|', 'regex'], ['concatenation']]), +class RegexToAST(object): + def visit_regex(self, node): + length = len(node.children) + if length == 1: + return self.visit_concatenation(node.children[0]) + children = [] + children.extend(self.visit_concatenation(node.children[0])) + children.extend([node.children[1]]) + children.extend(self.visit_regex(node.children[2])) + return [Nonterminal(node.symbol, children)] + def visit_concatenation(self, node): + length = len(node.children) + if length == 1: + return self.visit_repetition(node.children[0]) + children = [] + children.extend(self.visit_repetition(node.children[0])) + children.extend(self.visit_concatenation(node.children[1])) + return [Nonterminal(node.symbol, children)] + def visit_repetition(self, node): + length = len(node.children) + if length == 1: + return self.visit_primary(node.children[0]) + if length == 2: + if node.children[1].symbol == '__1_*': + children = [] + children.extend(self.visit_primary(node.children[0])) + children.extend([node.children[1]]) + return [Nonterminal(node.symbol, children)] + if node.children[1].symbol == '__2_+': + children = [] + children.extend(self.visit_primary(node.children[0])) + children.extend([node.children[1]]) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_primary(node.children[0])) + children.extend([node.children[1]]) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_primary(node.children[0])) + children.extend([node.children[1]]) + children.extend(self.visit_numrange(node.children[2])) + children.extend([node.children[3]]) + return [Nonterminal(node.symbol, children)] + def visit_primary(self, node): + length = len(node.children) + if length == 1: + if node.children[0].symbol == '__10_.': + children = [] + children.extend([node.children[0]]) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_char(node.children[0])) + return [Nonterminal(node.symbol, children)] + if node.children[0].symbol == '__6_(': + return self.visit_regex(node.children[1]) + children = [] + children.extend([node.children[0]]) + children.extend(self.visit_range(node.children[1])) + children.extend([node.children[2]]) + return [Nonterminal(node.symbol, children)] + def visit_char(self, node): + length = len(node.children) + if node.children[0].symbol == 'CHAR': + children = [] + children.extend([node.children[0]]) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend([node.children[0]]) + return [Nonterminal(node.symbol, children)] + def visit_range(self, node): + length = len(node.children) + if length == 1: + children = [] + children.extend(self.visit_subrange(node.children[0])) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend([node.children[0]]) + children.extend(self.visit_subrange(node.children[1])) + return [Nonterminal(node.symbol, children)] + def visit__plus_symbol0(self, node): + length = len(node.children) + if length == 1: + children = [] + children.extend(self.visit_rangeelement(node.children[0])) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_rangeelement(node.children[0])) + expr = self.visit__plus_symbol0(node.children[1]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] + def visit_subrange(self, node): + children = [] + expr = self.visit__plus_symbol0(node.children[0]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] + def visit_rangeelement(self, node): + length = len(node.children) + if length == 1: + children = [] + children.extend(self.visit_char(node.children[0])) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend(self.visit_char(node.children[0])) + children.extend([node.children[1]]) + children.extend(self.visit_char(node.children[2])) + return [Nonterminal(node.symbol, children)] + def visit_numrange(self, node): + length = len(node.children) + if length == 1: + return self.visit_num(node.children[0]) + children = [] + children.extend(self.visit_num(node.children[0])) + children.extend([node.children[1]]) + children.extend(self.visit_num(node.children[2])) + return [Nonterminal(node.symbol, children)] + def visit__plus_symbol1(self, node): + length = len(node.children) + if length == 1: + children = [] + children.extend([node.children[0]]) + return [Nonterminal(node.symbol, children)] + children = [] + children.extend([node.children[0]]) + expr = self.visit__plus_symbol1(node.children[1]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] + def visit_num(self, node): + children = [] + expr = self.visit__plus_symbol1(node.children[0]) + assert len(expr) == 1 + children.extend(expr[0].children) + return [Nonterminal(node.symbol, children)] +parser = PackratParser([Rule('regex', [['concatenation', '__0_|', 'regex'], ['concatenation']]), Rule('concatenation', [['repetition', 'concatenation'], ['repetition']]), - Rule('repetition', [['primary', '*'], ['primary', '+'], ['primary', '?'], ['primary', '{', 'numrange', '}'], ['primary']]), - Rule('primary', [['(', 'regex', ')'], ['[', 'range', ']'], ['char'], ['.']]), + Rule('repetition', [['primary', '__1_*'], ['primary', '__2_+'], ['primary', '__3_?'], ['primary', '__4_{', 'numrange', '__5_}'], ['primary']]), + Rule('primary', [['__6_(', 'regex', '__7_)'], ['__8_[', 'range', '__9_]'], ['char'], ['__10_.']]), Rule('char', [['QUOTEDCHAR'], ['CHAR']]), - Rule('range', [['^', 'subrange'], ['subrange']]), - Rule('subrange', [['char', '-', 'char', 'subrange'], ['char', '-', 'char'], ['char', 'subrange'], ['char']]), - Rule('numrange', [['num', ',', 'num'], ['num']]), - Rule('num', [['CHAR', 'num'], ['CHAR']])], + Rule('range', [['__11_^', 'subrange'], ['subrange']]), + Rule('_plus_symbol0', [['rangeelement', '_plus_symbol0'], ['rangeelement']]), + Rule('subrange', [['_plus_symbol0']]), + Rule('rangeelement', [['char', '__12_-', 'char'], ['char']]), + Rule('numrange', [['num', '__13_,', 'num'], ['num']]), + Rule('_plus_symbol1', [['CHAR', '_plus_symbol1'], ['CHAR']]), + Rule('num', [['_plus_symbol1']])], 'regex') def recognize(runner, i): assert i >= 0 @@ -224,6 +395,87 @@ state = 16 else: break + if state == 769: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 769 + return i + if char == '1': + state = 847 + elif char == '0': + state = 848 + elif char == '3': + state = 849 + elif char == '2': + state = 850 + elif char == '5': + state = 851 + elif char == '4': + state = 852 + elif char == '7': + state = 853 + elif char == '6': + state = 854 + else: + break + if state == 770: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 770 + return i + if char == '1': + state = 839 + elif char == '0': + state = 840 + elif char == '3': + state = 841 + elif char == '2': + state = 842 + elif char == '5': + state = 843 + elif char == '4': + state = 844 + elif char == '7': + state = 845 + elif char == '6': + state = 846 + else: + break + if state == 771: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 771 + return i + if char == '0': + state = 832 + elif char == '3': + state = 833 + elif char == '2': + state = 834 + elif char == '5': + state = 835 + elif char == '4': + state = 836 + elif char == '7': + state = 837 + elif char == '6': + state = 838 + elif char == '1': + state = 831 + else: + break if state == 4: runner.last_matched_index = i - 1 runner.last_matched_state = state @@ -281,1711 +533,2485 @@ state = 39 elif char == '\xaf': state = 40 - elif char == '0': - state = 41 elif char == '\xb3': + state = 41 + elif char == '\xb7': state = 42 - elif char == '4': + elif char == '8': state = 43 - elif char == '\xb7': + elif char == '\xbb': state = 44 - elif char == '8': + elif char == '<': state = 45 - elif char == '\xbb': + elif char == '\xbf': state = 46 - elif char == '<': + elif char == '@': state = 47 - elif char == '\xbf': + elif char == '\xc3': state = 48 - elif char == '@': + elif char == 'D': state = 49 - elif char == '\xc3': + elif char == '\xc7': state = 50 - elif char == 'D': + elif char == 'H': state = 51 - elif char == '\xc7': + elif char == '\xcb': state = 52 - elif char == 'H': + elif char == 'L': state = 53 - elif char == '\xcb': + elif char == '\xcf': state = 54 - elif char == 'L': + elif char == 'P': state = 55 - elif char == '\xcf': + elif char == '\xd3': state = 56 - elif char == 'P': + elif char == 'T': state = 57 - elif char == '\xd3': + elif char == '\xd7': state = 58 - elif char == 'T': + elif char == 'X': state = 59 - elif char == '\xd7': + elif char == '\xdb': state = 60 - elif char == 'X': + elif char == '\\': state = 61 - elif char == '\xdb': + elif char == '\xdf': state = 62 - elif char == '\\': + elif char == '`': state = 63 - elif char == '\xdf': + elif char == '\xe3': state = 64 - elif char == '`': + elif char == 'd': state = 65 - elif char == '\xe3': + elif char == '\xe7': state = 66 - elif char == 'd': + elif char == 'h': state = 67 - elif char == '\xe7': + elif char == '\xeb': state = 68 - elif char == 'h': + elif char == 'l': state = 69 - elif char == '\xeb': + elif char == '\xef': state = 70 - elif char == 'l': + elif char == 'p': state = 71 - elif char == '\xef': + elif char == '\xf3': state = 72 - elif char == 'p': + elif char == 't': state = 73 - elif char == '\xf3': + elif char == '\xf7': state = 74 - elif char == 't': + elif char == 'x': state = 75 - elif char == '\xf7': + elif char == '\xfb': state = 76 - elif char == 'x': + elif char == '|': state = 77 - elif char == '\xfb': + elif char == '\xff': state = 78 - elif char == '|': + elif char == '\x80': state = 79 - elif char == '\xff': + elif char == '\x03': state = 80 - elif char == '\x80': + elif char == '\x84': state = 81 - elif char == '\x03': + elif char == '\x07': state = 82 - elif char == '\x84': + elif char == '\x88': state = 83 - elif char == '\x07': + elif char == '\x0b': state = 84 - elif char == '\x88': + elif char == '\x8c': state = 85 - elif char == '\x0b': + elif char == '\x0f': state = 86 - elif char == '\x8c': + elif char == '\x90': state = 87 - elif char == '\x0f': + elif char == '\x13': state = 88 - elif char == '\x90': + elif char == '\x94': state = 89 - elif char == '\x13': + elif char == '\x17': state = 90 - elif char == '\x94': + elif char == '\x98': state = 91 - elif char == '\x17': + elif char == '\x1b': state = 92 - elif char == '\x98': + elif char == '\x9c': state = 93 - elif char == '\x1b': + elif char == '\x1f': state = 94 - elif char == '\x9c': + elif char == '\xa0': state = 95 - elif char == '\x1f': + elif char == '#': state = 96 - elif char == '\xa0': + elif char == '\xa4': state = 97 - elif char == '#': + elif char == "'": state = 98 - elif char == '\xa4': + elif char == '\xa8': state = 99 - elif char == "'": + elif char == '+': state = 100 - elif char == '\xa8': + elif char == '\xac': state = 101 - elif char == '+': + elif char == '/': state = 102 - elif char == '\xac': + elif char == '\xb0': state = 103 - elif char == '/': + elif char == '\xb4': state = 104 - elif char == '\xb0': + elif char == '\xb8': state = 105 - elif char == '3': + elif char == ';': state = 106 - elif char == '\xb4': + elif char == '\xbc': state = 107 - elif char == '7': + elif char == '?': state = 108 - elif char == '\xb8': + elif char == '\xc0': state = 109 - elif char == ';': + elif char == 'C': state = 110 - elif char == '\xbc': + elif char == '\xc4': state = 111 - elif char == '?': + elif char == 'G': state = 112 - elif char == '\xc0': + elif char == '\xc8': state = 113 - elif char == 'C': + elif char == 'K': state = 114 - elif char == '\xc4': + elif char == '\xcc': state = 115 - elif char == 'G': + elif char == 'O': state = 116 - elif char == '\xc8': + elif char == '\xd0': state = 117 - elif char == 'K': + elif char == 'S': state = 118 - elif char == '\xcc': + elif char == '\xd4': state = 119 - elif char == 'O': + elif char == 'W': state = 120 - elif char == '\xd0': + elif char == '\xd8': state = 121 - elif char == 'S': + elif char == '[': state = 122 - elif char == '\xd4': + elif char == '\xdc': state = 123 - elif char == 'W': + elif char == '_': state = 124 - elif char == '\xd8': + elif char == '\xe0': state = 125 - elif char == '[': + elif char == 'c': state = 126 - elif char == '\xdc': + elif char == '\xe4': state = 127 - elif char == '_': + elif char == 'g': state = 128 - elif char == '\xe0': + elif char == '\xe8': state = 129 - elif char == 'c': + elif char == 'k': state = 130 - elif char == '\xe4': + elif char == '\xec': state = 131 - elif char == 'g': + elif char == 'o': state = 132 - elif char == '\xe8': + elif char == '\xf0': state = 133 - elif char == 'k': + elif char == 's': state = 134 - elif char == '\xec': + elif char == '\xf4': state = 135 - elif char == 'o': + elif char == 'w': state = 136 - elif char == '\xf0': + elif char == '\xf8': state = 137 - elif char == 's': + elif char == '{': state = 138 - elif char == '\xf4': + elif char == '\xfc': state = 139 - elif char == 'w': + elif char == '\x7f': state = 140 - elif char == '\xf8': + elif char == '\x81': state = 141 - elif char == '{': + elif char == '\x02': state = 142 - elif char == '\xfc': + elif char == '\x85': state = 143 - elif char == '\x7f': + elif char == '\x06': state = 144 - elif char == '\x81': + elif char == '\x89': state = 145 - elif char == '\x02': + elif char == '\n': state = 146 - elif char == '\x85': + elif char == '\x8d': state = 147 - elif char == '\x06': + elif char == '\x0e': state = 148 - elif char == '\x89': + elif char == '\x91': state = 149 - elif char == '\n': + elif char == '\x12': state = 150 - elif char == '\x8d': + elif char == '\x95': state = 151 - elif char == '\x0e': + elif char == '\x16': state = 152 - elif char == '\x91': + elif char == '\x99': state = 153 - elif char == '\x12': + elif char == '\x1a': state = 154 - elif char == '\x95': + elif char == '\x9d': state = 155 - elif char == '\x16': + elif char == '\x1e': state = 156 - elif char == '\x99': + elif char == '\xa1': state = 157 - elif char == '\x1a': + elif char == '"': state = 158 - elif char == '\x9d': + elif char == '\xa5': state = 159 - elif char == '\x1e': + elif char == '&': state = 160 - elif char == '\xa1': + elif char == '\xa9': state = 161 - elif char == '"': + elif char == '*': state = 162 - elif char == '\xa5': + elif char == '\xad': state = 163 - elif char == '&': + elif char == '.': state = 164 - elif char == '\xa9': + elif char == '\xb1': state = 165 - elif char == '*': + elif char == '\xb5': state = 166 - elif char == '\xad': + elif char == '\xb9': state = 167 - elif char == '.': + elif char == ':': state = 168 - elif char == '\xb1': + elif char == '\xbd': state = 169 - elif char == '2': + elif char == '>': state = 170 - elif char == '\xb5': + elif char == '\xc1': state = 171 - elif char == '6': + elif char == 'B': state = 172 - elif char == '\xb9': + elif char == '\xc5': state = 173 - elif char == ':': + elif char == 'F': state = 174 - elif char == '\xbd': + elif char == '\xc9': state = 175 - elif char == '>': + elif char == 'J': state = 176 - elif char == '\xc1': + elif char == '\xcd': state = 177 - elif char == 'B': + elif char == 'N': state = 178 - elif char == '\xc5': + elif char == '\xd1': state = 179 - elif char == 'F': + elif char == 'R': state = 180 - elif char == '\xc9': + elif char == '\xd5': state = 181 - elif char == 'J': + elif char == 'V': state = 182 - elif char == '\xcd': + elif char == '\xd9': state = 183 - elif char == 'N': + elif char == 'Z': state = 184 - elif char == '\xd1': + elif char == '\xdd': state = 185 - elif char == 'R': + elif char == '^': state = 186 - elif char == '\xd5': + elif char == '\xe1': state = 187 - elif char == 'V': + elif char == 'b': state = 188 - elif char == '\xd9': + elif char == '\xe5': state = 189 - elif char == 'Z': + elif char == 'f': state = 190 - elif char == '\xdd': + elif char == '\xe9': state = 191 - elif char == '^': + elif char == 'j': state = 192 - elif char == '\xe1': + elif char == '\xed': state = 193 - elif char == 'b': + elif char == 'n': state = 194 - elif char == '\xe5': + elif char == '\xf1': state = 195 - elif char == 'f': + elif char == 'r': state = 196 - elif char == '\xe9': + elif char == '\xf5': state = 197 - elif char == 'j': + elif char == 'v': state = 198 - elif char == '\xed': + elif char == '\xf9': state = 199 - elif char == 'n': + elif char == 'z': state = 200 - elif char == '\xf1': + elif char == '\xfd': state = 201 - elif char == 'r': + elif char == '~': state = 202 - elif char == '\xf5': + elif char == '\x01': state = 203 - elif char == 'v': + elif char == '\x82': state = 204 - elif char == '\xf9': + elif char == '\x05': state = 205 - elif char == 'z': + elif char == '\x86': state = 206 - elif char == '\xfd': + elif char == '\t': state = 207 - elif char == '~': + elif char == '\x8a': state = 208 - elif char == '\x01': + elif char == '\r': state = 209 - elif char == '\x82': + elif char == '\x8e': state = 210 - elif char == '\x05': + elif char == '\x11': state = 211 - elif char == '\x86': + elif char == '\x92': state = 212 - elif char == '\t': + elif char == '\x15': state = 213 - elif char == '\x8a': + elif char == '\x96': state = 214 - elif char == '\r': + elif char == '\x19': state = 215 - elif char == '\x8e': + elif char == '\x9a': state = 216 - elif char == '\x11': + elif char == '\x1d': state = 217 - elif char == '\x92': + elif char == '\x9e': state = 218 - elif char == '\x15': + elif char == '!': state = 219 - elif char == '\x96': + elif char == '\xa2': state = 220 - elif char == '\x19': + elif char == '%': state = 221 - elif char == '\x9a': + elif char == '\xa6': state = 222 - elif char == '\x1d': + elif char == ')': state = 223 - elif char == '\x9e': + elif char == '\xaa': state = 224 - elif char == '!': + elif char == '-': state = 225 - elif char == '\xa2': + elif char == '\xae': state = 226 - elif char == '%': + elif char == '\xb2': state = 227 - elif char == '\xa6': + elif char == '\xb6': state = 228 - elif char == ')': + elif char == '9': state = 229 - elif char == '\xaa': + elif char == '\xba': state = 230 - elif char == '-': + elif char == '=': state = 231 - elif char == '\xae': + elif char == '\xbe': state = 232 - elif char == '1': + elif char == 'A': state = 233 - elif char == '\xb2': + elif char == '\xc2': state = 234 - elif char == '5': + elif char == 'E': state = 235 - elif char == '\xb6': + elif char == '\xc6': state = 236 - elif char == '9': + elif char == 'I': state = 237 - elif char == '\xba': + elif char == '\xca': state = 238 - elif char == '=': + elif char == 'M': state = 239 - elif char == '\xbe': + elif char == '\xce': state = 240 - elif char == 'A': + elif char == 'Q': state = 241 - elif char == '\xc2': + elif char == '\xd2': state = 242 - elif char == 'E': + elif char == 'U': state = 243 - elif char == '\xc6': + elif char == '\xd6': state = 244 - elif char == 'I': + elif char == 'Y': state = 245 - elif char == '\xca': + elif char == '\xda': state = 246 - elif char == 'M': + elif char == ']': state = 247 - elif char == '\xce': + elif char == '\xde': state = 248 - elif char == 'Q': + elif char == 'a': state = 249 - elif char == '\xd2': + elif char == '\xe2': state = 250 - elif char == 'U': + elif char == 'e': state = 251 - elif char == '\xd6': + elif char == '\xe6': state = 252 - elif char == 'Y': + elif char == 'i': state = 253 - elif char == '\xda': + elif char == '\xea': state = 254 - elif char == ']': + elif char == 'm': state = 255 - elif char == '\xde': - state = 256 - elif char == 'a': - state = 257 - elif char == '\xe2': - state = 258 - elif char == 'e': - state = 259 - elif char == '\xe6': - state = 260 - elif char == 'i': - state = 261 - elif char == '\xea': - state = 262 - elif char == 'm': - state = 263 elif char == '\xee': - state = 264 + state = 256 elif char == 'q': - state = 265 + state = 257 elif char == '\xf2': - state = 266 + state = 258 elif char == 'u': - state = 267 + state = 259 elif char == '\xf6': - state = 268 + state = 260 elif char == 'y': - state = 269 + state = 261 elif char == '\xfa': - state = 270 + state = 262 elif char == '}': - state = 271 + state = 263 elif char == '\xfe': - state = 272 + state = 264 else: break - if state == 273: + if state == 773: + runner.last_matched_index = i - 1 + runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 273 - return ~i - if char == 'C': - state = 768 - elif char == 'B': - state = 769 - elif char == 'E': - state = 770 - elif char == 'D': - state = 771 - elif char == 'F': - state = 772 - elif char == 'a': - state = 773 - elif char == 'c': - state = 774 - elif char == 'b': - state = 775 - elif char == 'e': - state = 776 - elif char == 'd': - state = 777 - elif char == 'f': - state = 778 - elif char == '1': - state = 757 + runner.state = 773 + return i + if char == '1': + state = 815 elif char == '0': - state = 758 + state = 816 elif char == '3': - state = 759 + state = 817 elif char == '2': - state = 760 + state = 818 elif char == '5': - state = 761 + state = 819 elif char == '4': - state = 762 + state = 820 elif char == '7': - state = 763 + state = 821 elif char == '6': - state = 764 - elif char == '9': - state = 765 - elif char == '8': - state = 766 - elif char == 'A': - state = 767 + state = 822 else: break - if state == 274: + if state == 774: + runner.last_matched_index = i - 1 + runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 274 - return ~i + runner.state = 774 + return i if char == '1': - state = 735 + state = 807 elif char == '0': - state = 736 + state = 808 elif char == '3': - state = 737 + state = 809 elif char == '2': - state = 738 + state = 810 elif char == '5': - state = 739 + state = 811 elif char == '4': - state = 740 + state = 812 elif char == '7': - state = 741 + state = 813 elif char == '6': - state = 742 - elif char == '9': - state = 743 - elif char == '8': - state = 744 - elif char == 'A': - state = 745 - elif char == 'C': - state = 746 - elif char == 'B': - state = 747 - elif char == 'E': - state = 748 - elif char == 'D': - state = 749 - elif char == 'F': - state = 750 - elif char == 'a': - state = 751 - elif char == 'c': - state = 752 - elif char == 'b': - state = 753 - elif char == 'e': - state = 754 - elif char == 'd': - state = 755 - elif char == 'f': - state = 756 + state = 814 else: break - if state == 275: + if state == 942: + runner.last_matched_index = i - 1 + runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 275 + runner.state = 942 + return i + if char == '1': + state = 1011 + elif char == '0': + state = 1012 + elif char == '3': + state = 1013 + elif char == '2': + state = 1014 + elif char == '5': + state = 1015 + elif char == '4': + state = 1016 + elif char == '7': + state = 1017 + elif char == '6': + state = 1018 + else: + break + if state == 776: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 776 + return i + if char == '1': + state = 791 + elif char == '0': + state = 792 + elif char == '3': + state = 793 + elif char == '2': + state = 794 + elif char == '5': + state = 795 + elif char == '4': + state = 796 + elif char == '7': + state = 797 + elif char == '6': + state = 798 + else: + break + if state == 265: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 265 return ~i if char == '1': - state = 713 + state = 941 elif char == '0': - state = 714 + state = 942 + continue elif char == '3': - state = 715 + state = 943 elif char == '2': - state = 716 + state = 944 elif char == '5': - state = 717 + state = 945 elif char == '4': - state = 718 + state = 946 elif char == '7': - state = 719 + state = 947 elif char == '6': - state = 720 + state = 948 elif char == '9': - state = 721 + state = 949 elif char == '8': - state = 722 + state = 950 elif char == 'A': - state = 723 + state = 951 elif char == 'C': - state = 724 + state = 952 elif char == 'B': - state = 725 + state = 953 elif char == 'E': - state = 726 + state = 954 elif char == 'D': - state = 727 + state = 955 elif char == 'F': - state = 728 + state = 956 elif char == 'a': - state = 729 + state = 957 elif char == 'c': - state = 730 + state = 958 elif char == 'b': - state = 731 + state = 959 elif char == 'e': - state = 732 + state = 960 elif char == 'd': - state = 733 + state = 961 elif char == 'f': - state = 734 + state = 962 else: break - if state == 276: + if state == 266: if i < len(input): char = input[i] i += 1 else: - runner.state = 276 + runner.state = 266 return ~i if char == '1': - state = 691 + state = 855 elif char == '0': - state = 692 + state = 856 elif char == '3': - state = 693 + state = 857 elif char == '2': - state = 694 + state = 858 elif char == '5': - state = 695 + state = 859 elif char == '4': - state = 696 + state = 860 elif char == '7': - state = 697 + state = 861 elif char == '6': - state = 698 + state = 862 elif char == '9': - state = 699 + state = 863 elif char == '8': - state = 700 + state = 864 elif char == 'A': - state = 701 + state = 865 elif char == 'C': - state = 702 + state = 866 elif char == 'B': - state = 703 + state = 867 elif char == 'E': - state = 704 + state = 868 elif char == 'D': - state = 705 + state = 869 elif char == 'F': - state = 706 + state = 870 elif char == 'a': - state = 707 + state = 871 elif char == 'c': - state = 708 + state = 872 elif char == 'b': - state = 709 + state = 873 elif char == 'e': - state = 710 + state = 874 elif char == 'd': - state = 711 + state = 875 elif char == 'f': - state = 712 + state = 876 else: break - if state == 277: + if state == 267: if i < len(input): char = input[i] i += 1 else: - runner.state = 277 + runner.state = 267 return ~i if char == '1': - state = 669 + state = 769 + continue elif char == '0': - state = 670 + state = 770 + continue elif char == '3': - state = 671 + state = 771 + continue elif char == '2': - state = 672 + state = 772 elif char == '5': - state = 673 + state = 773 + continue elif char == '4': - state = 674 + state = 774 + continue elif char == '7': - state = 675 + state = 775 elif char == '6': - state = 676 + state = 776 + continue elif char == '9': - state = 677 + state = 777 elif char == '8': - state = 678 + state = 778 elif char == 'A': - state = 679 + state = 779 elif char == 'C': - state = 680 + state = 780 elif char == 'B': - state = 681 + state = 781 elif char == 'E': - state = 682 + state = 782 elif char == 'D': - state = 683 + state = 783 elif char == 'F': - state = 684 + state = 784 elif char == 'a': - state = 685 + state = 785 elif char == 'c': - state = 686 + state = 786 elif char == 'b': - state = 687 + state = 787 elif char == 'e': - state = 688 + state = 788 elif char == 'd': - state = 689 + state = 789 elif char == 'f': - state = 690 + state = 790 else: break - if state == 278: + if state == 268: if i < len(input): char = input[i] i += 1 else: - runner.state = 278 + runner.state = 268 return ~i if char == '1': - state = 647 + state = 683 elif char == '0': - state = 648 + state = 684 elif char == '3': - state = 649 + state = 685 elif char == '2': - state = 650 + state = 686 elif char == '5': - state = 651 + state = 687 elif char == '4': - state = 652 + state = 688 elif char == '7': - state = 653 + state = 689 elif char == '6': - state = 654 + state = 690 elif char == '9': - state = 655 + state = 691 elif char == '8': - state = 656 + state = 692 elif char == 'A': - state = 657 + state = 693 elif char == 'C': - state = 658 + state = 694 elif char == 'B': - state = 659 + state = 695 elif char == 'E': - state = 660 + state = 696 elif char == 'D': - state = 661 + state = 697 elif char == 'F': - state = 662 + state = 698 elif char == 'a': - state = 663 + state = 699 elif char == 'c': - state = 664 + state = 700 elif char == 'b': - state = 665 + state = 701 elif char == 'e': - state = 666 + state = 702 elif char == 'd': - state = 667 + state = 703 elif char == 'f': - state = 668 + state = 704 else: break - if state == 279: + if state == 269: if i < len(input): char = input[i] i += 1 else: - runner.state = 279 + runner.state = 269 return ~i - if char == 'F': - state = 640 - elif char == 'a': - state = 641 - elif char == 'c': - state = 642 - elif char == 'b': - state = 643 - elif char == 'e': - state = 644 - elif char == 'd': - state = 645 - elif char == 'f': - state = 646 - elif char == '1': - state = 625 + if char == '1': + state = 661 elif char == '0': - state = 626 + state = 662 elif char == '3': - state = 627 + state = 663 elif char == '2': - state = 628 + state = 664 elif char == '5': - state = 629 + state = 665 elif char == '4': - state = 630 + state = 666 elif char == '7': - state = 631 + state = 667 elif char == '6': - state = 632 + state = 668 elif char == '9': - state = 633 + state = 669 elif char == '8': - state = 634 + state = 670 elif char == 'A': - state = 635 + state = 671 elif char == 'C': - state = 636 + state = 672 elif char == 'B': - state = 637 + state = 673 elif char == 'E': - state = 638 + state = 674 elif char == 'D': - state = 639 + state = 675 + elif char == 'F': + state = 676 + elif char == 'a': + state = 677 + elif char == 'c': + state = 678 + elif char == 'b': + state = 679 + elif char == 'e': + state = 680 + elif char == 'd': + state = 681 + elif char == 'f': + state = 682 else: break - if state == 280: + if state == 270: if i < len(input): char = input[i] i += 1 else: - runner.state = 280 + runner.state = 270 return ~i - if char == '1': - state = 603 - elif char == '0': - state = 604 + if char == '0': + state = 640 elif char == '3': - state = 605 + state = 641 elif char == '2': - state = 606 + state = 642 elif char == '5': - state = 607 + state = 643 elif char == '4': - state = 608 + state = 644 elif char == '7': - state = 609 + state = 645 elif char == '6': - state = 610 + state = 646 elif char == '9': - state = 611 + state = 647 elif char == '8': - state = 612 + state = 648 elif char == 'A': - state = 613 + state = 649 elif char == 'C': - state = 614 + state = 650 elif char == 'B': - state = 615 + state = 651 elif char == 'E': - state = 616 + state = 652 elif char == 'D': - state = 617 + state = 653 elif char == 'F': - state = 618 + state = 654 elif char == 'a': - state = 619 + state = 655 elif char == 'c': - state = 620 + state = 656 elif char == 'b': - state = 621 + state = 657 elif char == 'e': - state = 622 + state = 658 elif char == 'd': - state = 623 + state = 659 elif char == 'f': - state = 624 + state = 660 + elif char == '1': + state = 639 else: break - if state == 281: + if state == 271: if i < len(input): char = input[i] i += 1 else: - runner.state = 281 + runner.state = 271 return ~i if char == '1': - state = 581 + state = 617 elif char == '0': - state = 582 + state = 618 elif char == '3': - state = 583 + state = 619 elif char == '2': - state = 584 + state = 620 elif char == '5': - state = 585 + state = 621 elif char == '4': - state = 586 + state = 622 elif char == '7': - state = 587 + state = 623 elif char == '6': - state = 588 + state = 624 elif char == '9': - state = 589 + state = 625 elif char == '8': - state = 590 + state = 626 elif char == 'A': - state = 591 + state = 627 elif char == 'C': - state = 592 + state = 628 elif char == 'B': - state = 593 + state = 629 elif char == 'E': - state = 594 + state = 630 elif char == 'D': - state = 595 + state = 631 elif char == 'F': - state = 596 + state = 632 elif char == 'a': - state = 597 + state = 633 elif char == 'c': - state = 598 + state = 634 elif char == 'b': - state = 599 + state = 635 elif char == 'e': - state = 600 + state = 636 elif char == 'd': - state = 601 + state = 637 elif char == 'f': - state = 602 + state = 638 else: break - if state == 282: + if state == 272: if i < len(input): char = input[i] i += 1 else: - runner.state = 282 + runner.state = 272 return ~i if char == '1': - state = 559 + state = 595 elif char == '0': - state = 560 + state = 596 elif char == '3': - state = 561 + state = 597 elif char == '2': - state = 562 + state = 598 elif char == '5': - state = 563 + state = 599 elif char == '4': - state = 564 + state = 600 elif char == '7': - state = 565 + state = 601 elif char == '6': - state = 566 + state = 602 elif char == '9': - state = 567 + state = 603 elif char == '8': - state = 568 + state = 604 elif char == 'A': - state = 569 + state = 605 elif char == 'C': - state = 570 + state = 606 elif char == 'B': - state = 571 + state = 607 elif char == 'E': - state = 572 + state = 608 elif char == 'D': - state = 573 + state = 609 elif char == 'F': - state = 574 + state = 610 elif char == 'a': - state = 575 + state = 611 elif char == 'c': - state = 576 + state = 612 elif char == 'b': - state = 577 + state = 613 elif char == 'e': - state = 578 + state = 614 elif char == 'd': - state = 579 + state = 615 elif char == 'f': - state = 580 + state = 616 else: break - if state == 283: + if state == 273: if i < len(input): char = input[i] i += 1 else: - runner.state = 283 + runner.state = 273 return ~i if char == '1': - state = 537 + state = 573 elif char == '0': - state = 538 + state = 574 elif char == '3': - state = 539 + state = 575 elif char == '2': - state = 540 + state = 576 elif char == '5': - state = 541 + state = 577 elif char == '4': - state = 542 + state = 578 elif char == '7': - state = 543 + state = 579 elif char == '6': - state = 544 + state = 580 elif char == '9': - state = 545 + state = 581 elif char == '8': - state = 546 + state = 582 elif char == 'A': - state = 547 + state = 583 elif char == 'C': - state = 548 + state = 584 elif char == 'B': - state = 549 + state = 585 elif char == 'E': - state = 550 + state = 586 elif char == 'D': - state = 551 + state = 587 elif char == 'F': - state = 552 + state = 588 elif char == 'a': - state = 553 + state = 589 elif char == 'c': - state = 554 + state = 590 elif char == 'b': - state = 555 + state = 591 elif char == 'e': - state = 556 + state = 592 elif char == 'd': - state = 557 + state = 593 elif char == 'f': - state = 558 + state = 594 else: break - if state == 284: + if state == 274: if i < len(input): char = input[i] i += 1 else: - runner.state = 284 + runner.state = 274 return ~i if char == '1': - state = 515 + state = 551 elif char == '0': - state = 516 + state = 552 elif char == '3': - state = 517 + state = 553 elif char == '2': - state = 518 + state = 554 elif char == '5': - state = 519 + state = 555 elif char == '4': - state = 520 + state = 556 elif char == '7': - state = 521 + state = 557 elif char == '6': - state = 522 + state = 558 elif char == '9': - state = 523 + state = 559 elif char == '8': - state = 524 + state = 560 elif char == 'A': - state = 525 + state = 561 elif char == 'C': - state = 526 + state = 562 elif char == 'B': - state = 527 + state = 563 elif char == 'E': - state = 528 + state = 564 elif char == 'D': - state = 529 + state = 565 elif char == 'F': - state = 530 + state = 566 elif char == 'a': - state = 531 + state = 567 elif char == 'c': - state = 532 + state = 568 elif char == 'b': - state = 533 + state = 569 elif char == 'e': - state = 534 + state = 570 elif char == 'd': - state = 535 + state = 571 elif char == 'f': - state = 536 + state = 572 else: break - if state == 285: + if state == 275: if i < len(input): char = input[i] i += 1 else: - runner.state = 285 + runner.state = 275 return ~i - if char == 'e': - state = 512 - elif char == 'd': - state = 513 - elif char == 'f': - state = 514 - elif char == '1': - state = 493 + if char == '1': + state = 529 elif char == '0': - state = 494 + state = 530 elif char == '3': - state = 495 + state = 531 elif char == '2': - state = 496 + state = 532 elif char == '5': - state = 497 + state = 533 elif char == '4': - state = 498 + state = 534 elif char == '7': - state = 499 + state = 535 elif char == '6': - state = 500 + state = 536 elif char == '9': - state = 501 + state = 537 elif char == '8': - state = 502 + state = 538 elif char == 'A': - state = 503 + state = 539 elif char == 'C': - state = 504 + state = 540 elif char == 'B': - state = 505 + state = 541 elif char == 'E': - state = 506 + state = 542 elif char == 'D': - state = 507 + state = 543 elif char == 'F': - state = 508 + state = 544 elif char == 'a': - state = 509 + state = 545 elif char == 'c': - state = 510 + state = 546 elif char == 'b': - state = 511 + state = 547 + elif char == 'e': + state = 548 + elif char == 'd': + state = 549 + elif char == 'f': + state = 550 else: break - if state == 286: + if state == 276: if i < len(input): char = input[i] i += 1 else: - runner.state = 286 + runner.state = 276 return ~i - if char == '1': - state = 471 - elif char == '0': - state = 472 - elif char == '3': - state = 473 - elif char == '2': - state = 474 - elif char == '5': - state = 475 - elif char == '4': - state = 476 + if char == '4': + state = 512 elif char == '7': - state = 477 + state = 513 elif char == '6': - state = 478 + state = 514 elif char == '9': - state = 479 + state = 515 elif char == '8': - state = 480 + state = 516 elif char == 'A': - state = 481 + state = 517 elif char == 'C': - state = 482 + state = 518 elif char == 'B': - state = 483 + state = 519 elif char == 'E': - state = 484 + state = 520 elif char == 'D': - state = 485 + state = 521 elif char == 'F': - state = 486 + state = 522 elif char == 'a': - state = 487 + state = 523 elif char == 'c': - state = 488 + state = 524 elif char == 'b': - state = 489 + state = 525 elif char == 'e': - state = 490 + state = 526 elif char == 'd': - state = 491 + state = 527 elif char == 'f': - state = 492 + state = 528 + elif char == '1': + state = 507 + elif char == '0': + state = 508 + elif char == '3': + state = 509 + elif char == '2': + state = 510 + elif char == '5': + state = 511 else: break - if state == 287: + if state == 277: if i < len(input): char = input[i] i += 1 else: - runner.state = 287 + runner.state = 277 return ~i if char == '1': - state = 449 + state = 485 elif char == '0': - state = 450 + state = 486 elif char == '3': - state = 451 + state = 487 elif char == '2': - state = 452 + state = 488 elif char == '5': - state = 453 + state = 489 elif char == '4': - state = 454 + state = 490 elif char == '7': - state = 455 + state = 491 elif char == '6': - state = 456 + state = 492 elif char == '9': - state = 457 + state = 493 elif char == '8': - state = 458 + state = 494 elif char == 'A': - state = 459 + state = 495 elif char == 'C': - state = 460 + state = 496 elif char == 'B': - state = 461 + state = 497 elif char == 'E': - state = 462 + state = 498 elif char == 'D': - state = 463 + state = 499 elif char == 'F': - state = 464 + state = 500 elif char == 'a': - state = 465 + state = 501 elif char == 'c': - state = 466 + state = 502 elif char == 'b': - state = 467 + state = 503 elif char == 'e': - state = 468 + state = 504 elif char == 'd': - state = 469 + state = 505 elif char == 'f': - state = 470 + state = 506 else: break - if state == 288: + if state == 278: if i < len(input): char = input[i] i += 1 else: - runner.state = 288 + runner.state = 278 return ~i if char == '1': - state = 427 + state = 463 elif char == '0': - state = 428 + state = 464 elif char == '3': - state = 429 + state = 465 elif char == '2': - state = 430 + state = 466 elif char == '5': - state = 431 + state = 467 elif char == '4': - state = 432 + state = 468 elif char == '7': - state = 433 + state = 469 elif char == '6': - state = 434 + state = 470 elif char == '9': - state = 435 + state = 471 elif char == '8': - state = 436 + state = 472 elif char == 'A': - state = 437 + state = 473 elif char == 'C': - state = 438 + state = 474 elif char == 'B': - state = 439 + state = 475 elif char == 'E': - state = 440 + state = 476 elif char == 'D': - state = 441 + state = 477 elif char == 'F': - state = 442 + state = 478 elif char == 'a': - state = 443 + state = 479 elif char == 'c': - state = 444 + state = 480 elif char == 'b': - state = 445 + state = 481 elif char == 'e': - state = 446 + state = 482 elif char == 'd': - state = 447 + state = 483 elif char == 'f': - state = 448 + state = 484 else: break - if state == 289: + if state == 279: if i < len(input): char = input[i] i += 1 else: - runner.state = 289 + runner.state = 279 return ~i if char == '1': - state = 405 + state = 441 elif char == '0': - state = 406 + state = 442 elif char == '3': - state = 407 + state = 443 elif char == '2': - state = 408 + state = 444 elif char == '5': - state = 409 + state = 445 elif char == '4': - state = 410 + state = 446 elif char == '7': - state = 411 + state = 447 elif char == '6': - state = 412 + state = 448 elif char == '9': - state = 413 + state = 449 elif char == '8': - state = 414 + state = 450 elif char == 'A': - state = 415 + state = 451 elif char == 'C': - state = 416 + state = 452 elif char == 'B': - state = 417 + state = 453 elif char == 'E': - state = 418 + state = 454 elif char == 'D': - state = 419 + state = 455 elif char == 'F': - state = 420 + state = 456 elif char == 'a': - state = 421 + state = 457 elif char == 'c': - state = 422 + state = 458 elif char == 'b': - state = 423 + state = 459 elif char == 'e': - state = 424 + state = 460 elif char == 'd': - state = 425 + state = 461 elif char == 'f': - state = 426 + state = 462 else: break - if state == 290: + if state == 280: if i < len(input): char = input[i] i += 1 else: - runner.state = 290 + runner.state = 280 return ~i - if char == '0': - state = 384 + if char == '1': + state = 419 + elif char == '0': + state = 420 elif char == '3': - state = 385 + state = 421 elif char == '2': - state = 386 + state = 422 elif char == '5': - state = 387 + state = 423 elif char == '4': - state = 388 + state = 424 elif char == '7': - state = 389 + state = 425 elif char == '6': - state = 390 + state = 426 elif char == '9': - state = 391 + state = 427 elif char == '8': - state = 392 + state = 428 elif char == 'A': - state = 393 + state = 429 elif char == 'C': - state = 394 + state = 430 elif char == 'B': - state = 395 + state = 431 elif char == 'E': - state = 396 + state = 432 elif char == 'D': - state = 397 + state = 433 elif char == 'F': - state = 398 + state = 434 elif char == 'a': - state = 399 + state = 435 elif char == 'c': - state = 400 + state = 436 elif char == 'b': - state = 401 + state = 437 elif char == 'e': - state = 402 + state = 438 elif char == 'd': - state = 403 + state = 439 elif char == 'f': - state = 404 - elif char == '1': - state = 383 + state = 440 else: break - if state == 291: + if state == 281: if i < len(input): char = input[i] i += 1 else: - runner.state = 291 + runner.state = 281 return ~i if char == '1': - state = 361 + state = 397 elif char == '0': - state = 362 + state = 398 elif char == '3': - state = 363 + state = 399 elif char == '2': - state = 364 + state = 400 elif char == '5': - state = 365 + state = 401 elif char == '4': - state = 366 + state = 402 elif char == '7': - state = 367 + state = 403 elif char == '6': - state = 368 + state = 404 elif char == '9': - state = 369 + state = 405 elif char == '8': - state = 370 + state = 406 elif char == 'A': - state = 371 + state = 407 elif char == 'C': - state = 372 + state = 408 elif char == 'B': - state = 373 + state = 409 elif char == 'E': - state = 374 + state = 410 elif char == 'D': - state = 375 + state = 411 elif char == 'F': - state = 376 + state = 412 elif char == 'a': - state = 377 + state = 413 elif char == 'c': - state = 378 + state = 414 elif char == 'b': - state = 379 + state = 415 elif char == 'e': - state = 380 + state = 416 elif char == 'd': - state = 381 + state = 417 + elif char == 'f': + state = 418 + else: + break + if state == 282: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 282 + return ~i + if char == '8': + state = 384 + elif char == 'A': + state = 385 + elif char == 'C': + state = 386 + elif char == 'B': + state = 387 + elif char == 'E': + state = 388 + elif char == 'D': + state = 389 + elif char == 'F': + state = 390 + elif char == 'a': + state = 391 + elif char == 'c': + state = 392 + elif char == 'b': + state = 393 + elif char == 'e': + state = 394 + elif char == 'd': + state = 395 elif char == 'f': + state = 396 + elif char == '1': + state = 375 + elif char == '0': + state = 376 + elif char == '3': + state = 377 + elif char == '2': + state = 378 + elif char == '5': + state = 379 + elif char == '4': + state = 380 + elif char == '7': + state = 381 + elif char == '6': state = 382 + elif char == '9': + state = 383 + else: + break + if state == 283: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 283 + return ~i + if char == '1': + state = 353 + elif char == '0': + state = 354 + elif char == '3': + state = 355 + elif char == '2': + state = 356 + elif char == '5': + state = 357 + elif char == '4': + state = 358 + elif char == '7': + state = 359 + elif char == '6': + state = 360 + elif char == '9': + state = 361 + elif char == '8': + state = 362 + elif char == 'A': + state = 363 + elif char == 'C': + state = 364 + elif char == 'B': + state = 365 + elif char == 'E': + state = 366 + elif char == 'D': + state = 367 + elif char == 'F': + state = 368 + elif char == 'a': + state = 369 + elif char == 'c': + state = 370 + elif char == 'b': + state = 371 + elif char == 'e': + state = 372 + elif char == 'd': + state = 373 + elif char == 'f': + state = 374 + else: + break + if state == 284: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 284 + return ~i + if char == '1': + state = 331 + elif char == '0': + state = 332 + elif char == '3': + state = 333 + elif char == '2': + state = 334 + elif char == '5': + state = 335 + elif char == '4': + state = 336 + elif char == '7': + state = 337 + elif char == '6': + state = 338 + elif char == '9': + state = 339 + elif char == '8': + state = 340 + elif char == 'A': + state = 341 + elif char == 'C': + state = 342 + elif char == 'B': + state = 343 + elif char == 'E': + state = 344 + elif char == 'D': + state = 345 + elif char == 'F': + state = 346 + elif char == 'a': + state = 347 + elif char == 'c': + state = 348 + elif char == 'b': + state = 349 + elif char == 'e': + state = 350 + elif char == 'd': + state = 351 + elif char == 'f': + state = 352 + else: + break + if state == 285: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 285 + return ~i + if char == '1': + state = 309 + elif char == '0': + state = 310 + elif char == '3': + state = 311 + elif char == '2': + state = 312 + elif char == '5': + state = 313 + elif char == '4': + state = 314 + elif char == '7': + state = 315 + elif char == '6': + state = 316 + elif char == '9': + state = 317 + elif char == '8': + state = 318 + elif char == 'A': + state = 319 + elif char == 'C': + state = 320 + elif char == 'B': + state = 321 + elif char == 'E': + state = 322 + elif char == 'D': + state = 323 + elif char == 'F': + state = 324 + elif char == 'a': + state = 325 + elif char == 'c': + state = 326 + elif char == 'b': + state = 327 + elif char == 'e': + state = 328 + elif char == 'd': + state = 329 + elif char == 'f': + state = 330 + else: + break + if state == 286: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 286 + return ~i + if char == '1': + state = 287 + elif char == '0': + state = 288 + elif char == '3': + state = 289 + elif char == '2': + state = 290 + elif char == '5': + state = 291 + elif char == '4': + state = 292 + elif char == '7': + state = 293 + elif char == '6': + state = 294 + elif char == '9': + state = 295 + elif char == '8': + state = 296 + elif char == 'A': + state = 297 + elif char == 'C': + state = 298 + elif char == 'B': + state = 299 + elif char == 'E': + state = 300 + elif char == 'D': + state = 301 + elif char == 'F': + state = 302 + elif char == 'a': + state = 303 + elif char == 'c': + state = 304 + elif char == 'b': + state = 305 + elif char == 'e': + state = 306 + elif char == 'd': + state = 307 + elif char == 'f': + state = 308 + else: + break + if state == 944: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 944 + return i + if char == '1': + state = 995 + elif char == '0': + state = 996 + elif char == '3': + state = 997 + elif char == '2': + state = 998 + elif char == '5': + state = 999 + elif char == '4': + state = 1000 + elif char == '7': + state = 1001 + elif char == '6': + state = 1002 + else: + break + if state == 689: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 689 + return i + if char == '1': + state = 713 + elif char == '0': + state = 714 + elif char == '3': + state = 715 + elif char == '2': + state = 716 + elif char == '5': + state = 717 + elif char == '4': + state = 718 + elif char == '7': + state = 719 + elif char == '6': + state = 720 + else: + break + if state == 683: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 683 + return i + if char == '6': + state = 768 + elif char == '1': + state = 761 + elif char == '0': + state = 762 + elif char == '3': + state = 763 + elif char == '2': + state = 764 + elif char == '5': + state = 765 + elif char == '4': + state = 766 + elif char == '7': + state = 767 + else: + break + if state == 684: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 684 + return i + if char == '1': + state = 753 + elif char == '0': + state = 754 + elif char == '3': + state = 755 + elif char == '2': + state = 756 + elif char == '5': + state = 757 + elif char == '4': + state = 758 + elif char == '7': + state = 759 + elif char == '6': + state = 760 + else: + break + if state == 941: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 941 + return i + if char == '4': + state = 1024 + elif char == '7': + state = 1025 + elif char == '6': + state = 1026 + elif char == '1': + state = 1019 + elif char == '0': + state = 1020 + elif char == '3': + state = 1021 + elif char == '2': + state = 1022 + elif char == '5': + state = 1023 + else: + break + if state == 686: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 686 + return i + if char == '1': + state = 737 + elif char == '0': + state = 738 + elif char == '3': + state = 739 + elif char == '2': + state = 740 + elif char == '5': + state = 741 + elif char == '4': + state = 742 + elif char == '7': + state = 743 + elif char == '6': + state = 744 + else: + break + if state == 943: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 943 + return i + if char == '1': + state = 1003 + elif char == '0': + state = 1004 + elif char == '3': + state = 1005 + elif char == '2': + state = 1006 + elif char == '5': + state = 1007 + elif char == '4': + state = 1008 + elif char == '7': + state = 1009 + elif char == '6': + state = 1010 + else: + break + if state == 688: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 688 + return i + if char == '1': + state = 721 + elif char == '0': + state = 722 + elif char == '3': + state = 723 + elif char == '2': + state = 724 + elif char == '5': + state = 725 + elif char == '4': + state = 726 + elif char == '7': + state = 727 + elif char == '6': + state = 728 + else: + break + if state == 945: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 945 + return i + if char == '4': + state = 992 + elif char == '7': + state = 993 + elif char == '6': + state = 994 + elif char == '1': + state = 987 + elif char == '0': + state = 988 + elif char == '3': + state = 989 + elif char == '2': + state = 990 + elif char == '5': + state = 991 + else: + break + if state == 690: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 690 + return i + if char == '1': + state = 705 + elif char == '0': + state = 706 + elif char == '3': + state = 707 + elif char == '2': + state = 708 + elif char == '5': + state = 709 + elif char == '4': + state = 710 + elif char == '7': + state = 711 + elif char == '6': + state = 712 + else: + break + if state == 947: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 947 + return i + if char == '1': + state = 971 + elif char == '0': + state = 972 + elif char == '3': + state = 973 + elif char == '2': + state = 974 + elif char == '5': + state = 975 + elif char == '4': + state = 976 + elif char == '7': + state = 977 + elif char == '6': + state = 978 + else: + break + if state == 948: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 948 + return i + if char == '1': + state = 963 + elif char == '0': + state = 964 + elif char == '3': + state = 965 + elif char == '2': + state = 966 + elif char == '5': + state = 967 + elif char == '4': + state = 968 + elif char == '7': + state = 969 + elif char == '6': + state = 970 + else: + break + if state == 687: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 687 + return i + if char == '6': + state = 736 + elif char == '1': + state = 729 + elif char == '0': + state = 730 + elif char == '3': + state = 731 + elif char == '2': + state = 732 + elif char == '5': + state = 733 + elif char == '4': + state = 734 + elif char == '7': + state = 735 + else: + break + if state == 75: + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 75 + return ~i + if char == '1': + state = 265 + continue + elif char == '0': + state = 266 + continue + elif char == '3': + state = 267 + continue + elif char == '2': + state = 268 + continue + elif char == '5': + state = 269 + continue + elif char == '4': + state = 270 + continue + elif char == '7': + state = 271 + continue + elif char == '6': + state = 272 + continue + elif char == '9': + state = 273 + continue + elif char == '8': + state = 274 + continue + elif char == 'A': + state = 275 + continue + elif char == 'C': + state = 276 + continue + elif char == 'B': + state = 277 + continue + elif char == 'E': + state = 278 + continue + elif char == 'D': + state = 279 + continue + elif char == 'F': + state = 280 + continue + elif char == 'a': + state = 281 + continue + elif char == 'c': + state = 282 + continue + elif char == 'b': + state = 283 + continue + elif char == 'e': + state = 284 + continue + elif char == 'd': + state = 285 + continue + elif char == 'f': + state = 286 + continue + else: + break + if state == 855: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 855 + return i + if char == '1': + state = 933 + elif char == '0': + state = 934 + elif char == '3': + state = 935 + elif char == '2': + state = 936 + elif char == '5': + state = 937 + elif char == '4': + state = 938 + elif char == '7': + state = 939 + elif char == '6': + state = 940 + else: + break + if state == 856: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 856 + return i + if char == '2': + state = 928 + elif char == '5': + state = 929 + elif char == '4': + state = 930 + elif char == '7': + state = 931 + elif char == '6': + state = 932 + elif char == '1': + state = 925 + elif char == '0': + state = 926 + elif char == '3': + state = 927 + else: + break + if state == 857: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 857 + return i + if char == '1': + state = 917 + elif char == '0': + state = 918 + elif char == '3': + state = 919 + elif char == '2': + state = 920 + elif char == '5': + state = 921 + elif char == '4': + state = 922 + elif char == '7': + state = 923 + elif char == '6': + state = 924 + else: + break + if state == 858: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 858 + return i + if char == '1': + state = 909 + elif char == '0': + state = 910 + elif char == '3': + state = 911 + elif char == '2': + state = 912 + elif char == '5': + state = 913 + elif char == '4': + state = 914 + elif char == '7': + state = 915 + elif char == '6': + state = 916 + else: + break + if state == 859: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 859 + return i + if char == '1': + state = 901 + elif char == '0': + state = 902 + elif char == '3': + state = 903 + elif char == '2': + state = 904 + elif char == '5': + state = 905 + elif char == '4': + state = 906 + elif char == '7': + state = 907 + elif char == '6': + state = 908 + else: + break + if state == 860: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 860 + return i + if char == '2': + state = 896 + elif char == '5': + state = 897 + elif char == '4': + state = 898 + elif char == '7': + state = 899 + elif char == '6': + state = 900 + elif char == '1': + state = 893 + elif char == '0': + state = 894 + elif char == '3': + state = 895 + else: + break + if state == 861: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 861 + return i + if char == '1': + state = 885 + elif char == '0': + state = 886 + elif char == '3': + state = 887 + elif char == '2': + state = 888 + elif char == '5': + state = 889 + elif char == '4': + state = 890 + elif char == '7': + state = 891 + elif char == '6': + state = 892 else: break - if state == 292: + if state == 862: + runner.last_matched_index = i - 1 + runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 292 - return ~i + runner.state = 862 + return i if char == '1': - state = 339 + state = 877 elif char == '0': - state = 340 + state = 878 elif char == '3': - state = 341 + state = 879 elif char == '2': - state = 342 + state = 880 elif char == '5': - state = 343 + state = 881 elif char == '4': - state = 344 + state = 882 elif char == '7': - state = 345 + state = 883 elif char == '6': - state = 346 - elif char == '9': - state = 347 - elif char == '8': - state = 348 - elif char == 'A': - state = 349 - elif char == 'C': - state = 350 - elif char == 'B': - state = 351 - elif char == 'E': - state = 352 - elif char == 'D': - state = 353 - elif char == 'F': - state = 354 - elif char == 'a': - state = 355 - elif char == 'c': - state = 356 - elif char == 'b': - state = 357 - elif char == 'e': - state = 358 - elif char == 'd': - state = 359 - elif char == 'f': - state = 360 + state = 884 else: break - if state == 293: + if state == 685: + runner.last_matched_index = i - 1 + runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 293 - return ~i + runner.state = 685 + return i if char == '1': - state = 317 + state = 745 elif char == '0': - state = 318 + state = 746 elif char == '3': - state = 319 + state = 747 elif char == '2': - state = 320 + state = 748 elif char == '5': - state = 321 + state = 749 elif char == '4': - state = 322 + state = 750 elif char == '7': - state = 323 + state = 751 elif char == '6': - state = 324 - elif char == '9': - state = 325 - elif char == '8': - state = 326 - elif char == 'A': - state = 327 - elif char == 'C': - state = 328 - elif char == 'B': - state = 329 - elif char == 'E': - state = 330 - elif char == 'D': - state = 331 - elif char == 'F': - state = 332 - elif char == 'a': - state = 333 - elif char == 'c': - state = 334 - elif char == 'b': - state = 335 - elif char == 'e': - state = 336 - elif char == 'd': - state = 337 - elif char == 'f': - state = 338 + state = 752 else: break - if state == 294: + if state == 772: + runner.last_matched_index = i - 1 + runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 294 - return ~i + runner.state = 772 + return i if char == '1': - state = 295 + state = 823 elif char == '0': - state = 296 + state = 824 elif char == '3': - state = 297 + state = 825 elif char == '2': - state = 298 + state = 826 elif char == '5': - state = 299 + state = 827 elif char == '4': - state = 300 + state = 828 elif char == '7': - state = 301 + state = 829 elif char == '6': - state = 302 - elif char == '9': - state = 303 - elif char == '8': - state = 304 - elif char == 'A': - state = 305 - elif char == 'C': - state = 306 - elif char == 'B': - state = 307 - elif char == 'E': - state = 308 - elif char == 'D': - state = 309 - elif char == 'F': - state = 310 - elif char == 'a': - state = 311 - elif char == 'c': - state = 312 - elif char == 'b': - state = 313 - elif char == 'e': - state = 314 - elif char == 'd': - state = 315 - elif char == 'f': - state = 316 + state = 830 else: break - if state == 77: + if state == 775: + runner.last_matched_index = i - 1 + runner.last_matched_state = state if i < len(input): char = input[i] i += 1 else: - runner.state = 77 - return ~i + runner.state = 775 + return i + if char == '0': + state = 800 + elif char == '3': + state = 801 + elif char == '2': + state = 802 + elif char == '5': + state = 803 + elif char == '4': + state = 804 + elif char == '7': + state = 805 + elif char == '6': + state = 806 + elif char == '1': + state = 799 + else: + break + if state == 946: + runner.last_matched_index = i - 1 + runner.last_matched_state = state + if i < len(input): + char = input[i] + i += 1 + else: + runner.state = 946 + return i if char == '1': - state = 273 - continue + state = 979 elif char == '0': - state = 274 - continue + state = 980 elif char == '3': - state = 275 - continue + state = 981 elif char == '2': - state = 276 - continue + state = 982 elif char == '5': - state = 277 - continue + state = 983 elif char == '4': - state = 278 - continue + state = 984 elif char == '7': - state = 279 - continue + state = 985 elif char == '6': - state = 280 - continue - elif char == '9': - state = 281 - continue - elif char == '8': - state = 282 - continue - elif char == 'A': - state = 283 - continue - elif char == 'C': - state = 284 - continue - elif char == 'B': - state = 285 - continue - elif char == 'E': - state = 286 - continue - elif char == 'D': - state = 287 - continue - elif char == 'F': - state = 288 - continue - elif char == 'a': - state = 289 - continue - elif char == 'c': - state = 290 - continue - elif char == 'b': - state = 291 - continue - elif char == 'e': - state = 292 - continue - elif char == 'd': - state = 293 - continue - elif char == 'f': - state = 294 - continue + state = 986 else: break runner.last_matched_state = state @@ -1998,7 +3024,7 @@ break runner.state = state return ~i -lexer = DummyLexer(recognize, DFA(779, +lexer = DummyLexer(recognize, DFA(1027, {(0, '\t'): 1, (0, '\n'): 1, (0, '\x0b'): 1, @@ -2100,786 +3126,1305 @@ (0, '}'): 16, (0, '~'): 1, (4, '\x00'): 17, - (4, '\x01'): 209, - (4, '\x02'): 146, - (4, '\x03'): 82, + (4, '\x01'): 203, + (4, '\x02'): 142, + (4, '\x03'): 80, (4, '\x04'): 19, - (4, '\x05'): 211, - (4, '\x06'): 148, - (4, '\x07'): 84, + (4, '\x05'): 205, + (4, '\x06'): 144, + (4, '\x07'): 82, (4, '\x08'): 21, - (4, '\t'): 213, - (4, '\n'): 150, - (4, '\x0b'): 86, + (4, '\t'): 207, + (4, '\n'): 146, + (4, '\x0b'): 84, (4, '\x0c'): 23, - (4, '\r'): 215, - (4, '\x0e'): 152, - (4, '\x0f'): 88, + (4, '\r'): 209, + (4, '\x0e'): 148, + (4, '\x0f'): 86, (4, '\x10'): 25, - (4, '\x11'): 217, - (4, '\x12'): 154, - (4, '\x13'): 90, + (4, '\x11'): 211, + (4, '\x12'): 150, + (4, '\x13'): 88, (4, '\x14'): 27, - (4, '\x15'): 219, - (4, '\x16'): 156, - (4, '\x17'): 92, + (4, '\x15'): 213, + (4, '\x16'): 152, + (4, '\x17'): 90, (4, '\x18'): 29, - (4, '\x19'): 221, - (4, '\x1a'): 158, - (4, '\x1b'): 94, + (4, '\x19'): 215, + (4, '\x1a'): 154, + (4, '\x1b'): 92, (4, '\x1c'): 31, - (4, '\x1d'): 223, - (4, '\x1e'): 160, - (4, '\x1f'): 96, + (4, '\x1d'): 217, + (4, '\x1e'): 156, + (4, '\x1f'): 94, (4, ' '): 33, - (4, '!'): 225, - (4, '"'): 162, - (4, '#'): 98, + (4, '!'): 219, + (4, '"'): 158, + (4, '#'): 96, (4, '$'): 35, - (4, '%'): 227, - (4, '&'): 164, - (4, "'"): 100, + (4, '%'): 221, + (4, '&'): 160, + (4, "'"): 98, (4, '('): 37, - (4, ')'): 229, - (4, '*'): 166, - (4, '+'): 102, + (4, ')'): 223, + (4, '*'): 162, + (4, '+'): 100, (4, ','): 39, - (4, '-'): 231, - (4, '.'): 168, - (4, '/'): 104, - (4, '0'): 41, - (4, '1'): 233, - (4, '2'): 170, - (4, '3'): 106, - (4, '4'): 43, - (4, '5'): 235, - (4, '6'): 172, - (4, '7'): 108, - (4, '8'): 45, - (4, '9'): 237, - (4, ':'): 174, - (4, ';'): 110, - (4, '<'): 47, - (4, '='): 239, - (4, '>'): 176, - (4, '?'): 112, - (4, '@'): 49, - (4, 'A'): 241, - (4, 'B'): 178, - (4, 'C'): 114, - (4, 'D'): 51, - (4, 'E'): 243, - (4, 'F'): 180, - (4, 'G'): 116, - (4, 'H'): 53, - (4, 'I'): 245, - (4, 'J'): 182, - (4, 'K'): 118, - (4, 'L'): 55, - (4, 'M'): 247, - (4, 'N'): 184, - (4, 'O'): 120, - (4, 'P'): 57, - (4, 'Q'): 249, - (4, 'R'): 186, - (4, 'S'): 122, - (4, 'T'): 59, - (4, 'U'): 251, - (4, 'V'): 188, - (4, 'W'): 124, - (4, 'X'): 61, - (4, 'Y'): 253, - (4, 'Z'): 190, - (4, '['): 126, - (4, '\\'): 63, - (4, ']'): 255, - (4, '^'): 192, - (4, '_'): 128, - (4, '`'): 65, - (4, 'a'): 257, - (4, 'b'): 194, - (4, 'c'): 130, - (4, 'd'): 67, - (4, 'e'): 259, - (4, 'f'): 196, - (4, 'g'): 132, - (4, 'h'): 69, - (4, 'i'): 261, - (4, 'j'): 198, - (4, 'k'): 134, - (4, 'l'): 71, - (4, 'm'): 263, - (4, 'n'): 200, - (4, 'o'): 136, - (4, 'p'): 73, - (4, 'q'): 265, - (4, 'r'): 202, - (4, 's'): 138, - (4, 't'): 75, - (4, 'u'): 267, - (4, 'v'): 204, - (4, 'w'): 140, - (4, 'x'): 77, - (4, 'y'): 269, - (4, 'z'): 206, - (4, '{'): 142, - (4, '|'): 79, - (4, '}'): 271, - (4, '~'): 208, - (4, '\x7f'): 144, - (4, '\x80'): 81, - (4, '\x81'): 145, - (4, '\x82'): 210, + (4, '-'): 225, + (4, '.'): 164, + (4, '/'): 102, + (4, '8'): 43, + (4, '9'): 229, + (4, ':'): 168, + (4, ';'): 106, + (4, '<'): 45, + (4, '='): 231, + (4, '>'): 170, + (4, '?'): 108, + (4, '@'): 47, + (4, 'A'): 233, + (4, 'B'): 172, + (4, 'C'): 110, + (4, 'D'): 49, + (4, 'E'): 235, + (4, 'F'): 174, + (4, 'G'): 112, + (4, 'H'): 51, + (4, 'I'): 237, + (4, 'J'): 176, + (4, 'K'): 114, + (4, 'L'): 53, + (4, 'M'): 239, + (4, 'N'): 178, + (4, 'O'): 116, + (4, 'P'): 55, + (4, 'Q'): 241, + (4, 'R'): 180, + (4, 'S'): 118, + (4, 'T'): 57, + (4, 'U'): 243, + (4, 'V'): 182, + (4, 'W'): 120, + (4, 'X'): 59, + (4, 'Y'): 245, + (4, 'Z'): 184, + (4, '['): 122, + (4, '\\'): 61, + (4, ']'): 247, + (4, '^'): 186, + (4, '_'): 124, + (4, '`'): 63, + (4, 'a'): 249, + (4, 'b'): 188, + (4, 'c'): 126, + (4, 'd'): 65, + (4, 'e'): 251, + (4, 'f'): 190, + (4, 'g'): 128, + (4, 'h'): 67, + (4, 'i'): 253, + (4, 'j'): 192, + (4, 'k'): 130, + (4, 'l'): 69, + (4, 'm'): 255, + (4, 'n'): 194, + (4, 'o'): 132, + (4, 'p'): 71, + (4, 'q'): 257, + (4, 'r'): 196, + (4, 's'): 134, + (4, 't'): 73, + (4, 'u'): 259, + (4, 'v'): 198, + (4, 'w'): 136, + (4, 'x'): 75, + (4, 'y'): 261, + (4, 'z'): 200, + (4, '{'): 138, + (4, '|'): 77, + (4, '}'): 263, + (4, '~'): 202, + (4, '\x7f'): 140, + (4, '\x80'): 79, + (4, '\x81'): 141, + (4, '\x82'): 204, (4, '\x83'): 18, - (4, '\x84'): 83, - (4, '\x85'): 147, - (4, '\x86'): 212, + (4, '\x84'): 81, + (4, '\x85'): 143, + (4, '\x86'): 206, (4, '\x87'): 20, - (4, '\x88'): 85, - (4, '\x89'): 149, - (4, '\x8a'): 214, + (4, '\x88'): 83, + (4, '\x89'): 145, + (4, '\x8a'): 208, (4, '\x8b'): 22, - (4, '\x8c'): 87, - (4, '\x8d'): 151, - (4, '\x8e'): 216, + (4, '\x8c'): 85, + (4, '\x8d'): 147, + (4, '\x8e'): 210, (4, '\x8f'): 24, - (4, '\x90'): 89, - (4, '\x91'): 153, - (4, '\x92'): 218, + (4, '\x90'): 87, + (4, '\x91'): 149, + (4, '\x92'): 212, (4, '\x93'): 26, - (4, '\x94'): 91, - (4, '\x95'): 155, - (4, '\x96'): 220, + (4, '\x94'): 89, + (4, '\x95'): 151, + (4, '\x96'): 214, (4, '\x97'): 28, - (4, '\x98'): 93, - (4, '\x99'): 157, - (4, '\x9a'): 222, + (4, '\x98'): 91, + (4, '\x99'): 153, + (4, '\x9a'): 216, (4, '\x9b'): 30, - (4, '\x9c'): 95, - (4, '\x9d'): 159, - (4, '\x9e'): 224, + (4, '\x9c'): 93, + (4, '\x9d'): 155, + (4, '\x9e'): 218, (4, '\x9f'): 32, - (4, '\xa0'): 97, - (4, '\xa1'): 161, - (4, '\xa2'): 226, + (4, '\xa0'): 95, + (4, '\xa1'): 157, + (4, '\xa2'): 220, (4, '\xa3'): 34, - (4, '\xa4'): 99, - (4, '\xa5'): 163, - (4, '\xa6'): 228, + (4, '\xa4'): 97, + (4, '\xa5'): 159, + (4, '\xa6'): 222, (4, '\xa7'): 36, - (4, '\xa8'): 101, - (4, '\xa9'): 165, - (4, '\xaa'): 230, + (4, '\xa8'): 99, + (4, '\xa9'): 161, + (4, '\xaa'): 224, (4, '\xab'): 38, - (4, '\xac'): 103, - (4, '\xad'): 167, - (4, '\xae'): 232, + (4, '\xac'): 101, + (4, '\xad'): 163, + (4, '\xae'): 226, (4, '\xaf'): 40, - (4, '\xb0'): 105, - (4, '\xb1'): 169, - (4, '\xb2'): 234, - (4, '\xb3'): 42, - (4, '\xb4'): 107, - (4, '\xb5'): 171, - (4, '\xb6'): 236, - (4, '\xb7'): 44, - (4, '\xb8'): 109, - (4, '\xb9'): 173, - (4, '\xba'): 238, - (4, '\xbb'): 46, - (4, '\xbc'): 111, - (4, '\xbd'): 175, - (4, '\xbe'): 240, - (4, '\xbf'): 48, - (4, '\xc0'): 113, - (4, '\xc1'): 177, - (4, '\xc2'): 242, - (4, '\xc3'): 50, - (4, '\xc4'): 115, - (4, '\xc5'): 179, - (4, '\xc6'): 244, - (4, '\xc7'): 52, - (4, '\xc8'): 117, - (4, '\xc9'): 181, - (4, '\xca'): 246, - (4, '\xcb'): 54, - (4, '\xcc'): 119, - (4, '\xcd'): 183, - (4, '\xce'): 248, - (4, '\xcf'): 56, - (4, '\xd0'): 121, - (4, '\xd1'): 185, - (4, '\xd2'): 250, - (4, '\xd3'): 58, - (4, '\xd4'): 123, - (4, '\xd5'): 187, - (4, '\xd6'): 252, - (4, '\xd7'): 60, - (4, '\xd8'): 125, - (4, '\xd9'): 189, - (4, '\xda'): 254, - (4, '\xdb'): 62, - (4, '\xdc'): 127, - (4, '\xdd'): 191, - (4, '\xde'): 256, - (4, '\xdf'): 64, - (4, '\xe0'): 129, - (4, '\xe1'): 193, - (4, '\xe2'): 258, - (4, '\xe3'): 66, - (4, '\xe4'): 131, - (4, '\xe5'): 195, - (4, '\xe6'): 260, - (4, '\xe7'): 68, - (4, '\xe8'): 133, - (4, '\xe9'): 197, - (4, '\xea'): 262, - (4, '\xeb'): 70, - (4, '\xec'): 135, - (4, '\xed'): 199, - (4, '\xee'): 264, - (4, '\xef'): 72, - (4, '\xf0'): 137, - (4, '\xf1'): 201, - (4, '\xf2'): 266, - (4, '\xf3'): 74, - (4, '\xf4'): 139, - (4, '\xf5'): 203, - (4, '\xf6'): 268, - (4, '\xf7'): 76, - (4, '\xf8'): 141, - (4, '\xf9'): 205, - (4, '\xfa'): 270, - (4, '\xfb'): 78, - (4, '\xfc'): 143, - (4, '\xfd'): 207, - (4, '\xfe'): 272, - (4, '\xff'): 80, - (77, '0'): 274, - (77, '1'): 273, - (77, '2'): 276, - (77, '3'): 275, - (77, '4'): 278, - (77, '5'): 277, - (77, '6'): 280, - (77, '7'): 279, - (77, '8'): 282, - (77, '9'): 281, - (77, 'A'): 283, - (77, 'B'): 285, - (77, 'C'): 284, - (77, 'D'): 287, - (77, 'E'): 286, - (77, 'F'): 288, - (77, 'a'): 289, - (77, 'b'): 291, - (77, 'c'): 290, - (77, 'd'): 293, - (77, 'e'): 292, - (77, 'f'): 294, - (273, '0'): 758, - (273, '1'): 757, - (273, '2'): 760, - (273, '3'): 759, - (273, '4'): 762, - (273, '5'): 761, - (273, '6'): 764, - (273, '7'): 763, - (273, '8'): 766, - (273, '9'): 765, - (273, 'A'): 767, - (273, 'B'): 769, - (273, 'C'): 768, - (273, 'D'): 771, - (273, 'E'): 770, - (273, 'F'): 772, - (273, 'a'): 773, - (273, 'b'): 775, - (273, 'c'): 774, - (273, 'd'): 777, - (273, 'e'): 776, - (273, 'f'): 778, - (274, '0'): 736, - (274, '1'): 735, - (274, '2'): 738, - (274, '3'): 737, - (274, '4'): 740, - (274, '5'): 739, - (274, '6'): 742, - (274, '7'): 741, - (274, '8'): 744, - (274, '9'): 743, - (274, 'A'): 745, - (274, 'B'): 747, - (274, 'C'): 746, - (274, 'D'): 749, - (274, 'E'): 748, - (274, 'F'): 750, - (274, 'a'): 751, - (274, 'b'): 753, - (274, 'c'): 752, - (274, 'd'): 755, - (274, 'e'): 754, - (274, 'f'): 756, - (275, '0'): 714, - (275, '1'): 713, - (275, '2'): 716, - (275, '3'): 715, - (275, '4'): 718, - (275, '5'): 717, - (275, '6'): 720, - (275, '7'): 719, - (275, '8'): 722, - (275, '9'): 721, - (275, 'A'): 723, - (275, 'B'): 725, - (275, 'C'): 724, - (275, 'D'): 727, - (275, 'E'): 726, - (275, 'F'): 728, - (275, 'a'): 729, - (275, 'b'): 731, - (275, 'c'): 730, - (275, 'd'): 733, - (275, 'e'): 732, - (275, 'f'): 734, - (276, '0'): 692, - (276, '1'): 691, - (276, '2'): 694, - (276, '3'): 693, - (276, '4'): 696, - (276, '5'): 695, - (276, '6'): 698, - (276, '7'): 697, - (276, '8'): 700, - (276, '9'): 699, - (276, 'A'): 701, - (276, 'B'): 703, - (276, 'C'): 702, - (276, 'D'): 705, - (276, 'E'): 704, - (276, 'F'): 706, - (276, 'a'): 707, - (276, 'b'): 709, - (276, 'c'): 708, - (276, 'd'): 711, - (276, 'e'): 710, - (276, 'f'): 712, - (277, '0'): 670, - (277, '1'): 669, - (277, '2'): 672, - (277, '3'): 671, - (277, '4'): 674, - (277, '5'): 673, - (277, '6'): 676, - (277, '7'): 675, - (277, '8'): 678, - (277, '9'): 677, - (277, 'A'): 679, - (277, 'B'): 681, - (277, 'C'): 680, - (277, 'D'): 683, - (277, 'E'): 682, - (277, 'F'): 684, - (277, 'a'): 685, - (277, 'b'): 687, - (277, 'c'): 686, - (277, 'd'): 689, - (277, 'e'): 688, - (277, 'f'): 690, - (278, '0'): 648, - (278, '1'): 647, - (278, '2'): 650, - (278, '3'): 649, - (278, '4'): 652, - (278, '5'): 651, - (278, '6'): 654, - (278, '7'): 653, - (278, '8'): 656, - (278, '9'): 655, - (278, 'A'): 657, - (278, 'B'): 659, - (278, 'C'): 658, - (278, 'D'): 661, - (278, 'E'): 660, - (278, 'F'): 662, - (278, 'a'): 663, - (278, 'b'): 665, - (278, 'c'): 664, - (278, 'd'): 667, - (278, 'e'): 666, - (278, 'f'): 668, - (279, '0'): 626, - (279, '1'): 625, - (279, '2'): 628, - (279, '3'): 627, - (279, '4'): 630, - (279, '5'): 629, - (279, '6'): 632, - (279, '7'): 631, - (279, '8'): 634, - (279, '9'): 633, - (279, 'A'): 635, - (279, 'B'): 637, - (279, 'C'): 636, - (279, 'D'): 639, - (279, 'E'): 638, - (279, 'F'): 640, - (279, 'a'): 641, - (279, 'b'): 643, - (279, 'c'): 642, - (279, 'd'): 645, - (279, 'e'): 644, - (279, 'f'): 646, - (280, '0'): 604, - (280, '1'): 603, - (280, '2'): 606, - (280, '3'): 605, - (280, '4'): 608, - (280, '5'): 607, - (280, '6'): 610, - (280, '7'): 609, - (280, '8'): 612, - (280, '9'): 611, - (280, 'A'): 613, - (280, 'B'): 615, - (280, 'C'): 614, - (280, 'D'): 617, - (280, 'E'): 616, - (280, 'F'): 618, - (280, 'a'): 619, - (280, 'b'): 621, - (280, 'c'): 620, - (280, 'd'): 623, - (280, 'e'): 622, - (280, 'f'): 624, - (281, '0'): 582, - (281, '1'): 581, - (281, '2'): 584, - (281, '3'): 583, - (281, '4'): 586, - (281, '5'): 585, - (281, '6'): 588, - (281, '7'): 587, - (281, '8'): 590, - (281, '9'): 589, - (281, 'A'): 591, - (281, 'B'): 593, - (281, 'C'): 592, - (281, 'D'): 595, - (281, 'E'): 594, - (281, 'F'): 596, - (281, 'a'): 597, - (281, 'b'): 599, - (281, 'c'): 598, - (281, 'd'): 601, - (281, 'e'): 600, - (281, 'f'): 602, - (282, '0'): 560, - (282, '1'): 559, - (282, '2'): 562, - (282, '3'): 561, - (282, '4'): 564, - (282, '5'): 563, - (282, '6'): 566, - (282, '7'): 565, - (282, '8'): 568, - (282, '9'): 567, - (282, 'A'): 569, - (282, 'B'): 571, - (282, 'C'): 570, - (282, 'D'): 573, - (282, 'E'): 572, - (282, 'F'): 574, - (282, 'a'): 575, - (282, 'b'): 577, - (282, 'c'): 576, - (282, 'd'): 579, - (282, 'e'): 578, - (282, 'f'): 580, - (283, '0'): 538, - (283, '1'): 537, - (283, '2'): 540, - (283, '3'): 539, - (283, '4'): 542, - (283, '5'): 541, - (283, '6'): 544, - (283, '7'): 543, - (283, '8'): 546, - (283, '9'): 545, - (283, 'A'): 547, - (283, 'B'): 549, - (283, 'C'): 548, - (283, 'D'): 551, - (283, 'E'): 550, - (283, 'F'): 552, - (283, 'a'): 553, - (283, 'b'): 555, - (283, 'c'): 554, - (283, 'd'): 557, - (283, 'e'): 556, - (283, 'f'): 558, - (284, '0'): 516, - (284, '1'): 515, - (284, '2'): 518, - (284, '3'): 517, - (284, '4'): 520, - (284, '5'): 519, - (284, '6'): 522, - (284, '7'): 521, - (284, '8'): 524, - (284, '9'): 523, - (284, 'A'): 525, - (284, 'B'): 527, - (284, 'C'): 526, - (284, 'D'): 529, - (284, 'E'): 528, - (284, 'F'): 530, - (284, 'a'): 531, - (284, 'b'): 533, - (284, 'c'): 532, - (284, 'd'): 535, - (284, 'e'): 534, - (284, 'f'): 536, - (285, '0'): 494, - (285, '1'): 493, - (285, '2'): 496, - (285, '3'): 495, - (285, '4'): 498, - (285, '5'): 497, - (285, '6'): 500, - (285, '7'): 499, - (285, '8'): 502, - (285, '9'): 501, - (285, 'A'): 503, - (285, 'B'): 505, - (285, 'C'): 504, - (285, 'D'): 507, - (285, 'E'): 506, - (285, 'F'): 508, - (285, 'a'): 509, - (285, 'b'): 511, - (285, 'c'): 510, - (285, 'd'): 513, - (285, 'e'): 512, - (285, 'f'): 514, - (286, '0'): 472, - (286, '1'): 471, - (286, '2'): 474, - (286, '3'): 473, - (286, '4'): 476, - (286, '5'): 475, - (286, '6'): 478, - (286, '7'): 477, - (286, '8'): 480, - (286, '9'): 479, - (286, 'A'): 481, - (286, 'B'): 483, - (286, 'C'): 482, - (286, 'D'): 485, - (286, 'E'): 484, - (286, 'F'): 486, - (286, 'a'): 487, - (286, 'b'): 489, - (286, 'c'): 488, - (286, 'd'): 491, - (286, 'e'): 490, - (286, 'f'): 492, - (287, '0'): 450, - (287, '1'): 449, - (287, '2'): 452, - (287, '3'): 451, - (287, '4'): 454, - (287, '5'): 453, - (287, '6'): 456, - (287, '7'): 455, - (287, '8'): 458, - (287, '9'): 457, - (287, 'A'): 459, - (287, 'B'): 461, - (287, 'C'): 460, - (287, 'D'): 463, - (287, 'E'): 462, - (287, 'F'): 464, - (287, 'a'): 465, - (287, 'b'): 467, - (287, 'c'): 466, - (287, 'd'): 469, - (287, 'e'): 468, - (287, 'f'): 470, - (288, '0'): 428, - (288, '1'): 427, - (288, '2'): 430, - (288, '3'): 429, - (288, '4'): 432, - (288, '5'): 431, - (288, '6'): 434, - (288, '7'): 433, - (288, '8'): 436, - (288, '9'): 435, - (288, 'A'): 437, - (288, 'B'): 439, - (288, 'C'): 438, - (288, 'D'): 441, - (288, 'E'): 440, - (288, 'F'): 442, - (288, 'a'): 443, - (288, 'b'): 445, - (288, 'c'): 444, - (288, 'd'): 447, - (288, 'e'): 446, - (288, 'f'): 448, - (289, '0'): 406, - (289, '1'): 405, - (289, '2'): 408, - (289, '3'): 407, - (289, '4'): 410, - (289, '5'): 409, - (289, '6'): 412, - (289, '7'): 411, - (289, '8'): 414, - (289, '9'): 413, - (289, 'A'): 415, - (289, 'B'): 417, - (289, 'C'): 416, - (289, 'D'): 419, - (289, 'E'): 418, - (289, 'F'): 420, - (289, 'a'): 421, - (289, 'b'): 423, - (289, 'c'): 422, - (289, 'd'): 425, - (289, 'e'): 424, - (289, 'f'): 426, - (290, '0'): 384, - (290, '1'): 383, - (290, '2'): 386, - (290, '3'): 385, - (290, '4'): 388, - (290, '5'): 387, - (290, '6'): 390, - (290, '7'): 389, - (290, '8'): 392, - (290, '9'): 391, - (290, 'A'): 393, - (290, 'B'): 395, - (290, 'C'): 394, - (290, 'D'): 397, - (290, 'E'): 396, - (290, 'F'): 398, - (290, 'a'): 399, - (290, 'b'): 401, - (290, 'c'): 400, - (290, 'd'): 403, - (290, 'e'): 402, - (290, 'f'): 404, - (291, '0'): 362, - (291, '1'): 361, - (291, '2'): 364, - (291, '3'): 363, - (291, '4'): 366, - (291, '5'): 365, - (291, '6'): 368, - (291, '7'): 367, - (291, '8'): 370, - (291, '9'): 369, - (291, 'A'): 371, - (291, 'B'): 373, - (291, 'C'): 372, - (291, 'D'): 375, - (291, 'E'): 374, - (291, 'F'): 376, - (291, 'a'): 377, - (291, 'b'): 379, - (291, 'c'): 378, - (291, 'd'): 381, - (291, 'e'): 380, - (291, 'f'): 382, - (292, '0'): 340, - (292, '1'): 339, - (292, '2'): 342, - (292, '3'): 341, - (292, '4'): 344, - (292, '5'): 343, - (292, '6'): 346, - (292, '7'): 345, - (292, '8'): 348, - (292, '9'): 347, - (292, 'A'): 349, - (292, 'B'): 351, - (292, 'C'): 350, - (292, 'D'): 353, - (292, 'E'): 352, - (292, 'F'): 354, - (292, 'a'): 355, - (292, 'b'): 357, - (292, 'c'): 356, - (292, 'd'): 359, - (292, 'e'): 358, - (292, 'f'): 360, - (293, '0'): 318, - (293, '1'): 317, - (293, '2'): 320, - (293, '3'): 319, - (293, '4'): 322, - (293, '5'): 321, - (293, '6'): 324, - (293, '7'): 323, - (293, '8'): 326, - (293, '9'): 325, - (293, 'A'): 327, - (293, 'B'): 329, - (293, 'C'): 328, - (293, 'D'): 331, - (293, 'E'): 330, - (293, 'F'): 332, - (293, 'a'): 333, - (293, 'b'): 335, - (293, 'c'): 334, - (293, 'd'): 337, - (293, 'e'): 336, - (293, 'f'): 338, - (294, '0'): 296, - (294, '1'): 295, - (294, '2'): 298, - (294, '3'): 297, - (294, '4'): 300, - (294, '5'): 299, - (294, '6'): 302, - (294, '7'): 301, - (294, '8'): 304, - (294, '9'): 303, - (294, 'A'): 305, - (294, 'B'): 307, - (294, 'C'): 306, - (294, 'D'): 309, - (294, 'E'): 308, - (294, 'F'): 310, - (294, 'a'): 311, - (294, 'b'): 313, - (294, 'c'): 312, - (294, 'd'): 315, - (294, 'e'): 314, - (294, 'f'): 316}, - set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778]), - set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778]), - ['0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0', + (4, '\xb0'): 103, + (4, '\xb1'): 165, + (4, '\xb2'): 227, + (4, '\xb3'): 41, + (4, '\xb4'): 104, + (4, '\xb5'): 166, + (4, '\xb6'): 228, + (4, '\xb7'): 42, + (4, '\xb8'): 105, + (4, '\xb9'): 167, + (4, '\xba'): 230, + (4, '\xbb'): 44, + (4, '\xbc'): 107, + (4, '\xbd'): 169, + (4, '\xbe'): 232, + (4, '\xbf'): 46, + (4, '\xc0'): 109, + (4, '\xc1'): 171, + (4, '\xc2'): 234, + (4, '\xc3'): 48, + (4, '\xc4'): 111, + (4, '\xc5'): 173, + (4, '\xc6'): 236, + (4, '\xc7'): 50, + (4, '\xc8'): 113, + (4, '\xc9'): 175, + (4, '\xca'): 238, + (4, '\xcb'): 52, + (4, '\xcc'): 115, + (4, '\xcd'): 177, + (4, '\xce'): 240, + (4, '\xcf'): 54, + (4, '\xd0'): 117, + (4, '\xd1'): 179, + (4, '\xd2'): 242, + (4, '\xd3'): 56, + (4, '\xd4'): 119, + (4, '\xd5'): 181, + (4, '\xd6'): 244, + (4, '\xd7'): 58, + (4, '\xd8'): 121, + (4, '\xd9'): 183, + (4, '\xda'): 246, + (4, '\xdb'): 60, + (4, '\xdc'): 123, + (4, '\xdd'): 185, + (4, '\xde'): 248, + (4, '\xdf'): 62, + (4, '\xe0'): 125, + (4, '\xe1'): 187, + (4, '\xe2'): 250, + (4, '\xe3'): 64, + (4, '\xe4'): 127, + (4, '\xe5'): 189, + (4, '\xe6'): 252, + (4, '\xe7'): 66, + (4, '\xe8'): 129, + (4, '\xe9'): 191, + (4, '\xea'): 254, + (4, '\xeb'): 68, + (4, '\xec'): 131, + (4, '\xed'): 193, + (4, '\xee'): 256, + (4, '\xef'): 70, + (4, '\xf0'): 133, + (4, '\xf1'): 195, + (4, '\xf2'): 258, + (4, '\xf3'): 72, + (4, '\xf4'): 135, + (4, '\xf5'): 197, + (4, '\xf6'): 260, + (4, '\xf7'): 74, + (4, '\xf8'): 137, + (4, '\xf9'): 199, + (4, '\xfa'): 262, + (4, '\xfb'): 76, + (4, '\xfc'): 139, + (4, '\xfd'): 201, + (4, '\xfe'): 264, + (4, '\xff'): 78, + (75, '0'): 266, + (75, '1'): 265, + (75, '2'): 268, + (75, '3'): 267, + (75, '4'): 270, + (75, '5'): 269, + (75, '6'): 272, + (75, '7'): 271, + (75, '8'): 274, + (75, '9'): 273, + (75, 'A'): 275, + (75, 'B'): 277, + (75, 'C'): 276, + (75, 'D'): 279, + (75, 'E'): 278, + (75, 'F'): 280, + (75, 'a'): 281, + (75, 'b'): 283, + (75, 'c'): 282, + (75, 'd'): 285, + (75, 'e'): 284, + (75, 'f'): 286, + (265, '0'): 942, + (265, '1'): 941, + (265, '2'): 944, + (265, '3'): 943, + (265, '4'): 946, + (265, '5'): 945, + (265, '6'): 948, + (265, '7'): 947, + (265, '8'): 950, + (265, '9'): 949, + (265, 'A'): 951, + (265, 'B'): 953, + (265, 'C'): 952, + (265, 'D'): 955, + (265, 'E'): 954, + (265, 'F'): 956, + (265, 'a'): 957, + (265, 'b'): 959, + (265, 'c'): 958, + (265, 'd'): 961, + (265, 'e'): 960, + (265, 'f'): 962, + (266, '0'): 856, + (266, '1'): 855, + (266, '2'): 858, + (266, '3'): 857, + (266, '4'): 860, + (266, '5'): 859, + (266, '6'): 862, + (266, '7'): 861, + (266, '8'): 864, + (266, '9'): 863, + (266, 'A'): 865, + (266, 'B'): 867, + (266, 'C'): 866, + (266, 'D'): 869, + (266, 'E'): 868, + (266, 'F'): 870, + (266, 'a'): 871, + (266, 'b'): 873, + (266, 'c'): 872, + (266, 'd'): 875, + (266, 'e'): 874, + (266, 'f'): 876, + (267, '0'): 770, + (267, '1'): 769, + (267, '2'): 772, + (267, '3'): 771, + (267, '4'): 774, + (267, '5'): 773, + (267, '6'): 776, + (267, '7'): 775, + (267, '8'): 778, + (267, '9'): 777, + (267, 'A'): 779, + (267, 'B'): 781, + (267, 'C'): 780, + (267, 'D'): 783, + (267, 'E'): 782, + (267, 'F'): 784, + (267, 'a'): 785, + (267, 'b'): 787, + (267, 'c'): 786, + (267, 'd'): 789, + (267, 'e'): 788, + (267, 'f'): 790, + (268, '0'): 684, + (268, '1'): 683, + (268, '2'): 686, + (268, '3'): 685, + (268, '4'): 688, + (268, '5'): 687, + (268, '6'): 690, + (268, '7'): 689, + (268, '8'): 692, + (268, '9'): 691, + (268, 'A'): 693, + (268, 'B'): 695, + (268, 'C'): 694, + (268, 'D'): 697, + (268, 'E'): 696, + (268, 'F'): 698, + (268, 'a'): 699, + (268, 'b'): 701, + (268, 'c'): 700, + (268, 'd'): 703, + (268, 'e'): 702, + (268, 'f'): 704, + (269, '0'): 662, + (269, '1'): 661, + (269, '2'): 664, + (269, '3'): 663, + (269, '4'): 666, + (269, '5'): 665, + (269, '6'): 668, + (269, '7'): 667, + (269, '8'): 670, + (269, '9'): 669, + (269, 'A'): 671, + (269, 'B'): 673, + (269, 'C'): 672, + (269, 'D'): 675, + (269, 'E'): 674, + (269, 'F'): 676, + (269, 'a'): 677, + (269, 'b'): 679, + (269, 'c'): 678, + (269, 'd'): 681, + (269, 'e'): 680, + (269, 'f'): 682, + (270, '0'): 640, + (270, '1'): 639, + (270, '2'): 642, + (270, '3'): 641, + (270, '4'): 644, + (270, '5'): 643, + (270, '6'): 646, + (270, '7'): 645, + (270, '8'): 648, + (270, '9'): 647, + (270, 'A'): 649, + (270, 'B'): 651, + (270, 'C'): 650, + (270, 'D'): 653, + (270, 'E'): 652, + (270, 'F'): 654, + (270, 'a'): 655, + (270, 'b'): 657, + (270, 'c'): 656, + (270, 'd'): 659, + (270, 'e'): 658, + (270, 'f'): 660, + (271, '0'): 618, + (271, '1'): 617, + (271, '2'): 620, + (271, '3'): 619, + (271, '4'): 622, + (271, '5'): 621, + (271, '6'): 624, + (271, '7'): 623, + (271, '8'): 626, + (271, '9'): 625, + (271, 'A'): 627, + (271, 'B'): 629, + (271, 'C'): 628, + (271, 'D'): 631, + (271, 'E'): 630, + (271, 'F'): 632, + (271, 'a'): 633, + (271, 'b'): 635, + (271, 'c'): 634, + (271, 'd'): 637, + (271, 'e'): 636, + (271, 'f'): 638, + (272, '0'): 596, + (272, '1'): 595, + (272, '2'): 598, + (272, '3'): 597, + (272, '4'): 600, + (272, '5'): 599, + (272, '6'): 602, + (272, '7'): 601, + (272, '8'): 604, + (272, '9'): 603, + (272, 'A'): 605, + (272, 'B'): 607, + (272, 'C'): 606, + (272, 'D'): 609, + (272, 'E'): 608, + (272, 'F'): 610, + (272, 'a'): 611, + (272, 'b'): 613, + (272, 'c'): 612, + (272, 'd'): 615, + (272, 'e'): 614, + (272, 'f'): 616, + (273, '0'): 574, + (273, '1'): 573, + (273, '2'): 576, + (273, '3'): 575, + (273, '4'): 578, + (273, '5'): 577, + (273, '6'): 580, + (273, '7'): 579, + (273, '8'): 582, + (273, '9'): 581, + (273, 'A'): 583, + (273, 'B'): 585, + (273, 'C'): 584, + (273, 'D'): 587, + (273, 'E'): 586, + (273, 'F'): 588, + (273, 'a'): 589, + (273, 'b'): 591, + (273, 'c'): 590, + (273, 'd'): 593, + (273, 'e'): 592, + (273, 'f'): 594, + (274, '0'): 552, + (274, '1'): 551, + (274, '2'): 554, + (274, '3'): 553, + (274, '4'): 556, + (274, '5'): 555, + (274, '6'): 558, + (274, '7'): 557, + (274, '8'): 560, + (274, '9'): 559, + (274, 'A'): 561, + (274, 'B'): 563, + (274, 'C'): 562, + (274, 'D'): 565, + (274, 'E'): 564, + (274, 'F'): 566, + (274, 'a'): 567, + (274, 'b'): 569, + (274, 'c'): 568, + (274, 'd'): 571, + (274, 'e'): 570, + (274, 'f'): 572, + (275, '0'): 530, + (275, '1'): 529, + (275, '2'): 532, + (275, '3'): 531, + (275, '4'): 534, + (275, '5'): 533, + (275, '6'): 536, + (275, '7'): 535, + (275, '8'): 538, + (275, '9'): 537, + (275, 'A'): 539, + (275, 'B'): 541, + (275, 'C'): 540, + (275, 'D'): 543, + (275, 'E'): 542, + (275, 'F'): 544, + (275, 'a'): 545, + (275, 'b'): 547, + (275, 'c'): 546, + (275, 'd'): 549, + (275, 'e'): 548, + (275, 'f'): 550, + (276, '0'): 508, + (276, '1'): 507, + (276, '2'): 510, + (276, '3'): 509, + (276, '4'): 512, + (276, '5'): 511, + (276, '6'): 514, + (276, '7'): 513, + (276, '8'): 516, + (276, '9'): 515, + (276, 'A'): 517, + (276, 'B'): 519, + (276, 'C'): 518, + (276, 'D'): 521, + (276, 'E'): 520, + (276, 'F'): 522, + (276, 'a'): 523, + (276, 'b'): 525, + (276, 'c'): 524, + (276, 'd'): 527, + (276, 'e'): 526, + (276, 'f'): 528, + (277, '0'): 486, + (277, '1'): 485, + (277, '2'): 488, + (277, '3'): 487, + (277, '4'): 490, + (277, '5'): 489, + (277, '6'): 492, + (277, '7'): 491, + (277, '8'): 494, + (277, '9'): 493, + (277, 'A'): 495, + (277, 'B'): 497, + (277, 'C'): 496, + (277, 'D'): 499, + (277, 'E'): 498, + (277, 'F'): 500, + (277, 'a'): 501, + (277, 'b'): 503, + (277, 'c'): 502, + (277, 'd'): 505, + (277, 'e'): 504, + (277, 'f'): 506, + (278, '0'): 464, + (278, '1'): 463, + (278, '2'): 466, + (278, '3'): 465, + (278, '4'): 468, + (278, '5'): 467, + (278, '6'): 470, + (278, '7'): 469, + (278, '8'): 472, + (278, '9'): 471, + (278, 'A'): 473, + (278, 'B'): 475, + (278, 'C'): 474, + (278, 'D'): 477, + (278, 'E'): 476, + (278, 'F'): 478, + (278, 'a'): 479, + (278, 'b'): 481, + (278, 'c'): 480, + (278, 'd'): 483, + (278, 'e'): 482, + (278, 'f'): 484, + (279, '0'): 442, + (279, '1'): 441, + (279, '2'): 444, + (279, '3'): 443, + (279, '4'): 446, + (279, '5'): 445, + (279, '6'): 448, + (279, '7'): 447, + (279, '8'): 450, + (279, '9'): 449, + (279, 'A'): 451, + (279, 'B'): 453, + (279, 'C'): 452, + (279, 'D'): 455, + (279, 'E'): 454, + (279, 'F'): 456, + (279, 'a'): 457, + (279, 'b'): 459, + (279, 'c'): 458, + (279, 'd'): 461, + (279, 'e'): 460, + (279, 'f'): 462, + (280, '0'): 420, + (280, '1'): 419, + (280, '2'): 422, + (280, '3'): 421, + (280, '4'): 424, + (280, '5'): 423, + (280, '6'): 426, + (280, '7'): 425, + (280, '8'): 428, + (280, '9'): 427, + (280, 'A'): 429, + (280, 'B'): 431, + (280, 'C'): 430, + (280, 'D'): 433, + (280, 'E'): 432, + (280, 'F'): 434, + (280, 'a'): 435, + (280, 'b'): 437, + (280, 'c'): 436, + (280, 'd'): 439, + (280, 'e'): 438, + (280, 'f'): 440, + (281, '0'): 398, + (281, '1'): 397, + (281, '2'): 400, + (281, '3'): 399, + (281, '4'): 402, + (281, '5'): 401, + (281, '6'): 404, + (281, '7'): 403, + (281, '8'): 406, + (281, '9'): 405, + (281, 'A'): 407, + (281, 'B'): 409, + (281, 'C'): 408, + (281, 'D'): 411, + (281, 'E'): 410, + (281, 'F'): 412, + (281, 'a'): 413, + (281, 'b'): 415, + (281, 'c'): 414, + (281, 'd'): 417, + (281, 'e'): 416, + (281, 'f'): 418, + (282, '0'): 376, + (282, '1'): 375, + (282, '2'): 378, + (282, '3'): 377, + (282, '4'): 380, + (282, '5'): 379, + (282, '6'): 382, + (282, '7'): 381, + (282, '8'): 384, + (282, '9'): 383, + (282, 'A'): 385, + (282, 'B'): 387, + (282, 'C'): 386, + (282, 'D'): 389, + (282, 'E'): 388, + (282, 'F'): 390, + (282, 'a'): 391, + (282, 'b'): 393, + (282, 'c'): 392, + (282, 'd'): 395, + (282, 'e'): 394, + (282, 'f'): 396, + (283, '0'): 354, + (283, '1'): 353, + (283, '2'): 356, + (283, '3'): 355, + (283, '4'): 358, + (283, '5'): 357, + (283, '6'): 360, + (283, '7'): 359, + (283, '8'): 362, + (283, '9'): 361, + (283, 'A'): 363, + (283, 'B'): 365, + (283, 'C'): 364, + (283, 'D'): 367, + (283, 'E'): 366, + (283, 'F'): 368, + (283, 'a'): 369, + (283, 'b'): 371, + (283, 'c'): 370, + (283, 'd'): 373, + (283, 'e'): 372, + (283, 'f'): 374, + (284, '0'): 332, + (284, '1'): 331, + (284, '2'): 334, + (284, '3'): 333, + (284, '4'): 336, + (284, '5'): 335, + (284, '6'): 338, + (284, '7'): 337, + (284, '8'): 340, + (284, '9'): 339, + (284, 'A'): 341, + (284, 'B'): 343, + (284, 'C'): 342, + (284, 'D'): 345, + (284, 'E'): 344, + (284, 'F'): 346, + (284, 'a'): 347, + (284, 'b'): 349, + (284, 'c'): 348, + (284, 'd'): 351, + (284, 'e'): 350, + (284, 'f'): 352, + (285, '0'): 310, + (285, '1'): 309, + (285, '2'): 312, + (285, '3'): 311, + (285, '4'): 314, + (285, '5'): 313, + (285, '6'): 316, + (285, '7'): 315, + (285, '8'): 318, + (285, '9'): 317, + (285, 'A'): 319, + (285, 'B'): 321, + (285, 'C'): 320, + (285, 'D'): 323, + (285, 'E'): 322, + (285, 'F'): 324, + (285, 'a'): 325, + (285, 'b'): 327, + (285, 'c'): 326, + (285, 'd'): 329, + (285, 'e'): 328, + (285, 'f'): 330, + (286, '0'): 288, + (286, '1'): 287, + (286, '2'): 290, + (286, '3'): 289, + (286, '4'): 292, + (286, '5'): 291, + (286, '6'): 294, + (286, '7'): 293, + (286, '8'): 296, + (286, '9'): 295, + (286, 'A'): 297, + (286, 'B'): 299, + (286, 'C'): 298, + (286, 'D'): 301, + (286, 'E'): 300, + (286, 'F'): 302, + (286, 'a'): 303, + (286, 'b'): 305, + (286, 'c'): 304, + (286, 'd'): 307, + (286, 'e'): 306, + (286, 'f'): 308, + (683, '0'): 762, + (683, '1'): 761, + (683, '2'): 764, + (683, '3'): 763, + (683, '4'): 766, + (683, '5'): 765, + (683, '6'): 768, + (683, '7'): 767, + (684, '0'): 754, + (684, '1'): 753, + (684, '2'): 756, + (684, '3'): 755, + (684, '4'): 758, + (684, '5'): 757, + (684, '6'): 760, + (684, '7'): 759, + (685, '0'): 746, + (685, '1'): 745, + (685, '2'): 748, + (685, '3'): 747, + (685, '4'): 750, + (685, '5'): 749, + (685, '6'): 752, + (685, '7'): 751, + (686, '0'): 738, + (686, '1'): 737, + (686, '2'): 740, + (686, '3'): 739, + (686, '4'): 742, + (686, '5'): 741, + (686, '6'): 744, + (686, '7'): 743, + (687, '0'): 730, + (687, '1'): 729, + (687, '2'): 732, + (687, '3'): 731, + (687, '4'): 734, + (687, '5'): 733, + (687, '6'): 736, + (687, '7'): 735, + (688, '0'): 722, + (688, '1'): 721, + (688, '2'): 724, + (688, '3'): 723, + (688, '4'): 726, + (688, '5'): 725, + (688, '6'): 728, + (688, '7'): 727, + (689, '0'): 714, + (689, '1'): 713, + (689, '2'): 716, + (689, '3'): 715, + (689, '4'): 718, + (689, '5'): 717, + (689, '6'): 720, + (689, '7'): 719, + (690, '0'): 706, + (690, '1'): 705, + (690, '2'): 708, + (690, '3'): 707, + (690, '4'): 710, + (690, '5'): 709, + (690, '6'): 712, + (690, '7'): 711, + (769, '0'): 848, + (769, '1'): 847, + (769, '2'): 850, + (769, '3'): 849, + (769, '4'): 852, + (769, '5'): 851, + (769, '6'): 854, + (769, '7'): 853, + (770, '0'): 840, + (770, '1'): 839, + (770, '2'): 842, + (770, '3'): 841, + (770, '4'): 844, + (770, '5'): 843, + (770, '6'): 846, + (770, '7'): 845, + (771, '0'): 832, + (771, '1'): 831, + (771, '2'): 834, + (771, '3'): 833, + (771, '4'): 836, + (771, '5'): 835, + (771, '6'): 838, + (771, '7'): 837, + (772, '0'): 824, + (772, '1'): 823, + (772, '2'): 826, + (772, '3'): 825, + (772, '4'): 828, + (772, '5'): 827, + (772, '6'): 830, + (772, '7'): 829, + (773, '0'): 816, + (773, '1'): 815, + (773, '2'): 818, + (773, '3'): 817, + (773, '4'): 820, + (773, '5'): 819, + (773, '6'): 822, + (773, '7'): 821, + (774, '0'): 808, + (774, '1'): 807, + (774, '2'): 810, + (774, '3'): 809, + (774, '4'): 812, + (774, '5'): 811, + (774, '6'): 814, + (774, '7'): 813, + (775, '0'): 800, + (775, '1'): 799, + (775, '2'): 802, + (775, '3'): 801, + (775, '4'): 804, + (775, '5'): 803, + (775, '6'): 806, + (775, '7'): 805, + (776, '0'): 792, + (776, '1'): 791, + (776, '2'): 794, + (776, '3'): 793, + (776, '4'): 796, + (776, '5'): 795, + (776, '6'): 798, + (776, '7'): 797, + (855, '0'): 934, + (855, '1'): 933, + (855, '2'): 936, + (855, '3'): 935, + (855, '4'): 938, + (855, '5'): 937, + (855, '6'): 940, + (855, '7'): 939, + (856, '0'): 926, + (856, '1'): 925, + (856, '2'): 928, + (856, '3'): 927, + (856, '4'): 930, + (856, '5'): 929, + (856, '6'): 932, + (856, '7'): 931, + (857, '0'): 918, + (857, '1'): 917, + (857, '2'): 920, + (857, '3'): 919, + (857, '4'): 922, + (857, '5'): 921, + (857, '6'): 924, + (857, '7'): 923, + (858, '0'): 910, + (858, '1'): 909, + (858, '2'): 912, + (858, '3'): 911, + (858, '4'): 914, + (858, '5'): 913, + (858, '6'): 916, + (858, '7'): 915, + (859, '0'): 902, + (859, '1'): 901, + (859, '2'): 904, + (859, '3'): 903, + (859, '4'): 906, + (859, '5'): 905, + (859, '6'): 908, + (859, '7'): 907, + (860, '0'): 894, + (860, '1'): 893, + (860, '2'): 896, + (860, '3'): 895, + (860, '4'): 898, + (860, '5'): 897, + (860, '6'): 900, + (860, '7'): 899, + (861, '0'): 886, + (861, '1'): 885, + (861, '2'): 888, + (861, '3'): 887, + (861, '4'): 890, + (861, '5'): 889, + (861, '6'): 892, + (861, '7'): 891, + (862, '0'): 878, + (862, '1'): 877, + (862, '2'): 880, + (862, '3'): 879, + (862, '4'): 882, + (862, '5'): 881, + (862, '6'): 884, + (862, '7'): 883, + (941, '0'): 1020, + (941, '1'): 1019, + (941, '2'): 1022, + (941, '3'): 1021, + (941, '4'): 1024, + (941, '5'): 1023, + (941, '6'): 1026, + (941, '7'): 1025, + (942, '0'): 1012, + (942, '1'): 1011, + (942, '2'): 1014, + (942, '3'): 1013, + (942, '4'): 1016, + (942, '5'): 1015, + (942, '6'): 1018, + (942, '7'): 1017, + (943, '0'): 1004, + (943, '1'): 1003, + (943, '2'): 1006, + (943, '3'): 1005, + (943, '4'): 1008, + (943, '5'): 1007, + (943, '6'): 1010, + (943, '7'): 1009, + (944, '0'): 996, + (944, '1'): 995, + (944, '2'): 998, + (944, '3'): 997, + (944, '4'): 1000, + (944, '5'): 999, + (944, '6'): 1002, + (944, '7'): 1001, + (945, '0'): 988, + (945, '1'): 987, + (945, '2'): 990, + (945, '3'): 989, + (945, '4'): 992, + (945, '5'): 991, + (945, '6'): 994, + (945, '7'): 993, + (946, '0'): 980, + (946, '1'): 979, + (946, '2'): 982, + (946, '3'): 981, + (946, '4'): 984, + (946, '5'): 983, + (946, '6'): 986, + (946, '7'): 985, + (947, '0'): 972, + (947, '1'): 971, + (947, '2'): 974, + (947, '3'): 973, + (947, '4'): 976, + (947, '5'): 975, + (947, '6'): 978, + (947, '7'): 977, + (948, '0'): 964, + (948, '1'): 963, + (948, '2'): 966, + (948, '3'): 965, + (948, '4'): 968, + (948, '5'): 967, + (948, '6'): 970, + (948, '7'): 969}, + set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026]), + set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026]), + ['0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, start|, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0', 'CHAR', - '(', - ',', - 'CHAR', - '|', - '+', - '?', - '[', - '{', - '*', - '.', - '^', - ')', - '-', - ']', - '}', + '__6_(', + '__13_,', + 'QUOTEDCHAR', + '__0_|', + '__2_+', + '__3_?', + '__8_[', + '__4_{', + '__1_*', + '__10_.', + '__11_^', + '__7_)', + '__12_-', + '__9_]', + '__5_}', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + '2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + 'QUOTEDCHAR', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', + 'QUOTEDCHAR', 'QUOTEDCHAR', 'QUOTEDCHAR', 'QUOTEDCHAR', @@ -2940,7 +4485,6 @@ 'QUOTEDCHAR', 'QUOTEDCHAR', 'QUOTEDCHAR', - '2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2', 'QUOTEDCHAR', 'QUOTEDCHAR', 'QUOTEDCHAR', @@ -3136,28 +4680,6 @@ 'QUOTEDCHAR', 'QUOTEDCHAR', 'QUOTEDCHAR', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', - '3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3', 'QUOTEDCHAR', 'QUOTEDCHAR', 'QUOTEDCHAR', @@ -3650,8 +5172,10 @@ s = "# GENERATED CODE BETWEEN THIS LINE AND ITS OTHER OCCURENCE\n".lower() pre, gen, after = oldcontent.split(s) - parser, lexer = make_regex_parser() - newcontent = "%s%sparser = %r\n%s\n%s%s" % ( - pre, s, parser, lexer.get_dummy_repr(), s, after) + parser, lexer, ToAST = make_regex_parser() + transformer = ToAST.source + newcontent = "%s%s%s\nparser = %r\n%s\n%s%s" % ( + pre, s, ToAST.source.replace("ToAST", "RegexToAST"), + parser, lexer.get_dummy_repr(), s, after) print newcontent f.write(newcontent) Modified: pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py Mon Nov 27 19:01:48 2006 @@ -46,7 +46,7 @@ assert tree.visit(MyEvalVisitor()) == 10 + 999 def test_toast(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" DECIMAL: "0|[1-9][0-9]*"; IGNORE: " "; additive: multitive ["+!"] additive | ; @@ -54,13 +54,8 @@ primary: "(" ")" | ; """) parse = make_parse_function(regexs, rules) - print transformer - ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} - exec py.code.Source(transformer).compile() in ns - ToAST = ns["ToAST"] tree = parse("(0 +! 10) *! (999 +! 10) +! 1") - print transformer - tree = tree.visit(ToAST()) + tree = tree.visit(ToAST())[0] assert len(tree.children) == 2 assert tree.children[0].children[0].symbol == "additive" assert tree.children[1].symbol == "DECIMAL" @@ -74,7 +69,7 @@ multitive: primary "*!" multitive | primary; #nonsense! primary: "(" additive0_9 ")" | DECIMAL; """ - regexs, rules, transformer = parse_ebnf(grammar) + regexs, rules, ToAST = parse_ebnf(grammar) class MyEvalVisitor(EvaluateVisitor): def visit_primary(self, node): if len(node.children) == 3: @@ -92,7 +87,7 @@ def test_prolog(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" ATOM: "[a-z]([a-zA-Z0-9]|_)*"; VAR: "[A-Z]([a-zA-Z0-9]|_)*|_"; NUMBER: "0|[1-9][0-9]*"; @@ -112,7 +107,7 @@ assert tree is not None def test_toast_bigger(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" BOOLCONST: "TRUE|FALSE"; IDENTIFIER: "[a-zA-Z_][a-zA-Z0-9_]*"; NUMBER: "0|[1-9][0-9]*"; @@ -124,19 +119,15 @@ primary "%" unaryexpr | ; unaryexpr: "+" unaryexpr | "-" unaryexpr | ; primary: "(" ")" | | ; -boolexpr: ; #XXX +boolexpr: ; #strange thing """) parse = make_parse_function(regexs, rules) tree = parse("x * floor + 1") - print transformer - ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} - exec py.code.Source(transformer).compile() in ns - ToAST = ns["ToAST"] - tree = tree.visit(ToAST()) + tree = ToAST().transform(tree) assert tree.children[2].symbol == "NUMBER" def test_parser_repr_is_evalable(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" BOOLCONST: "TRUE|FALSE"; IDENTIFIER: "[a-zA-Z_][a-zA-Z0-9_]*"; NUMBER: "0|[1-9][0-9]*"; @@ -148,7 +139,7 @@ primary "%" unaryexpr | ; unaryexpr: "+" unaryexpr | "-" unaryexpr | ; primary: "(" ")" | | ; -boolexpr: ; #XXX +boolexpr: ; #strange thing """) parser = PackratParser(rules, rules[0].nonterminal) @@ -158,7 +149,7 @@ assert repr(newparser) == s def test_lexer_end_string_corner_case(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" NUMBER: "[0-9]*(\.[0-9]+)?"; ATOM: "\."; IGNORE: " "; @@ -170,7 +161,7 @@ assert t.children[1].additional_info == "." def test_escape_quotes(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" QUOTE: "a\\""; IGNORE: " "; expr: QUOTE "\\"" EOF;""") @@ -180,7 +171,7 @@ assert t.children[1].additional_info == '"' def test_leftrecursion(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" A: "a"; B: "b"; IGNORE: " |\n"; @@ -190,7 +181,7 @@ py.test.raises(AssertionError, make_parse_function, regexs, rules, True) def test_dictparse(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" QUOTED_STRING: "'[^\\']*'"; IGNORE: " |\n"; data: | | ; @@ -242,33 +233,40 @@ 'tokenizer': '[object Object]', 'varDecls': '' }""") - ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} - exec py.code.Source(transformer).compile() in ns - ToAST = ns["ToAST"] - print transformer - t = t.visit(ToAST()) + t = ToAST().transform(t) def test_starparse(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" QUOTED_STRING: "'[^\\']*'"; IGNORE: " |\n"; list: ["["] (QUOTED_STRING [","])* QUOTED_STRING ["]"]; """) parse = make_parse_function(regexs, rules, eof=True) t = parse("""['a', 'b', 'c']""") - print transformer - exec py.code.Source(transformer).compile() - t = t.visit(ToAST()) + t = ToAST().transform(t) assert t.symbol == "list" - assert len(t.children) == 2 - assert t.children[0].symbol == "__list" - assert len(t.children[0].children) == 2 - assert [c.symbol for c in t.children[0].children] == ["QUOTED_STRING"] * 2 + assert len(t.children) == 3 + assert [c.symbol for c in t.children] == ["QUOTED_STRING"] * 3 t = parse("['a']") + t = ToAST().transform(t) + assert t.symbol == "list" + assert len(t.children) == 1 + assert [c.symbol for c in t.children] == ["QUOTED_STRING"] * 1 + +def test_double_star(): + regexs, rules, ToAST = parse_ebnf(""" + IGNORE: " |\n"; + start: "a"* "b"* "c"; +""") + parse = make_parse_function(regexs, rules, eof=True) + for s in ["a a a b b c", "a b b c", "a a c", "b b c", "c"]: + t = parse(s) + t = ToAST().transform(t) + assert [c.additional_info for c in t.children] == s.split() def test_transform_star(): - py.test.skip("This needs to be fixed - generated transformer is buggy") - regexs, rules, transformer = parse_ebnf(""" + #py.test.skip("This needs to be fixed - generated transformer is buggy") + regexs, rules, ToAST = parse_ebnf(""" IGNORE: " "; ATOM: "[\+a-zA-Z_][a-zA-Z0-9_]*"; @@ -277,20 +275,18 @@ """) parse = make_parse_function(regexs, rules) tree = parse("()") - print transformer - ns = {"RPythonVisitor": RPythonVisitor, "Nonterminal": Nonterminal} - exec py.code.Source(transformer).compile() in ns - ToAST = ns["ToAST"] - list_expr = tree.visit(ToAST()).children[0] + list_expr = tree.visit(ToAST())[0].children[0] assert list_expr.symbol == 'list' # should have two children, "(" and ")" assert len(list_expr.children) == 2 - assert list_expr.children[0].symbol == '(' - assert list_expr.children[1].symbol == ')' + assert list_expr.children[0].additional_info == '(' + assert list_expr.children[1].additional_info == ')' + tree = parse("(a b c)") + list_expr = ToAST().transform(tree) def test_quoting(): - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" ATOM: "[a-z]*"; IGNORE: " "; list: ATOM "\n" ATOM; @@ -300,3 +296,114 @@ abd""") assert len(t.children) == 3 assert t.children[1].additional_info == "\n" + +def test_check_for_missing_names(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +DECIMAL: "0|[1-9][0-9]*"; +additive: multitive "+" additive | multitive; +multitive: primary "*" multitive | primari; # observe the typo +# the following too! +primary: "(" additive ")" | DECIMAL; +""") + excinfo = py.test.raises(ValueError, make_parse_function, regexs, rules) + assert "primari" in str(excinfo.value) + +def test_starred_star(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +start: ("b"* "a")* EOF; + """) + parse = make_parse_function(regexs, rules, eof=True) + for s in ["b b b b a b b a", "b a b a", "a a", ""]: + t = parse(s) + t = ToAST().transform(t) + assert [c.additional_info for c in t.children] == (s + " EOF").split() + +def test_transform_greater_than(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +x: ["a"] >b< "c"; +b: "A" "A"; + """) + parse = make_parse_function(regexs, rules) + t = parse("a A A c") + t = ToAST().transform(t) + assert len(t.children) == 3 + assert t.children[0].additional_info == "A" + assert t.children[1].additional_info == "A" + assert t.children[2].additional_info == "c" + +def test_plus(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +x: "A"+ "B"; + """) + parse = make_parse_function(regexs, rules) + t = parse("A A B") + t = ToAST().transform(t) + assert len(t.children) == 3 + assert t.children[0].additional_info == "A" + assert t.children[1].additional_info == "A" + assert t.children[2].additional_info == "B" + py.test.raises(ParseError, parse, "B") + +def test_questionmark(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +x: ["A"] ("B" ["C"] "D")? "E"; + """) + parse = make_parse_function(regexs, rules) + t = parse("A B C D E") + py.test.raises(ParseError, parse, "A B C D B C D E") + t = ToAST().transform(t) + assert len(t.children) == 3 + assert t.children[0].additional_info == "B" + assert t.children[1].additional_info == "D" + assert t.children[2].additional_info == "E" + t = parse("A E") + t = ToAST().transform(t) + assert len(t.children) == 1 + assert t.children[0].additional_info == "E" + +def test_grouping_only_parens(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +x: ["m"] ("a" "b") "c" | ; +y: ["n"] "a" "b" "c"; + """) + parse = make_parse_function(regexs, rules) + t0 = ToAST().transform(parse("m a b c")) + t1 = ToAST().transform(parse("n a b c")) + assert len(t0.children) == len(t1.children) + +def test_mix_star_and_questionmark(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +y: x "END"; +x: "B" ("A" "B")* "A"?; + """) + parse = make_parse_function(regexs, rules) + t = ToAST().transform(parse("B A B END")) + assert len(t.children[0].children) == 3 + +def test_nest_star_and_questionmark(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +y: x "END"; +x: "B" ("A" "B"?)*; + """) + parse = make_parse_function(regexs, rules) + t = ToAST().transform(parse("B A B A B END")) + t = ToAST().transform(parse("B A A A END")) + +def test_clash_literal_nonterminal(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +y: x "END"; +x: "y"; +a: "x"; + """) + parse = make_parse_function(regexs, rules) + py.test.raises(ParseError, parse, "x END") + parse("y END") Modified: pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_parseerrors.py Mon Nov 27 19:01:48 2006 @@ -16,8 +16,7 @@ """ def setup_class(cls): - regexs, rules, transformer = parse_ebnf(cls.dictebnf) - exec py.code.Source(transformer).compile() + regexs, rules, ToAST = parse_ebnf(cls.dictebnf) cls.ToAST = ToAST parse = make_parse_function(regexs, rules, eof=True) cls.parse = staticmethod(parse) @@ -50,6 +49,7 @@ assert source_pos.lineno == 4 assert source_pos.columnno == 13 msg = excinfo.value.nice_error_message("", source) + print msg assert msg == """\ File , line 4 'length':: '1', Modified: pypy/dist/pypy/rlib/parsing/test/test_regexparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_regexparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_regexparse.py Mon Nov 27 19:01:48 2006 @@ -135,4 +135,16 @@ assert r.recognize("'X'") assert not r.recognize("''") +def test_unescape(): + from pypy.rlib.parsing.regexparse import unescape + s = "".join(["\\x%s%s" % (a, b) for a in "0123456789abcdefABCDEF" + for b in "0123456789ABCDEFabcdef"]) + assert unescape(s) == eval("'" + s + "'") +def test_escaped_quote(): + r = make_runner(r'"[^\\"]*(\\.[^\\"]*)*"') + assert r.recognize(r'""') + assert r.recognize(r'"a"') + assert r.recognize(r'"a\"b"') + assert r.recognize(r'"\\\""') + assert not r.recognize(r'"\\""') Modified: pypy/dist/pypy/rlib/parsing/test/test_translate.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_translate.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_translate.py Mon Nov 27 19:01:48 2006 @@ -92,14 +92,9 @@ res2 = func(True) assert res1 == res2 -def make_transformer(transformer): - from pypy.rlib.parsing.tree import RPythonVisitor - exec py.code.Source(transformer).compile() - return ToAST - def test_translate_ast_visitor(): from pypy.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function - regexs, rules, transformer = parse_ebnf(""" + regexs, rules, ToAST = parse_ebnf(""" DECIMAL: "0|[1-9][0-9]*"; IGNORE: " "; additive: multitive ["+!"] additive | ; @@ -107,19 +102,17 @@ primary: "(" ")" | ; """) parse = make_parse_function(regexs, rules) - print transformer - ToAST = make_transformer(transformer) def f(): tree = parse("(0 +! 10) *! (999 +! 10) +! 1") - tree = ToAST().dispatch(tree) + tree = ToAST().visit_additive(tree) + assert len(tree) == 1 + tree = tree[0] return tree.symbol + " " + "-&-".join([c.symbol for c in tree.children]) + res1 = f() t = Translation(f) t.annotate() - t.backendopt() t.rtype() + t.backendopt() func = t.compile_c() - res1 = f() res2 = func() assert res1 == res2 - - Modified: pypy/dist/pypy/rlib/parsing/tree.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/tree.py (original) +++ pypy/dist/pypy/rlib/parsing/tree.py Mon Nov 27 19:01:48 2006 @@ -28,7 +28,7 @@ def visit(self, visitor): "NOT_RPYTHON" if isinstance(visitor, RPythonVisitor): - visitor.dispatch(self) + return visitor.dispatch(self) method = getattr(visitor, "visit_" + self.symbol, None) if method is None: return self From cfbolz at codespeak.net Mon Nov 27 19:02:29 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 27 Nov 2006 19:02:29 +0100 (CET) Subject: [pypy-svn] r35049 - in pypy/dist/pypy/config: . test Message-ID: <20061127180229.0738A10082@code0.codespeak.net> Author: cfbolz Date: Mon Nov 27 19:02:27 2006 New Revision: 35049 Modified: pypy/dist/pypy/config/pypyoption.py pypy/dist/pypy/config/test/test_pypyoption.py Log: hm, I can't remember why I thought that thunk clashes with geninterp. removing that. Modified: pypy/dist/pypy/config/pypyoption.py ============================================================================== --- pypy/dist/pypy/config/pypyoption.py (original) +++ pypy/dist/pypy/config/pypyoption.py Mon Nov 27 19:02:27 2006 @@ -24,7 +24,6 @@ ["std", "flow", "logic", "thunk", "cpy", "dump", "sand"], "std", requires = { - #"thunk": [("objspace.geninterp", False)], uh? why? "logic": [("objspace.geninterp", False), ("objspace.usemodules._stackless", True)], }, Modified: pypy/dist/pypy/config/test/test_pypyoption.py ============================================================================== --- pypy/dist/pypy/config/test/test_pypyoption.py (original) +++ pypy/dist/pypy/config/test/test_pypyoption.py Mon Nov 27 19:02:27 2006 @@ -16,9 +16,6 @@ def test_objspace_incopatibilities(): conf = Config(pypy_optiondescription) - conf.objspace.name = "thunk" - assert not conf.objspace.geninterp - conf = Config(pypy_optiondescription) conf.objspace.name = "logic" assert not conf.objspace.geninterp From ac at codespeak.net Mon Nov 27 20:21:10 2006 From: ac at codespeak.net (ac at codespeak.net) Date: Mon, 27 Nov 2006 20:21:10 +0100 (CET) Subject: [pypy-svn] r35052 - in pypy/dist/pypy/jit/timeshifter: . test Message-ID: <20061127192110.A3D841007F@code0.codespeak.net> Author: ac Date: Mon Nov 27 20:21:09 2006 New Revision: 35052 Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py pypy/dist/pypy/jit/timeshifter/test/test_portal.py Log: (pedronis, arre) Add support for recursive calls to the portal. Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/hrtyper.py (original) +++ pypy/dist/pypy/jit/timeshifter/hrtyper.py Mon Nov 27 20:21:09 2006 @@ -153,11 +153,12 @@ bk = self.annotator.bookkeeper bk.compute_after_normalization() entrygraph = self.annotator.translator.graphs[0] + self.origportalgraph = origportalgraph if origportalgraph: - portalgraph = bk.get_graph_by_key(origportalgraph, None) - leaveportalgraph = portalgraph + self.portalgraph = bk.get_graph_by_key(origportalgraph, None) + leaveportalgraph = self.portalgraph else: - portalgraph = None + self.portalgraph = None # in the case of tests not specifying a portal # we still need to force merges when entry # returns @@ -182,10 +183,26 @@ self.timeshift_graph(graph) if origportalgraph: - self.rewire_portal(origportalgraph, portalgraph) + self.rewire_portal() + + # remember a shared pointer for the portal graph, + # so that it can be later patched by rewire_portal. + # this pointer is going to be used by the resuming logic + # and portal (re)entry. + def naked_tsfnptr(self, tsgraph): + if tsgraph is self.portalgraph: + try: + return self.portal_tsfnptr + except AttributeError: + self.portal_tsfnptr = self.gettscallable(tsgraph) + return self.portal_tsfnptr + return self.gettscallable(tsgraph) - def rewire_portal(self, origportalgraph, portalgraph): + def rewire_portal(self): + origportalgraph = self.origportalgraph + portalgraph = self.portalgraph annhelper = self.annhelper + rgenop = self.RGenOp() argcolors = [] portal_args_s = [] @@ -200,12 +217,20 @@ portal_args_s.append(self.s_RedBox) argcolors.append(color) - portal_fnptr = self.rtyper.type_system.getcallable(portalgraph) + tsportalgraph = portalgraph + # patch the shared portal pointer + portalgraph = flowmodel.copygraph(tsportalgraph, shallow=True) + portal_fnptr = self.naked_tsfnptr(self.portalgraph) + portal_fnptr._obj.graph = portalgraph + portal_fn = PseudoHighLevelCallable( portal_fnptr, [self.s_JITState] + portal_args_s, self.s_JITState) FUNC = self.get_residual_functype(portalgraph) + RESTYPE = FUNC.RESULT + reskind = rgenop.kindToken(RESTYPE) + boxbuilder = rvalue.ll_redboxbuilder(RESTYPE) argcolors = unrolling_iterable(argcolors) fresh_jitstate = self.ll_fresh_jitstate finish_jitstate = self.ll_finish_jitstate @@ -215,7 +240,6 @@ self.cache = {} state = PortalState() - rgenop = self.RGenOp() # debug helper def readportal(*args): @@ -230,12 +254,15 @@ i = i + 1 cache = state.cache try: - return cache[key] + gv_generated = cache[key] except KeyError: return lltype.nullptr(FUNC) - + fn = gv_generated.revealconst(lltype.Ptr(FUNC)) + return fn + def readallportals(): - return state.cache.values() + return [gv_gen.revealconst(lltype.Ptr(FUNC)) + for gv_gen in state.cache.values()] def portalentry(*args): i = 0 @@ -252,12 +279,13 @@ i = i + 1 cache = state.cache try: - fn = cache[key] + gv_generated = cache[key] except KeyError: portal_ts_args = () sigtoken = rgenop.sigToken(FUNC) builder, gv_generated, inputargs_gv = rgenop.newgraph(sigtoken, "generated") + cache[key] = gv_generated i = 0 for color in argcolors: if color == "green": @@ -281,11 +309,11 @@ finish_jitstate(top_jitstate, sigtoken) builder.end() - fn = gv_generated.revealconst(lltype.Ptr(FUNC)) builder.show_incremental_progress() - cache[key] = fn + fn = gv_generated.revealconst(lltype.Ptr(FUNC)) return fn(*residualargs) + args_s = [annmodel.lltype_to_annotation(v.concretetype) for v in origportalgraph.getargs()] s_result = annmodel.lltype_to_annotation( @@ -297,16 +325,87 @@ self.readportalgraph = annhelper.getgraph(readportal, args_s, s_funcptr) - s_funcptrlist = annmodel.SomeList(listdef.ListDef(None, s_funcptr)) + s_funcptrlist = annmodel.SomeList(listdef.ListDef(None, s_funcptr, + resized=True)) self.readallportalsgraph = annhelper.getgraph(readallportals, [], s_funcptrlist) + TYPES = [v.concretetype for v in origportalgraph.getargs()] + argcolorandtypes = unrolling_iterable(zip(argcolors, + TYPES)) + + def portalreentry(jitstate, *args): + i = 0 + key = () + curbuilder = jitstate.curbuilder + args_gv = [] + for color in argcolors: + if color == "green": + x = args[i] + if isinstance(lltype.typeOf(x), lltype.Ptr): + x = llmemory.cast_ptr_to_adr(x) + key = key + (x,) + else: + box = args[i] + args_gv.append(box.getgenvar(curbuilder)) + i = i + 1 + sigtoken = rgenop.sigToken(FUNC) + cache = state.cache + try: + gv_generated = cache[key] + except KeyError: + portal_ts_args = () + builder, gv_generated, inputargs_gv = rgenop.newgraph(sigtoken, + "generated") + cache[key] = gv_generated + i = 0 + for color, T in argcolorandtypes: + if color == "green": + llvalue = args[0] + args = args[1:] + portal_ts_args += (llvalue,) + else: + args = args[1:] + kind = rgenop.kindToken(T) + boxcls = rvalue.ll_redboxcls(T) + gv_arg = inputargs_gv[i] + box = boxcls(kind, gv_arg) + i += 1 + portal_ts_args += (box,) + + top_jitstate = fresh_jitstate(builder) + top_jitstate = portal_fn(top_jitstate, *portal_ts_args) + if top_jitstate is not None: + finish_jitstate(top_jitstate, sigtoken) + + builder.end() + builder.show_incremental_progress() + + + gv_res = curbuilder.genop_call(sigtoken, gv_generated, args_gv) + if RESTYPE == lltype.Void: + retbox = None + else: + retbox = boxbuilder(reskind, gv_res) + + jitstate.returnbox = retbox + assert jitstate.next is None + return jitstate + + portalreentrygraph = annhelper.getgraph(portalreentry, + [self.s_JITState] + portal_args_s, self.s_JITState) + portalreentrygraph.tag = "portal_reentry" + annhelper.finish() origportalgraph.startblock = portalentrygraph.startblock origportalgraph.returnblock = portalentrygraph.returnblock origportalgraph.exceptblock = portalentrygraph.exceptblock - # name, func? + + tsportalgraph.startblock = portalreentrygraph.startblock + tsportalgraph.returnblock = portalreentrygraph.returnblock + tsportalgraph.exceptblock = portalreentrygraph.exceptblock + def transform_graph(self, graph, is_portal=False): # prepare the graphs by inserting all bookkeeping/dispatching logic @@ -972,7 +1071,7 @@ attrname = hop.args_v[1].value N = mpfamily.resumepoint_after_mergepoint[attrname] tsgraph = mpfamily.tsgraph - ts_fnptr = self.gettscallable(tsgraph) + ts_fnptr = self.naked_tsfnptr(tsgraph) TS_FUNC = lltype.typeOf(ts_fnptr) dummy_args = [ARG._defl() for ARG in TS_FUNC.TO.ARGS[1:]] dummy_args = tuple(dummy_args) Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py ============================================================================== --- pypy/dist/pypy/jit/timeshifter/test/test_portal.py (original) +++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py Mon Nov 27 20:21:09 2006 @@ -309,3 +309,47 @@ res = self.timeshift_from_portal(ll_function, ll_function, [0], policy=P_NOVIRTUAL) assert res == ord('2') self.check_insns(indirect_call=0, malloc=0) + + def test_simple_recursive_portal_call(self): + + def main(code, x): + return evaluate(code, x) + + def evaluate(y, x): + hint(y, concrete=True) + if y <= 0: + return x + z = 1 + evaluate(y - 1, x) + return z + + res = self.timeshift_from_portal(main, evaluate, [3, 2]) + assert res == 5 + + res = self.timeshift_from_portal(main, evaluate, [3, 5]) + assert res == 8 + + res = self.timeshift_from_portal(main, evaluate, [4, 7]) + assert res == 11 + + + def test_simple_recursive_portal_call2(self): + + def main(code, x): + return evaluate(code, x) + + def evaluate(y, x): + hint(y, concrete=True) + if x <= 0: + return y + z = evaluate(y, x - 1) + 1 + return z + + res = self.timeshift_from_portal(main, evaluate, [3, 2]) + assert res == 5 + + res = self.timeshift_from_portal(main, evaluate, [3, 5]) + assert res == 8 + + res = self.timeshift_from_portal(main, evaluate, [4, 7]) + assert res == 11 + From cfbolz at codespeak.net Mon Nov 27 21:03:47 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 27 Nov 2006 21:03:47 +0100 (CET) Subject: [pypy-svn] r35055 - pypy/dist/pypy/lang/js/test Message-ID: <20061127200347.A92DA10087@code0.codespeak.net> Author: cfbolz Date: Mon Nov 27 21:03:46 2006 New Revision: 35055 Modified: pypy/dist/pypy/lang/js/test/test_interp.py pypy/dist/pypy/lang/js/test/test_parser.py Log: skip js tests if the javascript interpreter (which is used to parse js currently) is not found. Modified: pypy/dist/pypy/lang/js/test/test_interp.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_interp.py (original) +++ pypy/dist/pypy/lang/js/test/test_interp.py Mon Nov 27 21:03:46 2006 @@ -13,6 +13,17 @@ def parse_d(code): return build_interpreter(parse(code)) +def js_is_on_path(): + try: + py.path.local.sysfind("js") + except py.error.ENOENT: + return False + return True + +if not js_is_on_path(): + py.test.skip("js binary not found") + + class TestInterp(object): def test_simple(self): assert Plus(Number(3), Number(4)).call().floatval == 7 Modified: pypy/dist/pypy/lang/js/test/test_parser.py ============================================================================== --- pypy/dist/pypy/lang/js/test/test_parser.py (original) +++ pypy/dist/pypy/lang/js/test/test_parser.py Mon Nov 27 21:03:46 2006 @@ -1,6 +1,12 @@ from pypy.lang.js.parser import read_js_output, JsSyntaxError, parse +from pypy.lang.js.test.test_interp import js_is_on_path import py + +if not js_is_on_path(): + py.test.skip("js binary not found") + + def test_read_js_output(): assert read_js_output("1+1").find("PLUS") > -1 assert read_js_output(""" From cfbolz at codespeak.net Mon Nov 27 21:20:36 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 27 Nov 2006 21:20:36 +0100 (CET) Subject: [pypy-svn] r35057 - pypy/dist/pypy/rlib/parsing/test Message-ID: <20061127202036.336491008D@code0.codespeak.net> Author: cfbolz Date: Mon Nov 27 21:20:34 2006 New Revision: 35057 Added: pypy/dist/pypy/rlib/parsing/test/pygrammar.txt pypy/dist/pypy/rlib/parsing/test/test_pythonparse.py Log: in an attempt to find some more bugs by trying a more complex grammar: convert the python 2.4 grammar to my ebnf format, requires a few changes but parses python code :-) Added: pypy/dist/pypy/rlib/parsing/test/pygrammar.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/rlib/parsing/test/pygrammar.txt Mon Nov 27 21:20:34 2006 @@ -0,0 +1,136 @@ +# tokens + +#IGNORE: "[ \f\t]*|#[^\n]*"; +#NAME: "[a-zA-Z_][a-zA-Z0-9_]*"; +#NUMBER: "(0[xX][0-9a-fA-F]*[lL]?)|(0[0-7]*[lL]?)|([1-9][0-9]*[lL]?)" +#STRING: "\"[^\\\"\n]*\""; +#NEWLINE: "\$\$NEWLINE" +#INDENT: "\$\$INDENT" +#DEDENT: "\$\$DEDENT" + +# 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! +file_input: newline_or_stmt* [EOF]; +single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE; +newline_or_stmt: NEWLINE | ; +eval_input: testlist NEWLINE* EOF; + +decorator: "@" dotted_name ( "(" [arglist] ")" )? NEWLINE; +decorators: decorator+; +funcdef: decorators? ["def"] NAME parameters [":"] suite; +parameters: ["("] >varargslist< [")"] | ["("] [")"]; +varargslist: (parameter ",")* >star_or_starstarargs< | + parameter ("," parameter)* ","?; +parameter: fpdef ("=" test)?; +star_or_starstarargs: starargs [","] starstarargs | starargs | starstarargs; +starargs: ["*"] NAME; +starstarargs: ["**"] NAME; +fpdef: | "(" fplist ")"; +fplist: fpdef ("," fpdef)* ","?; + +stmt: | ; +simple_stmt: small_stmt ([";"] small_stmt)* [";"]? [NEWLINE]; +small_stmt: | | | | + | | | | + ; +expr_stmt: testlist augassign testlist | testlist ("=" testlist)*; +augassign: "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | + ">>=" | "**=" | "//="; +# For normal assignments, additional restrictions enforced by the interpreter + +print_stmt: "print" ">>" test (("," test)+ ","?)? | + "print" (test ("," test)* ","?)?; +del_stmt: "del" exprlist; +pass_stmt: "pass"; +flow_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_what; +import_what: "*" | "(" import_as_names ","? ")" | import_as_names; + +# the second NAME is the "as" (which is not a keyword in Python) +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: "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)+ + ("else" ":" suite)? | "try" ":" suite "finally" ":" suite; + +except_clause: "except" (test ("," test)?)?; +suite: simple_stmt | [NEWLINE] [INDENT] stmt+ [DEDENT]; + +test: and_test "or" test | | ; +and_test: not_test "and" and_test | ; +not_test: "not" not_test | ; +comparison: expr >comp_op< comparison | ; +comp_op: "<" | ">" | "==" | ">=" | "<=" | "<>" | "!=" | "in" | "not" "in" | + "is" "not" | "is"; +expr: xor_expr "|" expr | ; +xor_expr: and_expr "^" xor_expr | ; +and_expr: shift_expr "&" and_expr | ; +shift_expr: arith_expr "<<" shift_expr | # was (("<<"|">>") arith_expr)* + arith_expr ">>" shift_expr | + ; +arith_expr: term "+" arith_expr | # was (("+"|"-") term)* + term "-" arith_expr | + ; +term: factor "*" term | # was (("*"|"/"|"%"|"//") factor)* + factor "/" term | + factor "%" term | + factor "//" term | + ; +factor: "+" factor | "-" factor | "~" factor | ; +power: atom trailer+ ("**" factor)? | atom "**" factor | ; +atom: "(" testlist_gexp? ")" | "[" listmaker? "]" | + "{" dictmaker? "}" | "`" testlist1 "`" | | | STRING+; +listmaker: test list_for | + test ("," test)* ","?; +testlist_gexp: test gen_for | + test ("," test)* ","?; +lambdef: "lambda" varargslist? ":" test; +trailer: "(" ")" | "(" arglist ")" | "[" subscriptlist "]" | "." NAME; +subscriptlist: subscript ("," subscript)* ","?; +subscript: "." "." "." | test? ":" test? sliceop? | test; +sliceop: ":" test?; +exprlist: expr ("," expr)* ","?; +testlist: test ("," test)* ","?; +testlist_safe: test (("," test)+ ","?)?; +dictmaker: test ":" test ("," test ":" test)* ","?; + +classdef: ["class"] NAME (["("] testlist [")"])? [":"] suite; + +arglist: (argument [","])* arglist_rest; +arglist_rest: "*" test ("," "**" test)? | "**" test | argument ","?; +argument: (test "=")? test gen_for?; + +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" 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; Added: pypy/dist/pypy/rlib/parsing/test/test_pythonparse.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/rlib/parsing/test/test_pythonparse.py Mon Nov 27 21:20:34 2006 @@ -0,0 +1,170 @@ +""" test file to experiment with a an adapted CPython grammar """ + +import py +from pypy.rlib.parsing.lexer import Lexer +from pypy.rlib.parsing.deterministic import LexerError +from pypy.rlib.parsing.tree import Nonterminal, Symbol, RPythonVisitor +from pypy.rlib.parsing.parsing import PackratParser, Symbol, ParseError, Rule +from pypy.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function + +grammar = py.magic.autopath().dirpath().join("pygrammar.txt").read() + + +def test_parse_grammar(): + _, rules, ToAST = parse_ebnf(grammar) + +def test_parse_python_args(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +NAME: "[a-zA-Z_]*"; +NUMBER: "0|[1-9][0-9]*"; +parameters: ["("] >varargslist< [")"] | ["("] [")"]; +varargslist: (fpdef ("=" test)? ",")* star_or_starstarargs | + fpdef ("=" test)? ("," fpdef ("=" test)?)* ","?; +star_or_starstarargs: "*" NAME "," "**" NAME | "*" NAME | "**" NAME; +fpdef: NAME | "(" fplist ")"; +fplist: fpdef ("," fpdef)* ","?; +test: NUMBER; + """) + parse = make_parse_function(regexs, rules) + t = parse("(a)").visit(ToAST())[0] + t = parse("(a,)").visit(ToAST())[0] + t = parse("(a,b,c,d)").visit(ToAST())[0] + t = parse("(a,b,c,d,)").visit(ToAST())[0] + t = parse("((a, b, c),b,c,d,)").visit(ToAST())[0] + t = parse("((a, b, c),b,c,d,*args)").visit(ToAST())[0] + t = parse("((a, b, c),b,c,d,**kwargs)").visit(ToAST())[0] + t = parse("((a, b, c),b,c,d,*args, **args)").visit(ToAST())[0] + t = parse("()").visit(ToAST())[0] + t = parse("(*args, **args)").visit(ToAST())[0] + t = parse("(a=1)").visit(ToAST())[0] + t = parse("(a=2,)").visit(ToAST())[0] + t = parse("(a,b,c,d=3)").visit(ToAST())[0] + t = parse("(a,b,c,d=4,)").visit(ToAST())[0] + t = parse("((a, b, c),b,c,(c, d)=1,)").visit(ToAST())[0] + t = parse("((a, b, c),b,c,d=1,*args)").visit(ToAST())[0] + t = parse("((a, b, c),b,c,d=2,**kwargs)").visit(ToAST())[0] + t = parse("((a, b, c),b,c,(c, d)=4,*args, **args)").visit(ToAST())[0] + t = parse("(self, a, b, args)").visit(ToAST())[0] + +def test_parse_funcdef(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +NAME: "[a-zA-Z_]*"; +NUMBER: "0|[1-9][0-9]*"; +funcdef: "def" NAME parameters ":" suite; +parameters: ["("] >varargslist< [")"] | ["("] [")"]; +varargslist: (fpdef ("=" test)? ",")* star_or_starstarargs | + fpdef ("=" test)? ("," fpdef ("=" test)?)* ","?; +star_or_starstarargs: "*" NAME "," "**" NAME | "*" NAME | "**" NAME; +fpdef: NAME | "(" fplist ")"; +fplist: fpdef ("," fpdef)* ","?; +test: NUMBER; +suite: simple_stmt | ["NEWLINE"] ["INDENT"] stmt+ ["DEDENT"]; +simple_stmt: stmt; +stmt: "pass"; + """) + parse = make_parse_function(regexs, rules) + t = parse("def f(a): NEWLINE INDENT pass DEDENT").visit(ToAST())[0] + + +class TestParser(object): + def setup_class(cls): + from pypy.rlib.parsing.parsing import PackratParser + regexs, rules, ToAST = parse_ebnf(grammar) + cls.ToAST = ToAST() + cls.parser = PackratParser(rules, rules[0].nonterminal) + cls.regexs = regexs + names, regexs = zip(*regexs) + cls.lexer = Lexer(list(regexs), list(names)) + + def parse(self, source): + tokens = list(self.tokenize(source)) + s = self.parser.parse(tokens) + return s + + def tokenize(self, source): + # use tokenize module but rewrite tokens slightly + import tokenize, cStringIO + pos = 0 + readline = cStringIO.StringIO(source).readline + for token in tokenize.generate_tokens(readline): + typ, s, (row, col), _, line = token + pos += len(s) + typ = tokenize.tok_name[typ] + if typ == "ENDMARKER": + typ = s = "EOF" + elif typ == "NL": + continue + elif typ == "COMMENT": + continue + try: + tokens = self.lexer.tokenize(s, eof=False) + if len(tokens) == 1: + typ, s, _, _, _ = tokens[0] + yield typ, s, pos, row, col + continue + except LexerError: + pass + yield (typ, s, pos, row, col) + + + def test_simple(self): + t = self.parse(""" +def f(x, null=0): + if x >= null: + return null + x + else: + pass + return null - x + """) + t = t.visit(self.ToAST) + assert len(t) == 1 + t = t[0] + + def test_class(self): + t = self.parse(""" +class A(object): + def __init__(self, a, b, *args): + self.a = a + self.b = b + if args: + self.len = len(args) + self.args = [a, b] + list(args) + + def diagonal(self): + return (self.a ** 2 + self.b ** 2) ** 0.5 + """) + t = t.visit(self.ToAST)[0] + + def test_while(self): + t = self.parse(""" +def f(x, null=0): + i = null + result = 0 + while i < x: + result += i + i += 1 + if result % 625 == 13: + break + else: + return result - 15 + return result + """) + t = t.visit(self.ToAST) + assert len(t) == 1 + t = t[0] + + def test_comment(self): + t = self.parse(""" +def f(x): + # this does some fancy stuff + return x +""") + t = self.ToAST.transform(t) + + def test_parse_this(self): + s = py.magic.autopath().read() + s = s[s.index("\nclass"):] + t = self.parse(s) + t = t.visit(self.ToAST)[0] From cfbolz at codespeak.net Mon Nov 27 22:08:46 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 27 Nov 2006 22:08:46 +0100 (CET) Subject: [pypy-svn] r35060 - pypy/dist/pypy/translator/tool/pygame Message-ID: <20061127210846.165AE10094@code0.codespeak.net> Author: cfbolz Date: Mon Nov 27 22:08:45 2006 New Revision: 35060 Modified: pypy/dist/pypy/translator/tool/pygame/drawgraph.py Log: give slightly better error message when the remote dot crashes Modified: pypy/dist/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/dist/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/dist/pypy/translator/tool/pygame/drawgraph.py Mon Nov 27 22:08:45 2006 @@ -61,6 +61,9 @@ lines[i] = lines[i][:-2] + lines[i+1] del lines[i+1] header = splitline(lines.pop(0)) + # XXX very simple-minded way to give a somewhat better error message + if header[0] == ' Author: ericvrp Date: Mon Nov 27 22:21:42 2006 New Revision: 35061 Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: Attempt to use global data from JITed code in the llvm codegenereator. Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Mon Nov 27 22:21:42 2006 @@ -3,6 +3,8 @@ #include "libllvmjit.h" #include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/GlobalVariable.h" #include "llvm/Assembly/Parser.h" #include "llvm/Bytecode/Writer.h" #include "llvm/Analysis/Verifier.h" @@ -38,6 +40,9 @@ static cl::list PassList(cl::desc("Optimizations available:")); +//some global data for the tests to play with +char g_char[2] = {10,0}; + // //code... @@ -100,3 +105,24 @@ return gv.IntVal; } + +char* get_pointer_to_global_char() { + printf("get_pointer_to_global_char g_char=%08x\n", g_char); + return g_char; +} + + +void add_global_mapping(const char* name, void* address) { + //GlobalValue(const Type *Ty, ValueTy vty, Use *Ops, unsigned NumOps, LinkageTypes linkage, const std::string &name = ""); + + /// GlobalVariable ctor - If a parent module is specified, the global is + // /// automatically inserted into the end of the specified modules global list. + // GlobalVariable(const Type *Ty, bool isConstant, LinkageTypes Linkage, + // Constant *Initializer = 0, const std::string &Name = "", + // Module *Parent = 0); + + GlobalVariable var(Type::UByteTy, false, GlobalVariable::ExternalLinkage, 0, name, gp_module); + printf("add_global_mapping address=%08x\n", address); + gp_execution_engine->addGlobalMapping(&var, address); +} + Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h Mon Nov 27 22:21:42 2006 @@ -9,6 +9,8 @@ int compile(const char* llsource); void* find_function(const char* funcname); int execute(const void* function, int param); +char* get_pointer_to_global_char(); +void add_global_mapping(const char* name, void* address); #ifdef __cplusplus } Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Mon Nov 27 22:21:42 2006 @@ -61,3 +61,11 @@ execute.restype = c_int execute.argtypes = [c_void_p, c_int] +get_pointer_to_global_char= llvmjit.get_pointer_to_global_char +get_pointer_to_global_char.restype = c_char_p +get_pointer_to_global_char.argtypes = [] + +add_global_mapping = llvmjit.add_global_mapping +#add_global_mapping.restype = c_void +add_global_mapping.argtypes = [c_char_p, c_void_p] + Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Mon Nov 27 22:21:42 2006 @@ -14,13 +14,11 @@ curdir = dirname(__file__) llsquare = '''int %square(int %n) { -block0: %n2 = mul int %n, %n ret int %n2 }''' llmul2 = '''int %mul2(int %n) { -block0: %n2 = mul int %n, 2 ret int %n2 }''' @@ -43,13 +41,11 @@ implementation int %across1(int %n) { -block0: %n2 = mul int %n, 3 ret int %n2 } int %across1to2(int %n) { -block0: %n2 = add int %n, 5 %n3 = call int %across2(int %n2) ret int %n3 @@ -60,18 +56,30 @@ implementation int %across2(int %n) { -block0: %n2 = mul int %n, 7 ret int %n2 } int %across2to1(int %n) { -block0: %n2 = add int %n, 9 %n3 = call int %across1(int %n2) ret int %n3 }''' +llglobalmul4 = '''%my_global_ubyte = external global ubyte + +implementation + +int %globalmul4(int %a) { + %aa = cast int %a to ubyte + %v0 = load ubyte* %my_global_ubyte + %v1 = mul ubyte %v0, 4 + %v2 = add ubyte %v1, %aa + store ubyte %v2, ubyte* %my_global_ubyte + %v3 = cast ubyte %v2 to int + ret int %v3 +}''' + #helpers def execute(llsource, function_name, param): assert llvmjit.compile(llsource) @@ -154,7 +162,15 @@ assert llvmjit.execute(deadcode, 30) == 30 * 2 def DONTtest_modify_global_data(): - pass + llvmjit.restart() + gp_char = llvmjit.get_pointer_to_global_char() + assert len(gp_char) == 1 + assert ord(gp_char[0]) == 10 + llvmjit.add_global_mapping('my_global_ubyte', gp_char) #note: should be prior to compile() + llvmjit.compile(llglobalmul4) #XXX assert error, incorrect types??? + globalmul4 = llvmjit.find_function('globalmul4') + assert llvmjit.execute(globalmul4, 5) == 10 * 4 + 5 + assert ord(gp_char[0]) == 10 * 4 + 5 def DONTtest_call_back_to_parent(): #call JIT-compiler again for it to add case(s) to flexswitch pass From guido at codespeak.net Mon Nov 27 23:14:03 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 27 Nov 2006 23:14:03 +0100 (CET) Subject: [pypy-svn] r35062 - pypy/dist/pypy/doc Message-ID: <20061127221403.4F39C1007E@code0.codespeak.net> Author: guido Date: Mon Nov 27 23:14:02 2006 New Revision: 35062 Modified: pypy/dist/pypy/doc/index.txt Log: Typo, mostly to test the svn hooks on codespeak.net that regenerate the website docs. Modified: pypy/dist/pypy/doc/index.txt ============================================================================== --- pypy/dist/pypy/doc/index.txt (original) +++ pypy/dist/pypy/doc/index.txt Mon Nov 27 23:14:02 2006 @@ -17,7 +17,7 @@ `coding guide`_ helps you to write code for PyPy (especially also describes coding in RPython a bit). -`development methodology`_ describe our sprint-driven approach. +`development methodology`_ describes our sprint-driven approach. `sprint reports`_ lists reports written at most of our sprints, from 2003 to the present. @@ -318,3 +318,4 @@ .. _Mono: http://www.mono-project.com/ .. include:: _ref.txt + From guido at codespeak.net Mon Nov 27 23:19:15 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 27 Nov 2006 23:19:15 +0100 (CET) Subject: [pypy-svn] r35063 - pypy/dist/pypy/doc Message-ID: <20061127221915.755B51008D@code0.codespeak.net> Author: guido Date: Mon Nov 27 23:19:14 2006 New Revision: 35063 Modified: pypy/dist/pypy/doc/index.txt Log: Another typo still testing svn hooks... Modified: pypy/dist/pypy/doc/index.txt ============================================================================== --- pypy/dist/pypy/doc/index.txt (original) +++ pypy/dist/pypy/doc/index.txt Mon Nov 27 23:19:14 2006 @@ -29,7 +29,7 @@ into PyPy. `PyPy video documentation`_ is a page linking to the videos (e.g. of talks and -introductions) that is available. +introductions) that are available. `license`_ contains licensing details (basically a straight MIT-license). From guido at codespeak.net Mon Nov 27 23:29:47 2006 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 27 Nov 2006 23:29:47 +0100 (CET) Subject: [pypy-svn] r35064 - pypy/dist/pypy/doc Message-ID: <20061127222947.C562C10080@code0.codespeak.net> Author: guido Date: Mon Nov 27 23:29:44 2006 New Revision: 35064 Modified: pypy/dist/pypy/doc/index.txt Log: Another typo. Modified: pypy/dist/pypy/doc/index.txt ============================================================================== --- pypy/dist/pypy/doc/index.txt (original) +++ pypy/dist/pypy/doc/index.txt Mon Nov 27 23:29:44 2006 @@ -80,7 +80,7 @@ `rlib`_ describes some modules that can be used when implementing programs in RPython. -`JavaScript backend`_ describes how to use JavaScript backend to create +`JavaScript backend`_ describes how to use the JavaScript backend to create AJAX-based web pages. `EU reports`_ is a page that contains links to the From fijal at codespeak.net Mon Nov 27 23:29:51 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 27 Nov 2006 23:29:51 +0100 (CET) Subject: [pypy-svn] r35065 - in pypy/extradoc/talk/warsaw2006: . src Message-ID: <20061127222951.A5A6310079@code0.codespeak.net> Author: fijal Date: Mon Nov 27 23:29:42 2006 New Revision: 35065 Added: pypy/extradoc/talk/warsaw2006/src/ Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Log: update. Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt ============================================================================== --- pypy/extradoc/talk/warsaw2006/fireworks-slides.txt (original) +++ pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Mon Nov 27 23:29:42 2006 @@ -1,4 +1,3 @@ -============== PyPy fireworks ============== @@ -6,6 +5,11 @@ :Location: Warsaw Univeristy :Date: 1.XII.2006 +.. raw:: html + + + What is PyPy? ============= Added: pypy/extradoc/talk/warsaw2006/style.css ============================================================================== --- (empty file) +++ pypy/extradoc/talk/warsaw2006/style.css Tue Nov 28 14:09:41 2006 @@ -0,0 +1,14 @@ +body { + background-color: #FFE; + color: #530; + font-family: Trebuchet MS, Verdana; + font-size: 1.4em; +} + +#metaspace, #docinfoline { + display: none; +} + +.section { + height: 700px; +} From cfbolz at codespeak.net Tue Nov 28 18:44:20 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 28 Nov 2006 18:44:20 +0100 (CET) Subject: [pypy-svn] r35093 - pypy/branch/builtin-call-speedup/pypy/interpreter Message-ID: <20061128174420.14D5410082@code0.codespeak.net> Author: cfbolz Date: Tue Nov 28 18:44:19 2006 New Revision: 35093 Added: pypy/branch/builtin-call-speedup/pypy/interpreter/specialcode.py Log: slightly embarassing: of course this file is need to make anything actually work Added: pypy/branch/builtin-call-speedup/pypy/interpreter/specialcode.py ============================================================================== --- (empty file) +++ pypy/branch/builtin-call-speedup/pypy/interpreter/specialcode.py Tue Nov 28 18:44:19 2006 @@ -0,0 +1,34 @@ +class CallLikelyBuiltinMixin(object): + _mixin_ = True + + def CALL_LIKELY_BUILTIN(f, oparg): + from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module + from pypy.objspace.std.warydictobject import W_WaryDictObject + w_globals = f.w_globals + num = oparg >> 8 + if (isinstance(w_globals, W_WaryDictObject) and + not w_globals.shadowed[num]): + w_builtins = f.builtin + assert isinstance(w_builtins, Module) + print "fast CALL_LIKELY_BUILTIN" + w_value = w_builtins.builtins_by_index[num] + else: + w_varname = f.space.wrap(OPTIMIZED_BUILTINS[num]) + 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 + 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)) + nargs = oparg & 0xff + w_function = w_value + try: + w_result = f.space.call_valuestack(w_function, nargs, f.valuestack) + # XXX XXX fix the problem of resume points! + #rstack.resume_point("CALL_FUNCTION", f, nargs, returns=w_result) + finally: + f.valuestack.drop(nargs) + f.valuestack.push(w_result) From rxe at codespeak.net Tue Nov 28 20:58:00 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Tue, 28 Nov 2006 20:58:00 +0100 (CET) Subject: [pypy-svn] r35094 - pypy/dist/pypy/interpreter Message-ID: <20061128195800.7402010076@code0.codespeak.net> Author: rxe Date: Tue Nov 28 20:57:33 2006 New Revision: 35094 Modified: pypy/dist/pypy/interpreter/mixedmodule.py Log: un-hardcode path Modified: pypy/dist/pypy/interpreter/mixedmodule.py ============================================================================== --- pypy/dist/pypy/interpreter/mixedmodule.py (original) +++ pypy/dist/pypy/interpreter/mixedmodule.py Tue Nov 28 20:57:33 2006 @@ -193,7 +193,7 @@ # ____________________________________________________________ # Helper to test mixed modules on top of CPython -def testmodule(name): +def testmodule(name, basepath='pypy.module'): """Helper to test mixed modules on top of CPython, running with the CPy Object Space. The module should behave more or less as if it had been compiled, either with the @@ -204,7 +204,8 @@ import sys, new from pypy.objspace.cpy.objspace import CPyObjSpace space = CPyObjSpace() - fullname = "pypy.module.%s" % name + + fullname = "%s.%s" % (basepath, name) Module = __import__(fullname, None, None, ["Module"]).Module if Module.applevel_name is not None: From ericvrp at codespeak.net Tue Nov 28 23:46:40 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Tue, 28 Nov 2006 23:46:40 +0100 (CET) Subject: [pypy-svn] r35095 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061128224640.859CD10080@code0.codespeak.net> Author: ericvrp Date: Tue Nov 28 23:46:37 2006 New Revision: 35095 Added: pypy/dist/pypy/jit/codegen/llvm/autopath.py (contents, props changed) Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: llvm jit codegen modification of global data works. test enabled. Added: pypy/dist/pypy/jit/codegen/llvm/autopath.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/jit/codegen/llvm/autopath.py Tue Nov 28 23:46:37 2006 @@ -0,0 +1,114 @@ +""" +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) + + pypy_root = os.path.join(head, '') + try: + sys.path.remove(head) + except ValueError: + pass + sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + if '.' in name: + continue + fn = getattr(mod, '__file__', None) + if 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/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Tue Nov 28 23:46:37 2006 @@ -41,7 +41,7 @@ PassList(cl::desc("Optimizations available:")); //some global data for the tests to play with -char g_char[2] = {10,0}; +int g_data; // @@ -106,23 +106,24 @@ } -char* get_pointer_to_global_char() { - printf("get_pointer_to_global_char g_char=%08x\n", g_char); - return g_char; +int get_global_data() { + return g_data; } -void add_global_mapping(const char* name, void* address) { - //GlobalValue(const Type *Ty, ValueTy vty, Use *Ops, unsigned NumOps, LinkageTypes linkage, const std::string &name = ""); +void set_global_data(int n) { + g_data = n; +} - /// GlobalVariable ctor - If a parent module is specified, the global is - // /// automatically inserted into the end of the specified modules global list. - // GlobalVariable(const Type *Ty, bool isConstant, LinkageTypes Linkage, - // Constant *Initializer = 0, const std::string &Name = "", - // Module *Parent = 0); - - GlobalVariable var(Type::UByteTy, false, GlobalVariable::ExternalLinkage, 0, name, gp_module); - printf("add_global_mapping address=%08x\n", address); - gp_execution_engine->addGlobalMapping(&var, address); + +int* get_pointer_to_global_data() { + return &g_data; +} + + +void add_global_mapping(const char* name, void* address) { + //note: using getNamedGlobal implies that we can not have globals of different type + // but with identical names! This is probably easy to do. + gp_execution_engine->addGlobalMapping(gp_module->getNamedGlobal(name), address); } Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h Tue Nov 28 23:46:37 2006 @@ -9,7 +9,9 @@ int compile(const char* llsource); void* find_function(const char* funcname); int execute(const void* function, int param); -char* get_pointer_to_global_char(); +int get_global_data(); +void set_global_data(int n); +int* get_pointer_to_global_data(); void add_global_mapping(const char* name, void* address); #ifdef __cplusplus Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Tue Nov 28 23:46:37 2006 @@ -6,6 +6,7 @@ This file contains the ctypes specification to use the llvmjit library! ''' +import autopath from pypy.rpython.rctypes import implementation from pypy.rpython.rctypes.tool.util import load_library @@ -13,10 +14,11 @@ from ctypes import * import os -path = os.path.join(os.path.dirname(__file__), 'libllvmjit.so') - +newdir = os.path.dirname(__file__) +path = os.path.join(newdir, 'libllvmjit.so') curdir = os.getcwd() -os.chdir(os.path.dirname(__file__)) +if newdir: + os.chdir(newdir) #With py.test --session=R the master server rsyncs the .so library too!?! #So we always need to recompile the library if its platform (output of file libllvmjit.so) @@ -61,11 +63,17 @@ execute.restype = c_int execute.argtypes = [c_void_p, c_int] -get_pointer_to_global_char= llvmjit.get_pointer_to_global_char -get_pointer_to_global_char.restype = c_char_p -get_pointer_to_global_char.argtypes = [] +get_global_data= llvmjit.get_global_data +get_global_data.restype = c_int +get_global_data.argtypes = [] + +set_global_data= llvmjit.set_global_data +set_global_data.argtypes = [c_int] + +get_pointer_to_global_data= llvmjit.get_pointer_to_global_data +get_pointer_to_global_data.restype = POINTER(c_int) +get_pointer_to_global_data.argtypes = [] add_global_mapping = llvmjit.add_global_mapping -#add_global_mapping.restype = c_void add_global_mapping.argtypes = [c_char_p, c_void_p] Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Tue Nov 28 23:46:37 2006 @@ -66,18 +66,16 @@ ret int %n3 }''' -llglobalmul4 = '''%my_global_ubyte = external global ubyte +llglobalmul4 = '''%my_global_data = external global int implementation int %globalmul4(int %a) { - %aa = cast int %a to ubyte - %v0 = load ubyte* %my_global_ubyte - %v1 = mul ubyte %v0, 4 - %v2 = add ubyte %v1, %aa - store ubyte %v2, ubyte* %my_global_ubyte - %v3 = cast ubyte %v2 to int - ret int %v3 + %v0 = load int* %my_global_data + %v1 = mul int %v0, 4 + %v2 = add int %v1, %a + store int %v2, int* %my_global_data + ret int %v2 }''' #helpers @@ -161,16 +159,16 @@ assert llvmjit.transform("instcombine simplifycfg printm verify") assert llvmjit.execute(deadcode, 30) == 30 * 2 -def DONTtest_modify_global_data(): +def test_modify_global_data(): llvmjit.restart() - gp_char = llvmjit.get_pointer_to_global_char() - assert len(gp_char) == 1 - assert ord(gp_char[0]) == 10 - llvmjit.add_global_mapping('my_global_ubyte', gp_char) #note: should be prior to compile() - llvmjit.compile(llglobalmul4) #XXX assert error, incorrect types??? + llvmjit.set_global_data(10) + assert llvmjit.get_global_data() == 10 + gp_data = llvmjit.get_pointer_to_global_data() + llvmjit.compile(llglobalmul4) + llvmjit.add_global_mapping('my_global_data', gp_data) #note: should be prior to execute() globalmul4 = llvmjit.find_function('globalmul4') assert llvmjit.execute(globalmul4, 5) == 10 * 4 + 5 - assert ord(gp_char[0]) == 10 * 4 + 5 + assert llvmjit.get_global_data() == 10 * 4 + 5 def DONTtest_call_back_to_parent(): #call JIT-compiler again for it to add case(s) to flexswitch pass From rxe at codespeak.net Wed Nov 29 01:22:53 2006 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 29 Nov 2006 01:22:53 +0100 (CET) Subject: [pypy-svn] r35096 - pypy/dist/pypy/doc Message-ID: <20061129002253.09D4F10082@code0.codespeak.net> Author: rxe Date: Wed Nov 29 01:22:42 2006 New Revision: 35096 Modified: pypy/dist/pypy/doc/rlib.txt Log: minor grammar tweaks/typos Modified: pypy/dist/pypy/doc/rlib.txt ============================================================================== --- pypy/dist/pypy/doc/rlib.txt (original) +++ pypy/dist/pypy/doc/rlib.txt Wed Nov 29 01:22:42 2006 @@ -8,11 +8,11 @@ This page lists some of the modules in `pypy/rlib`_ together with some hints -for what they can be used. The modules there are supposed to make up some sort -of library for RPython programs (since most of the standard library modules are -not RPython). Most of these modules are somewhat rough still and are likely to -be changed at one point. Usually it is useful to look at the tests in -`pypy/rlib/test`_ to get an impression how the modules should be used. +for what they can be used for. The modules here will make up some general +library useful for RPython programs (since most of the standard library modules +are not RPython). Most of these modules are somewhat rough still and are likely +to change at some point. Usually it is useful to look at the tests in +`pypy/rlib/test`_ to get an impression of how to use a module. .. _`pypy/rlib`: ../../pypy/rlib .. _`pypy/rlib/test`: ../../pypy/rlib/test @@ -54,7 +54,7 @@ ``ComputedIntSymbolic``: Instances of ``ComputedIntSymbolic`` are treated like integers of unknown - value by the annotator. Their value is determined by a non-argument function + value by the annotator. The value is determined by a non-argument function (which needs to be passed into the constructor of the class). When the backend emits code, the function is called to determine the value. @@ -214,7 +214,7 @@ The streamio_ contains an RPython stream I/O implementation (which was started by Guido van Rossum as `sio.py`_ in the CPython sandbox as a prototype for the -upcoming new file implementation in Python 300). +upcoming new file implementation in Python 3000). .. _streamio: ../../pypy/rlib/streamio.py .. _`sio.py`: http://svn.python.org/view/sandbox/trunk/sio/sio.py @@ -223,7 +223,7 @@ ========== The unroll_ module most importantly contains the function ``unrolling_iterable`` -wich wraps an iterator. Looping over the iterator in RPython code will not +which wraps an iterator. Looping over the iterator in RPython code will not produce a loop in the resulting flow graph but will unroll the loop instead. .. _unroll: ../../pypy/rlib/unroll.py From mwh at codespeak.net Wed Nov 29 10:36:20 2006 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 29 Nov 2006 10:36:20 +0100 (CET) Subject: [pypy-svn] r35102 - in pypy/branch/builtin-call-speedup/pypy: interpreter module/__builtin__/test objspace/std Message-ID: <20061129093620.3F11D10072@code0.codespeak.net> Author: mwh Date: Wed Nov 29 10:36:11 2006 New Revision: 35102 Modified: pypy/branch/builtin-call-speedup/pypy/interpreter/specialcode.py pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py Log: (cfbolz, mwh) small rewrites for correctness and translatability. Modified: pypy/branch/builtin-call-speedup/pypy/interpreter/specialcode.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/interpreter/specialcode.py (original) +++ pypy/branch/builtin-call-speedup/pypy/interpreter/specialcode.py Wed Nov 29 10:36:11 2006 @@ -1,3 +1,5 @@ +from pypy.interpreter.error import OperationError + class CallLikelyBuiltinMixin(object): _mixin_ = True @@ -6,23 +8,27 @@ from pypy.objspace.std.warydictobject import W_WaryDictObject w_globals = f.w_globals num = oparg >> 8 - if (isinstance(w_globals, W_WaryDictObject) and - not w_globals.shadowed[num]): - w_builtins = f.builtin - assert isinstance(w_builtins, Module) - print "fast CALL_LIKELY_BUILTIN" - w_value = w_builtins.builtins_by_index[num] + if isinstance(w_globals, W_WaryDictObject): + if w_globals.shadowed[num] is None: + w_builtins = f.builtin + assert isinstance(w_builtins, Module) + print "fast CALL_LIKELY_BUILTIN" + w_builtin_dict = w_builtins.w_dict + assert isinstance(w_builtin_dict, W_WaryDictObject) + w_value = w_builtin_dict.shadowed[num] + else: + w_value = w_globals.shadowed[num] else: w_varname = f.space.wrap(OPTIMIZED_BUILTINS[num]) 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 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)) + if w_value is None: + varname = f.space.wrap(OPTIMIZED_BUILTINS[num]) + message = "global name '%s' is not defined" % varname + raise OperationError(f.space.w_NameError, + f.space.wrap(message)) nargs = oparg & 0xff w_function = w_value try: Modified: pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py (original) +++ pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py Wed Nov 29 10:36:11 2006 @@ -465,6 +465,10 @@ exec s in ns ns["test"]() + def test_delete_from_builtins(self): + s = """ """ + # XXX write this test! + class TestInternal: def setup_method(self,method): Modified: pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py (original) +++ pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py Wed Nov 29 10:36:11 2006 @@ -112,7 +112,9 @@ # XXX add to option_to_typename somehow if config.objspace.withfastbuiltins: - self.typeorder[warydictobject.W_WaryDictObject] = [] + self.typeorder[warydictobject.W_WaryDictObject] = [ + (warydictobject.W_WaryDictObject, None), + (dictobject.W_DictObject, None)] imported_but_not_registered = { dictobject.W_DictObject: True, Modified: pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py ============================================================================== --- pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py (original) +++ pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py Wed Nov 29 10:36:11 2006 @@ -12,10 +12,10 @@ W_DictObject.__init__(w_self, space, w_otherdict) if wary_of is None: wary_of = BUILTIN_TO_INDEX - if w_otherdict is None: - w_self.shadowed = [False] * len(wary_of) - else: - w_self.shadowed = [True] * len(wary_of) + w_self.shadowed = [None] * len(wary_of) + if w_otherdict: + for key in wary_of: + w_self.shadowed[wary_of[key]] = w_otherdict.get(space.wrap(key), None) w_self.wary_of = wary_of registerimplementation(W_WaryDictObject) @@ -25,7 +25,7 @@ s = space.str_w(w_key) i = w_dict.wary_of.get(s, -1) if i != -1: - w_dict.shadowed[i] = True + w_dict.shadowed[i] = w_newvalue w_dict.content[w_key] = w_newvalue def delitem__WaryDict_ANY(space, w_dict, w_lookup): @@ -34,7 +34,7 @@ s = space.str_w(w_lookup) i = w_dict.wary_of.get(s, -1) if i != -1: - w_dict.shadowed[i] = False + w_dict.shadowed[i] = None del w_dict.content[w_lookup] except KeyError: raise OperationError(space.w_KeyError, w_lookup) From ericvrp at codespeak.net Wed Nov 29 11:10:38 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 29 Nov 2006 11:10:38 +0100 (CET) Subject: [pypy-svn] r35109 - in pypy/dist/pypy/jit/codegen/llvm: . lib test Message-ID: <20061129101038.8EE8610089@code0.codespeak.net> Author: ericvrp Date: Wed Nov 29 11:10:34 2006 New Revision: 35109 Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h pypy/dist/pypy/jit/codegen/llvm/llvmjit.py pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Log: * renamed llvmjit.compile to llvmjit.parse * added (currently skipped) test for recompiling functions (with different code of course Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Wed Nov 29 11:10:34 2006 @@ -76,7 +76,7 @@ } -int compile(const char* llsource) { +int parse(const char* llsource) { Module* module = ParseAssemblyString(llsource, gp_module); if (!module) { std::cerr << "Can not parse:\n" << llsource << "\n" << std::flush; @@ -92,6 +92,28 @@ } +int freeMachineCodeForFunction(const void* function) { + if (!function) { + std::cerr << "No function supplied to libllvmjit.freeMachineCodeForFunction(...)\n" << std::flush; + return 0; + } + + gp_execution_engine->freeMachineCodeForFunction((Function*)function); + return 1; +} + + +int recompile(const void* function) { + if (!function) { + std::cerr << "No function supplied to libllvmjit.recompile(...)\n" << std::flush; + return 0; + } + + gp_execution_engine->recompileAndRelinkFunction((Function*)function); + return 1; +} + + int execute(const void* function, int param) { //XXX allow different function signatures if (!function) { std::cerr << "No function supplied to libllvmjit.execute(...)\n" << std::flush; Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.h Wed Nov 29 11:10:34 2006 @@ -6,8 +6,10 @@ void restart(); int transform(const char* passnames); -int compile(const char* llsource); +int parse(const char* llsource); void* find_function(const char* funcname); +int freeMachineCodeForFunction(const void* function); +int recompile(const void* function); int execute(const void* function, int param); int get_global_data(); void set_global_data(int n); Modified: pypy/dist/pypy/jit/codegen/llvm/llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/llvmjit.py Wed Nov 29 11:10:34 2006 @@ -51,14 +51,22 @@ transform.restype = c_int transform.argtypes = [c_char_p] -compile = llvmjit.compile -compile.restype = c_int -compile.argtypes = [c_char_p] +parse = llvmjit.parse +parse.restype = c_int +parse.argtypes = [c_char_p] find_function = llvmjit.find_function find_function.restype = c_void_p find_function.argtypes = [c_char_p] +freeMachineCodeForFunction = llvmjit.freeMachineCodeForFunction +freeMachineCodeForFunction.restype = c_int +freeMachineCodeForFunction.argtypes = [c_void_p] + +recompile = llvmjit.recompile +recompile.restype = c_int +recompile.argtypes = [c_void_p] + execute = llvmjit.execute execute.restype = c_int execute.argtypes = [c_void_p, c_int] Modified: pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py (original) +++ pypy/dist/pypy/jit/codegen/llvm/test/test_llvmjit.py Wed Nov 29 11:10:34 2006 @@ -10,9 +10,7 @@ except OSError: py.test.skip("can not load libllvmjit library (see ../README.TXT)") -#helper data -curdir = dirname(__file__) - +# llsquare = '''int %square(int %n) { %n2 = mul int %n, %n ret int %n2 @@ -23,6 +21,7 @@ ret int %n2 }''' +# lldeadcode = '''int %deadcode(int %n) { Test: %cond = seteq int %n, %n @@ -36,6 +35,18 @@ ret int -1 }''' +# +llfuncA = '''int %func(int %n) { + %n2 = add int %n, %n + ret int %n2 +}''' + +llfuncB = '''int %func(int %n) { + %n2 = mul int %n, %n + ret int %n2 +}''' + +# llacross1 = '''declare int %across2(int) implementation @@ -66,6 +77,7 @@ ret int %n3 }''' +# llglobalmul4 = '''%my_global_data = external global int implementation @@ -80,7 +92,7 @@ #helpers def execute(llsource, function_name, param): - assert llvmjit.compile(llsource) + assert llvmjit.parse(llsource) function = llvmjit.find_function(function_name) assert function return llvmjit.execute(function, param) @@ -90,7 +102,7 @@ for i in range(3): llvmjit.restart() assert not llvmjit.find_function('square') - assert llvmjit.compile(llsquare) + assert llvmjit.parse(llsquare) assert llvmjit.find_function('square') def test_find_function(): @@ -98,13 +110,13 @@ llvmjit.restart() assert not llvmjit.find_function('square') assert not llvmjit.find_function('square') - assert llvmjit.compile(llsquare) + assert llvmjit.parse(llsquare) assert llvmjit.find_function('square') assert llvmjit.find_function('square') -def test_compile(): +def test_parse(): llvmjit.restart() - assert llvmjit.compile(llsquare) + assert llvmjit.parse(llsquare) def test_execute(): llvmjit.restart() @@ -116,8 +128,8 @@ def test_execute_multiple(): llvmjit.restart() - llvmjit.compile(llsquare) - llvmjit.compile(llmul2) + llvmjit.parse(llsquare) + llvmjit.parse(llmul2) square = llvmjit.find_function('square') mul2 = llvmjit.find_function('mul2') for i in range(5): @@ -138,17 +150,39 @@ return my_across1(n + 9) llvmjit.restart() - llvmjit.compile(llacross1) - llvmjit.compile(llacross2) + llvmjit.parse(llacross1) + llvmjit.parse(llacross2) across1to2 = llvmjit.find_function('across1to2') across2to1 = llvmjit.find_function('across2to1') for i in range(5): assert llvmjit.execute(across1to2, i) == my_across1to2(i) assert llvmjit.execute(across2to1, i) == my_across2to1(i) +def test_recompile(): + py.test.skip("recompile new function implementation test is work in progress") + + def funcA(n): + return n + n + + def funcB(n): + return n * n + llvmjit.restart() + llvmjit.parse(llfuncA) + _llfuncA = llvmjit.find_function('func') + print '_llfuncA', _llfuncA + for i in range(5): + assert llvmjit.execute(_llfuncA, i) == funcA(i) + llvmjit.freeMachineCodeForFunction(_llfuncA) + llvmjit.parse(llfuncB) + _llfuncB = llvmjit.find_function('func') + print '_llfuncB', _llfuncB + llvmjit.recompile(_llfuncB) #note: because %func has changed because of the 2nd parse + for i in range(5): + assert llvmjit.execute(_llfuncB, i) == funcB(i) + def test_transform(): #XXX This uses Module transforms, think about Function transforms too. llvmjit.restart() - llvmjit.compile(lldeadcode) + llvmjit.parse(lldeadcode) deadcode = llvmjit.find_function('deadcode') assert llvmjit.execute(deadcode, 10) == 10 * 2 @@ -164,7 +198,7 @@ llvmjit.set_global_data(10) assert llvmjit.get_global_data() == 10 gp_data = llvmjit.get_pointer_to_global_data() - llvmjit.compile(llglobalmul4) + llvmjit.parse(llglobalmul4) llvmjit.add_global_mapping('my_global_data', gp_data) #note: should be prior to execute() globalmul4 = llvmjit.find_function('globalmul4') assert llvmjit.execute(globalmul4, 5) == 10 * 4 + 5 From fijal at codespeak.net Wed Nov 29 12:39:25 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 29 Nov 2006 12:39:25 +0100 (CET) Subject: [pypy-svn] r35112 - pypy/dist/pypy/translator/js/examples Message-ID: <20061129113925.CB31B10034@code0.codespeak.net> Author: fijal Date: Wed Nov 29 12:39:23 2006 New Revision: 35112 Added: pypy/dist/pypy/translator/js/examples/server.py - copied, changed from r35078, py/dist/py/test/rsession/web.py Log: Added custom server for subclassing From fijal at codespeak.net Wed Nov 29 12:55:36 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 29 Nov 2006 12:55:36 +0100 (CET) Subject: [pypy-svn] r35113 - in pypy/extradoc/talk/warsaw2006: . src Message-ID: <20061129115536.0C7DB10034@code0.codespeak.net> Author: fijal Date: Wed Nov 29 12:55:33 2006 New Revision: 35113 Modified: pypy/extradoc/talk/warsaw2006/confrest.py pypy/extradoc/talk/warsaw2006/fireworks-slides.txt pypy/extradoc/talk/warsaw2006/src/slideshow.py pypy/extradoc/talk/warsaw2006/src/web.py pypy/extradoc/talk/warsaw2006/style.css Log: Next version of my talk Modified: pypy/extradoc/talk/warsaw2006/confrest.py ============================================================================== --- pypy/extradoc/talk/warsaw2006/confrest.py (original) +++ pypy/extradoc/talk/warsaw2006/confrest.py Wed Nov 29 12:55:33 2006 @@ -11,6 +11,10 @@ stylesheet = 'style.css' encoding = 'latin1' prefix_title = "PyPy " - logo = '' + logo = html.div( + html.a( + html.img(alt="PyPy", id="pyimg", + src="http://codespeak.net/pypy/img/py-web1.png", + height=110, width=149))) Page = PyPyFireworksPage Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt ============================================================================== --- pypy/extradoc/talk/warsaw2006/fireworks-slides.txt (original) +++ pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Wed Nov 29 12:55:33 2006 @@ -26,16 +26,16 @@ Compiler toolchain: =================== -* (picture) - * eats RPython * C considered harmfull +* is kind-of-stable right now + Flow graphs & annotation: ========================= -* We create flow graph out of RPython code:: +* We create flow graph out of RPython code `flow`_:: def g(x): return 1 @@ -43,17 +43,17 @@ def f(x): return g(x) + 3 -.. raw:: html - - Show +* We `annotate`_ variables encountered -* We annotate variables encountered +* It must be "static-enough" to perform such operation -* "static-enough" +* We `RType`_ (creating low-level types) -* (picture) +* Source generation -* (demo) +.. _`flow`: javascript:flow() +.. _`annotate`: javascript:annotate() +.. _`RType`: javascript:rtype() RPython: ======== @@ -66,32 +66,54 @@ * Is build "as we need it", so no real definition -* rctypes +* rctypes (like ctypes, but will change to C calls) -* (examples) +Backends & more flow graphs: +============================ -Multiple backends: -================== +* LLtype-based: C, LLVM, -* Actually: C, LLVM, CLI, JVM, JavaScript, (CL and Squek in some state). +* OOtype-based: CLI, JVM, JavaScript, (CL and Squek in some state). -* PyPy the way you like it. +* All optimisations are done on flow graphs -JavaScript backend (1/2): -========================= +* XXX: constant-folding demo + +* Wide range of possible things to do with it + +JavaScript backend: +=================== * Co-funded by Google Summer of Code *and* Summer of PyPy. * Mochikit: Makes JavaScript suck less... -JavaScript backend (2/2): -========================= +JavaScript backend: +=================== + +* pypy.js: makes JavaScript suck less by not using it:: + + def f(x): + return dom.get_document().getElementById(x) + +* Unittest in python run in browser:: + + def test_f(): + assert isinstance(f("id"), dom.Element) + +* Python semantics (not only syntax):: + + try: + {'a':3}['b'] + except KeyError: + # will arrive here -* pypy.js: makes JavaScript suck less by not using it +JavaScript example one (console): +================================= -* Unittest in python run in browser +JavaScript example two (Bub'n'Bros): +==================================== -* AJAX by method calls. Transparent proxy: ================== Modified: pypy/extradoc/talk/warsaw2006/src/slideshow.py ============================================================================== --- pypy/extradoc/talk/warsaw2006/src/slideshow.py (original) +++ pypy/extradoc/talk/warsaw2006/src/slideshow.py Wed Nov 29 12:55:33 2006 @@ -23,6 +23,9 @@ content = dom.get_document().getElementById("contentspace") for child in content.childNodes[:]: content.removeChild(child) + content.style.position = "absolute" + content.style.top = "0px" + content.style.left = "170px" def show(self, num): content = dom.get_document().getElementById("contentspace") @@ -48,10 +51,16 @@ page.delete_nodes() page.show(0) dom.get_document().onkeypress = keydown - createLoggingPane(True) + #createLoggingPane(True) def comeback(msg): pass def flow(): exported_methods.flow_basic(comeback) + +def annotate(): + exported_methods.annotate_basic(comeback) + +def rtype(): + exported_methods.rtype_basic(comeback) Modified: pypy/extradoc/talk/warsaw2006/src/web.py ============================================================================== --- pypy/extradoc/talk/warsaw2006/src/web.py (original) +++ pypy/extradoc/talk/warsaw2006/src/web.py Wed Nov 29 12:55:33 2006 @@ -4,19 +4,18 @@ """ import py -from py.__.test.rsession import web +from pypy.translator.js.examples import server from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal,\ described -from pypy.translator.js.main import rpython2javascript, Options from pypy.translator.js import commproxy -from pypy.translator.js import json +from pypy.translator.js.main import rpython2javascript from pypy.translator.interactive import Translation commproxy.USE_MOCHIKIT = True -FUNCTION_LIST = ['show', 'flow'] +FUNCTION_LIST = ['show', 'flow', 'annotate', 'rtype'] class ExportedMethods(BasicExternal): _render_xmlhttp = True @@ -30,36 +29,50 @@ def g(x): return f(x) + 3 - self.t = Translation(f) + self.t = Translation(g) @described(retval=None) def flow_basic(self): self._create_t() self.t.view() - return json.write(None) + + @described(retval=None) + def annotate_basic(self): + self._create_t() + self.t.annotate([int]) + self.t.view() + + @described(retval=None) + def rtype_basic(self): + self._create_t() + self.t.annotate([int]) + self.t.rtype() + self.t.view() exported_methods = ExportedMethods() main_path = py.path.local(__file__).dirpath() -class Handler(web.TestHandler): +class Handler(server.TestHandler): exported_methods = exported_methods - def run_(self): - self.run_index() - - def run_index(self): - data_name = main_path.dirpath().join("fireworks-slides.html") - data = data_name.open().read() - self.serve_data("text/html", data) + def index(self): + return main_path.dirpath().join("fireworks-slides.html").open().read() + index.exposed = True - def run_jssource_js(self): + def jssource_js(self): import slideshow javascript_source = rpython2javascript(slideshow, FUNCTION_LIST) - self.serve_data("text/javascript", javascript_source) + return "text/javascript", javascript_source + jssource_js.exposed = True - def run_MochiKit_js(self): - self.serve_data("text/javascript", main_path.join("MochiKit.js").open().read()) + def MochiKit_js(self): + return "text/javascript", main_path.join("MochiKit.js").open().read() + MochiKit_js.exposed = True + + def style_css(self): + return "text/css", main_path.dirpath().join("style.css").open().read() + style_css.exposed = True if __name__ == '__main__': - web.start_server(handler=Handler, start_new=False) + server.start_server(handler=Handler, start_new=False) Modified: pypy/extradoc/talk/warsaw2006/style.css ============================================================================== --- pypy/extradoc/talk/warsaw2006/style.css (original) +++ pypy/extradoc/talk/warsaw2006/style.css Wed Nov 29 12:55:33 2006 @@ -1,14 +1,18 @@ body { - background-color: #FFE; + background-color: #FFF; color: #530; font-family: Trebuchet MS, Verdana; font-size: 1.4em; } -#metaspace, #docinfoline { +#metaspace { display: none; } .section { height: 700px; } + +li { + min-height: 50px; +} \ No newline at end of file From cfbolz at codespeak.net Wed Nov 29 13:06:27 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 29 Nov 2006 13:06:27 +0100 (CET) Subject: [pypy-svn] r35114 - pypy/extradoc/talk/warsaw2006 Message-ID: <20061129120627.6CAC110086@code0.codespeak.net> Author: cfbolz Date: Wed Nov 29 13:06:26 2006 New Revision: 35114 Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Log: typo Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt ============================================================================== --- pypy/extradoc/talk/warsaw2006/fireworks-slides.txt (original) +++ pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Wed Nov 29 13:06:26 2006 @@ -28,7 +28,7 @@ * eats RPython -* C considered harmfull +* C considered harmful * is kind-of-stable right now From fijal at codespeak.net Wed Nov 29 13:18:52 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 29 Nov 2006 13:18:52 +0100 (CET) Subject: [pypy-svn] r35115 - pypy/extradoc/talk/warsaw2006 Message-ID: <20061129121852.7016F10063@code0.codespeak.net> Author: fijal Date: Wed Nov 29 13:18:50 2006 New Revision: 35115 Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Log: From arigo at codespeak.net Wed Nov 29 13:24:00 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 29 Nov 2006 13:24:00 +0100 (CET) Subject: [pypy-svn] r35116 - pypy/extradoc/planning/secprototype Message-ID: <20061129122400.CA23610089@code0.codespeak.net> Author: arigo Date: Wed Nov 29 13:23:59 2006 New Revision: 35116 Added: pypy/extradoc/planning/secprototype/abstract.txt (contents, props changed) Log: (pedronis, arigo) A proposed abstract. Quite vague, but points a bit in the direction "object space proxy". Added: pypy/extradoc/planning/secprototype/abstract.txt ============================================================================== --- (empty file) +++ pypy/extradoc/planning/secprototype/abstract.txt Wed Nov 29 13:23:59 2006 @@ -0,0 +1,16 @@ +Security issues in Python and approaches in PyPy +================================================== + +Python in its design favors expressivity, full reflection and +dynamism. In its current incarnation it has no form of encapsulation. +So far, two ways to approach security issues have been tried: sandboxing +(generally at the level of the OS process), and some delicate C-level +proxying together with language restrictions. + +In this talk, we will present PyPy's architecture - a Python interpreter +written in Python, aiming for flexibility - and discuss how it can +provide better alternatives to security issues in particular. It is +easy in PyPy to add a layer controlling all operations at run-time. We +will discuss how this can be used to experiment with approaches like +attaching security labels to objects and execution frames, forbidding +access to I/O built-ins to code without enough priviledges, etc. From fijal at codespeak.net Wed Nov 29 13:34:54 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 29 Nov 2006 13:34:54 +0100 (CET) Subject: [pypy-svn] r35117 - pypy/extradoc/talk/warsaw2006 Message-ID: <20061129123454.E051810086@code0.codespeak.net> Author: fijal Date: Wed Nov 29 13:34:52 2006 New Revision: 35117 Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Log: .... Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt ============================================================================== --- pypy/extradoc/talk/warsaw2006/fireworks-slides.txt (original) +++ pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Wed Nov 29 13:34:52 2006 @@ -154,6 +154,30 @@ * Each 'part' has it's own "parent coroutine" +Things that I didn't talk about: +================================ + +* Offline partial evaluation + +* Prolog interpreter written in RPython + +* Security approaches + +* Garbage collectors (Boehm, mark&sweep, refcounting) + +* GIL + +* pylib (support library for pypy) + +Developement process: +===================== + +* Test driven (few thousand tests) + +* Distributed team + +* Sprint driven (every 2 months) + Summer of PyPy: =============== From arigo at codespeak.net Wed Nov 29 13:45:28 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 29 Nov 2006 13:45:28 +0100 (CET) Subject: [pypy-svn] r35118 - pypy/branch/jit-real-world Message-ID: <20061129124528.BABE010090@code0.codespeak.net> Author: arigo Date: Wed Nov 29 13:45:27 2006 New Revision: 35118 Added: pypy/branch/jit-real-world/ - copied from r35117, pypy/dist/ Log: (arre, pedronis, arigo) Be afraid. Very afraid. (pedronis) A branch to experiment with throwing PyPy at the JIT. (arigo) From antocuni at codespeak.net Wed Nov 29 15:05:09 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 29 Nov 2006 15:05:09 +0100 (CET) Subject: [pypy-svn] r35119 - pypy/dist/pypy/module/_dotnet Message-ID: <20061129140509.21B861007F@code0.codespeak.net> Author: antocuni Date: Wed Nov 29 15:05:08 2006 New Revision: 35119 Modified: pypy/dist/pypy/module/_dotnet/interp_dotnet.py Log: Use b_ (which stands for boxed) as a prefix for native .NET object Modified: pypy/dist/pypy/module/_dotnet/interp_dotnet.py ============================================================================== --- pypy/dist/pypy/module/_dotnet/interp_dotnet.py (original) +++ pypy/dist/pypy/module/_dotnet/interp_dotnet.py Wed Nov 29 15:05:08 2006 @@ -5,8 +5,6 @@ from pypy.rpython.ootypesystem import ootype from pypy.translator.cli.dotnet import CLR, box, unbox, NativeException, native_exc, new_array, init_array -# TODO: this code is not translatable - Type = CLR.System.Type Object = CLR.System.Object TargetInvocationException = NativeException(CLR.System.Reflection.TargetInvocationException) @@ -14,30 +12,30 @@ import sys class W_CliObject(Wrappable): - def __init__(self, space, obj): + def __init__(self, space, b_obj): self.space = space - self.obj = obj + self.b_obj = b_obj def call_method(self, name, w_args): - t = self.obj.GetType() - meth = t.GetMethod(name) # TODO: overloading! - args = self.rewrap_args(w_args) + b_type = self.b_obj.GetType() + b_meth = b_type.GetMethod(name) # TODO: overloading! + b_args = self.rewrap_args(w_args) try: - res = meth.Invoke(self.obj, args) + b_res = b_meth.Invoke(self.b_obj, b_args) except TargetInvocationException, e: - inner = native_exc(e).get_InnerException() - message = str(inner.get_Message()) + b_inner = native_exc(e).get_InnerException() + message = str(b_inner.get_Message()) # TODO: use the appropriate exception, not StandardError raise OperationError(self.space.w_StandardError, self.space.wrap(message)) - return self.cli2py(res) + return self.cli2py(b_res) call_method.unwrap_spec = ['self', str, W_Root] def rewrap_args(self, w_args): - py_args = self.space.unpackiterable(w_args) - res = new_array(Object, len(py_args)) - for i in range(len(py_args)): - res[i] = self.py2cli(py_args[i]) - return res + args = self.space.unpackiterable(w_args) + b_res = new_array(Object, len(args)) + for i in range(len(args)): + b_res[i] = self.py2cli(args[i]) + return b_res def py2cli(self, w_obj): space = self.space @@ -46,16 +44,16 @@ else: assert False - def cli2py(self, obj): - intval = unbox(obj, ootype.Signed) # TODO: support other types + def cli2py(self, b_obj): + intval = unbox(b_obj, ootype.Signed) # TODO: support other types return self.space.wrap(intval) def cli_object_new(space, w_subtype, typename): - t = Type.GetType(typename) - ctor = t.GetConstructor(init_array(Type)) - obj = ctor.Invoke(init_array(Object)) - return space.wrap(W_CliObject(space, obj)) + b_type = Type.GetType(typename) + b_ctor = b_type.GetConstructor(init_array(Type)) + b_obj = b_ctor.Invoke(init_array(Object)) + return space.wrap(W_CliObject(space, b_obj)) cli_object_new.unwrap_spec = [ObjSpace, W_Root, str] From antocuni at codespeak.net Wed Nov 29 15:24:29 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 29 Nov 2006 15:24:29 +0100 (CET) Subject: [pypy-svn] r35120 - pypy/dist/pypy/module/_dotnet Message-ID: <20061129142429.C692510088@code0.codespeak.net> Author: antocuni Date: Wed Nov 29 15:24:28 2006 New Revision: 35120 Modified: pypy/dist/pypy/module/_dotnet/interp_dotnet.py Log: Raise a nice exception instead of crashing when encountering a unknown type. Modified: pypy/dist/pypy/module/_dotnet/interp_dotnet.py ============================================================================== --- pypy/dist/pypy/module/_dotnet/interp_dotnet.py (original) +++ pypy/dist/pypy/module/_dotnet/interp_dotnet.py Wed Nov 29 15:24:28 2006 @@ -42,7 +42,9 @@ if space.is_true(space.isinstance(w_obj, self.space.w_int)): return box(space.int_w(w_obj)) else: - assert False + typename = space.type(w_obj).getname(space, '?') + msg = "Can't convert type %s to .NET" % typename + raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) def cli2py(self, b_obj): intval = unbox(b_obj, ootype.Signed) # TODO: support other types From cfbolz at codespeak.net Wed Nov 29 16:22:53 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 29 Nov 2006 16:22:53 +0100 (CET) Subject: [pypy-svn] r35123 - in pypy/dist/pypy/doc: . image Message-ID: <20061129152253.0C5BA10082@code0.codespeak.net> Author: cfbolz Date: Wed Nov 29 16:22:51 2006 New Revision: 35123 Added: pypy/dist/pypy/doc/image/parsing_example1.dot pypy/dist/pypy/doc/image/parsing_example2.dot pypy/dist/pypy/doc/image/parsing_example3.dot pypy/dist/pypy/doc/image/parsing_example4.dot pypy/dist/pypy/doc/image/parsing_example5.dot pypy/dist/pypy/doc/image/parsing_example6.dot pypy/dist/pypy/doc/image/parsing_example7.dot pypy/dist/pypy/doc/image/parsing_example8.dot pypy/dist/pypy/doc/image/parsing_example9.dot Modified: pypy/dist/pypy/doc/rlib.txt Log: the result of another fruitful lecture: some docs about the parsing stuff (although quite rough) Added: pypy/dist/pypy/doc/image/parsing_example1.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example1.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,27 @@ +digraph G{ +"-1213931828" [label="additive"]; +"-1213931828" -> "-1213951956"; +"-1213951956" [label="multitive"]; +"-1213951956" -> "-1213949172"; +"-1213949172" [label="primary"]; +"-1213949172" -> "-1213949812"; +"-1213949812" [shape=box,label="DECIMAL\l'12'"]; +"-1213931828" -> "-1213935220"; +"-1213935220" [shape=box,label="__0_+\l'+'"]; +"-1213931828" -> "-1213951316"; +"-1213951316" [label="additive"]; +"-1213951316" -> "-1213948180"; +"-1213948180" [label="multitive"]; +"-1213948180" -> "-1213951380"; +"-1213951380" [label="primary"]; +"-1213951380" -> "-1213951508"; +"-1213951508" [shape=box,label="DECIMAL\l'4'"]; +"-1213948180" -> "-1213948788"; +"-1213948788" [shape=box,label="__1_*\l'*'"]; +"-1213948180" -> "-1213951060"; +"-1213951060" [label="multitive"]; +"-1213951060" -> "-1213948980"; +"-1213948980" [label="primary"]; +"-1213948980" -> "-1213950420"; +"-1213950420" [shape=box,label="DECIMAL\l'5'"]; +} Added: pypy/dist/pypy/doc/image/parsing_example2.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example2.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,17 @@ +digraph G{ +"-1213678004" [label="n"]; +"-1213678004" -> "-1213681108"; +"-1213681108" [shape=box,label="__0_A\n'A'"]; +"-1213678004" -> "-1213681332"; +"-1213681332" [shape=box,label="__1_,\n','"]; +"-1213678004" -> "-1213837780"; +"-1213837780" [label="n"]; +"-1213837780" -> "-1213837716"; +"-1213837716" [shape=box,label="__0_A\n'A'"]; +"-1213837780" -> "-1213839476"; +"-1213839476" [shape=box,label="__1_,\n','"]; +"-1213837780" -> "-1213839956"; +"-1213839956" [label="n"]; +"-1213839956" -> "-1213840948"; +"-1213840948" [shape=box,label="__0_A\n'A'"]; +} Added: pypy/dist/pypy/doc/image/parsing_example3.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example3.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,13 @@ +digraph G{ +"-1219325716" [label="n"]; +"-1219325716" -> "-1219325844"; +"-1219325844" [shape=box,label="__0_A\n'A'"]; +"-1219325716" -> "-1219324372"; +"-1219324372" [label="n"]; +"-1219324372" -> "-1219325524"; +"-1219325524" [shape=box,label="__0_A\n'A'"]; +"-1219324372" -> "-1219324308"; +"-1219324308" [label="n"]; +"-1219324308" -> "-1219325492"; +"-1219325492" [shape=box,label="__0_A\n'A'"]; +} Added: pypy/dist/pypy/doc/image/parsing_example4.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example4.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,27 @@ +digraph G{ +"-1214029460" [label="n"]; +"-1214029460" -> "-1214026452"; +"-1214026452" [shape=box,label="__0_a\n'a'"]; +"-1214029460" -> "-1214028276"; +"-1214028276" [shape=box,label="__1_b\n'b'"]; +"-1214029460" -> "-1214027316"; +"-1214027316" [shape=box,label="__2_c\n'c'"]; +"-1214029460" -> "-1214026868"; +"-1214026868" [label="m"]; +"-1214026868" -> "-1214140436"; +"-1214140436" [shape=box,label="__3_(\n'('"]; +"-1214026868" -> "-1214143508"; +"-1214143508" [label="n"]; +"-1214143508" -> "-1214141364"; +"-1214141364" [shape=box,label="__0_a\n'a'"]; +"-1214143508" -> "-1214141748"; +"-1214141748" [shape=box,label="__1_b\n'b'"]; +"-1214143508" -> "-1214140756"; +"-1214140756" [shape=box,label="__2_c\n'c'"]; +"-1214143508" -> "-1214144468"; +"-1214144468" [label="m"]; +"-1214144468" -> "-1214414868"; +"-1214414868" [shape=box,label="__5_d\n'd'"]; +"-1214026868" -> "-1214141492"; +"-1214141492" [shape=box,label="__4_)\n')'"]; +} \ No newline at end of file Added: pypy/dist/pypy/doc/image/parsing_example5.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example5.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,21 @@ +digraph G{ +"-1219949908" [label="n"]; +"-1219949908" -> "-1214026452"; +"-1214026452" [shape=box,label="__0_a\n'a'"]; +"-1219949908" -> "-1214028276"; +"-1214028276" [shape=box,label="__1_b\n'b'"]; +"-1219949908" -> "-1214027316"; +"-1214027316" [shape=box,label="__2_c\n'c'"]; +"-1219949908" -> "-1219949876"; +"-1219949876" [label="n"]; +"-1219949876" -> "-1214141364"; +"-1214141364" [shape=box,label="__0_a\n'a'"]; +"-1219949876" -> "-1214141748"; +"-1214141748" [shape=box,label="__1_b\n'b'"]; +"-1219949876" -> "-1214140756"; +"-1214140756" [shape=box,label="__2_c\n'c'"]; +"-1219949876" -> "-1219949748"; +"-1219949748" [label="m"]; +"-1219949748" -> "-1214414868"; +"-1214414868" [shape=box,label="__5_d\n'd'"]; +} \ No newline at end of file Added: pypy/dist/pypy/doc/image/parsing_example6.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example6.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,9 @@ +digraph G{ +"-1213518708" [label="list"]; +"-1213518708" -> "-1213518196"; +"-1213518196" [shape=box,label="DECIMAL\n'1'"]; +"-1213518708" -> "-1213518260"; +"-1213518260" [label="list"]; +"-1213518260" -> "-1213520308"; +"-1213520308" [shape=box,label="DECIMAL\n'2'"]; +} \ No newline at end of file Added: pypy/dist/pypy/doc/image/parsing_example7.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example7.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,7 @@ +digraph G{ +"-1219505652" [label="list"]; +"-1219505652" -> "-1213518196"; +"-1213518196" [shape=box,label="DECIMAL\n'1'"]; +"-1219505652" -> "-1213520308"; +"-1213520308" [shape=box,label="DECIMAL\n'2'"]; +} \ No newline at end of file Added: pypy/dist/pypy/doc/image/parsing_example8.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example8.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,21 @@ +digraph G{ +"-1213611892" [label="list"]; +"-1213611892" -> "-1213608980"; +"-1213608980" [shape=box,label="DECIMAL\n'1'"]; +"-1213611892" -> "-1213623476"; +"-1213623476" [label="list"]; +"-1213623476" -> "-1213623380"; +"-1213623380" [shape=box,label="DECIMAL\n'2'"]; +"-1213623476" -> "-1213442868"; +"-1213442868" [label="list"]; +"-1213442868" -> "-1213441652"; +"-1213441652" [shape=box,label="DECIMAL\n'3'"]; +"-1213442868" -> "-1213441332"; +"-1213441332" [label="list"]; +"-1213441332" -> "-1213441620"; +"-1213441620" [shape=box,label="DECIMAL\n'4'"]; +"-1213441332" -> "-1213443060"; +"-1213443060" [label="list"]; +"-1213443060" -> "-1213442100"; +"-1213442100" [shape=box,label="DECIMAL\n'5'"]; +} \ No newline at end of file Added: pypy/dist/pypy/doc/image/parsing_example9.dot ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/image/parsing_example9.dot Wed Nov 29 16:22:51 2006 @@ -0,0 +1,13 @@ +digraph G{ +"-1219430228" [label="list"]; +"-1219430228" -> "-1213608980"; +"-1213608980" [shape=box,label="DECIMAL\n'1'"]; +"-1219430228" -> "-1213623380"; +"-1213623380" [shape=box,label="DECIMAL\n'2'"]; +"-1219430228" -> "-1213441652"; +"-1213441652" [shape=box,label="DECIMAL\n'3'"]; +"-1219430228" -> "-1213441620"; +"-1213441620" [shape=box,label="DECIMAL\n'4'"]; +"-1219430228" -> "-1213442100"; +"-1213442100" [shape=box,label="DECIMAL\n'5'"]; +} \ No newline at end of file Modified: pypy/dist/pypy/doc/rlib.txt ============================================================================== --- pypy/dist/pypy/doc/rlib.txt (original) +++ pypy/dist/pypy/doc/rlib.txt Wed Nov 29 16:22:51 2006 @@ -227,3 +227,284 @@ produce a loop in the resulting flow graph but will unroll the loop instead. .. _unroll: ../../pypy/rlib/unroll.py + +``parsing`` +=========== + +The parsing_ module is a still in-development module to generate tokenizers and +parsers in RPython. It is still highly experimental and only really used by the +`Prolog interpreter`_ (although in slightly non-standard ways). The easiest way +to specify a tokenizer/grammar is to write it down using regular expressions and +simple EBNF format. + +The regular expressions are implemented using finite automatons. The parsing +engine uses packrat parsing, which has O(n) parsing time but is more powerful +than LL(n) and LR(n) grammars. + +Regular Expressions +------------------- + +The regular expression syntax is mostly a subset of the syntax of the `re`_ +module. By default, non-special characters match themselves. If you concatenate +regular expressions the result will match the concatenation of strings matched +by the single regular expressions. + +``|`` + ``R|S`` matches any string that *either* matches R or matches S. + +``*`` + ``R*`` matches 0 or more repetitions of R. + +``+`` + ``R+`` matches 1 or more repetitions of R. + +``?`` + ``R?`` matches 0 or 1 repetition of R. + +``(...)`` + Parenthesis can be used to group regular expressions (note that in constrast + to Python's re module you cannot later match the content of this group). + +``{m}`` + ``R{m}`` matches exactly m repetitions of R. + +``{m, n}`` + ``R{m, n}`` matches between m and n repetitions of R (including m and n). + +``[]`` + Matches a set of characters. The characters to be matched can be listed + sequentially. A range of characters can be specified using ``-``. For + examples ``[ac-eg]`` matches the characters a, c, d, e and g. + The whole set can be inverted by starting it with ``^``. So [^a] matches + anything except a. + +To parse a regular expression and to get a matcher for it, you can use the +function ``make_runner(s)`` in the ``pypy.rlib.parsing.parseregex`` module. It +returns a object with a ``recognize(input)`` method that returns True or False +depending on whether ``input`` matches the string or not. + +.. _`re`: http://docs.python.org/XXX + +EBNF +---- + +To describe a tokenizer and a grammar the ``pypy.rlib.parsing.ebnfparse`` +defines a syntax for doing that. + +The syntax file contains a sequence or rules. Every rule either describes a +regular expression or a grammar rule. + +Regular expressions rules have the form:: + + NAME: "regex"; + +NAME is the name of the token that the regular expression +produces (it has to consist of upper-case letters), ``regex`` is a regular +expression with the syntax described above. One token name is special-cased: a +token called ``IGNORE`` will be filtered out of the token stream before being +passed on to the parser and can thus be used to match comments or +non-significant whitespace. + +Grammar rules have the form:: + + name: expansion_1 | expansion_2 | ... | expansion_n; + +Where ``expansion_i`` is a sequence of nonterminal or token names:: + + symbol_1 symbol_2 symbol_3 ... symbol_n + +This means that the nonterminal symbol ``name`` (which has to consist of +lower-case letters) can be expanded into any of the expansions. The expansions +can consist of a sequence of token names, nonterminal names or literals, which +are strings in quotes that are matched literally. + +An example to make this clearer:: + + IGNORE: " "; + DECIMAL: "0|[1-9][0-9]*"; + additive: multitive "+" additive | + multitive "-" additive | + multitive; + multitive: primary "*" multitive | + primary "/" multitive | + primary; + primary: "(" additive ")" | DECIMAL; + +This grammar describes the syntax of arithmetic impressions. The tokenizer +produces a stream of either DECIMAL tokens or tokens that have matched one of +the literals "+", "-", "*" or "/". Any space will be ignored. The grammar +produces a syntax tree that follows the precedence of the operators. For example +the expression ``12 + 4 * 5`` is parsed into the following tree: + +.. graphviz:: image/parsing_example1.dot + +Parse Trees +----------- + +The parsing process builds up a tree consisting of intances of ``Symbol`` and +``Nonterminal``, the former corresponding to tokens, the latter to nonterminal +symbols. Both classes live in the `pypy.rlib.parsing.tree`_ module. You can use +the ``view()`` method ``Nonterminal`` instances to get a pygame view of the +parse tree. + +``Symbol`` instances have the following attributes: ``symbol``, which is the +name of the token and ``additional_info`` which is the matched source. + +``Nonterminal`` instances have the following attributes: ``symbol`` is the name +of the nonterminal and ``children`` which is a list of the children attributes. + + +.. _`pypy.rlib.parsing.tree`: ../../pypy/rlib/parsing/tree.py + +Visitors +++++++++ + +To write tree visitors for the parse trees that are RPython, there is a special +metaclass ``CreateDispatchDictionaryMetaclass`` in ``pypy.rlib.parsing.tree``_ +to use. If your class uses this, it will grow a ``dispatch(node)`` method, that +calls an appropriate ``visit_`` method, depending on the ``node`` +argument. Here the is replaced by the ``symbol`` attribute of the +visited node. + +For the visitor to be RPython, the return values of all the visit methods need +to be of the same type. + + +Tree Transformations +-------------------- + +As the tree of arithmetic example above shows, by default the parse tree +contains a lot of nodes that are not really conveying useful information. +To get rid of some of them, there is some support in the grammar format to +automatically create a visitor that transforms the tree to remove the additional +nodes. The simplest such transformation is to just remove nodes, but there are +more complex ones. + +The syntax for these transformations is to enclose symbols in expansions of a +nonterminal by [...], <...> or >...<. + +[symbol_1 symbol_2 ... symbol_n] +++++++++++++++++++++++++++++++++ + +This will produce a transformer that completely removes the enclosed symbols +from the tree. + +Example:: + + IGNORE: " "; + n: "A" [","] n | "A"; + +Parsing the string "A, A, A" gives the tree: + +.. graphviz:: image/parsing_example2.dot + +After transformation the tree has the "," nodes removed: + +.. graphviz:: image/parsing_example3.dot + + +++++++++ + +This will replace the parent with symbol. Every expansion can contain at most +one symbol that is enclosed by <...>, because the parent can only be replaced +once, obviously. + +Example:: + + IGNORE: " "; + n: "a" "b" "c" m; + m: "(" ")" | "d"; + +Parsing the string "a b c (a b c d)" gives the tree: + +.. graphviz:: image/parsing_example4.dot + +After transformation the tree looks like this: + +.. graphviz:: image/parsing_example5.dot + + +>nonterminal_1 nonterminal_2 ... nonterminal_n< ++++++++++++++++++++++++++++++++++++++++++++++++ + +This replaces the nodes nonterminal_1 to nonterminal_n by their children. + +Example:: + + IGNORE: " "; + DECIMAL: "0|[1-9][0-9]*"; + list: DECIMAL >list< | DECIMAL; + +Parsing the string "1 2" gives the tree: + +.. graphviz:: image/parsing_example6.dot + +after the transformation the tree looks like: + +.. graphviz:: image/parsing_example7.dot + +Note that the transformation works recursively. That means that the following +also works: if the string "1 2 3 4 5" is parsed the tree at first looks like +this: + +.. graphviz:: image/parsing_example8.dot + +But after transformation the whole thing collapses to one node with a lot of +children: + +.. graphviz:: image/parsing_example9.dot + + +Extensions to the EBNF grammar format +------------------------------------- + +There are some extensions to the EBNF grammar format that are really only +syntactic sugar but make writing grammars less tedious. These are: + +``symbol?``: + matches 0 or 1 repetitions of symbol + +``symbol*``: + matches 0 or more repetitions of symbol. After the tree transformation all + these repetitions are children of the current symbol. + +``symbol+``: + matches 1 or more repetitions of symbol. After the tree transformation all + these repetitions are children of the current symbol. + +These are implemented by adding some more rules to the grammar in the correct +way. Examples: the grammar:: + + s: a b? c; + +is transformed to look like this:: + + s: a >_maybe_symbol_0_< c | a c; + _maybe_symbol_0_: b; + +The grammar:: + + s: a b* c; + +is transformed to look like this:: + + s: a >_star_symbol_0< c | a c; + _star_symbol_0: b >_symbol_star_0< | b; + +The grammar:: + + s: a b+ c; + +is transformed to look like this:: + + s: a >_plus_symbol_0< c; + _plus_symbol_0: b >_plus_symbol_0< | b; + + +Full Example +------------ + +XXX to be written + +.. _`Prolog interpreter`: ../../pypy/lang/prolog/ +.. _parsing: ../../pypy/rlib/parsing/ From cfbolz at codespeak.net Wed Nov 29 16:32:34 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 29 Nov 2006 16:32:34 +0100 (CET) Subject: [pypy-svn] r35124 - pypy/dist/pypy/doc Message-ID: <20061129153234.DA0901008A@code0.codespeak.net> Author: cfbolz Date: Wed Nov 29 16:32:33 2006 New Revision: 35124 Modified: pypy/dist/pypy/doc/rlib.txt Log: add a link to packrat parsing and fix the one to the re module Modified: pypy/dist/pypy/doc/rlib.txt ============================================================================== --- pypy/dist/pypy/doc/rlib.txt (original) +++ pypy/dist/pypy/doc/rlib.txt Wed Nov 29 16:32:33 2006 @@ -238,8 +238,10 @@ simple EBNF format. The regular expressions are implemented using finite automatons. The parsing -engine uses packrat parsing, which has O(n) parsing time but is more powerful -than LL(n) and LR(n) grammars. +engine uses `packrat parsing`_, which has O(n) parsing time but is more +powerful than LL(n) and LR(n) grammars. + +.. _`packrat parsing`: http://pdos.csail.mit.edu/~baford/packrat/ Regular Expressions ------------------- @@ -283,7 +285,7 @@ returns a object with a ``recognize(input)`` method that returns True or False depending on whether ``input`` matches the string or not. -.. _`re`: http://docs.python.org/XXX +.. _`re`: http://docs.python.org/lib/module-re.html EBNF ---- From ericvrp at codespeak.net Wed Nov 29 16:36:00 2006 From: ericvrp at codespeak.net (ericvrp at codespeak.net) Date: Wed, 29 Nov 2006 16:36:00 +0100 (CET) Subject: [pypy-svn] r35125 - pypy/dist/pypy/jit/codegen/llvm/lib Message-ID: <20061129153600.D8EB910074@code0.codespeak.net> Author: ericvrp Date: Wed Nov 29 16:35:58 2006 New Revision: 35125 Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Log: Fix to make the llvmjit tests pass again on Darwin. It looks like the llvm libraries were not initialize prior to llvmjit?!? Modified: pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp ============================================================================== --- pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp (original) +++ pypy/dist/pypy/jit/codegen/llvm/lib/libllvmjit.cpp Wed Nov 29 16:35:58 2006 @@ -32,13 +32,12 @@ using namespace llvm; -Module* gp_module = new Module("llvmjit"); -ExecutionEngine* gp_execution_engine = ExecutionEngine::create( - new ExistingModuleProvider(gp_module), false); +Module* gp_module; // = new Module("llvmjit"); +ExecutionEngine* gp_execution_engine; // = ExecutionEngine::create(new ExistingModuleProvider(gp_module), false); //all optimization/transform passes -static cl::list - PassList(cl::desc("Optimizations available:")); +//static cl::list +// PassList(cl::desc("Optimizations available:")); //some global data for the tests to play with int g_data; From cfbolz at codespeak.net Wed Nov 29 16:41:16 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 29 Nov 2006 16:41:16 +0100 (CET) Subject: [pypy-svn] r35126 - pypy/dist/pypy/doc Message-ID: <20061129154116.DB8C110092@code0.codespeak.net> Author: cfbolz Date: Wed Nov 29 16:41:15 2006 New Revision: 35126 Modified: pypy/dist/pypy/doc/rlib.txt Log: just recommend the use of the base class Modified: pypy/dist/pypy/doc/rlib.txt ============================================================================== --- pypy/dist/pypy/doc/rlib.txt (original) +++ pypy/dist/pypy/doc/rlib.txt Wed Nov 29 16:41:15 2006 @@ -362,11 +362,10 @@ ++++++++ To write tree visitors for the parse trees that are RPython, there is a special -metaclass ``CreateDispatchDictionaryMetaclass`` in ``pypy.rlib.parsing.tree``_ -to use. If your class uses this, it will grow a ``dispatch(node)`` method, that -calls an appropriate ``visit_`` method, depending on the ``node`` -argument. Here the is replaced by the ``symbol`` attribute of the -visited node. +baseclass ``RPythonVisitor`` in ``pypy.rlib.parsing.tree``_ to use. If your +class uses this, it will grow a ``dispatch(node)`` method, that calls an +appropriate ``visit_`` method, depending on the ``node`` argument. Here +the is replaced by the ``symbol`` attribute of the visited node. For the visitor to be RPython, the return values of all the visit methods need to be of the same type. From afayolle at codespeak.net Wed Nov 29 17:01:30 2006 From: afayolle at codespeak.net (afayolle at codespeak.net) Date: Wed, 29 Nov 2006 17:01:30 +0100 (CET) Subject: [pypy-svn] r35128 - pypy/dist/pypy/doc Message-ID: <20061129160130.4FC9F10088@code0.codespeak.net> Author: afayolle Date: Wed Nov 29 17:01:28 2006 New Revision: 35128 Added: pypy/dist/pypy/doc/README.Debian Log: a few notes about Debian and pypy. Work in progress Added: pypy/dist/pypy/doc/README.Debian ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/README.Debian Wed Nov 29 17:01:28 2006 @@ -0,0 +1,25 @@ +=============== +Pypy and Debian +=============== + +Dependencies +------------ + +The following debian packages are useful when working with pypy: + +- python2.4 (of course) +- libgc-dev (boehm garbage collector) +- mono-gmcs (CLI backend +- llvm-cfe (llvm backend) +- spidermonkey-bin (javascript backend) +- (to be continued) + +Quirks and tips +--------------- + +llvm backend +~~~~~~~~~~~~ + +The translation using the llvm backend needs llvm-gcc to be in the +PATH. You will need to add /usr/lib/llvm/llvm-gcc4/bin to you PATH +environment variable. From arigo at codespeak.net Wed Nov 29 17:22:09 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 29 Nov 2006 17:22:09 +0100 (CET) Subject: [pypy-svn] r35129 - in pypy/dist/pypy: annotation/test objspace/std translator/goal Message-ID: <20061129162209.B69D610090@code0.codespeak.net> Author: arigo Date: Wed Nov 29 17:22:07 2006 New Revision: 35129 Modified: pypy/dist/pypy/annotation/test/test_annrpython.py pypy/dist/pypy/objspace/std/complexobject.py pypy/dist/pypy/translator/goal/ann_override.py Log: (arre, pedronis, arigo) Argh! This call to newbool(float) was making all calls to newbool() convert their argument to a float and back :-/ Modified: pypy/dist/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_annrpython.py (original) +++ pypy/dist/pypy/annotation/test/test_annrpython.py Wed Nov 29 17:22:07 2006 @@ -2438,6 +2438,20 @@ assert s.const == ("42", "4") + def test_float_cmp(self): + def fun(x, y): + return (x < y, + x <= y, + x == y, + x != y, + x > y, + x >= y) + + a = self.RPythonAnnotator(policy=policy.AnnotatorPolicy()) + s = a.build_types(fun, [float, float]) + assert [s_item.knowntype for s_item in s.items] == [bool] * 6 + + def g(n): return [0,1,2,n] Modified: pypy/dist/pypy/objspace/std/complexobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/complexobject.py (original) +++ pypy/dist/pypy/objspace/std/complexobject.py Wed Nov 29 17:22:07 2006 @@ -243,7 +243,8 @@ def nonzero__Complex(space, w_complex): assert space.is_true(space.isinstance(w_complex, space.w_complex)) - return space.newbool(w_complex.realval or w_complex.imagval) + return space.newbool((w_complex.realval != 0.0) or + (w_complex.imagval != 0.0)) def coerce__Complex_Complex(space, w_complex1, w_complex2): return space.newtuple([w_complex1, w_complex2]) Modified: pypy/dist/pypy/translator/goal/ann_override.py ============================================================================== --- pypy/dist/pypy/translator/goal/ann_override.py (original) +++ pypy/dist/pypy/translator/goal/ann_override.py Wed Nov 29 17:22:07 2006 @@ -1,11 +1,18 @@ # overrides for annotation specific to PyPy codebase -from pypy.annotation.policy import AnnotatorPolicy +from pypy.annotation.policy import AnnotatorPolicy, Sig # for some reason, model must be imported first, # or we create a cycle. from pypy.objspace.flow.model import Constant from pypy.annotation import model as annmodel from pypy.annotation.bookkeeper import getbookkeeper from pypy.annotation import specialize +from pypy.interpreter import baseobjspace + + +# patch - mostly for debugging, to enfore some signatures +baseobjspace.ObjSpace.newbool.im_func._annenforceargs_ = Sig(lambda s1,s2: s1, + bool) + class PyPyAnnotatorPolicy(AnnotatorPolicy): allow_someobjects = False From afayolle at codespeak.net Wed Nov 29 17:22:16 2006 From: afayolle at codespeak.net (afayolle at codespeak.net) Date: Wed, 29 Nov 2006 17:22:16 +0100 (CET) Subject: [pypy-svn] r35130 - pypy/dist/pypy/doc Message-ID: <20061129162216.61C9410090@code0.codespeak.net> Author: afayolle Date: Wed Nov 29 17:22:13 2006 New Revision: 35130 Modified: pypy/dist/pypy/doc/README.Debian Log: updated with feedback from #pypy Modified: pypy/dist/pypy/doc/README.Debian ============================================================================== --- pypy/dist/pypy/doc/README.Debian (original) +++ pypy/dist/pypy/doc/README.Debian Wed Nov 29 17:22:13 2006 @@ -5,15 +5,27 @@ Dependencies ------------ -The following debian packages are useful when working with pypy: +The following debian packages are required when working with pypy: - python2.4 (of course) +- python2.4-dev (for the C backend) +- gcc (for the C backend) - libgc-dev (boehm garbage collector) - mono-gmcs (CLI backend - llvm-cfe (llvm backend) - spidermonkey-bin (javascript backend) +- gcl-dev (for the common LISP backend) (to be confirmed) - (to be continued) +Squeak (for the smalltalk backend) is not included in Debian, but +packages are available. See the `squeak wiki` for details. + + + +Recommended packages include: + +- python-pygame (to display translation graphs) + Quirks and tips --------------- @@ -23,3 +35,6 @@ The translation using the llvm backend needs llvm-gcc to be in the PATH. You will need to add /usr/lib/llvm/llvm-gcc4/bin to you PATH environment variable. + + +.. `squeak wiki`: http://minnow.cc.gatech.edu/squeak/3616 From antocuni at codespeak.net Wed Nov 29 17:49:26 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 29 Nov 2006 17:49:26 +0100 (CET) Subject: [pypy-svn] r35131 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20061129164926.798CD10097@code0.codespeak.net> Author: antocuni Date: Wed Nov 29 17:49:25 2006 New Revision: 35131 Modified: pypy/dist/pypy/translator/cli/dotnet.py pypy/dist/pypy/translator/cli/test/test_dotnet.py Log: Make box really return real boxed objects when run on top of pythonnet. This is necessary for e.g. calling a method on them. Modified: pypy/dist/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/dotnet.py (original) +++ pypy/dist/pypy/translator/cli/dotnet.py Wed Nov 29 17:49:25 2006 @@ -271,17 +271,42 @@ CLR = CliNamespace(None) - BOXABLE_TYPES = [ootype.Signed, ootype.Unsigned, ootype.SignedLongLong, ootype.UnsignedLongLong, ootype.Bool, ootype.Float, ootype.Char, ootype.String] def box(x): - return x + t = type(x) + if t is int: + return CLR.System.Int32(x) + elif t is r_uint: + return CLR.System.UInt32(x) + elif t is r_longlong: + return CLR.System.Int64(x) + elif t is r_ulonglong: + return CLR.System.UInt64(x) + elif t is bool: + return CLR.System.Boolean(x) + elif t is float: + return CLR.System.Double(x) + elif t is str: + if len(x) == 1: + return CLR.System.Char(x) + else: + return CLR.System.String(x) + else: + assert False def unbox(x, TYPE): # TODO: check that x is really of type TYPE - return x + + # this is a workaround against a pythonnet limitation: you can't + # directly get the, e.g., python int from the System.Int32 object: + # a simple way to do this is to put it into an ArrayList and + # retrieve the value. + tmp = PythonNet.System.Collections.ArrayList() + tmp.Add(x) + return tmp[0] class Entry(ExtRegistryEntry): @@ -319,7 +344,6 @@ return hop.genop('cliunbox', [v_obj, v_type], hop.r_result.lowleveltype) - native_exc_cache = {} def NativeException(cliClass): try: Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Wed Nov 29 17:49:25 2006 @@ -168,6 +168,14 @@ return unbox(x.get_Item(0), ootype.String) assert self.interpret(fn, []) == 'foo' + def test_box_method(self): + def fn(): + x = box(42) + t = x.GetType() + return t.get_Name() + res = self.interpret(fn, []) + assert res == 'Int32' + def test_exception(self): py.test.skip("It doesn't work so far") def fn(): @@ -198,7 +206,7 @@ def test_init_array(self): def fn(): - x = init_array([box(42), box(43)]) + x = init_array(System.Object, box(42), box(43)) return unbox(x[0], ootype.Signed) + unbox(x[1], ootype.Signed) assert self.interpret(fn, []) == 42+43 From antocuni at codespeak.net Wed Nov 29 17:55:17 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Wed, 29 Nov 2006 17:55:17 +0100 (CET) Subject: [pypy-svn] r35132 - pypy/dist/pypy/translator/cli Message-ID: <20061129165517.D95301009F@code0.codespeak.net> Author: antocuni Date: Wed Nov 29 17:55:17 2006 New Revision: 35132 Modified: pypy/dist/pypy/translator/cli/dotnet.py Log: Missing import. Modified: pypy/dist/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/dotnet.py (original) +++ pypy/dist/pypy/translator/cli/dotnet.py Wed Nov 29 17:55:17 2006 @@ -3,6 +3,7 @@ from pypy.annotation.pairtype import pair, pairtype from pypy.annotation.model import SomeObject, SomeInstance, SomeOOInstance, SomeInteger, s_None,\ s_ImpossibleValue, lltype_to_annotation, annotation_to_lltype, SomeChar, SomeString +from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong from pypy.rpython.error import TyperError from pypy.rpython.extregistry import ExtRegistryEntry from pypy.rpython.rmodel import Repr @@ -433,3 +434,4 @@ c_index = hop.inputconst(ootype.Signed, i) hop.genop('cli_setelem', [v_array, c_index, v_elem], ootype.Void) return v_array + From arigo at codespeak.net Wed Nov 29 19:13:29 2006 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 29 Nov 2006 19:13:29 +0100 (CET) Subject: [pypy-svn] r35133 - in pypy/branch/jit-real-world/pypy: annotation/test config interpreter jit/codegen/ppc/test jit/goal jit/hintannotator jit/hintannotator/test jit/timeshifter objspace/std translator/goal Message-ID: <20061129181329.5A3421009C@code0.codespeak.net> Author: arigo Date: Wed Nov 29 19:13:19 2006 New Revision: 35133 Added: pypy/branch/jit-real-world/pypy/jit/goal/ (props changed) pypy/branch/jit-real-world/pypy/jit/goal/__init__.py (contents, props changed) pypy/branch/jit-real-world/pypy/jit/goal/jitstep.py (contents, props changed) pypy/branch/jit-real-world/pypy/jit/goal/targetjit.py (contents, props changed) Modified: pypy/branch/jit-real-world/pypy/annotation/test/test_annrpython.py pypy/branch/jit-real-world/pypy/config/pypyoption.py pypy/branch/jit-real-world/pypy/interpreter/pyframe.py pypy/branch/jit-real-world/pypy/interpreter/pyopcode.py pypy/branch/jit-real-world/pypy/jit/codegen/ppc/test/test_emit_moves.py (props changed) pypy/branch/jit-real-world/pypy/jit/codegen/ppc/test/test_genc_ts.py (props changed) pypy/branch/jit-real-world/pypy/jit/hintannotator/annotator.py pypy/branch/jit-real-world/pypy/jit/hintannotator/bookkeeper.py pypy/branch/jit-real-world/pypy/jit/hintannotator/model.py pypy/branch/jit-real-world/pypy/jit/hintannotator/test/test_annotator.py pypy/branch/jit-real-world/pypy/jit/timeshifter/transform.py pypy/branch/jit-real-world/pypy/objspace/std/complexobject.py pypy/branch/jit-real-world/pypy/translator/goal/ann_override.py pypy/branch/jit-real-world/pypy/translator/goal/targetpypystandalone.py pypy/branch/jit-real-world/pypy/translator/goal/translate.py Log: (pedronis, arre, arigo) Intermediate check-in. Modified: pypy/branch/jit-real-world/pypy/annotation/test/test_annrpython.py ============================================================================== --- pypy/branch/jit-real-world/pypy/annotation/test/test_annrpython.py (original) +++ pypy/branch/jit-real-world/pypy/annotation/test/test_annrpython.py Wed Nov 29 19:13:19 2006 @@ -2438,6 +2438,20 @@ assert s.const == ("42", "4") + def test_float_cmp(self): + def fun(x, y): + return (x < y, + x <= y, + x == y, + x != y, + x > y, + x >= y) + + a = self.RPythonAnnotator(policy=policy.AnnotatorPolicy()) + s = a.build_types(fun, [float, float]) + assert [s_item.knowntype for s_item in s.items] == [bool] * 6 + + def g(n): return [0,1,2,n] Modified: pypy/branch/jit-real-world/pypy/config/pypyoption.py ============================================================================== --- pypy/branch/jit-real-world/pypy/config/pypyoption.py (original) +++ pypy/branch/jit-real-world/pypy/config/pypyoption.py Wed Nov 29 19:13:19 2006 @@ -192,7 +192,8 @@ cmdline=None), ChoiceOption("fork_before", "(UNIX) Create restartable checkpoint before step", - ["annotate", "rtype", "backendopt", "database", "source"], + ["annotate", "rtype", "backendopt", "database", "source", + "hintannotate"], default=None, cmdline="--fork-before"), OptionDescription("backendopt", "Backend Optimization Options", [ Modified: pypy/branch/jit-real-world/pypy/interpreter/pyframe.py ============================================================================== --- pypy/branch/jit-real-world/pypy/interpreter/pyframe.py (original) +++ pypy/branch/jit-real-world/pypy/interpreter/pyframe.py Wed Nov 29 19:13:19 2006 @@ -221,7 +221,9 @@ if we_are_translated(): # always raising, put the resume point just before! rstack.resume_point("eval", self, executioncontext) - self.dispatch_translated(executioncontext) + code = self.pycode.co_code + self.dispatch_translated(code, + executioncontext) else: self.dispatch(executioncontext) # catch asynchronous exceptions and turn them Modified: pypy/branch/jit-real-world/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/branch/jit-real-world/pypy/interpreter/pyopcode.py (original) +++ pypy/branch/jit-real-world/pypy/interpreter/pyopcode.py Wed Nov 29 19:13:19 2006 @@ -13,7 +13,7 @@ from pypy.interpreter.pycode import PyCode from pypy.interpreter.opcodeorder import opcodeorder from pypy.tool.sourcetools import func_with_new_name -from pypy.rlib.objectmodel import we_are_translated +from pypy.rlib.objectmodel import we_are_translated, hint from pypy.rlib.rarithmetic import intmask from pypy.tool import stdlib_opcode as pythonopcode from pypy.rlib import rstack # for resume points @@ -595,6 +595,7 @@ def JUMP_FORWARD(f, stepby): f.next_instr += stepby + JUMP_FORWARD.can_jump = True def JUMP_IF_FALSE(f, stepby): w_cond = f.valuestack.top() @@ -810,24 +811,33 @@ import py dispatch_code = ''' -def dispatch_translated(self, ec): - code = self.pycode.co_code +def dispatch_translated(self, code, ec): + hint(None, global_merge_point=True) + next_instr = hint(self.next_instr, promote=True) while True: - self.last_instr = intmask(self.next_instr) - ec.bytecode_trace(self) - self.next_instr = self.last_instr - opcode = ord(code[self.next_instr]) + hint(None, global_merge_point=True) + self.last_instr = intmask(next_instr) + #ec.bytecode_trace(self) JJJ + #self.next_instr = self.last_instr JJJ + opcode = ord(code[next_instr]) + opcode = hint(opcode, concrete=True) if self.space.config.objspace.logbytecodes: self.space.bytecodecounts[opcode] = self.space.bytecodecounts.get(opcode, 0) + 1 - self.next_instr += 1 + next_instr += 1 + self.next_instr = next_instr if opcode >= %s: - oparg = ord(code[self.next_instr]) | ord(code[self.next_instr + 1]) << 8 - self.next_instr += 2 + oparg = ord(code[next_instr]) | ord(code[next_instr + 1]) << 8 + oparg = hint(oparg, concrete=True) + next_instr += 2 + self.next_instr = next_instr while True: if opcode == %s: - opcode = ord(code[self.next_instr]) - oparg = oparg << 16 | ord(code[self.next_instr + 1]) | ord(code[self.next_instr + 2]) << 8 - self.next_instr += 3 + opcode = ord(code[next_instr]) + opcode = hint(opcode, concrete=True) + oparg = oparg << 16 | ord(code[next_instr + 1]) | ord(code[next_instr + 2]) << 8 + oparg = hint(oparg, concrete=True) + next_instr += 3 + self.next_instr = next_instr if opcode < %s: raise pyframe.BytecodeCorruption continue Added: pypy/branch/jit-real-world/pypy/jit/goal/__init__.py ============================================================================== Added: pypy/branch/jit-real-world/pypy/jit/goal/jitstep.py ============================================================================== --- (empty file) +++ pypy/branch/jit-real-world/pypy/jit/goal/jitstep.py Wed Nov 29 19:13:19 2006 @@ -0,0 +1,35 @@ +from pypy.interpreter.pyopcode import PyInterpFrame + +from pypy.translator.translator import graphof +from pypy.jit.hintannotator.annotator import HintAnnotator, HintAnnotatorPolicy +from pypy.jit.hintannotator.model import OriginFlags, SomeLLAbstractConstant + +PORTAL = PyInterpFrame.dispatch_translated.im_func +#from pypy.jit.goal.x import evaluate as PORTAL + + +class PyPyHintAnnotatorPolicy(HintAnnotatorPolicy): + + def look_inside_graph(self, graph): + func = graph.func + mod = func.__module__ or '?' + if mod.startswith('pypy.objspace.'): + return False + if mod.startswith('pypy.module.'): + return False + return True + +POLICY = PyPyHintAnnotatorPolicy(novirtualcontainer = True, + oopspec = True) + + +def hintannotate(drv): + t = drv.translator + portal_graph = graphof(t, PORTAL) + + hannotator = HintAnnotator(base_translator=t, policy=POLICY) + hs = hannotator.build_types(portal_graph, + [SomeLLAbstractConstant(v.concretetype, + {OriginFlags(): True}) + for v in portal_graph.getargs()]) + import pdb; pdb.set_trace() Added: pypy/branch/jit-real-world/pypy/jit/goal/targetjit.py ============================================================================== --- (empty file) +++ pypy/branch/jit-real-world/pypy/jit/goal/targetjit.py Wed Nov 29 19:13:19 2006 @@ -0,0 +1,33 @@ +from pypy.translator.goal import targetpypystandalone +from pypy.translator.driver import TranslationDriver, taskdef +from pypy.annotation.pairtype import extendabletype + +class __extend__(TranslationDriver): + __metaclass__ = extendabletype + + def task_hintannotate(self): + from pypy.jit.goal import jitstep + jitstep.hintannotate(self) + # + task_hintannotate = taskdef(task_hintannotate, + [TranslationDriver.BACKENDOPT], + "Hint-annotate") + + +class PyPyJITTarget(targetpypystandalone.PyPyTarget): + + usage = "target PyPy with JIT" + + #def target(self, driver, args): + # from pypy.jit.goal.x import main + # return main, None + + def handle_config(self, config): + config.translation.backendopt.inline_threshold = 0 + config.translation.fork_before = 'hintannotate' + + def handle_translate_config(self, translateconfig): + translateconfig.goals = ['hintannotate'] + + +PyPyJITTarget().interface(globals()) Modified: pypy/branch/jit-real-world/pypy/jit/hintannotator/annotator.py ============================================================================== --- pypy/branch/jit-real-world/pypy/jit/hintannotator/annotator.py (original) +++ pypy/branch/jit-real-world/pypy/jit/hintannotator/annotator.py Wed Nov 29 19:13:19 2006 @@ -1,12 +1,25 @@ +from pypy.annotation import policy from pypy.annotation.annrpython import RPythonAnnotator from pypy.jit.hintannotator import model as hintmodel from pypy.jit.hintannotator.bookkeeper import HintBookkeeper from pypy.rpython.lltypesystem import lltype +class HintAnnotatorPolicy(policy.AnnotatorPolicy): + + def __init__(self, novirtualcontainer=False, oopspec=False): + self.novirtualcontainer = novirtualcontainer + self.oopspec = oopspec + + def look_inside_graph(self, graph): + return True + +DEFPOL = HintAnnotatorPolicy() + + class HintAnnotator(RPythonAnnotator): - def __init__(self, translator=None, base_translator=None, policy=None): + def __init__(self, translator=None, base_translator=None, policy=DEFPOL): bookkeeper = HintBookkeeper(self) RPythonAnnotator.__init__(self, translator, policy=policy, bookkeeper=bookkeeper) @@ -22,7 +35,7 @@ def consider_op_malloc(self, hs_TYPE): TYPE = hs_TYPE.const - if getattr(self.policy, 'novirtualcontainer', False): + if self.policy.novirtualcontainer: return hintmodel.SomeLLAbstractVariable(lltype.Ptr(TYPE)) else: vstructdef = self.bookkeeper.getvirtualcontainerdef(TYPE) @@ -32,7 +45,7 @@ def consider_op_malloc_varsize(self, hs_TYPE, hs_length): TYPE = hs_TYPE.const - if getattr(self.policy, 'novirtualcontainer', False): + if self.policy.novirtualcontainer: return hintmodel.SomeLLAbstractVariable(lltype.Ptr(TYPE)) else: vcontainerdef = self.bookkeeper.getvirtualcontainerdef(TYPE) Modified: pypy/branch/jit-real-world/pypy/jit/hintannotator/bookkeeper.py ============================================================================== --- pypy/branch/jit-real-world/pypy/jit/hintannotator/bookkeeper.py (original) +++ pypy/branch/jit-real-world/pypy/jit/hintannotator/bookkeeper.py Wed Nov 29 19:13:19 2006 @@ -1,4 +1,6 @@ +import py from pypy.tool.tls import tlsobject +from pypy.tool.ansi_print import ansi_log from pypy.objspace.flow.model import copygraph, SpaceOperation, Constant from pypy.annotation import model as annmodel from pypy.rpython.lltypesystem import lltype @@ -6,6 +8,9 @@ TLS = tlsobject() +log = py.log.Producer("hintannotate") +py.log.setconsumer("hintannotate", ansi_log) + class GraphDesc(object): @@ -46,6 +51,7 @@ graph.name = alt_name self._cache[key] = graph self.bookkeeper.annotator.translator.graphs.append(graph) + log(str(graph)) return graph @@ -172,6 +178,11 @@ key = [] specialize = False for i, arg_hs in enumerate(args_hs): + if isinstance(arg_hs, hintmodel.SomeLLAbstractVariable): + key.append('v') + specialize = True + continue + if (isinstance(arg_hs, hintmodel.SomeLLAbstractConstant) and arg_hs.eager_concrete): key.append('E') Modified: pypy/branch/jit-real-world/pypy/jit/hintannotator/model.py ============================================================================== --- pypy/branch/jit-real-world/pypy/jit/hintannotator/model.py (original) +++ pypy/branch/jit-real-world/pypy/jit/hintannotator/model.py Wed Nov 29 19:13:19 2006 @@ -7,7 +7,7 @@ cast_pointer direct_call indirect_call - int_is_true int_neg + int_is_true int_neg int_invert bool_not uint_is_true cast_int_to_char cast_int_to_uint @@ -16,10 +16,12 @@ cast_bool_to_int ptr_nonzero ptr_iszero - debug_assert""".split() + debug_assert resume_point""".split() -BINARY_OPERATIONS = """int_add int_sub int_mul int_mod int_and int_rshift int_floordiv int_xor int_or - uint_add uint_sub uint_mul uint_mod uint_and uint_lshift uint_rshift uint_floordiv +BINARY_OPERATIONS = """int_add int_sub int_mul int_mod int_and int_rshift + int_lshift int_floordiv int_xor int_or + uint_add uint_sub uint_mul uint_mod uint_and + uint_lshift uint_rshift uint_floordiv char_gt char_lt char_le char_ge char_eq char_ne int_gt int_lt int_le int_ge int_eq int_ne uint_gt uint_lt uint_le uint_ge uint_eq uint_ne @@ -103,7 +105,7 @@ return False # was generalized, e.g. to SomeLLAbstractVariable hs_f1 = args_hs.pop(0) fnobj = hs_f1.const._obj - if (getattr(self.annotator.policy, 'oopspec', False) and + if (self.annotator.policy.oopspec and hasattr(fnobj._callable, 'oopspec')): assert False # XXX? @@ -183,12 +185,15 @@ """Compute the color of the variables with this annotation for the pygame viewer """ - if self.eager_concrete: - return (0,100,0) # green - elif self.is_green(): - return (50,140,0) # green-dark-cyan - else: - return None + try: + if self.eager_concrete: + return (0,100,0) # green + elif self.is_green(): + return (50,140,0) # green-dark-cyan + else: + return None + except KeyError: # can occur in is_green() if annotation crashed + return (0,200,200) annotationcolor = property(annotationcolor) @@ -276,7 +281,7 @@ return SomeLLAbstractConstant(hs_v1.concretetype, {origin: True}) if hs_flags.const.get('promote', False): hs_concrete = SomeLLAbstractConstant(hs_v1.concretetype, {}) - hs_concrete.eager_concrete = True + #hs_concrete.eager_concrete = True return hs_concrete for name in ["reverse_split_queue", "global_merge_point"]: if hs_flags.const.get(name, False): @@ -288,6 +293,9 @@ def debug_assert(hs_v1, *args_hs): pass + def resume_point(hs_v1, *args_hs): + pass + def getfield(hs_v1, hs_fieldname): S = hs_v1.concretetype.TO FIELD_TYPE = getattr(S, hs_fieldname.const) @@ -317,9 +325,15 @@ args_hs = args_hs[:-1] assert hs_graph_list.is_constant() graph_list = hs_graph_list.const - assert graph_list # XXX for now + if not graph_list: + # cannot follow + return SomeLLAbstractVariable(hs_v1.concretetype.TO.RESULT) bookkeeper = getbookkeeper() + for graph in graph_list: + if not bookkeeper.annotator.policy.look_inside_graph(graph): + return SomeLLAbstractVariable(hs_v1.concretetype.TO.RESULT) + fixed = bookkeeper.myorigin().read_fixed() hs_res = bookkeeper.graph_family_call(graph_list, fixed, args_hs) @@ -361,7 +375,7 @@ def direct_call(hs_f1, *args_hs): bookkeeper = getbookkeeper() fnobj = hs_f1.const._obj - if (getattr(bookkeeper.annotator.policy, 'oopspec', False) and + if (bookkeeper.annotator.policy.oopspec and hasattr(fnobj._callable, 'oopspec')): # try to handle the call as a high-level operation try: @@ -376,6 +390,14 @@ # normal call if not hasattr(fnobj, 'graph'): raise NotImplementedError("XXX call to externals or primitives") + if not bookkeeper.annotator.policy.look_inside_graph(fnobj.graph): + return SomeLLAbstractVariable(lltype.typeOf(fnobj).RESULT) + + # recursive call from the entry point to itself: ignore them and + # just hope the annotations are correct + if (bookkeeper.getdesc(fnobj.graph)._cache.get(None, None) is + bookkeeper.annotator.translator.graphs[0]): + return SomeLLAbstractVariable(lltype.typeOf(fnobj).RESULT) fixed = bookkeeper.myorigin().read_fixed() hs_res = bookkeeper.graph_call(fnobj.graph, fixed, args_hs) @@ -383,6 +405,11 @@ if isinstance(hs_res, SomeLLAbstractConstant): hs_res.myorigin = bookkeeper.myorigin() hs_res.myorigin.is_call_result = True +## elif fnobj.graph.name.startswith('ll_stritem'): +## if isinstance(hs_res, SomeLLAbstractVariable): +## print hs_res +## import pdb; pdb.set_trace() + # we need to make sure that hs_res does not become temporarily less # general as a result of calling another specialized version of the @@ -564,7 +591,7 @@ # ____________________________________________________________ def handle_highlevel_operation(bookkeeper, ll_func, *args_hs): - if getattr(bookkeeper.annotator.policy, 'novirtualcontainer', False): + if bookkeeper.annotator.policy.novirtualcontainer: # "blue variables" disabled, we just return a red var all the time. RESULT = bookkeeper.current_op_concretetype() if RESULT is lltype.Void: Modified: pypy/branch/jit-real-world/pypy/jit/hintannotator/test/test_annotator.py ============================================================================== --- pypy/branch/jit-real-world/pypy/jit/hintannotator/test/test_annotator.py (original) +++ pypy/branch/jit-real-world/pypy/jit/hintannotator/test/test_annotator.py Wed Nov 29 19:13:19 2006 @@ -1,25 +1,19 @@ import py from pypy.translator.translator import TranslationContext, graphof -from pypy.jit.hintannotator.annotator import HintAnnotator +from pypy.jit.hintannotator.annotator import HintAnnotator, HintAnnotatorPolicy from pypy.jit.hintannotator.bookkeeper import HintBookkeeper from pypy.jit.hintannotator.model import * from pypy.rpython.lltypesystem import lltype from pypy.rlib.objectmodel import hint from pypy.annotation import model as annmodel from pypy.objspace.flow import model as flowmodel -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 - -P_OOPSPEC_NOVIRTUAL = AnnotatorPolicy() -P_OOPSPEC_NOVIRTUAL.oopspec = True -P_OOPSPEC_NOVIRTUAL.novirtualcontainer = True - -P_NOVIRTUAL = AnnotatorPolicy() -P_NOVIRTUAL.novirtualcontainer = True +P_OOPSPEC = HintAnnotatorPolicy(oopspec=True) +P_OOPSPEC_NOVIRTUAL = HintAnnotatorPolicy(oopspec=True, + novirtualcontainer=True) +P_NOVIRTUAL = HintAnnotatorPolicy(novirtualcontainer=True) def hannotate(func, argtypes, policy=None, annotator=False, inline=None, backendoptimize=False): Modified: pypy/branch/jit-real-world/pypy/jit/timeshifter/transform.py ============================================================================== --- pypy/branch/jit-real-world/pypy/jit/timeshifter/transform.py (original) +++ pypy/branch/jit-real-world/pypy/jit/timeshifter/transform.py Wed Nov 29 19:13:19 2006 @@ -447,7 +447,7 @@ c_func = spaceop.args[0] fnobj = c_func.value._obj if (hasattr(fnobj._callable, 'oopspec') and - getattr(self.hannotator.policy, 'oopspec', False)): + self.hannotator.policy.oopspec): return 'oopspec' for v in spaceop.args: Modified: pypy/branch/jit-real-world/pypy/objspace/std/complexobject.py ============================================================================== --- pypy/branch/jit-real-world/pypy/objspace/std/complexobject.py (original) +++ pypy/branch/jit-real-world/pypy/objspace/std/complexobject.py Wed Nov 29 19:13:19 2006 @@ -243,7 +243,8 @@ def nonzero__Complex(space, w_complex): assert space.is_true(space.isinstance(w_complex, space.w_complex)) - return space.newbool(w_complex.realval or w_complex.imagval) + return space.newbool((w_complex.realval != 0.0) or + (w_complex.imagval != 0.0)) def coerce__Complex_Complex(space, w_complex1, w_complex2): return space.newtuple([w_complex1, w_complex2]) Modified: pypy/branch/jit-real-world/pypy/translator/goal/ann_override.py ============================================================================== --- pypy/branch/jit-real-world/pypy/translator/goal/ann_override.py (original) +++ pypy/branch/jit-real-world/pypy/translator/goal/ann_override.py Wed Nov 29 19:13:19 2006 @@ -1,11 +1,18 @@ # overrides for annotation specific to PyPy codebase -from pypy.annotation.policy import AnnotatorPolicy +from pypy.annotation.policy import AnnotatorPolicy, Sig # for some reason, model must be imported first, # or we create a cycle. from pypy.objspace.flow.model import Constant from pypy.annotation import model as annmodel from pypy.annotation.bookkeeper import getbookkeeper from pypy.annotation import specialize +from pypy.interpreter import baseobjspace + + +# patch - mostly for debugging, to enfore some signatures +baseobjspace.ObjSpace.newbool.im_func._annenforceargs_ = Sig(lambda s1,s2: s1, + bool) + class PyPyAnnotatorPolicy(AnnotatorPolicy): allow_someobjects = False Modified: pypy/branch/jit-real-world/pypy/translator/goal/targetpypystandalone.py ============================================================================== --- pypy/branch/jit-real-world/pypy/translator/goal/targetpypystandalone.py (original) +++ pypy/branch/jit-real-world/pypy/translator/goal/targetpypystandalone.py Wed Nov 29 19:13:19 2006 @@ -91,6 +91,9 @@ def handle_config(self, config): pass + def handle_translate_config(self, translateconfig): + pass + def print_help(self, config): self.opt_parser(config).print_help() @@ -150,7 +153,8 @@ return entry_point, None, PyPyAnnotatorPolicy(single_space = space) def interface(self, ns): - for name in ['take_options', 'handle_config', 'print_help', 'target']: + for name in ['take_options', 'handle_config', 'print_help', 'target', + 'handle_translate_config']: ns[name] = getattr(self, name) Modified: pypy/branch/jit-real-world/pypy/translator/goal/translate.py ============================================================================== --- pypy/branch/jit-real-world/pypy/translator/goal/translate.py (original) +++ pypy/branch/jit-real-world/pypy/translator/goal/translate.py Wed Nov 29 19:13:19 2006 @@ -150,6 +150,9 @@ if 'handle_config' in targetspec_dic: targetspec_dic['handle_config'](config) + if 'handle_translate_config' in targetspec_dic: + targetspec_dic['handle_translate_config'](translateconfig) + if translateconfig.help: opt_parser.print_help() if 'print_help' in targetspec_dic: From fijal at codespeak.net Thu Nov 30 00:19:18 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 30 Nov 2006 00:19:18 +0100 (CET) Subject: [pypy-svn] r35141 - pypy/dist/pypy/translator/js/modules Message-ID: <20061129231918.583C210086@code0.codespeak.net> Author: fijal Date: Thu Nov 30 00:19:16 2006 New Revision: 35141 Modified: pypy/dist/pypy/translator/js/modules/dom.py Log: We need that one Modified: pypy/dist/pypy/translator/js/modules/dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/dom.py (original) +++ pypy/dist/pypy/translator/js/modules/dom.py Thu Nov 30 00:19:16 2006 @@ -296,6 +296,9 @@ location = property(_getLocation, _setLocation) +def some_fun(): + pass + def setTimeout(func, delay): # scheduler call, but we don't want to mess with threads right now if one(): From fijal at codespeak.net Thu Nov 30 00:19:29 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 30 Nov 2006 00:19:29 +0100 (CET) Subject: [pypy-svn] r35142 - pypy/dist/pypy/translator/js/examples Message-ID: <20061129231929.7FF1C1007F@code0.codespeak.net> Author: fijal Date: Thu Nov 30 00:19:27 2006 New Revision: 35142 Modified: pypy/dist/pypy/translator/js/examples/server.py Log: Some improvements Modified: pypy/dist/pypy/translator/js/examples/server.py ============================================================================== --- pypy/dist/pypy/translator/js/examples/server.py (original) +++ pypy/dist/pypy/translator/js/examples/server.py Thu Nov 30 00:19:27 2006 @@ -57,6 +57,8 @@ else: getargs = "" name_path = path.replace(".", "_") + if name_path == "": + name_path = "index" method_to_call = getattr(self, name_path, None) if method_to_call is None or not getattr(method_to_call, 'exposed', None): exec_meth = getattr(self.exported_methods, name_path, None) @@ -65,7 +67,13 @@ else: self.serve_data('text/json', json.write(exec_meth(**self.parse_args(getargs)))) else: - method_to_call() + outp = method_to_call() + if isinstance(outp, str): + self.serve_data('text/html', outp) + elif isinstance(outp, tuple): + self.serve_data(*outp) + else: + raise ValueError("Don't know how to serve %s" % (outp,)) def parse_args(self, getargs): # parse get argument list From pedronis at codespeak.net Thu Nov 30 13:24:27 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 30 Nov 2006 13:24:27 +0100 (CET) Subject: [pypy-svn] r35154 - pypy/branch/jit-real-world/pypy/jit/hintannotator Message-ID: <20061130122427.B355D10075@code0.codespeak.net> Author: pedronis Date: Thu Nov 30 13:24:26 2006 New Revision: 35154 Modified: pypy/branch/jit-real-world/pypy/jit/hintannotator/annotator.py Log: use None to mean the default policy, like the base rpython annotator. Make hannotate in tests work as it is. Hint annotator tests pass again. Modified: pypy/branch/jit-real-world/pypy/jit/hintannotator/annotator.py ============================================================================== --- pypy/branch/jit-real-world/pypy/jit/hintannotator/annotator.py (original) +++ pypy/branch/jit-real-world/pypy/jit/hintannotator/annotator.py Thu Nov 30 13:24:26 2006 @@ -14,12 +14,12 @@ def look_inside_graph(self, graph): return True -DEFPOL = HintAnnotatorPolicy() - class HintAnnotator(RPythonAnnotator): - def __init__(self, translator=None, base_translator=None, policy=DEFPOL): + def __init__(self, translator=None, base_translator=None, policy=None): + if policy is None: + policy = HintAnnotatorPolicy() bookkeeper = HintBookkeeper(self) RPythonAnnotator.__init__(self, translator, policy=policy, bookkeeper=bookkeeper) From fijal at codespeak.net Thu Nov 30 14:12:03 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 30 Nov 2006 14:12:03 +0100 (CET) Subject: [pypy-svn] r35156 - pypy/dist/pypy/translator/js/test Message-ID: <20061130131203.DA14610079@code0.codespeak.net> Author: fijal Date: Thu Nov 30 14:12:02 2006 New Revision: 35156 Modified: pypy/dist/pypy/translator/js/test/test_basicexternal.py Log: Failing test for basicexternal method call Modified: pypy/dist/pypy/translator/js/test/test_basicexternal.py ============================================================================== --- pypy/dist/pypy/translator/js/test/test_basicexternal.py (original) +++ pypy/dist/pypy/translator/js/test/test_basicexternal.py Thu Nov 30 14:12:02 2006 @@ -92,3 +92,19 @@ return d.a fun1 = compile_function(return_dict, []) + +def test_method_call(): + py.test.skip("Fails") + class Meth(BasicExternal): + @described(retval=3) + def meth(self): + return 8 + + l = [] + + def callback(i): + l.append(i) + + meth = Meth() + meth.meth(callback) + assert l[0] == 8 From fijal at codespeak.net Thu Nov 30 14:42:33 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 30 Nov 2006 14:42:33 +0100 (CET) Subject: [pypy-svn] r35157 - in pypy/dist/pypy/translator/js: . modules/test test Message-ID: <20061130134233.519CA1008F@code0.codespeak.net> Author: fijal Date: Thu Nov 30 14:42:28 2006 New Revision: 35157 Added: pypy/dist/pypy/translator/js/tester.py (contents, props changed) Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py pypy/dist/pypy/translator/js/test/test_basicexternal.py Log: Added new testing possibilities. Modified: pypy/dist/pypy/translator/js/modules/test/test_dom.py ============================================================================== --- pypy/dist/pypy/translator/js/modules/test/test_dom.py (original) +++ pypy/dist/pypy/translator/js/modules/test/test_dom.py Thu Nov 30 14:42:28 2006 @@ -1,6 +1,7 @@ import py from pypy.translator.js.modules import dom from pypy.translator.js.main import rpython2javascript +from pypy.rpython.ootypesystem.bltregistry import BasicExternal, described from xml.dom.minidom import parseString import sys Modified: pypy/dist/pypy/translator/js/test/test_basicexternal.py ============================================================================== --- pypy/dist/pypy/translator/js/test/test_basicexternal.py (original) +++ pypy/dist/pypy/translator/js/test/test_basicexternal.py Thu Nov 30 14:42:28 2006 @@ -6,6 +6,7 @@ from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal, described from pypy.translator.js.test.runtest import compile_function, check_source_contains +from pypy.translator.js.tester import schedule_callbacks class A(BasicExternal): @described(retval=3) @@ -94,7 +95,6 @@ fun1 = compile_function(return_dict, []) def test_method_call(): - py.test.skip("Fails") class Meth(BasicExternal): @described(retval=3) def meth(self): @@ -107,4 +107,5 @@ meth = Meth() meth.meth(callback) + schedule_callbacks(meth) assert l[0] == 8 Added: pypy/dist/pypy/translator/js/tester.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/js/tester.py Thu Nov 30 14:42:28 2006 @@ -0,0 +1,31 @@ + +""" tester - support module for testing js code inside python + +Needs to be imported in case one wants tests involving calling BasicExternal +methods +""" + +from pypy.rpython.ootypesystem.bltregistry import BasicExternal + +def __getattr__(self, attr): + val = super(BasicExternal, self).__getattribute__(attr) + if not callable(val) or attr not in self._methods: + return val # we don't do anything special + # otherwise.... + def wrapper(*args, **kwargs): + args = list(args) + callback = args.pop() + res = val(*args, **kwargs) + if not hasattr(self, '__callbacks'): + self.__callbacks = [] + self.__callbacks.append((callback, res)) + wrapper.func_name = attr + return wrapper + +BasicExternal.__getattribute__ = __getattr__ + +def schedule_callbacks(*args): + for arg in args: + if hasattr(arg, '__callbacks'): + for callback, res in arg.__callbacks: + callback(res) From pedronis at codespeak.net Thu Nov 30 15:03:53 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 30 Nov 2006 15:03:53 +0100 (CET) Subject: [pypy-svn] r35159 - pypy/dist/pypy/doc Message-ID: <20061130140353.1F6C410074@code0.codespeak.net> Author: pedronis Date: Thu Nov 30 15:03:51 2006 New Revision: 35159 Added: pypy/dist/pypy/doc/draft-jit-outline.txt (contents, props changed) Log: draft of an outline for documenting the current jit generation status. Added: pypy/dist/pypy/doc/draft-jit-outline.txt ============================================================================== --- (empty file) +++ pypy/dist/pypy/doc/draft-jit-outline.txt Thu Nov 30 15:03:51 2006 @@ -0,0 +1,63 @@ +======================= +JIT Generation in PyPy +======================= + +Introduction +============= + +Intepreters to compilers, psyco parallel... + + +Hint-Annotation and Compile Time Values +========================================= + +Hint annotator and hint(concrete=True)... + + +Timeshifting: transforming interpreter into compilers +====================================================== + +intro and basics + +Split and Merges +-------------------- + +... + +Calls and inlining +--------------------- + +... + +Virtual Containers +-------------------- + +... + +Promotion and global merges +----------------------------- + +... + +partial data +------------- + +... + + +Portals +---------------------- + +... + + +Backends +==================== + +... + +The Backend interface +----------------------- + +... + From antocuni at codespeak.net Thu Nov 30 15:06:23 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 30 Nov 2006 15:06:23 +0100 (CET) Subject: [pypy-svn] r35160 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20061130140623.8E79210080@code0.codespeak.net> Author: antocuni Date: Thu Nov 30 15:06:23 2006 New Revision: 35160 Modified: pypy/dist/pypy/translator/cli/dotnet.py pypy/dist/pypy/translator/cli/metavm.py pypy/dist/pypy/translator/cli/opcodes.py pypy/dist/pypy/translator/cli/test/test_dotnet.py Log: New cli built-in: typeof, whose semantics is similar to the corresponding C# keyword. Modified: pypy/dist/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/dotnet.py (original) +++ pypy/dist/pypy/translator/cli/dotnet.py Thu Nov 30 15:06:23 2006 @@ -435,3 +435,21 @@ hop.genop('cli_setelem', [v_array, c_index, v_elem], ootype.Void) return v_array + +def typeof(cliClass): + TYPE = cliClass._INSTANCE + name = '%s.%s' % (TYPE._namespace, TYPE._classname) + return PythonNet.System.Type.GetType(name) + +class Entry(ExtRegistryEntry): + _about_ = typeof + + def compute_result_annotation(self, cliClass_s): + from query import load_class_maybe + assert cliClass_s.is_constant() + cliType = load_class_maybe('System.Type') + return SomeOOInstance(cliType._INSTANCE) + + def specialize_call(self, hop): + v_type, = hop.inputargs(*hop.args_r) + return hop.genop('cli_typeof', [v_type], hop.r_result.lowleveltype) Modified: pypy/dist/pypy/translator/cli/metavm.py ============================================================================== --- pypy/dist/pypy/translator/cli/metavm.py (original) +++ pypy/dist/pypy/translator/cli/metavm.py Thu Nov 30 15:06:23 2006 @@ -210,6 +210,15 @@ elemtype = generator.cts.lltype_to_cts(v_array.concretetype) generator.ilasm.opcode('stelem', elemtype) +class _TypeOf(MicroInstruction): + def render(self, generator, op): + v_type, = op.args + assert v_type.concretetype is ootype.Void + cliClass = v_type.value + fullname = cliClass._INSTANCE._name + generator.ilasm.opcode('ldtoken', fullname) + generator.ilasm.call('class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)') + Call = _Call() CallMethod = _CallMethod() @@ -224,3 +233,4 @@ NewArray = _NewArray() GetArrayElem = _GetArrayElem() SetArrayElem = _SetArrayElem() +TypeOf = _TypeOf() Modified: pypy/dist/pypy/translator/cli/opcodes.py ============================================================================== --- pypy/dist/pypy/translator/cli/opcodes.py (original) +++ pypy/dist/pypy/translator/cli/opcodes.py Thu Nov 30 15:06:23 2006 @@ -1,6 +1,7 @@ from pypy.translator.cli.metavm import Call, CallMethod, \ IndirectCall, GetField, SetField, CastTo, OOString, DownCast, NewCustomDict,\ - CastWeakAdrToPtr, MapException, Box, Unbox, NewArray, GetArrayElem, SetArrayElem + CastWeakAdrToPtr, MapException, Box, Unbox, NewArray, GetArrayElem, SetArrayElem,\ + TypeOf from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\ New, RuntimeNew from pypy.translator.cli.cts import WEAKREF @@ -39,6 +40,7 @@ 'cli_newarray': [NewArray], 'cli_getelem': [GetArrayElem], 'cli_setelem': [SetArrayElem], + 'cli_typeof': [TypeOf], 'oois': 'ceq', 'oononnull': [PushAllArgs, 'ldnull', 'ceq']+Not, 'instanceof': [CastTo, 'ldnull', 'cgt.un'], Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Thu Nov 30 15:06:23 2006 @@ -7,7 +7,7 @@ from pypy.translator.cli.test.runtest import CliTest from pypy.translator.cli.dotnet import SomeCliClass, SomeCliStaticMethod,\ NativeInstance, CLR, box, unbox, OverloadingResolver, NativeException,\ - native_exc, new_array, init_array + native_exc, new_array, init_array, typeof System = CLR.System Math = CLR.System.Math @@ -111,7 +111,8 @@ a = RPythonAnnotator() s = a.build_types(fn, []) assert isinstance(s, annmodel.SomeOOInstance) - assert s.ootype._name == '[mscorlib]System.Object' + assert s.ootype._name == '[mscorlib]System.Object' + class TestDotnetRtyping(CliTest): def _skip_pythonnet(self, msg): @@ -274,6 +275,13 @@ res = self.ll_to_string(self.interpret(fn, [])) assert res.startswith("Index is less than 0") + def test_typeof(self): + def fn(): + x = box(42) + return x.GetType() == typeof(System.Int32) + res = self.interpret(fn, []) + assert res is True + class TestPythonnet(TestDotnetRtyping): # don't interpreter functions but execute them directly through pythonnet def interpret(self, f, args): From pedronis at codespeak.net Thu Nov 30 15:10:22 2006 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 30 Nov 2006 15:10:22 +0100 (CET) Subject: [pypy-svn] r35161 - pypy/branch/jit-real-world/pypy/jit/timeshifter/test Message-ID: <20061130141022.232821008E@code0.codespeak.net> Author: pedronis Date: Thu Nov 30 15:10:20 2006 New Revision: 35161 Modified: pypy/branch/jit-real-world/pypy/jit/timeshifter/test/test_timeshift.py pypy/branch/jit-real-world/pypy/jit/timeshifter/test/test_vlist.py Log: fix policy construction. tests pass again on the branch. Modified: pypy/branch/jit-real-world/pypy/jit/timeshifter/test/test_timeshift.py ============================================================================== --- pypy/branch/jit-real-world/pypy/jit/timeshifter/test/test_timeshift.py (original) +++ pypy/branch/jit-real-world/pypy/jit/timeshifter/test/test_timeshift.py Thu Nov 30 15:10:20 2006 @@ -1,6 +1,6 @@ import py from pypy.translator.translator import TranslationContext, graphof -from pypy.jit.hintannotator.annotator import HintAnnotator +from pypy.jit.hintannotator.annotator import HintAnnotator, HintAnnotatorPolicy from pypy.jit.hintannotator.bookkeeper import HintBookkeeper from pypy.jit.hintannotator.model import * from pypy.jit.timeshifter.hrtyper import HintRTyper, originalconcretetype @@ -19,8 +19,7 @@ from pypy import conftest from pypy.jit.conftest import Benchmark -P_NOVIRTUAL = AnnotatorPolicy() -P_NOVIRTUAL.novirtualcontainer = True +P_NOVIRTUAL = HintAnnotatorPolicy(novirtualcontainer=True) def getargtypes(annotator, values): return [annotation(annotator, x) for x in values] Modified: pypy/branch/jit-real-world/pypy/jit/timeshifter/test/test_vlist.py ============================================================================== --- pypy/branch/jit-real-world/pypy/jit/timeshifter/test/test_vlist.py (original) +++ pypy/branch/jit-real-world/pypy/jit/timeshifter/test/test_vlist.py Thu Nov 30 15:10:20 2006 @@ -1,9 +1,7 @@ -from pypy.annotation.policy import AnnotatorPolicy +from pypy.jit.hintannotator.annotator import HintAnnotatorPolicy from pypy.jit.timeshifter.test.test_timeshift import TimeshiftingTests -P_OOPSPEC = AnnotatorPolicy() -P_OOPSPEC.novirtualcontainer = True -P_OOPSPEC.oopspec = True +P_OOPSPEC = HintAnnotatorPolicy(novirtualcontainer=True, oopspec=True) class TestVList(TimeshiftingTests): From ale at codespeak.net Thu Nov 30 15:18:24 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 30 Nov 2006 15:18:24 +0100 (CET) Subject: [pypy-svn] r35162 - pypy/dist/pypy/lib/pyontology Message-ID: <20061130141824.EFAF110094@code0.codespeak.net> Author: ale Date: Thu Nov 30 15:18:23 2006 New Revision: 35162 Added: pypy/dist/pypy/lib/pyontology/autopath.py Log: forgot this file Added: pypy/dist/pypy/lib/pyontology/autopath.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/pyontology/autopath.py Thu Nov 30 15:18:23 2006 @@ -0,0 +1,112 @@ +""" +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) + + pypy_root = os.path.join(head, '') + 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() From ale at codespeak.net Thu Nov 30 15:23:33 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 30 Nov 2006 15:23:33 +0100 (CET) Subject: [pypy-svn] r35163 - pypy/dist/pypy/lib/pyontology/test Message-ID: <20061130142333.400FB10094@code0.codespeak.net> Author: ale Date: Thu Nov 30 15:23:32 2006 New Revision: 35163 Modified: pypy/dist/pypy/lib/pyontology/test/test_ontology.py Log: Skip for now Modified: pypy/dist/pypy/lib/pyontology/test/test_ontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/test/test_ontology.py (original) +++ pypy/dist/pypy/lib/pyontology/test/test_ontology.py Thu Nov 30 15:23:32 2006 @@ -35,6 +35,7 @@ raises(ConsistencyFailure, O.consistency) def test_XMLSchema_string(): + py.test.skip("WIP") O = Ontology() a = URIRef(u'A') p = URIRef(u'P') @@ -46,6 +47,7 @@ O.consistency() def test_XMLSchema_string_fail(): + py.test.skip("WIP") O = Ontology() a = URIRef(u'A') p = URIRef(u'P') @@ -658,11 +660,6 @@ lll = len(O.variables) assert len(list(O.graph.triples((None,)*3))) > l -def test_allvalues_file(): - O = Ontology() - O.add_file('approved/allValuesFrom/premises002.rdf') - O.add_file('approved/allValuesFrom/nonconclusions002.rdf') - def test_import(): O = Ontology() s = URIRef('s') From ale at codespeak.net Thu Nov 30 15:28:06 2006 From: ale at codespeak.net (ale at codespeak.net) Date: Thu, 30 Nov 2006 15:28:06 +0100 (CET) Subject: [pypy-svn] r35164 - pypy/dist/pypy/lib/pyontology Message-ID: <20061130142806.65B321009B@code0.codespeak.net> Author: ale Date: Thu Nov 30 15:28:05 2006 New Revision: 35164 Modified: pypy/dist/pypy/lib/pyontology/pyontology.py Log: Intermediate checin Modified: pypy/dist/pypy/lib/pyontology/pyontology.py ============================================================================== --- pypy/dist/pypy/lib/pyontology/pyontology.py (original) +++ pypy/dist/pypy/lib/pyontology/pyontology.py Thu Nov 30 15:28:05 2006 @@ -233,11 +233,11 @@ if hasattr(other,'uri'): if self.uri == other.uri: return True - elif not hasattr(other,'uri'): - if self.uri == other: - return True elif other in self.sameas: return True + else: + if self.uri == other: + return True if not other or other in self.differentfrom: return False else: @@ -296,6 +296,7 @@ self._dict[key].append(val) def setValues(self, values): + self._dict= {} for key, val in values: self.addValue(key, val) @@ -454,8 +455,9 @@ getUriref('rdf', 'Literal') : Literal, # getUriref('rdf', 'type') : Property, } - XMLTypes = ['string', 'float', 'integer', 'date'] +#XMLTypes = {'string': str, 'float': float, 'integer': int, +# 'date': lambda x: datetime.date(*[int(v) for v in x.split('-')])} for typ in XMLTypes: uri = getUriref('xmlschema', typ) @@ -476,7 +478,7 @@ self.seen = {} self.var2ns ={} self.nr_of_triples = 0 - self.time = time.time() +# self.time = time.time() # for pr in builtin_voc: # name = self.mangle_name(pr) # Instantiate ClassDomains to record instances of the types @@ -526,7 +528,6 @@ def _sparql(self, query): qe = SP.Query.parseString(query) - prefixes = qe.Prefix[0] resvars = [] @@ -629,9 +630,6 @@ p_vals = self.variables[prop].getValuesPrKey(indi) var = self.make_var(Thing, trip[2]) self.variables[var].setValues((p_vals)) - if [dom for dom in self.variables.values() if isinstance(dom, Individual)]: - import pdb - pdb.set_trace() elif case == 4: # for all p's return p[0] if p[1]==o @@ -652,8 +650,6 @@ query_constr.append(PropertyConstrain2(prop_name, sub_name, obj)) elif case == 5: # return the values of p - #import pdb - ##pdb.set_trace() prop = self.make_var(Property, URIRef(trip[1])) query_dom[prop] = self.variables[prop] p_vals = list(self.variables[prop].getValues()) @@ -721,9 +717,9 @@ return self.nr_of_triples += 1 log("Doing triple nr %i: %r" % (self.nr_of_triples,(s, p, o))) - tim = time.time() - log.considerTriple("Triples per second %f" %(1./(tim-self.time))) - self.time = tim +# tim = time.time() +# log.considerTriple("Triples per second %f" %(1./(tim-self.time))) +# self.time = tim self.seen[(s, p, o)] = True if p.find('#') != -1: ns, func = p.split('#') @@ -747,7 +743,10 @@ else: val = Individual(obj, o) elif type(o) == rdflib_literal: - self.variables.setdefault('owl_Literal', ClassDomain('owl_Literal',u'')) + print "Literal type", repr(o.datatype) + if o.datatype in builtin_voc: + print "XML datatype" + o = XMLTypes[o.datatype.split('#')[-1]](o) self.variables['owl_Literal'].addValue(o) val = o else: From fijal at codespeak.net Thu Nov 30 16:34:28 2006 From: fijal at codespeak.net (fijal at codespeak.net) Date: Thu, 30 Nov 2006 16:34:28 +0100 (CET) Subject: [pypy-svn] r35166 - in pypy/extradoc/talk/warsaw2006: . src Message-ID: <20061130153428.4EF6310068@code0.codespeak.net> Author: fijal Date: Thu Nov 30 16:34:26 2006 New Revision: 35166 Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt pypy/extradoc/talk/warsaw2006/src/slideshow.py pypy/extradoc/talk/warsaw2006/src/web.py Log: (hopefully) final version Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt ============================================================================== --- pypy/extradoc/talk/warsaw2006/fireworks-slides.txt (original) +++ pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Thu Nov 30 16:34:26 2006 @@ -66,8 +66,6 @@ * Is build "as we need it", so no real definition -* rctypes (like ctypes, but will change to C calls) - Backends & more flow graphs: ============================ @@ -77,10 +75,19 @@ * All optimisations are done on flow graphs -* XXX: constant-folding demo +* `example`_, and a `constant-folded one`_:: + + def g(): + return 3 + + def f(): + return g() + 1 * 2 * Wide range of possible things to do with it +.. _`example`: javascript:example() +.. _`constant-folded one`: javascript:const_fold() + JavaScript backend: =================== @@ -117,10 +124,9 @@ Transparent proxy: ================== -* Idea (proxied to app-level), altough there is interp-level version +* Idea - proxied to app-level -* Possible usecase - shallow copy of remote objects (altough not working - because of lack of os.execv):: +* Possible usecase - shallow copy of remote objects:: elem = get_remote("obj") # accessed as a name in globals # remote type is faked here @@ -139,13 +145,37 @@ * So called "stackless" features -* Basically provides way of copying stack to heap and backwards +* Available primitives: coroutines, greenlets, tasklets:: + + c = channel() + + def f(): + c.send(3) + + def g(): + return c.receive() + + tasklet(f)() + assert g() == 3 + +* It provides way of copying stack to heap and backwards + +Stackless goodies: +================== + +* Very deep recursion + +* No deadlock + +* No race conditions (in a classic sense) + +* Explicit scheduling -* pickling coroutines +* Pickling coroutines -* cloning coroutines +* Cloning coroutines -* based on graph-transform +* All based on graph-transform Composability: ============== Modified: pypy/extradoc/talk/warsaw2006/src/slideshow.py ============================================================================== --- pypy/extradoc/talk/warsaw2006/src/slideshow.py (original) +++ pypy/extradoc/talk/warsaw2006/src/slideshow.py Thu Nov 30 16:34:26 2006 @@ -64,3 +64,10 @@ def rtype(): exported_methods.rtype_basic(comeback) + +def example(): + exported_methods.example(comeback) + +def const_fold(): + exported_methods.const_fold(comeback) + Modified: pypy/extradoc/talk/warsaw2006/src/web.py ============================================================================== --- pypy/extradoc/talk/warsaw2006/src/web.py (original) +++ pypy/extradoc/talk/warsaw2006/src/web.py Thu Nov 30 16:34:26 2006 @@ -15,7 +15,7 @@ commproxy.USE_MOCHIKIT = True -FUNCTION_LIST = ['show', 'flow', 'annotate', 'rtype'] +FUNCTION_LIST = ['show', 'flow', 'annotate', 'rtype', 'const_fold', 'example'] class ExportedMethods(BasicExternal): _render_xmlhttp = True @@ -31,6 +31,17 @@ self.t = Translation(g) + def _create_t2(self): + if hasattr(self, 't2'): + return + def g(): + return 3 + + def f(): + return g() + 1 * 2 + + self.t2 = Translation(f) + @described(retval=None) def flow_basic(self): self._create_t() @@ -49,6 +60,19 @@ self.t.rtype() self.t.view() + @described(retval=None) + def example(self): + self._create_t2() + self.t2.annotate() + self.t2.rtype() + self.t2.view() + + @described(retval=None) + def const_fold(self): + self._create_t2() + self.t2.backendopt() + self.t2.view() + exported_methods = ExportedMethods() main_path = py.path.local(__file__).dirpath() @@ -75,4 +99,4 @@ style_css.exposed = True if __name__ == '__main__': - server.start_server(handler=Handler, start_new=False) + server.start_server(server_address=('localhost', 7070), handler=Handler, start_new=False) From antocuni at codespeak.net Thu Nov 30 16:54:31 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 30 Nov 2006 16:54:31 +0100 (CET) Subject: [pypy-svn] r35167 - in pypy/dist/pypy/translator/cli: . test Message-ID: <20061130155431.BB4651007F@code0.codespeak.net> Author: antocuni Date: Thu Nov 30 16:54:30 2006 New Revision: 35167 Modified: pypy/dist/pypy/translator/cli/dotnet.py pypy/dist/pypy/translator/cli/test/test_dotnet.py Log: Make box() accept also arguments that inherits from System.Object: this is necessacy for compatibility with PythonNet; consider this case (at RPython level): x = ArrayList() x.Add(42) y = x.get_Item(0) y.ToString() when translated there is no problem, because y's ootype is NativeInstance(System.Object) e y is a boxed value. However when running on top of PythonNet the value is automatically unboxed, so y will contain a plain python int, which of course as no ToString() method. To solve, just box() the result of get_Item(): y = box(x.get_Item(0)) Modified: pypy/dist/pypy/translator/cli/dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/dotnet.py (original) +++ pypy/dist/pypy/translator/cli/dotnet.py Thu Nov 30 16:54:30 2006 @@ -295,6 +295,8 @@ return CLR.System.Char(x) else: return CLR.System.String(x) + elif isinstance(x, PythonNet.System.Object): + return x else: assert False @@ -318,14 +320,16 @@ def specialize_call(self, hop): v_obj, = hop.inputargs(*hop.args_r) - if v_obj.concretetype not in BOXABLE_TYPES: - raise TyperError, "Can't box values of type %s" % v_obj.concretetype - - if (v_obj.concretetype is ootype.String): + + TYPE = v_obj.concretetype + if (TYPE is ootype.String or isinstance(TYPE, NativeInstance)): return hop.genop('ooupcast', [v_obj], hop.r_result.lowleveltype) else: + if TYPE not in BOXABLE_TYPES: + raise TyperError, "Can't box values of type %s" % v_obj.concretetype return hop.genop('clibox', [v_obj], hop.r_result.lowleveltype) + class Entry(ExtRegistryEntry): _about_ = unbox Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Thu Nov 30 16:54:30 2006 @@ -177,6 +177,12 @@ res = self.interpret(fn, []) assert res == 'Int32' + def test_box_object(self): + def fn(): + return box(System.Object()).ToString() + res = self.interpret(fn, []) + assert res == 'System.Object' + def test_exception(self): py.test.skip("It doesn't work so far") def fn(): From antocuni at codespeak.net Thu Nov 30 16:55:58 2006 From: antocuni at codespeak.net (antocuni at codespeak.net) Date: Thu, 30 Nov 2006 16:55:58 +0100 (CET) Subject: [pypy-svn] r35168 - pypy/dist/pypy/translator/cli/test Message-ID: <20061130155558.75D8710080@code0.codespeak.net> Author: antocuni Date: Thu Nov 30 16:55:57 2006 New Revision: 35168 Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py Log: This issue has been resolved with the NativeException approach. Modified: pypy/dist/pypy/translator/cli/test/test_dotnet.py ============================================================================== --- pypy/dist/pypy/translator/cli/test/test_dotnet.py (original) +++ pypy/dist/pypy/translator/cli/test/test_dotnet.py Thu Nov 30 16:55:57 2006 @@ -183,18 +183,6 @@ res = self.interpret(fn, []) assert res == 'System.Object' - def test_exception(self): - py.test.skip("It doesn't work so far") - def fn(): - x = ArrayList() - try: - x.get_Item(0) - except System.ArgumentOutOfRangeException: - return 42 - else: - return 43 - assert self.interpret(fn, []) == 42 - def test_array(self): def fn(): x = ArrayList() From cfbolz at codespeak.net Thu Nov 30 17:02:21 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 30 Nov 2006 17:02:21 +0100 (CET) Subject: [pypy-svn] r35169 - pypy/dist/pypy/rlib/parsing/test Message-ID: <20061130160221.A60E11007F@code0.codespeak.net> Author: cfbolz Date: Thu Nov 30 17:02:20 2006 New Revision: 35169 Modified: pypy/dist/pypy/rlib/parsing/test/pygrammar.txt pypy/dist/pypy/rlib/parsing/test/test_pythonparse.py Log: some more experiments making the grammar nicer Modified: pypy/dist/pypy/rlib/parsing/test/pygrammar.txt ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/pygrammar.txt (original) +++ pypy/dist/pypy/rlib/parsing/test/pygrammar.txt Thu Nov 30 17:02:20 2006 @@ -22,8 +22,8 @@ decorators: decorator+; funcdef: decorators? ["def"] NAME parameters [":"] suite; parameters: ["("] >varargslist< [")"] | ["("] [")"]; -varargslist: (parameter ",")* >star_or_starstarargs< | - parameter ("," parameter)* ","?; +varargslist: (parameter [","])* >star_or_starstarargs< | + parameter ([","] parameter)* [","]?; parameter: fpdef ("=" test)?; star_or_starstarargs: starargs [","] starstarargs | starargs | starstarargs; starargs: ["*"] NAME; @@ -32,26 +32,29 @@ fplist: fpdef ("," fpdef)* ","?; stmt: | ; -simple_stmt: small_stmt ([";"] small_stmt)* [";"]? [NEWLINE]; -small_stmt: | | | | - | | | | - ; -expr_stmt: testlist augassign testlist | testlist ("=" testlist)*; +simple_stmt: small_stmt ([";"] small_stmt)+ [";"]? [NEWLINE] | + [";"]? [NEWLINE]; +small_stmt: | | | + | | | | + | ; +expr_stmt: | testlist (["="] testlist)*; +augassign_stmt: testlist >augassign< testlist; augassign: "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "**=" | "//="; # For normal assignments, additional restrictions enforced by the interpreter -print_stmt: "print" ">>" test (("," test)+ ","?)? | - "print" (test ("," test)* ","?)?; -del_stmt: "del" exprlist; -pass_stmt: "pass"; +print_stmt: ["print"] print_target (([","] test)+ [","]?)? | + ["print"] (test ([","] test)* [","]?)?; +print_target: [">>"] test; +del_stmt: ["del"] exprlist; +pass_stmt: ["pass"]; flow_stmt: | | | | ; -break_stmt: "break"; -continue_stmt: "continue"; +break_stmt: ["break"]; +continue_stmt: ["continue"]; return_stmt: ["return"] testlist?; -yield_stmt: "yield" testlist; -raise_stmt: "raise" (test ("," test ("," test)?)?)?; +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_what; @@ -71,12 +74,12 @@ | ; 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)?; +for_stmt: ["for"] exprlist ["in"] testlist [":"] suite (["else" ":"] suite)?; try_stmt: "try" ":" suite (except_clause ":" suite)+ ("else" ":" suite)? | "try" ":" suite "finally" ":" suite; except_clause: "except" (test ("," test)?)?; -suite: simple_stmt | [NEWLINE] [INDENT] stmt+ [DEDENT]; +suite: >simple_stmt< | [NEWLINE] [INDENT] stmt+ [DEDENT]; test: and_test "or" test | | ; and_test: not_test "and" and_test | ; @@ -100,13 +103,19 @@ ; factor: "+" factor | "-" factor | "~" factor | ; power: atom trailer+ ("**" factor)? | atom "**" factor | ; -atom: "(" testlist_gexp? ")" | "[" listmaker? "]" | - "{" dictmaker? "}" | "`" testlist1 "`" | | | STRING+; -listmaker: test list_for | - test ("," test)* ","?; + +atom: "(" testlist_gexp? ")" | | | + "`" testlist1 "`" | | | STRING+; +listliteral: ["[" "]"] | "[" "]" | ["["] >listmaker< ["]"]; +listcomprehension: test list_for; +listmaker: test ([","] test)* [","]?; testlist_gexp: test gen_for | test ("," test)* ","?; -lambdef: "lambda" varargslist? ":" test; + +dictliteral: ["{" "}"] | ["{"] dictitem ([","] dictitem)* [","]? ["}"]; +dictitem: test [":"] test; + +lambdef: ["lambda"] varargslist? [":"] test; trailer: "(" ")" | "(" arglist ")" | "[" subscriptlist "]" | "." NAME; subscriptlist: subscript ("," subscript)* ","?; subscript: "." "." "." | test? ":" test? sliceop? | test; @@ -114,7 +123,6 @@ exprlist: expr ("," expr)* ","?; testlist: test ("," test)* ","?; testlist_safe: test (("," test)+ ","?)?; -dictmaker: test ":" test ("," test ":" test)* ","?; classdef: ["class"] NAME (["("] testlist [")"])? [":"] suite; @@ -122,13 +130,13 @@ arglist_rest: "*" test ("," "**" test)? | "**" test | argument ","?; argument: (test "=")? test gen_for?; -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" test gen_iter?; -gen_if: "if" test gen_iter?; +list_iter: | ; +list_for: ["for"] exprlist ["in"] testlist_safe list_iter?; +list_if: ["if"] test list_iter?; + +gen_iter: | ; +gen_for: ["for"] exprlist ["in"] test gen_iter?; +gen_if: ["if"] test gen_iter?; testlist1: test ("," test)*; Modified: pypy/dist/pypy/rlib/parsing/test/test_pythonparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_pythonparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_pythonparse.py Thu Nov 30 17:02:20 2006 @@ -18,12 +18,12 @@ IGNORE: " "; NAME: "[a-zA-Z_]*"; NUMBER: "0|[1-9][0-9]*"; -parameters: ["("] >varargslist< [")"] | ["("] [")"]; -varargslist: (fpdef ("=" test)? ",")* star_or_starstarargs | - fpdef ("=" test)? ("," fpdef ("=" test)?)* ","?; -star_or_starstarargs: "*" NAME "," "**" NAME | "*" NAME | "**" NAME; -fpdef: NAME | "(" fplist ")"; -fplist: fpdef ("," fpdef)* ","?; +parameters: ["("] >varargslist | "(" ")"; +fplist: fpdef ([","] fpdef)* [","]?; test: NUMBER; """) parse = make_parse_function(regexs, rules) @@ -32,6 +32,7 @@ t = parse("(a,b,c,d)").visit(ToAST())[0] t = parse("(a,b,c,d,)").visit(ToAST())[0] t = parse("((a, b, c),b,c,d,)").visit(ToAST())[0] + t = parse("((a, b, (d, e, (f, g))), b, *args, **kwargs)").visit(ToAST())[0] t = parse("((a, b, c),b,c,d,*args)").visit(ToAST())[0] t = parse("((a, b, c),b,c,d,**kwargs)").visit(ToAST())[0] t = parse("((a, b, c),b,c,d,*args, **args)").visit(ToAST())[0] @@ -90,6 +91,7 @@ readline = cStringIO.StringIO(source).readline for token in tokenize.generate_tokens(readline): typ, s, (row, col), _, line = token + row -= 1 pos += len(s) typ = tokenize.tok_name[typ] if typ == "ENDMARKER": @@ -118,9 +120,7 @@ pass return null - x """) - t = t.visit(self.ToAST) - assert len(t) == 1 - t = t[0] + t = self.ToAST.transform(t) def test_class(self): t = self.parse(""" @@ -135,7 +135,7 @@ def diagonal(self): return (self.a ** 2 + self.b ** 2) ** 0.5 """) - t = t.visit(self.ToAST)[0] + t = self.ToAST.transform(t) def test_while(self): t = self.parse(""" @@ -151,9 +151,7 @@ return result - 15 return result """) - t = t.visit(self.ToAST) - assert len(t) == 1 - t = t[0] + t = self.ToAST.transform(t) def test_comment(self): t = self.parse(""" @@ -163,8 +161,77 @@ """) t = self.ToAST.transform(t) + def test_parse_print(self): + t = self.parse(""" +print >> f, a, b, c, +print >> f, a, b +print >> f +print +print 1 +print 1, 2 +print 1, 2, +""") + t = self.ToAST.transform(t) + + def test_assignment(self): + t = self.parse(""" +a = 1 +a = b = c +(a, b) = c +a += 1 +b //= 3 +""") + t = self.ToAST.transform(t) + + def test_lists(self): + t = self.parse(""" +l0 = [1, 2, [3, 4, [5, []]]] +l1 = [i for i in range(10)] +l1 = [i for i in range(10) if i ** 2 % 3 == 0] +l2 = [ ] +l3 = [ ] +l4 = [] +""") + t = self.ToAST.transform(t) + + def test_dicts(self): + t = self.parse(""" +{1: 2, 2: {1: 3},} +{} +""") + t = self.ToAST.transform(t) + + def test_calls(self): + #XXX horrible trees + t = self.parse(""" +f(a)(b)(c) +f() ** 2 +f(x) * 2 +f(x, y, z, *args) + 2 +""") + t = self.ToAST.transform(t) + + def test_errors(self): + source = """ +def f(x): + if a: + pass + else: + pass + else: + pass +""" + excinfo = py.test.raises(ParseError, self.parse, source) + error = excinfo.value.errorinformation + msg = excinfo.value.nice_error_message("", source) + def test_parse_this(self): s = py.magic.autopath().read() - s = s[s.index("\nclass"):] t = self.parse(s) - t = t.visit(self.ToAST)[0] + t = self.ToAST.transform(t) + + def test_parsing(self): + s = py.magic.autopath().dirpath().dirpath().join("parsing.py").read() + t = self.parse(s) + t = self.ToAST.transform(t) + From cfbolz at codespeak.net Thu Nov 30 17:03:39 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 30 Nov 2006 17:03:39 +0100 (CET) Subject: [pypy-svn] r35170 - in pypy/dist/pypy/rlib/parsing: . test Message-ID: <20061130160339.E7B4C10083@code0.codespeak.net> Author: cfbolz Date: Thu Nov 30 17:03:38 2006 New Revision: 35170 Modified: pypy/dist/pypy/rlib/parsing/regexparse.py pypy/dist/pypy/rlib/parsing/test/test_regexparse.py Log: move this useful function Modified: pypy/dist/pypy/rlib/parsing/regexparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/regexparse.py (original) +++ pypy/dist/pypy/rlib/parsing/regexparse.py Thu Nov 30 17:03:38 2006 @@ -106,6 +106,17 @@ assert res is not None return res +def make_runner(regex, view=False): + r = parse_regex(regex) + dfa = r.make_automaton().make_deterministic() + if view: + dfa.view() + dfa.optimize() + if view: + dfa.view() + r = dfa.get_runner() + return r + class RegexBuilder(object): def visit_regex(self, node): return node.children[0].visit(self) | node.children[2].visit(self) Modified: pypy/dist/pypy/rlib/parsing/test/test_regexparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_regexparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_regexparse.py Thu Nov 30 17:03:38 2006 @@ -1,14 +1,4 @@ -def make_runner(regex, view=False): - from pypy.rlib.parsing.regexparse import parse_regex - r = parse_regex(regex) - dfa = r.make_automaton().make_deterministic() - if view: - dfa.view() - dfa.optimize() - if view: - dfa.view() - r = dfa.get_runner() - return r +from pypy.rlib.parsing.regexparse import make_runner def test_simple(): r = make_runner("a*") From cfbolz at codespeak.net Thu Nov 30 17:04:43 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 30 Nov 2006 17:04:43 +0100 (CET) Subject: [pypy-svn] r35171 - pypy/dist/pypy/rlib/parsing/test Message-ID: <20061130160443.781BD10088@code0.codespeak.net> Author: cfbolz Date: Thu Nov 30 17:04:42 2006 New Revision: 35171 Modified: pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py Log: check in two of the exmaples of the docs as tests Modified: pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_ebnfparse.py Thu Nov 30 17:04:42 2006 @@ -27,6 +27,7 @@ assert r == 22 * 12 + 44 tree = parse("2*(3+5*2*(2+61))") assert tree.visit(MyEvalVisitor()) == 2 * (3 + 5 * 2 * (2 + 61)) + tree = parse("12 + 4 * 5)") def test_long_inline_quotes(): regexs, rules, transformer = parse_ebnf(""" @@ -407,3 +408,24 @@ parse = make_parse_function(regexs, rules) py.test.raises(ParseError, parse, "x END") parse("y END") + +def test_example1(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +n: "a" "b" "c" m; +m: "(" ")" | "d"; + """) + parse = make_parse_function(regexs, rules) + t = parse("a b c (a b c d)") + t = ToAST().transform(t) + +def test_example2(): + regexs, rules, ToAST = parse_ebnf(""" +IGNORE: " "; +DECIMAL: "0|[1-9][0-9]*"; +list: DECIMAL >list< | DECIMAL; + """) + parse = make_parse_function(regexs, rules) + t = parse("1 2 3 4 5") + t = ToAST().transform(t) + From cfbolz at codespeak.net Thu Nov 30 17:05:22 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 30 Nov 2006 17:05:22 +0100 (CET) Subject: [pypy-svn] r35172 - in pypy/dist/pypy/rlib/parsing: . test Message-ID: <20061130160522.D2CD810088@code0.codespeak.net> Author: cfbolz Date: Thu Nov 30 17:05:21 2006 New Revision: 35172 Modified: pypy/dist/pypy/rlib/parsing/parsing.py pypy/dist/pypy/rlib/parsing/test/test_parse.py pypy/dist/pypy/rlib/parsing/tree.py Log: allow a nonterminal to be replaced by nothing Modified: pypy/dist/pypy/rlib/parsing/parsing.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/parsing.py (original) +++ pypy/dist/pypy/rlib/parsing/parsing.py Thu Nov 30 17:05:21 2006 @@ -1,5 +1,5 @@ import py -from pypy.rlib.parsing.tree import Node, Symbol, Nonterminal, Epsilon +from pypy.rlib.parsing.tree import Node, Symbol, Nonterminal class Rule(object): def __init__(self, nonterminal, expansions): @@ -119,15 +119,11 @@ if node is None: error = combine_errors(error, error2) break - if not isinstance(node, Epsilon): - children.append(node) + children.append(node) curr = next else: - if children: - result = (Nonterminal(symbol, children), curr, error) - else: - assert expansion == [] - result = (Epsilon(), curr, error) + assert len(expansion) == len(children) + result = (Nonterminal(symbol, children), curr, error) self.matched[i, symbol] = result return result self.matched[i, symbol] = None, 0, error @@ -304,7 +300,7 @@ if expansionindex == %s:""" % (expansionindex, )) if not expansion: code.append("""\ - result = (Epsilon(), i) + result = (Nonterminal(symbol, []), i) self.matched_nonterminals%(number)s[i] = result return result""" % vars()) continue @@ -323,8 +319,6 @@ last_failed_position = next expansionindex = %(nextindex)s continue - if not isinstance(node, Epsilon): - children.append(node) curr = next""" % vars()) code.append("""\ result = (Nonterminal(%(symbol)r, children), curr) Modified: pypy/dist/pypy/rlib/parsing/test/test_parse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/test/test_parse.py (original) +++ pypy/dist/pypy/rlib/parsing/test/test_parse.py Thu Nov 30 17:05:21 2006 @@ -74,6 +74,4 @@ p = PackratParser([r1], "S") assert p.parse([(c, i) for i, c, in enumerate("xyx")]) is not None assert p.parse([(c, i) for i, c, in enumerate("xx")]) is not None - - - + t = p.parse([(c, i) for i, c, in enumerate("xxxxxx")]) Modified: pypy/dist/pypy/rlib/parsing/tree.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/tree.py (original) +++ pypy/dist/pypy/rlib/parsing/tree.py Thu Nov 30 17:05:21 2006 @@ -22,8 +22,9 @@ def dot(self): addinfo = str(self.additional_info).replace('"', "'") or "_" - yield ('"%s" [label="%r%r"];' % ( - id(self), self.symbol, addinfo)).replace("\\", "\\\\") + yield ('"%s" [shape=box,label="%s\\n%s"];' % ( + id(self), self.symbol.replace("\\", "\\\\"), + repr(addinfo).replace("\\", "\\\\"))) def visit(self, visitor): "NOT_RPYTHON" @@ -66,9 +67,6 @@ else: return specific(self) -class Epsilon(Node): - pass - class VisitError(Exception): def __init__(self, node): self.node = node From cfbolz at codespeak.net Thu Nov 30 17:06:34 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 30 Nov 2006 17:06:34 +0100 (CET) Subject: [pypy-svn] r35173 - pypy/dist/pypy/rlib/parsing Message-ID: <20061130160634.5056510088@code0.codespeak.net> Author: cfbolz Date: Thu Nov 30 17:06:33 2006 New Revision: 35173 Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py Log: nicer way to create the rules for *, ? and + Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/ebnfparse.py Thu Nov 30 17:06:33 2006 @@ -214,11 +214,14 @@ def add_all_possibilities(self): all_rules = [] + other_rules = [] all_changes = [] + other_changes = [] for rule, changes in zip(self.rules, self.changes): real_changes = [] real_expansions = [] - for expansion, change in zip(rule.expansions, changes): + for index, (expansion, change) in enumerate( + zip(rule.expansions, changes)): maybe_pattern = [symbol in self.maybe_rules for symbol in expansion] n = maybe_pattern.count(True) @@ -229,23 +232,41 @@ assert n != len(expansion), ( "currently an expansion needs at least one" "symbol that always has to occur") - maybe_index = {} - for i, star in enumerate(maybe_pattern): - if star: - maybe_index[i] = len(maybe_index) - for i in range(2 ** n): - real_expansion = [] - real_change = [] - for j, (symbol, ch) in enumerate(zip(expansion, change)): - if (j not in maybe_index or - (i & (2 ** (n - 1) >> maybe_index[j])) == 0): - real_expansion.append(symbol) - real_change.append(ch) - real_expansions.append(real_expansion) - real_changes.append(real_change) + slices = [] + start = 0 + for i, (maybe, symbol) in enumerate( + zip(maybe_pattern, expansion)): + if maybe: + slices.append((start, i + 1)) + start = i + 1 + rest_slice = (start, i + 1) + name = rule.nonterminal + for i, (start, stop) in enumerate(slices): + nextname = "__%s_rest_%s_%s" % (rule.nonterminal, index, i) + if i < len(slices) - 1: + new_expansions = [ + expansion[start: stop] + [nextname], + expansion[start: stop - 1] + [nextname]] + new_changes = [change[start: stop] + ">", + change[start: stop - 1] + ">"] + else: + rest_expansion = expansion[slice(*rest_slice)] + new_expansions = [ + expansion[start: stop] + rest_expansion, + expansion[start: stop - 1] + rest_expansion] + rest_change = change[slice(*rest_slice)] + new_changes = [change[start: stop] + rest_change, + change[start: stop - 1] + rest_change] + if i == 0: + real_expansions += new_expansions + real_changes += new_changes + else: + other_rules.append(Rule(name, new_expansions)) + other_changes.append(new_changes) + name = nextname all_rules.append(Rule(rule.nonterminal, real_expansions)) all_changes.append(real_changes) - return all_rules, all_changes + return all_rules + other_rules, all_changes + other_changes class TransformerMaker(object): def __init__(self, rules, changes): @@ -280,6 +301,7 @@ assert isinstance(ToAST, type) assert ToAST.__name__ == "ToAST" ToAST.source = code + ToAST.changes = self.changes return ToAST def emit(self, line): From cfbolz at codespeak.net Thu Nov 30 17:08:05 2006 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 30 Nov 2006 17:08:05 +0100 (CET) Subject: [pypy-svn] r35174 - pypy/dist/pypy/rlib/parsing Message-ID: <20061130160805.450AF10089@code0.codespeak.net> Author: cfbolz Date: Thu Nov 30 17:08:04 2006 New Revision: 35174 Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py Log: oops, don't add an this expansion, will be added automatically later Modified: pypy/dist/pypy/rlib/parsing/ebnfparse.py ============================================================================== --- pypy/dist/pypy/rlib/parsing/ebnfparse.py (original) +++ pypy/dist/pypy/rlib/parsing/ebnfparse.py Thu Nov 30 17:08:04 2006 @@ -156,7 +156,7 @@ if node.children[1].additional_info == "*": name = "_star_symbol%s" % (len(self.maybe_rules), ) maybe_rule = True - expansions = [expansions + [name], expansions] + expansions = [expansions + [name]] changes = [changes + ">", changes] elif node.children[1].additional_info == "+": name = "_plus_symbol%s" % (self.num_plus_symbols, ) From bea at codespeak.net Thu Nov 30 20:41:21 2006 From: bea at codespeak.net (bea at codespeak.net) Date: Thu, 30 Nov 2006 20:41:21 +0100 (CET) Subject: [pypy-svn] r35176 - pypy/extradoc/talk/warsaw2006 Message-ID: <20061130194121.078F61007D@code0.codespeak.net> Author: bea Date: Thu Nov 30 20:41:20 2006 New Revision: 35176 Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Log: Read and fixed typo - hope that is ok. Good luck Majiek! Modified: pypy/extradoc/talk/warsaw2006/fireworks-slides.txt ============================================================================== --- pypy/extradoc/talk/warsaw2006/fireworks-slides.txt (original) +++ pypy/extradoc/talk/warsaw2006/fireworks-slides.txt Thu Nov 30 20:41:20 2006 @@ -71,7 +71,7 @@ * LLtype-based: C, LLVM, -* OOtype-based: CLI, JVM, JavaScript, (CL and Squek in some state). +* OOtype-based: CLI, JVM, JavaScript, (CL and Squeak in some state). * All optimisations are done on flow graphs From xoraxax at codespeak.net Thu Nov 30 22:08:17 2006 From: xoraxax at codespeak.net (xoraxax at codespeak.net) Date: Thu, 30 Nov 2006 22:08:17 +0100 (CET) Subject: [pypy-svn] r35177 - in pypy/dist/pypy: config translator/goal Message-ID: <20061130210817.7C6EC10074@code0.codespeak.net> Author: xoraxax Date: Thu Nov 30 22:08:16 2006 New Revision: 35177 Modified: pypy/dist/pypy/config/config.py pypy/dist/pypy/translator/goal/targetpypystandalone.py pypy/dist/pypy/translator/goal/translate.py Log: Clarify the difference between global and target specific options in the `translate.py --help` output. Modified: pypy/dist/pypy/config/config.py ============================================================================== --- pypy/dist/pypy/config/config.py (original) +++ pypy/dist/pypy/config/config.py Thu Nov 30 22:08:16 2006 @@ -1,6 +1,8 @@ from py.compat import optparse +SUPPRESS_USAGE = optparse.SUPPRESS_USAGE + class AmbigousOptionError(Exception): pass Modified: pypy/dist/pypy/translator/goal/targetpypystandalone.py ============================================================================== --- pypy/dist/pypy/translator/goal/targetpypystandalone.py (original) +++ pypy/dist/pypy/translator/goal/targetpypystandalone.py Thu Nov 30 22:08:16 2006 @@ -14,7 +14,7 @@ from pypy.interpreter.error import OperationError from pypy.translator.goal.ann_override import PyPyAnnotatorPolicy from pypy.config.pypyoption import pypy_optiondescription -from pypy.config.config import Config, to_optparse, make_dict +from pypy.config.config import Config, to_optparse, make_dict, SUPPRESS_USAGE from pypy.tool.option import make_objspace thisdir = py.magic.autopath().dirpath() @@ -79,7 +79,7 @@ class PyPyTarget(object): - usage = "target PyPy standalone" + usage = SUPPRESS_USAGE take_options = True Modified: pypy/dist/pypy/translator/goal/translate.py ============================================================================== --- pypy/dist/pypy/translator/goal/translate.py (original) +++ pypy/dist/pypy/translator/goal/translate.py Thu Nov 30 22:08:16 2006 @@ -150,9 +150,10 @@ if 'handle_config' in targetspec_dic: targetspec_dic['handle_config'](config) - if translateconfig.help: + if translateconfig.help: opt_parser.print_help() if 'print_help' in targetspec_dic: + print "\n\nTarget specific help:\n\n" targetspec_dic['print_help'](config) sys.exit(0)