[pypy-svn] r18565 - in pypy/branch/hl-backend/pypy: doc doc/image interpreter/pyparser/test module/Numeric module/_socket module/_socket/test objspace/flow objspace/flow/test objspace/std objspace/std/test rpython rpython/l3interp rpython/memory rpython/memory/test rpython/module rpython/test translator translator/asm translator/asm/i386gen translator/asm/ppc translator/asm/ppcgen translator/asm/test translator/c translator/c/src translator/c/test translator/goal translator/js translator/js/test translator/llvm translator/llvm/module
boria at codespeak.net
boria at codespeak.net
Fri Oct 14 17:44:59 CEST 2005
Author: boria
Date: Fri Oct 14 17:44:56 2005
New Revision: 18565
Added:
pypy/branch/hl-backend/pypy/doc/image/JIT.dot
- copied unchanged from r18564, pypy/dist/pypy/doc/image/JIT.dot
pypy/branch/hl-backend/pypy/module/Numeric/ (props changed)
- copied from r18564, pypy/dist/pypy/module/Numeric/
pypy/branch/hl-backend/pypy/module/_socket/ (props changed)
- copied from r18564, pypy/dist/pypy/module/_socket/
pypy/branch/hl-backend/pypy/rpython/l3interp/
- copied from r18564, pypy/dist/pypy/rpython/l3interp/
pypy/branch/hl-backend/pypy/rpython/module/ll_stack.py
- copied unchanged from r18564, pypy/dist/pypy/rpython/module/ll_stack.py
pypy/branch/hl-backend/pypy/translator/asm/ppc/
- copied from r18564, pypy/dist/pypy/translator/asm/ppc/
pypy/branch/hl-backend/pypy/translator/asm/regalloc.py
- copied unchanged from r18564, pypy/dist/pypy/translator/asm/regalloc.py
pypy/branch/hl-backend/pypy/translator/asm/simulator.py
- copied unchanged from r18564, pypy/dist/pypy/translator/asm/simulator.py
pypy/branch/hl-backend/pypy/translator/asm/test/test_simulator.py
- copied unchanged from r18564, pypy/dist/pypy/translator/asm/test/test_simulator.py
pypy/branch/hl-backend/pypy/translator/c/src/stack.h
- copied unchanged from r18564, pypy/dist/pypy/translator/c/src/stack.h
pypy/branch/hl-backend/pypy/translator/goal/targetrpystonedalone.py
- copied unchanged from r18564, pypy/dist/pypy/translator/goal/targetrpystonedalone.py
Modified:
pypy/branch/hl-backend/pypy/doc/draft-dynamic-language-translation.txt
pypy/branch/hl-backend/pypy/doc/image/lattice1.dot
pypy/branch/hl-backend/pypy/doc/news.txt
pypy/branch/hl-backend/pypy/interpreter/pyparser/test/test_astbuilder.py
pypy/branch/hl-backend/pypy/interpreter/pyparser/test/test_astcompiler.py
pypy/branch/hl-backend/pypy/module/_socket/test/ (props changed)
pypy/branch/hl-backend/pypy/objspace/flow/model.py
pypy/branch/hl-backend/pypy/objspace/flow/objspace.py
pypy/branch/hl-backend/pypy/objspace/flow/test/test_objspace.py
pypy/branch/hl-backend/pypy/objspace/std/longobject.py
pypy/branch/hl-backend/pypy/objspace/std/test/test_longobject.py
pypy/branch/hl-backend/pypy/rpython/extfunctable.py
pypy/branch/hl-backend/pypy/rpython/llinterp.py
pypy/branch/hl-backend/pypy/rpython/memory/gc.py
pypy/branch/hl-backend/pypy/rpython/memory/lltypesimulation.py
pypy/branch/hl-backend/pypy/rpython/memory/simulator.py
pypy/branch/hl-backend/pypy/rpython/memory/test/test_gc.py
pypy/branch/hl-backend/pypy/rpython/memory/test/test_lltypesimulation.py
pypy/branch/hl-backend/pypy/rpython/module/ll_stackless.py
pypy/branch/hl-backend/pypy/rpython/objectmodel.py
pypy/branch/hl-backend/pypy/rpython/rint.py
pypy/branch/hl-backend/pypy/rpython/rtyper.py
pypy/branch/hl-backend/pypy/rpython/test/test_rint.py
pypy/branch/hl-backend/pypy/rpython/test/test_rlist.py
pypy/branch/hl-backend/pypy/rpython/test/test_rstr.py
pypy/branch/hl-backend/pypy/translator/asm/genasm.py
pypy/branch/hl-backend/pypy/translator/asm/i386gen/ (props changed)
pypy/branch/hl-backend/pypy/translator/asm/infregmachine.py (contents, props changed)
pypy/branch/hl-backend/pypy/translator/asm/ppcgen/func_builder.py
pypy/branch/hl-backend/pypy/translator/asm/test/test_asm.py
pypy/branch/hl-backend/pypy/translator/c/extfunc.py
pypy/branch/hl-backend/pypy/translator/c/funcgen.py
pypy/branch/hl-backend/pypy/translator/c/gc.py
pypy/branch/hl-backend/pypy/translator/c/genc.py
pypy/branch/hl-backend/pypy/translator/c/src/address.h
pypy/branch/hl-backend/pypy/translator/c/src/g_include.h
pypy/branch/hl-backend/pypy/translator/c/src/ll_stackless.h
pypy/branch/hl-backend/pypy/translator/c/src/mem.h
pypy/branch/hl-backend/pypy/translator/c/src/support.h
pypy/branch/hl-backend/pypy/translator/c/stackless.py
pypy/branch/hl-backend/pypy/translator/c/test/test_annotated.py
pypy/branch/hl-backend/pypy/translator/c/test/test_extfunc.py
pypy/branch/hl-backend/pypy/translator/c/test/test_lladdresses.py
pypy/branch/hl-backend/pypy/translator/c/test/test_standalone.py
pypy/branch/hl-backend/pypy/translator/c/test/test_typed.py
pypy/branch/hl-backend/pypy/translator/goal/bench-windows.py
pypy/branch/hl-backend/pypy/translator/goal/driver.py
pypy/branch/hl-backend/pypy/translator/goal/targetnopstandalone.py
pypy/branch/hl-backend/pypy/translator/goal/targetrichards.py
pypy/branch/hl-backend/pypy/translator/goal/translate_pypy.py
pypy/branch/hl-backend/pypy/translator/js/arraynode.py
pypy/branch/hl-backend/pypy/translator/js/codewriter.py
pypy/branch/hl-backend/pypy/translator/js/database.py
pypy/branch/hl-backend/pypy/translator/js/funcnode.py
pypy/branch/hl-backend/pypy/translator/js/js.py
pypy/branch/hl-backend/pypy/translator/js/node.py
pypy/branch/hl-backend/pypy/translator/js/opaquenode.py
pypy/branch/hl-backend/pypy/translator/js/opwriter.py
pypy/branch/hl-backend/pypy/translator/js/structnode.py
pypy/branch/hl-backend/pypy/translator/js/test/test_genllvm1.py
pypy/branch/hl-backend/pypy/translator/llvm/build_llvm_module.py
pypy/branch/hl-backend/pypy/translator/llvm/externs2ll.py
pypy/branch/hl-backend/pypy/translator/llvm/gc.py
pypy/branch/hl-backend/pypy/translator/llvm/module/genexterns.c
pypy/branch/hl-backend/pypy/translator/transform.py
pypy/branch/hl-backend/pypy/translator/translator.py
Log:
* Merged trunk (dist/pypy/) at revision 18564 into hl-backend branch.
Modified: pypy/branch/hl-backend/pypy/doc/draft-dynamic-language-translation.txt
==============================================================================
--- pypy/branch/hl-backend/pypy/doc/draft-dynamic-language-translation.txt (original)
+++ pypy/branch/hl-backend/pypy/doc/draft-dynamic-language-translation.txt Fri Oct 14 17:44:56 2005
@@ -783,8 +783,8 @@
- *b*, *b'*, *b''*... are maps from *V* to *A*.
We call *state* a pair *(b,E)*. We say that a state *(b',E')* is more
-general than a state *(b,E)* if for all variables *v* we have *b'(v) >=
-b(v)* and *E'* includes at least all relations of *E*. There is:
+general than a state *(b,E)* if for all variables *v* we have ``b'(v) >=
+b(v)`` and *E'* includes at least all relations of *E*. There is:
- a most general state, with *bmax(v) = Top* for all *v* and *Emax*
identifying all variables with each other;
@@ -854,15 +854,15 @@
.. _merge_into:
In the sequel, a lot of rules will be based on the following
-``merge_into`` operator. Given two variables *x* and *y*,
-``merge_into(x,y)`` modifies the state as follows::
+``merge_into`` operator. Given an annotation *a* and a variable *x*,
+``merge_into(a,x)`` modifies the state as follows::
- merge_into(x,y):
- if b(x)=List(v) and b(y)=List(w):
+ merge_into(a,x):
+ if a=List(v) and b(x)=List(w):
b' = b
- E' = E union (v~w)
+ E' = E union (v ~ w)
else:
- b' = b with (y -> b(x) \/ b(y))
+ b' = b with (x -> a \/ b(x))
E' = E
where ``\/`` is the union in the lattice *A*.
@@ -875,7 +875,7 @@
y = phi(x)
----------------------------------------
- merge_into(x,y)
+ merge_into(b(x),y)
The purpose of the equivalence relation *E* is to force two identified
variables to keep the same binding. The rationale for this is explained
@@ -884,13 +884,13 @@
(x~y) in E
----------------------------------------
- merge_into(x,y)
- merge_into(y,x)
+ merge_into(b(x),y)
+ merge_into(b(y),x)
-Note that in theory, all rules should be tried repeatedly until none of
+Note that a priori, all rules should be tried repeatedly until none of
them generalizes the state any more, at which point we have reached a
-fixpoint. In practice, the rules are well suited to a simple metarule
-that tracks a small set of rules that can possibly apply. Only these
+fixpoint. However, the rules are well suited to a simple metarule that
+tracks a small set of rules that can possibly apply. Only these
"scheduled" rules are tried. The metarule is as follows:
- when an identification *x~y* is added to *E*, then the rule
@@ -966,7 +966,7 @@
setitem(x,y,z), b(x)=List(v)
--------------------------------------------
- merge_into(z,v)
+ merge_into(b(z),v)
Reading an item out a list requires care to ensure that the rule is
rescheduled if the binding of the hidden variable is generalized. We do
@@ -1019,9 +1019,9 @@
instances". By default, instances of some user-defined class that
happens to pre-exist annotation have no constantness requirement on
their own; after annotation and possibly compilation, these instances
-will continue to behave as regular mutable instances of that class.
-These prebuilt instances are decribed in another section (`Constant
-annotations`_). However, the user program can give a hint that forces
+will continue to behave as regular mutable instances of that class,
+turned into mostly regular ``Inst(C)`` annotations when the annotator
+encounters them. However, the user program can give a hint that forces
the annotator to consider the object as a "frozen prebuilt constant".
The object is then considered as a now-immutable container of
attributes. It looses its object-oriented aspects and its class becomes
@@ -1071,15 +1071,15 @@
program that is static enough, it must reconstruct a static structure
for each class in the hierarchy. It does so by observing the usage
patterns of the classes and their instances, by propagating annotations
-of the form ``SomeInstance(cls)`` -- which stands for "an instance of
-the class *cls* or any subclass". Instance fields are attached to a
-class whenever we see that the field is being written to an instance of
-this class. If the user program manipulates instances polymorphically,
-the variables holding the instances will be annotated
-``SomeInstance(cls)`` with some abstract base class *cls*; accessing
-attributes on such generalized instances lifts the inferred attribute
-declarations up to *cls*. The same technique works for inferring the
-location of both fields and methods.
+of the form ``Inst(cls)`` -- which stands for "an instance of the class
+*cls* or any subclass". Instance fields are attached to a class
+whenever we see that the field is being written to an instance of this
+class. If the user program manipulates instances polymorphically, the
+variables holding the instances will be annotated ``Inst(cls)`` with
+some abstract base class *cls*; accessing attributes on such generalized
+instances lifts the inferred attribute declarations up to *cls*. The
+same technique works for inferring the location of both fields and
+methods.
~~~~~~~~~~~~~~~~~~~~~~
@@ -1119,135 +1119,139 @@
setattr(x,attr,z), b(x)=Inst(C)
---------------------------------------------------------------------
E' = E union (v_C.attr ~ v_D.attr) for all D subclass of C
- merge_into(z, v_C.attr)
-
-The purpose of ``lookup_filter`` is to avoid loosing precision in method
-calls. Indeed, as described more precisely in `Constant annotations`_
-below, if ``attr`` names a method of the class ``C`` then the binding
-``b(v_C.attr)`` is a ``Pbc`` that includes all the "potental bound
-method" objects ``D.f``, for each subclass ``D`` of ``C`` where a
-function ``f`` is present under the name ``attr``.
-
-XXX
-
-
-if ``attr`` is a method defined on XXX::
-
- lookup_filter(Pbc(set), class) = Pbc(newset) where
- we only keep in newset the non-methods, and the following methods:
- * the ones bound to a strict subclass of 'class', and
- * among the methods bound the 'class' or superclasses, only the
- one from the most derived class.
- lookup_filter(NonPbcAnnotation, class) = NonPbcAnnotation
+ merge_into(b(z), v_C.attr)
Note the similarity with the ``getitem`` and ``setitem`` of lists, in
particular the usage of the auxiliary variable *z'*.
-XXX
-
+The purpose of ``lookup_filter`` is to avoid loosing precision in method
+calls. Indeed, if ``attr`` names a method of the class ``C`` then the
+binding ``b(v_C.attr)`` is initialized to ``Pbc(m)``, where *m* is the
+following set:
-Constant annotations
-~~~~~~~~~~~~~~~~~~~~
+* for each subclass ``D`` of ``C``, if the class ``D`` introduces a method
+ ``attr`` implemented as, say, the function ``f``, then the "potential
+ bound method" object ``D.f`` belongs to *m*.
-XXX constant arguments to operations
+However, because of the possible identification between the variable
+``v_C.attr`` and the corresponding variable ``v_B.attr`` of a
+superclass, the set *m* might end up containing potential bound methods
+of other unrelated subclasses of ``B``, even when performing a
+``getattr`` on what we know is an instance of ``C``. The
+``lookup_filter`` reverses this effect as follows::
+ lookup_filter(Pbc(set), C) = Pbc(newset)
+ lookup_filter(NonPbcAnnotation, C) = NonPbcAnnotation
-Draft
-~~~~~
+where the *newset* only keeps the non-methods of *set* (if any) plus the
+following methods:
-::
+* the ones bound to a strict subclass of ``C``, plus
- Char
-
- Inst(class)
-
- List(x)
-
- Dict(x, y)
-
- Tup(ann_1, ..., ann_n)
-
- Pbc({... a finite set ...})
-
- with: None
- f
- class
- class.f
-
- v_n = op(v_n1, ...) | v_n', v_n''
-
- v_class.attr
-
- v_n: Annotation
-
- for each function f:
- arg_f_1 ... arg_f_n
- returnvar_f
-
-
- E: eq rel on V
- b: V->A
- V: set of variables
- A: fixed lattice of the above annotation terms
+* among the methods bound to ``C`` or superclasses of ``C``, only the
+ one from the most derived class.
- z=getattr(x,attr) | z', b(x)=Inst(A)
- ---------------------------------------------------------------------
- E' = E union (A.attr ~ A'.attr) for all A' subclass of A
- E' = E union (z' ~ A.attr)
- b' = b with (z->lookup_filter(b(z'), A))
-
-
- setattr(x,attr,z), b(x)=Inst(A)
- ---------------------------------------------------------------------
- assert b(z) is not a Pbc containing methods
- E' = E union (A.attr ~ A'.attr) for all A' subclass of A
- merge_into(z, A.attr)
+Calls
+~~~~~
+The ``Pbc`` annotations regroup (among others) all user-defined callable
+objects: functions, methods and classes. A call in the user program
+turns into a ``simplecall`` operation whose first argument is the object
+to call. Here is the corresponding rule -- regrouping all cases because
+the same ``Pbc(set)`` could mix several kinds of callables::
z=simplecall(x,y1,...,yn), b(x)=Pbc(set)
---------------------------------------------------------------------
for each c in set:
if c is a function:
- E' = E union (z~returnvar_c)
- merge_into(y1, arg_c_1)
+ E' = E union (z ~ returnvar_c)
+ merge_into(b(y1), arg_c_1)
...
- merge_into(yn, arg_c_n)
+ merge_into(b(yn), arg_c_n)
if c is a class:
let f = c.__init__
- b' = b with (z->b(z)\/Inst(c))
- b' = b with (arg_f_1->b(arg_f_1)\/Inst(c))
- merge_into(y1, arg_f_2)
+ merge_into(Inst(c), z)
+ merge_into(Inst(c), arg_f_1)
+ merge_into(b(y1), arg_f_2)
...
- merge_into(yn, arg_f_(n+1))
+ merge_into(b(yn), arg_f_(n+1))
if c is a method:
let class.f = c
- E' = E union (z~returnvar_f)
- b' = b with (arg_f_1->b(arg_f_1)\/Inst(class))
- merge_into(y1, arg_f_2)
+ E' = E union (z ~ returnvar_f)
+ merge_into(Inst(class), arg_f_1)
+ merge_into(b(y1), arg_f_2)
...
- merge_into(yn, arg_f_(n+1))
+ merge_into(b(yn), arg_f_(n+1))
+
+Calling a class returns an instance and flows the annotations into the
+contructor ``__init__`` of the class. Calling a method inserts the
+instance annotation as the first argument of the underlying function
+(the annotation is exactly ``Inst(C)`` for the class ``C`` in which the
+method is found).
- lookup_filter(Pbc(set), class) = Pbc(newset) where
- we only keep in newset the non-methods, and the following methods:
- * the ones bound to a strict subclass of 'class', and
- * among the methods bound the 'class' or superclasses, only the
- one from the most derived class.
- lookup_filter(NonPbcAnnotation, class) = NonPbcAnnotation
+Termination and soundness
+~~~~~~~~~~~~~~~~~~~~~~~~~
+As the annotation process is a fix-point search, it is necessary for
+completeness to prove more formally that it is well-behaved. The
+following proofs are all rather easy given the approach we have taken.
Termination
-~~~~~~~~~~~
+***********
+
+We first have to check that each rule can only turn a state *(b,E)* into
+a state *(b',E')* that is either identical or more general. To do so,
+we first verify that they all have the following properties:
+
+* if *z* is the result variable of an operation, the binding ``b(z)`` is
+ only ever modified by the rule (or rules) about this operation: this
+ is true because *E* never identifies such a result variable with any
+ other variable.
+
+* the annotation ``b(z)`` of such a result variable can only become more
+ general: using the previous point, this can be checked on the rule (or
+ rules) of each operation independently. Indeed, there are only two
+ ways in which ``b(z)`` is modified: by ``merge_into(..., z)``, which
+ trivially guarantees the property by being based on the union operator
+ ``\/`` of the lattice, or explicitely in a way that can easily be
+ checked to respect the property.
+
+...
+
+
+Each basic step (execution of one rule) can lead to the generalization
+of the state. If it does, then other rules may be scheduled or
+re-scheduled for execution. The state can only be generalized a finite
+number of times because both the lattice *A* and the set of variables
+*V* of which *E* is an equivalence relation are finite. If a rule does
+not lead to any generalization, then it does not trigger re-scheduling
+of any other rule. This ensures that the process eventually terminates.
+
+The extended lattice used in practice is a priori not finite. As we did
+not describe this lattice formally here, we have to skip the (easy)
+proof that it still contains no infinite ascending chain. An ascending
+chain is a sequence where each item is strictly larger than the previous
+one.
+
+Soundness
+*********
+
+We define an annotation state to be *sound* if none of the rules would
+lead to further Xxx.
+
XXX termination + soundness + most-precise-fixpoint-ness + complexity
+Complexity
+**********
+
The lattice is finite, although its size depends on the size of the
program. The List part has the same size as *V*, and the Pbc part is
exponential on the number of prebuilt constants. However, in this model
-a chain of annotations (where each one is larger than the previous)
-cannot be longer than::
+a chain of annotations cannot be longer than::
max(5, number-of-pbcs + 3, depth-of-class-hierarchy + 3).
@@ -1258,6 +1262,9 @@
to prove that there is no infinite ascending chain, which is enough to
guarantee termination.
+Additionally, an important property of ``lookup_filter`` is to be
+monotonic: XXX
+
Non-static aspects
~~~~~~~~~~~~~~~~~~
Modified: pypy/branch/hl-backend/pypy/doc/image/lattice1.dot
==============================================================================
--- pypy/branch/hl-backend/pypy/doc/image/lattice1.dot (original)
+++ pypy/branch/hl-backend/pypy/doc/image/lattice1.dot Fri Oct 14 17:44:56 2005
@@ -4,11 +4,11 @@
Top -> "*instances*" -> Bottom;
"*instances*" -> None;
NullableStr -> None;
- Top -> "*callables*" -> Bottom;
- "*callables*" -> None;
+ Top -> "*PBCs*" -> Bottom;
+ "*PBCs*" -> None;
Top -> "*lists*" -> None -> Bottom;
"*lists*" [shape=box];
"*instances*" [shape=box];
- "*callables*" [shape=box];
+ "*PBCs*" [shape=box];
}
Modified: pypy/branch/hl-backend/pypy/doc/news.txt
==============================================================================
--- pypy/branch/hl-backend/pypy/doc/news.txt (original)
+++ pypy/branch/hl-backend/pypy/doc/news.txt Fri Oct 14 17:44:56 2005
@@ -18,12 +18,13 @@
`continuation-passing`_ style (stackless), making the translation process
work for target languages with more powerful object systems and some tiny
steps into the JIT_ direction. Michael and Carl have written
-a `report about day one`_. *(10/11/2005)*
+a `report about day one`_ and `one about day two and three`_. *(10/14/2005)*
.. _`Logilabs offices in Paris`: http://codespeak.net/pypy/extradoc/sprintinfo/paris-2005-sprint.html
.. _JIT: http://en.wikipedia.org/wiki/Just-in-time_compilation
.. _`continuation-passing`: http://en.wikipedia.org/wiki/Continuation_passing_style
.. _`report about day one`: http://codespeak.net/pipermail/pypy-dev/2005q4/002510.html
+.. _`one about day two and three`: http://codespeak.net/pipermail/pypy-dev/2005q4/002512.html
PyPy release 0.7.0
===================
Modified: pypy/branch/hl-backend/pypy/interpreter/pyparser/test/test_astbuilder.py
==============================================================================
--- pypy/branch/hl-backend/pypy/interpreter/pyparser/test/test_astbuilder.py (original)
+++ pypy/branch/hl-backend/pypy/interpreter/pyparser/test/test_astbuilder.py Fri Oct 14 17:44:56 2005
@@ -715,10 +715,8 @@
filepath = os.path.join(STDLIB_PATH, basename)
size = os.stat(filepath)[6]
# filter on size
- if size <= 10000:
- print "TESTING", filepath
- source = file(filepath).read()
- yield check_expression, source, 'exec'
+ source = file(filepath).read()
+ yield check_expression, source, 'exec'
def test_eval_string():
Modified: pypy/branch/hl-backend/pypy/interpreter/pyparser/test/test_astcompiler.py
==============================================================================
--- pypy/branch/hl-backend/pypy/interpreter/pyparser/test/test_astcompiler.py (original)
+++ pypy/branch/hl-backend/pypy/interpreter/pyparser/test/test_astcompiler.py Fri Oct 14 17:44:56 2005
@@ -204,6 +204,19 @@
source = file(filepath).read()
yield check_compile, source, 'exec'
+STDLIB_PATH = os.path.dirname(os.__file__)
+def test_on_stdlib():
+ py.test.skip('too ambitious for now (and time consuming)')
+ for basename in os.listdir(STDLIB_PATH):
+ if not basename.endswith('.py'):
+ continue
+ filepath = os.path.join(STDLIB_PATH, basename)
+ # size = os.stat(filepath)[6]
+ # filter on size
+ # if size <= 10000:
+ source = file(filepath).read()
+ yield check_compile, source, 'exec'
+
def test_libstuff():
for snippet_name in LIBSTUFF:
filepath = os.path.join(os.path.dirname(__file__), '../../../lib', snippet_name)
Modified: pypy/branch/hl-backend/pypy/objspace/flow/model.py
==============================================================================
--- pypy/branch/hl-backend/pypy/objspace/flow/model.py (original)
+++ pypy/branch/hl-backend/pypy/objspace/flow/model.py Fri Oct 14 17:44:56 2005
@@ -256,6 +256,7 @@
name = '_' + name
name = self.namesdict.setdefault(name, (name, 0))[0]
self._name = name
+ self._nr = -1
def set_name_from(self, v):
# this is for SSI_to_SSA only which should not know about internals
Modified: pypy/branch/hl-backend/pypy/objspace/flow/objspace.py
==============================================================================
--- pypy/branch/hl-backend/pypy/objspace/flow/objspace.py (original)
+++ pypy/branch/hl-backend/pypy/objspace/flow/objspace.py Fri Oct 14 17:44:56 2005
@@ -395,7 +395,7 @@
types.ClassType,
types.TypeType)) and
c.__module__ in ['__builtin__', 'exceptions']):
- exceptions = None
+ exceptions = implicit_exceptions.get(c, None)
self.handle_implicit_exceptions(exceptions)
return w_res
@@ -434,7 +434,9 @@
op_appendices[_exc] = _name
del _name, _exc
-implicit_exceptions = {}
+implicit_exceptions = {
+ int: [ValueError], # built-ins that can always raise exceptions
+ }
def _add_exceptions(names, exc):
for name in names.split():
Modified: pypy/branch/hl-backend/pypy/objspace/flow/test/test_objspace.py
==============================================================================
--- pypy/branch/hl-backend/pypy/objspace/flow/test/test_objspace.py (original)
+++ pypy/branch/hl-backend/pypy/objspace/flow/test/test_objspace.py Fri Oct 14 17:44:56 2005
@@ -267,7 +267,7 @@
def implicitException_int_and_id(x):
try:
return int(x) + id(x)
- except ValueError: # not captured by the flow graph!
+ except TypeError: # not captured by the flow graph!
return 0
def test_implicitException_int_and_id(self):
Modified: pypy/branch/hl-backend/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/branch/hl-backend/pypy/objspace/std/longobject.py (original)
+++ pypy/branch/hl-backend/pypy/objspace/std/longobject.py Fri Oct 14 17:44:56 2005
@@ -99,10 +99,10 @@
def fromint(space, intval):
if intval < 0:
sign = -1
- ival = -intval
+ ival = r_uint(-intval)
elif intval > 0:
sign = 1
- ival = intval
+ ival = r_uint(intval)
else:
return W_LongObject(space, [0], 0)
# Count the number of Python digits.
@@ -118,7 +118,7 @@
t = ival
p = 0
while t:
- v.digits[p] = t & MASK
+ v.digits[p] = intmask(t & MASK)
t >>= SHIFT
p += 1
return v
Modified: pypy/branch/hl-backend/pypy/objspace/std/test/test_longobject.py
==============================================================================
--- pypy/branch/hl-backend/pypy/objspace/std/test/test_longobject.py (original)
+++ pypy/branch/hl-backend/pypy/objspace/std/test/test_longobject.py Fri Oct 14 17:44:56 2005
@@ -409,3 +409,9 @@
raises(ValueError, math.log, 0)
raises(ValueError, math.log, -1)
raises(ValueError, math.log, -2)
+
+ def test_long(self):
+ import sys
+ n = -sys.maxint-1
+ assert long(n) == n
+ assert str(long(n)) == str(n)
Modified: pypy/branch/hl-backend/pypy/rpython/extfunctable.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/extfunctable.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/extfunctable.py Fri Oct 14 17:44:56 2005
@@ -209,6 +209,9 @@
# stackless
from pypy.rpython import objectmodel
declare(objectmodel.stack_frames_depth, int, 'll_stackless/stack_frames_depth')
+declare(objectmodel.stack_too_big, bool, 'll_stack/too_big')
+declare(objectmodel.stack_check, noneannotation, 'll_stack/check')
+declare(objectmodel.stack_unwind, noneannotation, 'll_stack/unwind')
# ___________________________________________________________
# the exceptions that can be implicitely raised by some operations
@@ -224,4 +227,5 @@
KeyError : True,
IndexError : True,
AssertionError : True,
+ RuntimeError : True,
}
Modified: pypy/branch/hl-backend/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/llinterp.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/llinterp.py Fri Oct 14 17:44:56 2005
@@ -324,7 +324,10 @@
result = self.op_direct_call(malloc, *args)
return self.llinterpreter.gc.adjust_result_malloc(result, obj, size)
else:
- return self.llt.malloc(obj, size)
+ try:
+ return self.llt.malloc(obj, size)
+ except MemoryError, e:
+ self.make_llexception(e)
def op_flavored_malloc(self, flavor, obj):
assert isinstance(flavor, str)
Modified: pypy/branch/hl-backend/pypy/rpython/memory/gc.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/memory/gc.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/memory/gc.py Fri Oct 14 17:44:56 2005
@@ -34,12 +34,14 @@
ll = AddressLinkedList()
ll.append(NULL)
ll.append(raw_malloc(10))
+ ll.pop() #make the annotator see pop
return ll
def dummy_get_roots2():
ll = AddressLinkedList()
ll.append(raw_malloc(10))
ll.append(NULL)
+ ll.pop() #make the annotator see pop
return ll
@@ -67,6 +69,30 @@
"NOT_RPYTHON"
pass
+class DummyGC(GCBase):
+ _alloc_flavor_ = "raw"
+
+ def __init__(self, dummy=None, get_roots=None):
+ self.get_roots = get_roots
+ self.set_query_functions(None, None, None, None, None, None, None)
+
+ def malloc(self, typeid, length=0):
+ size = self.fixed_size(typeid)
+ if self.is_varsize(typeid):
+ size += length * self.varsize_item_sizes(typeid)
+ return raw_malloc(size)
+
+ def collect(self):
+ self.get_roots() #this is there so that the annotator thinks get_roots is a function
+
+ def size_gc_header(self, typeid=0):
+ return 0
+
+ def init_gc_object(self, addr, typeid):
+ return
+ init_gc_object_immortal = init_gc_object
+
+
class MarkSweepGC(GCBase):
_alloc_flavor_ = "raw"
Modified: pypy/branch/hl-backend/pypy/rpython/memory/lltypesimulation.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/memory/lltypesimulation.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/memory/lltypesimulation.py Fri Oct 14 17:44:56 2005
@@ -48,7 +48,7 @@
if isinstance(self._T, lltype.Array):
self._address.signed[0] = size
elif isinstance(self._T, lltype.Struct):
- if isinstance(self._T._flds[self._T._names[-1]], lltype.Array):
+ if self._T._arrayfld is not None:
addr = self._address + self._layout[self._T._arrayfld]
addr.signed[0] = size
else:
Modified: pypy/branch/hl-backend/pypy/rpython/memory/simulator.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/memory/simulator.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/memory/simulator.py Fri Oct 14 17:44:56 2005
@@ -113,7 +113,8 @@
return self.blocks[mid]
def malloc(self, size):
- assert size > 0
+ if size == 0:
+ size = 1
result = self.freememoryaddress
self.blocks.append(MemoryBlock(result, size))
self.freememoryaddress += size
Modified: pypy/branch/hl-backend/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/memory/test/test_gc.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/memory/test/test_gc.py Fri Oct 14 17:44:56 2005
@@ -5,7 +5,7 @@
from pypy.translator.annrpython import RPythonAnnotator
from pypy.rpython.rtyper import RPythonTyper
from pypy.rpython.memory.gc import GCError, MarkSweepGC, SemiSpaceGC
-from pypy.rpython.memory.gc import DeferredRefcountingGC
+from pypy.rpython.memory.gc import DeferredRefcountingGC, DummyGC
from pypy.rpython.memory.support import AddressLinkedList, INT_SIZE
from pypy.rpython.memory.lladdress import raw_malloc, raw_free, NULL
from pypy.rpython.memory.simulator import MemorySimulatorError
@@ -138,3 +138,22 @@
def teardown_class(cls):
gclltype.prepare_graphs_and_create_gc = cls.prep_old.im_func
gclltype.use_gc = cls.old
+
+class TestDummyGC(TestMarkSweepGC):
+ def setup_class(cls):
+ gclltype.use_gc = DummyGC
+ cls.old = gclltype.use_gc
+ def teardown_class(cls):
+ gclltype.use_gc = cls.old
+
+class TestDummyGCRunningOnLLinterp(TestMarkSweepGC):
+ def setup_class(cls):
+ cls.prep_old = gclltype.prepare_graphs_and_create_gc
+ gclltype.prepare_graphs_and_create_gc = gclltype.create_gc_run_on_llinterp
+ gclltype.use_gc = DummyGC
+ cls.old = gclltype.use_gc
+
+ def teardown_class(cls):
+ gclltype.prepare_graphs_and_create_gc = cls.prep_old.im_func
+ gclltype.use_gc = cls.old
+
Modified: pypy/branch/hl-backend/pypy/rpython/memory/test/test_lltypesimulation.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/memory/test/test_lltypesimulation.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/memory/test/test_lltypesimulation.py Fri Oct 14 17:44:56 2005
@@ -121,6 +121,11 @@
assert s1.a == 17
assert s1.rest[3].v == 5
+def test_empty_struct():
+ S1 = lltype.GcStruct("s1")
+ s1 = malloc(S1)
+ assert s1 == s1
+
def test_substructure_ptr():
S3 = lltype.Struct("s3", ('a', lltype.Signed))
S2 = lltype.Struct("s2", ('s3', S3), ('char', lltype.Char))
Modified: pypy/branch/hl-backend/pypy/rpython/module/ll_stackless.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/module/ll_stackless.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/module/ll_stackless.py Fri Oct 14 17:44:56 2005
@@ -1,6 +1,5 @@
from pypy.rpython import objectmodel
-
def ll_stackless_stack_frames_depth():
return objectmodel.stack_frames_depth()
ll_stackless_stack_frames_depth.suggested_primitive = True
Modified: pypy/branch/hl-backend/pypy/rpython/objectmodel.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/objectmodel.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/objectmodel.py Fri Oct 14 17:44:56 2005
@@ -38,9 +38,22 @@
def hlinvoke(repr, llcallable, *args):
raise TypeError, "hlinvoke is meant to be rtyped and not called direclty"
+def stack_unwind():
+ pass
+
def stack_frames_depth():
return len(inspect.stack())
+def stack_too_big():
+ return False
+
+def stack_check():
+ if stack_too_big():
+ # stack_unwind implementation is different depending on if stackless
+ # is enabled. If it is it unwinds the stack, otherwise it simply
+ # raises a RuntimeError.
+ stack_unwind()
+
# ____________________________________________________________
Modified: pypy/branch/hl-backend/pypy/rpython/rint.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/rint.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/rint.py Fri Oct 14 17:44:56 2005
@@ -295,7 +295,9 @@
sign = 0
if i < 0:
sign = 1
- i = -i
+ i = r_uint(-i)
+ else:
+ i = r_uint(i)
if i == 0:
len = 1
temp[0] = '0'
Modified: pypy/branch/hl-backend/pypy/rpython/rtyper.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/rtyper.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/rtyper.py Fri Oct 14 17:44:56 2005
@@ -25,6 +25,7 @@
from pypy.rpython.ootypesystem import ootype
from pypy.tool.sourcetools import func_with_new_name, valid_identifier
from pypy.translator.unsimplify import insert_empty_block
+from pypy.translator.transform import insert_stackcheck
from pypy.rpython.rmodel import Repr, inputconst
from pypy.rpython.rmodel import TyperError, BrokenReprTyperError
from pypy.rpython.rmodel import warning
@@ -139,8 +140,10 @@
"""Main entry point: specialize all annotated blocks of the program."""
self.crash_on_first_typeerror = crash_on_first_typeerror
# specialize depends on annotator simplifications
+ insert_stackcheck(self.annotator)
if not dont_simplify_again:
self.annotator.simplify()
+
# first make sure that all functions called in a group have exactly
# the same signature, by hacking their flow graphs if needed
perform_normalizations(self)
Modified: pypy/branch/hl-backend/pypy/rpython/test/test_rint.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/test/test_rint.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/test/test_rint.py Fri Oct 14 17:44:56 2005
@@ -1,3 +1,4 @@
+import sys
from pypy.translator.translator import Translator
from pypy.rpython.rtyper import RPythonTyper
from pypy.annotation import model as annmodel
@@ -62,7 +63,10 @@
res = interpret(dummy, [-123])
assert ''.join(res.chars) == '-123'
-
+
+ res = interpret(dummy, [-sys.maxint-1])
+ assert ''.join(res.chars) == str(-sys.maxint-1)
+
def test_hex_of_int():
def dummy(i):
return hex(i)
Modified: pypy/branch/hl-backend/pypy/rpython/test/test_rlist.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/test/test_rlist.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/test/test_rlist.py Fri Oct 14 17:44:56 2005
@@ -1,3 +1,4 @@
+import sys
from pypy.translator.translator import Translator
from pypy.rpython.lltype import *
from pypy.rpython.rtyper import RPythonTyper
@@ -500,3 +501,14 @@
assert res == 2
res = interpret(fn, [6])
assert res == 100
+
+def test_memoryerror():
+ def fn(i):
+ lst = [0] * i
+ lst[i-1] = 5
+ return lst[0]
+ res = interpret(fn, [1])
+ assert res == 5
+ res = interpret(fn, [2])
+ assert res == 0
+ interpret_raises(MemoryError, fn, [sys.maxint])
Modified: pypy/branch/hl-backend/pypy/rpython/test/test_rstr.py
==============================================================================
--- pypy/branch/hl-backend/pypy/rpython/test/test_rstr.py (original)
+++ pypy/branch/hl-backend/pypy/rpython/test/test_rstr.py Fri Oct 14 17:44:56 2005
@@ -472,6 +472,17 @@
res = interpret(fn, [i, j])
assert res == expected
+def test_int_valueerror():
+ s1 = ['42g', '?']
+ def fn(i):
+ try:
+ return int(s1[i])
+ except ValueError:
+ return -654
+ res = interpret(fn, [0])
+ assert res == -654
+ res = interpret(fn, [1])
+ assert res == -654
def test_char_mul_n():
def f(c, n):
Modified: pypy/branch/hl-backend/pypy/translator/asm/genasm.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/asm/genasm.py (original)
+++ pypy/branch/hl-backend/pypy/translator/asm/genasm.py Fri Oct 14 17:44:56 2005
@@ -2,6 +2,7 @@
from pypy.objspace.flow.model import traverse, Block, Variable, Constant
from pypy.translator.asm import infregmachine
from pypy.rpython.lltype import Signed
+from pypy.translator.asm.simulator import Machine, TranslateProgram
#Available Machine code targets (processor+operating system)
TARGET_UNKNOWN=0
@@ -33,7 +34,7 @@
from pypy.translator.asm.i386gen.i386_assembler import make_func
-def genasm(translator):
+def genasm(translator, processor):
f = translator.entrypoint
@@ -48,10 +49,27 @@
g = FuncGenerator(graph)
g.gencode()
-# g.assembler.dump()
- finreg = g.assembler.allocate_registers(30)
- return make_func(finreg.assemble(), 'i', 'i'*len(graph.startblock.inputargs))
+ if processor == 'virt':
+ def r(*args):
+ return Machine.RunProgram(g.assembler.instructions,
+ args,
+ tracing=True)
+
+ return r
+ elif processor == 'virtfinite':
+ insns = TranslateProgram(g.assembler.instructions, 50)
+ for i in insns:
+ print i
+ def r(*args):
+ return Machine.RunProgram(insns,
+ args,
+ tracing=True)
+
+ return r
+ elif processor == 'ppc':
+ from pypy.translator.asm.ppc import codegen
+ return codegen.make_native_code(graph, g.assembler.instructions)
class FuncGenerator(object):
@@ -71,7 +89,7 @@
self.assembler = infregmachine.Assembler()
for i, var in enumerate(graph.startblock.inputargs):
- self.emit('LIA', self.reg(var), i)
+ self.emit('LIA', self.reg(var), Constant(i))
def assign_register(self, var):
assert var not in self._var2reg
@@ -85,7 +103,7 @@
if isinstance(var, Constant):
r = self.next_register
assert isinstance(var.value, int)
- self.assembler.emit("LOAD", r, var.value)
+ self.assembler.emit("LOAD", r, var)
self.next_register += 1
return r
elif isinstance(var, Variable):
@@ -128,7 +146,8 @@
assert block.exitswitch is not None
falselink, truelink = block.exits
lastop = block.operations[-1]
- assert lastop.opname in ['int_gt', 'int_lt', 'int_ge']
+ assert lastop.opname in ['int_gt', 'int_lt', 'int_ge',
+ 'int_eq', 'int_le', 'int_ne']
A.emit(lastop.opname, *map(self.reg, lastop.args))
b = self.blockname()
A.emit('JT', b)
Modified: pypy/branch/hl-backend/pypy/translator/asm/infregmachine.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/asm/infregmachine.py (original)
+++ pypy/branch/hl-backend/pypy/translator/asm/infregmachine.py Fri Oct 14 17:44:56 2005
@@ -6,12 +6,15 @@
self.arguments = arguments
def registers_used(self):
- if self.name == 'LIA' or self.name == 'LOAD':
- return [self.arguments[0]]
- elif self.name in ('JT', 'JF', 'J'):
- return []
- else:
- return list(self.arguments)
+ return [a for a in self.arguments if isinstance(a, int)]
+
+ def renumber(self, regmap):
+ def _(a):
+ if isinstance(a, int) and a in regmap:
+ return regmap[a]
+ else:
+ return a
+ return Instruction(self.name, map(_, self.arguments))
def __repr__(self):
if self.name == 'LIA':
@@ -20,10 +23,28 @@
elif self.name in ('JT', 'JF', 'J'):
args = self.arguments[0]
elif self.name == 'LOAD':
- args = 'r%s, %s'%tuple(self.arguments)
+ args = 'r%s, #%s'%tuple(self.arguments)
else:
- args = ', '.join(['r%s'%a for a in self.arguments])
- return ' %-10s %s'%(self.name, args)
+ def c(x):
+ if isinstance(x, int):
+ return 'r%s'%x
+ else:
+ return str(x)
+ args = ', '.join(map(c, self.arguments))
+ return '%-30s'%(' %-10s %s'%(self.name, args),)
+
+class Program(object):
+ # approximately a list of Instructions, but with sprinkles
+ # not used yet.
+
+ def __init__(self, insns):
+ self.insns = insns
+
+ def iterinsns(self):
+ for insn in self.insns:
+ if isinstance(ins, str):
+ continue
+ yield insn
class Assembler(object):
def __init__(self):
@@ -40,67 +61,3 @@
if isinstance(i, str):
i += ':'
print i
-
- def allocate_registers(self, nregisters):
- r = FiniteRegisterAssembler(nregisters)
- for i in self.instructions:
- if not isinstance(i, str): # labels
- assert max(i.registers_used() + [0]) < nregisters
- r.instructions.append(i)
- return r
-
-class FiniteRegisterAssembler(Assembler):
- def __init__(self, nregisters):
- Assembler.__init__(self)
- self.nregisters = nregisters
-
- def assemble(self):
- from pypy.translator.asm.ppcgen import ppc_assembler
- A = ppc_assembler.PPCAssembler()
-
- for i in self.instructions:
- if isinstance(i, str):
- A.label(i)
- continue
-
- getattr(self, i.name)(A, *i.arguments)
-
- return A
-
- def LIA(self, A, dest, argindex):
- assert dest + 2 == argindex + 3
-
- def LOAD(self, A, dest, value):
- assert isinstance(value, int)
- assert -30000 < value < 30000
- A.li(dest + 2, value)
-
- def int_add(self, A, dest, a, b):
- A.add(dest + 2, a + 2, b + 2)
-
- def int_sub(self, A, dest, a, b):
- A.sub(dest + 2, a + 2, b + 2)
-
- def int_mul(self, A, dest, a, b):
- A.mullw(dest + 2, a + 2, b + 2)
-
- def int_gt(self, A, a, b):
- A.cmpw(a + 2, b + 2)
- A.crmove(0, 1)
-
- def int_lt(self, A, a, b):
- A.cmpw(a + 2, b + 2)
-
- def JT(self, A, branch):
- # should be "A.bt(BI=0, BD=branch)" but this crashes.
- A.blt(branch)
-
- def J(self, A, branch):
- A.b(branch)
-
- def RETPYTHON(self, A, reg):
- A.mr(3, reg + 2)
- A.blr()
-
- def MOV(self, A, dest, src):
- A.mr(dest + 2, src + 2)
Modified: pypy/branch/hl-backend/pypy/translator/asm/ppcgen/func_builder.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/asm/ppcgen/func_builder.py (original)
+++ pypy/branch/hl-backend/pypy/translator/asm/ppcgen/func_builder.py Fri Oct 14 17:44:56 2005
@@ -7,14 +7,14 @@
code.lwz(rD, r4, 12 + 4*argi)
if typecode == 'i':
code.load_word(r0, lookup("PyInt_Type"))
- code.lwz(r15, rD, 4) # XXX ick!
- code.cmpw(r0, r15)
+ code.lwz(r31, rD, 4) # XXX ick!
+ code.cmpw(r0, r31)
code.bne("argserror")
code.lwz(rD, rD, 8)
elif typecode == 'f':
code.load_word(r0, lookup("PyFloat_Type"))
- code.lwz(r15, rD, 4)
- code.cmpw(r0, r15)
+ code.lwz(r31, rD, 4)
+ code.cmpw(r0, r31)
code.bne("argserror")
code.lfd(rD-2, rD, 8)
elif typecode != "O":
@@ -22,16 +22,18 @@
FAST_ENTRY_LABEL = "FAST-ENTRY-LABEL"
-def make_func(code, retcode, signature):
+def make_func(code, retcode, signature, localwords=0):
"""code shouldn't contain prologue/epilogue (or touch r31)"""
+ stacksize = 80 + 4*localwords
+
argcount = len(signature)
ourcode = MyPPCAssembler()
ourcode.mflr(r0)
ourcode.stmw(r31, r1, -4)
ourcode.stw(r0, r1, 8)
- ourcode.stwu(r1, r1, -80)
+ ourcode.stwu(r1, r1, -stacksize)
ourcode.lwz(r3, r4, 8)
ourcode.cmpwi(r3, argcount)
@@ -47,7 +49,7 @@
load_arg(ourcode, 1, signature[1])
ourcode.bl(FAST_ENTRY_LABEL)
-
+
if retcode == 'i':
s = lookup("PyInt_FromLong")
ourcode.load_word(r0, s)
@@ -60,8 +62,8 @@
ourcode.bctrl()
ourcode.label("epilogue")
- ourcode.lwz(r0, r1, 88)
- ourcode.addi(r1, r1, 80)
+ ourcode.lwz(r0, r1, stacksize + 8)
+ ourcode.addi(r1, r1, stacksize)
ourcode.mtlr(r0)
ourcode.lmw(r31, r1, -4)
ourcode.blr()
@@ -96,7 +98,7 @@
return r
def wrap(funcname, retcode, signature):
-
+
argcount = len(signature)
ourcode = MyPPCAssembler()
@@ -118,11 +120,11 @@
if argcount > 1:
load_arg(ourcode, 1, signature[1])
-
+
ourcode.load_word(r0, lookup(funcname))
ourcode.mtctr(r0)
ourcode.bctrl()
-
+
if retcode == 'i':
s = lookup("PyInt_FromLong")
ourcode.load_word(r0, s)
Modified: pypy/branch/hl-backend/pypy/translator/asm/test/test_asm.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/asm/test/test_asm.py (original)
+++ pypy/branch/hl-backend/pypy/translator/asm/test/test_asm.py Fri Oct 14 17:44:56 2005
@@ -1,14 +1,11 @@
from pypy.translator.translator import Translator
+from pypy.rpython.rarithmetic import ovfcheck
import py
import os
class TestAsm(object):
- def setup_class(cls):
- if not hasattr(os, "uname") or os.uname()[-1] != 'Power Macintosh':
- py.test.skip('asm generation only on PPC')
-
- cls.processor = 'ppc'
+ processor = 'virt'
def getcompiled(self, func, view=False):
t = Translator(func, simplifying=True)
@@ -44,8 +41,8 @@
return x + y - 42
f = self.getcompiled(testfn)#, view=True)
- assert f(2, 3) == testfn(2, 3)
assert f(-2, 3) == testfn(-2, 3)
+ assert f(2, 5) == testfn(2, 5)
def test_loop(self):
def testfn(lim=int):
@@ -61,4 +58,80 @@
assert f(10) == testfn(10)
assert f(100) == testfn(100)
assert f(1000) == testfn(1000)
-
+
+ def test_factor(self):
+ def factor(n=int):
+ i = 2
+ while i < n:
+ if n % i == 0:
+ return i
+ i += 1
+ return i
+ f = self.getcompiled(factor)
+
+ assert f(25) == 5
+ assert f(27) == 3
+ assert f(17*13) == 13
+ assert f(29) == 29
+
+ def test_from_psyco(self):
+ def f1(n=int):
+ "Arbitrary test function."
+ i = 0
+ x = 1
+ while i<n:
+ j = 0
+ while j<=i:
+ j = j + 1
+ x = x + (i&j)
+ i = i + 1
+ return x
+
+ f = self.getcompiled(f1)
+ assert f(10) == f1(10)
+
+ def test_comparisons(self):
+ def f(x=int):
+ if x == 0:
+ return 0
+ elif x > 10:
+ return 10
+ elif x >= 5:
+ return 5
+ elif x < -10:
+ return -10
+ elif x <= -5:
+ return -5
+ elif x != 1:
+ return 1
+ else:
+ return x
+ g = self.getcompiled(f)
+ for i in range(-20, 20):
+ assert g(i) == f(i)
+
+ def dont_test_overflow(self):
+ def f(x=int, y=int):
+ try:
+ return ovfcheck(x*y)
+ except OverflowError:
+ return 0
+ g = self.getcompiled(f, view=True)
+ assert f(3, 4) == g(3, 4)
+ big = 1000000000
+ assert f(big, big) == g(big, big)
+
+class TestAsmAfterAllocation(TestAsm):
+
+ processor = 'virtfinite'
+
+
+class TestAsmPPC(TestAsm):
+
+ processor = 'ppc'
+
+ def setup_class(cls):
+ if not hasattr(os, "uname") or os.uname()[-1] != 'Power Macintosh':
+ py.test.skip('asm generation only on PPC')
+
+
Modified: pypy/branch/hl-backend/pypy/translator/c/extfunc.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/extfunc.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/extfunc.py Fri Oct 14 17:44:56 2005
@@ -4,7 +4,8 @@
from pypy.rpython.rmodel import getfunctionptr
from pypy.rpython.rstr import STR
from pypy.rpython import rlist
-from pypy.rpython.module import ll_os, ll_time, ll_math, ll_strtod, ll_stackless
+from pypy.rpython.module import ll_os, ll_time, ll_math, ll_strtod
+from pypy.rpython.module import ll_stackless, ll_stack
from pypy.module.thread.rpython import ll_thread
@@ -50,6 +51,8 @@
ll_thread.ll_thread_start: 'LL_thread_start',
ll_thread.ll_thread_get_ident: 'LL_thread_get_ident',
ll_stackless.ll_stackless_stack_frames_depth: 'LL_stackless_stack_frames_depth',
+ ll_stack.ll_stack_unwind: 'LL_stack_unwind',
+ ll_stack.ll_stack_too_big: 'LL_stack_too_big',
}
#______________________________________________________
Modified: pypy/branch/hl-backend/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/funcgen.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/funcgen.py Fri Oct 14 17:44:56 2005
@@ -234,7 +234,11 @@
lst.append(self.expr(op.result))
lst.append(err)
line = '%s(%s);' % (macro, ', '.join(lst))
- yield line
+ if '\n' in line:
+ for subline in line.split('\n'):
+ yield subline
+ else:
+ yield line
if line.find(err) >= 0:
reachable_err = len(to_release)
to_release.append(op.result)
@@ -404,11 +408,11 @@
# skip assignment of 'void' return value
r = self.expr(op.result)
line = '%s = %s' % (r, line)
- line = '%s %s' % (line, self.check_directcall_result(op, err))
+ line = '%s\n%s' % (line, self.check_directcall_result(op, err))
return line
def check_directcall_result(self, op, err):
- return 'if (RPyExceptionOccurred()) FAIL(%s);' % err
+ return 'if (RPyExceptionOccurred())\n\tFAIL(%s);' % err
# low-level operations
def generic_get(self, op, sourceexpr):
@@ -418,7 +422,7 @@
# need to adjust the refcount of the result only for PyObjects
if T == PyObjPtr:
result.append(self.pyobj_incref_expr(newvalue, T))
- result = '\t'.join(result)
+ result = '\n'.join(result)
if T is Void:
result = '/* %s */' % result
return result
@@ -429,7 +433,7 @@
# insert write barrier
T = self.lltypemap(op.args[2])
self.gcpolicy.write_barrier(result, newvalue, T, targetexpr)
- result = '\t'.join(result)
+ result = '\n'.join(result)
if T is Void:
result = '/* %s */' % result
return result
@@ -513,12 +517,20 @@
eresult = self.expr(op.result)
if VARPART.OF is Void: # strange
esize = 'sizeof(%s)' % (cdecl(typename, ''),)
+ result = ''
else:
- esize = 'sizeof(%s)+((%s-1)*sizeof(%s))' % (cdecl(typename, ''),
- elength,
- cdecl(itemtypename, ''))
- result = self.gcpolicy.zero_malloc(TYPE, esize, eresult, err)
- result += '\t%s->%s = %s;' % (eresult, lenfld, elength)
+ itemtype = cdecl(itemtypename, '')
+ result = 'OP_MAX_VARSIZE(%s, %s, %s);\n' % (
+ elength,
+ itemtype,
+ err)
+ esize = 'sizeof(%s)-sizeof(%s)+%s*sizeof(%s)' % (
+ cdecl(typename, ''),
+ itemtype,
+ elength,
+ itemtype)
+ result += self.gcpolicy.zero_malloc(TYPE, esize, eresult, err)
+ result += '\n%s->%s = %s;' % (eresult, lenfld, elength)
return result
def OP_CAST_POINTER(self, op, err):
Modified: pypy/branch/hl-backend/pypy/translator/c/gc.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/gc.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/gc.py Fri Oct 14 17:44:56 2005
@@ -107,10 +107,12 @@
if increfstmt:
result.append(increfstmt)
if decrefstmt:
- result.insert(0, '{ %s = %s;' % (
+ result.insert(0, '%s = %s;' % (
cdecl(self.db.gettype(T), 'prev'),
targetexpr))
result.append(decrefstmt)
+ result[:] = ['\t%s' % line for line in result]
+ result[0] = '{' + result[0]
result.append('}')
def generic_dealloc(self, expr, T):
@@ -348,7 +350,7 @@
is_varsize,
err)
if gcinfo and gcinfo.finalizer:
- result += ('\tGC_REGISTER_FINALIZER(%s, %s, NULL, NULL, NULL);'
+ result += ('\nGC_REGISTER_FINALIZER(%s, %s, NULL, NULL, NULL);'
% (eresult, gcinfo.finalizer))
return result
Modified: pypy/branch/hl-backend/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/genc.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/genc.py Fri Oct 14 17:44:56 2005
@@ -11,7 +11,7 @@
from pypy.rpython import lltype
from pypy.tool.udir import udir
-class CBuilder:
+class CBuilder(object):
c_source_filename = None
_compiled = False
symboltable = None
@@ -23,7 +23,7 @@
if libraries is None:
libraries = []
- self.libraries = libraries
+ self.libraries = libraries
def generate_source(self):
assert self.c_source_filename is None
@@ -132,7 +132,8 @@
# ____________________________________________________________
-SPLIT_CRITERIA = 170
+#SPLIT_CRITERIA = 32767 # enable to support VC++ 6.0
+SPLIT_CRITERIA = 65535 # support VC++ 7.2
MARKER = '/*/*/' # provide an easy way to split after generating
@@ -148,9 +149,7 @@
def set_strategy(self, path):
all_nodes = list(self.database.globalcontainers())
- # split off non-function nodes
- # win32 has a problem: compiles but infinite recursion etc.
- # trytocicumvent this by placing all non-func nodes into one file.
+ # split off non-function nodes. We don't try to optimize these, yet.
funcnodes = []
othernodes = []
for node in all_nodes:
@@ -158,7 +157,8 @@
funcnodes.append(node)
else:
othernodes.append(node)
- if 1 or len(funcnodes) >= SPLIT_CRITERIA:##!!
+ # for now, only split for stand-alone programs.
+ if self.database.standalone:
self.one_source_file = False
self.funcnodes = funcnodes
self.othernodes = othernodes
@@ -180,15 +180,26 @@
def getothernodes(self):
return self.othernodes[:]
- def splitfuncnodes(self):
- # silly first split, just by node count
- # XXX filter constant stuff off and put it elsewhere
- nodes = self.funcnodes[:]
- nchunks = len(nodes) // SPLIT_CRITERIA or 1
- chunksize = (len(nodes) + nchunks - 1) // nchunks
- while nodes:
- yield self.uniquecname('implement.c'), nodes[:chunksize]
- del nodes[:chunksize]
+ def splitnodesimpl(self, basecname, nodes, nextra, nbetween):
+ # produce a sequence of nodes, grouped into files
+ # which have no more than SPLIT_CRITERIA lines
+ used = nextra
+ part = []
+ for node in nodes:
+ impl = list(node.implementation())
+ if not impl:
+ continue
+ cost = len(impl) + nbetween
+ if used + cost > SPLIT_CRITERIA and part:
+ # split if criteria met, unless we would produce nothing.
+ yield self.uniquecname(basecname), part
+ part = []
+ used = nextra
+ part.append( (node, impl) )
+ used += cost
+ # generate left pieces
+ if part:
+ yield self.uniquecname(basecname), part
def gen_readable_parts_of_source(self, f):
if self.one_source_file:
@@ -266,26 +277,33 @@
print >> fc, '/***********************************************************/'
fc.close()
- name = self.uniquecname('nonfuncnodes.c')
- print >> f, '/* %s */' % name
- fc = self.makefile(name)
- print >> fc, '/***********************************************************/'
- print >> fc, '/*** Non-function Implementations ***/'
- print >> fc
- print >> fc, '#define PYPY_NOT_MAIN_FILE'
- print >> fc, '#include "common_header.h"'
- print >> fc, '#include "structdef.h"'
- print >> fc, '#include "forwarddecl.h"'
- print >> fc
- print >> fc, '#include "src/g_include.h"'
- print >> fc
- print >> fc, MARKER
- for node in self.getothernodes():
- render_nonempty(node.implementation())
- print >> fc, '/***********************************************************/'
- fc.close()
+ nextralines = 11 + 1
+ for name, nodesimpl in self.splitnodesimpl('nonfuncnodes.c',
+ self.othernodes,
+ nextralines, 1):
+ print >> f, '/* %s */' % name
+ fc = self.makefile(name)
+ print >> fc, '/***********************************************************/'
+ print >> fc, '/*** Non-function Implementations ***/'
+ print >> fc
+ print >> fc, '#define PYPY_NOT_MAIN_FILE'
+ print >> fc, '#include "common_header.h"'
+ print >> fc, '#include "structdef.h"'
+ print >> fc, '#include "forwarddecl.h"'
+ print >> fc
+ print >> fc, '#include "src/g_include.h"'
+ print >> fc
+ print >> fc, MARKER
+ for node, impl in nodesimpl:
+ print >> fc, '\n'.join(impl)
+ print >> fc, MARKER
+ print >> fc, '/***********************************************************/'
+ fc.close()
- for name, nodes in self.splitfuncnodes():
+ nextralines = 8 + len(self.preimpl) + 4 + 1
+ for name, nodesimpl in self.splitnodesimpl('implement.c',
+ self.funcnodes,
+ nextralines, 1):
print >> f, '/* %s */' % name
fc = self.makefile(name)
print >> fc, '/***********************************************************/'
@@ -302,9 +320,9 @@
print >> fc, '#include "src/g_include.h"'
print >> fc
print >> fc, MARKER
- linecount = 12 + len(self.preimpl)
- for node in nodes:
- linecount += render_nonempty(node.implementation())
+ for node, impl in nodesimpl:
+ print >> fc, '\n'.join(impl)
+ print >> fc, MARKER
print >> fc, '/***********************************************************/'
fc.close()
print >> f
Modified: pypy/branch/hl-backend/pypy/translator/c/src/address.h
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/src/address.h (original)
+++ pypy/branch/hl-backend/pypy/translator/c/src/address.h Fri Oct 14 17:44:56 2005
@@ -5,9 +5,9 @@
/*** binary operations ***/
-#define OP_ADR_DELTA(x,y,r,err) r = ((x) - (y))
-#define OP_ADR_SUB(x,y,r,err) r = ((x) - (y))
-#define OP_ADR_ADD(x,y,r,err) r = ((x) + (y))
+#define OP_ADR_DELTA(x,y,r,err) r = ((char *)(x) - (char *)(y))
+#define OP_ADR_SUB(x,y,r,err) r = ((char *)(x) - (y))
+#define OP_ADR_ADD(x,y,r,err) r = ((char *)(x) + (y))
#define OP_ADR_EQ(x,y,r,err) r = ((x) == (y))
#define OP_ADR_NE(x,y,r,err) r = ((x) != (y))
Modified: pypy/branch/hl-backend/pypy/translator/c/src/g_include.h
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/src/g_include.h (original)
+++ pypy/branch/hl-backend/pypy/translator/c/src/g_include.h Fri Oct 14 17:44:56 2005
@@ -41,6 +41,8 @@
# include "src/ll_stackless.h"
#endif
+#include "src/stack.h"
+
#ifdef PYPY_STANDALONE
# include "src/main.h"
#endif
Modified: pypy/branch/hl-backend/pypy/translator/c/src/ll_stackless.h
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/src/ll_stackless.h (original)
+++ pypy/branch/hl-backend/pypy/translator/c/src/ll_stackless.h Fri Oct 14 17:44:56 2005
@@ -32,6 +32,7 @@
slp_frame_t* slp_new_frame(int size, int state);
long LL_stackless_stack_frames_depth(void);
void slp_main_loop(void);
+char LL_stackless_stack_too_big(void);
#ifndef PYPY_NOT_MAIN_FILE
@@ -53,6 +54,19 @@
return f;
}
+void LL_stackless_stack_unwind(void)
+{
+ if (slp_frame_stack_top)
+ goto resume;
+
+ slp_frame_stack_top = slp_frame_stack_bottom =
+ slp_new_frame(sizeof(slp_frame_t), 0);
+ return ;
+
+ resume:
+ slp_frame_stack_top = NULL;
+}
+
/* example function for testing */
@@ -62,7 +76,7 @@
goto resume;
slp_frame_stack_top = slp_frame_stack_bottom =
- slp_new_frame(sizeof(slp_frame_t), 0);
+ slp_new_frame(sizeof(slp_frame_t), 1);
return -1;
resume:
@@ -82,7 +96,6 @@
#include "slp_state_decoding.h"
-
void slp_main_loop(void)
{
int state, signature;
@@ -132,7 +145,8 @@
int slp_standalone_entry_point(RPyListOfString *argv)
{
- int result = PYPY_STANDALONE(argv);
+ int result;
+ result = PYPY_STANDALONE(argv);
if (slp_frame_stack_bottom) {
slp_main_loop();
result = (int) slp_retval_long;
@@ -142,4 +156,5 @@
#endif /* PYPY_NOT_MAIN_FILE */
-#endif USE_STACKLESS
+#endif /* USE_STACKLESS */
+
Modified: pypy/branch/hl-backend/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/src/mem.h (original)
+++ pypy/branch/hl-backend/pypy/translator/c/src/mem.h Fri Oct 14 17:44:56 2005
@@ -3,6 +3,17 @@
/*** C header subsection: operations on LowLevelTypes ***/
+/* a reasonably safe bound on the largest allowed argument value
+ that we can pass to malloc. This is used for var-sized mallocs
+ to compute the largest allowed number of items in the array. */
+#define MAXIMUM_MALLOCABLE_SIZE (LONG_MAX-4096)
+
+#define OP_MAX_VARSIZE(numitems, itemtype, err) { \
+ if ((numitems) > (MAXIMUM_MALLOCABLE_SIZE / sizeof(itemtype))) \
+ FAIL_EXCEPTION(err, PyExc_MemoryError, "addr space overflow"); \
+ }
+
+
/* XXX hack to initialize the refcount of global structures: officially,
we need a value equal to the number of references to this global from
other globals, plus one. This upper bound "approximation" will do... */
Modified: pypy/branch/hl-backend/pypy/translator/c/src/support.h
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/src/support.h (original)
+++ pypy/branch/hl-backend/pypy/translator/c/src/support.h Fri Oct 14 17:44:56 2005
@@ -34,8 +34,13 @@
PyObject* PyList_Pack(int n, ...);
PyObject* PyDict_Pack(int n, ...);
PyObject* PyTuple_Pack(int n, ...);
+#if PY_VERSION_HEX >= 0x02030000 /* 2.3 */
+# define PyObject_GetItem1 PyObject_GetItem
+# define PyObject_SetItem1 PyObject_SetItem
+#else
PyObject* PyObject_GetItem1(PyObject* obj, PyObject* index);
PyObject* PyObject_SetItem1(PyObject* obj, PyObject* index, PyObject* v);
+#endif
PyObject* CallWithShape(PyObject* callable, PyObject* shape, ...);
PyObject* decode_arg(PyObject* fname, int position, PyObject* name,
PyObject* vargs, PyObject* vkwds, PyObject* def);
@@ -168,10 +173,7 @@
}
#endif
-#if PY_VERSION_HEX >= 0x02030000 /* 2.3 */
-# define PyObject_GetItem1 PyObject_GetItem
-# define PyObject_SetItem1 PyObject_SetItem
-#else
+#if PY_VERSION_HEX < 0x02030000 /* 2.3 */
/* for Python 2.2 only */
PyObject* PyObject_GetItem1(PyObject* obj, PyObject* index)
{
Modified: pypy/branch/hl-backend/pypy/translator/c/stackless.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/stackless.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/stackless.py Fri Oct 14 17:44:56 2005
@@ -11,16 +11,18 @@
from pypy.translator.c.support import cdecl
from pypy.translator.c.funcgen import FunctionCodeGenerator
-
class StacklessData:
def __init__(self):
self.frame_types = {}
- self.globalstatecounter = 1
self.allsignatures = {}
self.decode_table = []
+
# start the decoding table with entries for the functions that
# are written manually in ll_stackless.h
+ self.registerunwindable('LL_stackless_stack_unwind',
+ lltype.FuncType([], lltype.Void),
+ resume_points=1)
self.registerunwindable('LL_stackless_stack_frames_depth',
lltype.FuncType([], lltype.Signed),
resume_points=1)
@@ -36,12 +38,17 @@
for n in range(1, resume_points):
self.decode_table.append(('NULL', n))
- def get_frame_type(self, n_integers, n_floats, n_pointers):
- key = n_integers, n_floats, n_pointers
+ def get_frame_type(self, counts):
+ """Return the frame struct name,
+ named after the number of saved variables of each kind.
+ counts is a sequence of numbers, ordered like STATE_TYPES
+ """
+ key = tuple(counts)
try:
return self.frame_types[key]
except KeyError:
- name = 'slp_frame_%d_%d_%d_s' % key
+ nums = "_".join([str(c) for c in key])
+ name = 'slp_frame_%s_s' % nums
self.frame_types[key] = name
return name
@@ -56,37 +63,38 @@
for line in sg.preimpl:
print >> fc, line
print >> fc, '#include "src/g_include.h"'
+
items = self.frame_types.items()
items.sort()
- for (n_integers, n_floats, n_pointers), structname in items:
- types = (['long']*n_integers +
- ['double']*n_floats +
- ['void *']*n_pointers)
- varnames = (['l%d' % i for i in range(n_integers)] +
- ['d%d' % i for i in range(n_floats)] +
- ['v%d' % i for i in range(n_pointers)])
+ for counts, structname in items:
+ varnames = []
+ for count, vartype in zip(counts, STATE_TYPES):
+ varnames.extend([(vartype.ctype, '%s%d' % (vartype.prefix, i))
+ for i in range(count)])
+
+ # generate the struct definition
fields = []
- for type, varname in zip(types, varnames):
+ for type, varname in varnames:
fields.append('%s %s;' % (type, varname))
print >> fi, 'struct %s { slp_frame_t header; %s };' % (
structname, ' '.join(fields))
+ # generate the 'save_' function
arguments = ['int state']
saving_lines = []
- for type, varname in zip(types, varnames):
+ for type, varname in varnames:
arguments.append('%s %s' % (type, varname))
saving_lines.append('((struct %s*) f)->%s = %s;' % (
structname, varname, varname))
- head = 'void *save_%(name)s(%(arguments)s);'
+ head = 'void save_%(name)s(%(arguments)s);'
code = str(py.code.Source('''
- void *save_%(name)s(%(arguments)s)
+ void save_%(name)s(%(arguments)s)
{
slp_frame_t* f = slp_new_frame(sizeof(struct %(name)s), state);
slp_frame_stack_bottom->f_back = f;
slp_frame_stack_bottom = f;
%(saving_lines)s
- return NULL;
}
'''))
argdict = {'name': structname,
@@ -110,11 +118,10 @@
functiontype = sg.database.gettype(lltype.Ptr(FUNC))
callexpr = '((%s) fn) (%s);' % (cdecl(functiontype, ''),
', '.join(dummyargs))
- globalretvalvartype = simplified_type(FUNC.RESULT)
+ globalretvalvartype = storage_type(FUNC.RESULT)
if globalretvalvartype is not None:
- globalretvalvarname = RETVALVARS[globalretvalvartype]
- callexpr = '%s = (%s) %s' % (globalretvalvarname,
- globalretvalvartype,
+ callexpr = '%s = (%s) %s' % (globalretvalvartype.global_name,
+ globalretvalvartype.ctype,
callexpr)
print >> fi, '\t' + callexpr
print >> fi, '\tbreak;'
@@ -163,11 +170,10 @@
# record extra data needed to generate the slp_*.h tables:
# find the signatures of all functions
slpdata = self.db.stacklessdata
- argtypes = [erase_ptr_type(v.concretetype)
+ argtypes = [signature_type(self.lltypemap(v))
for v in self.graph.getargs()]
argtypes = [T for T in argtypes if T is not lltype.Void]
- import sys
- rettype = erase_ptr_type(self.graph.getreturnvar().concretetype)
+ rettype = signature_type(self.lltypemap(self.graph.getreturnvar()))
FUNC = lltype.FuncType(argtypes, rettype)
slpdata.registerunwindable(self.functionname, FUNC,
resume_points = len(self.resumeblocks))
@@ -179,49 +185,38 @@
stacklessdata = self.db.stacklessdata
block = self.currentblock
curpos = block.operations.index(op)
-
- # XXX obscure: find all variables that are produced before 'op'
- vars = []
- for v in block.inputargs:
- vars.append(v)
- for op1 in block.operations[:curpos]:
- vars.append(op1.result)
+ vars = list(variables_to_save_across_op(block, curpos))
# get the simplified frame struct that can store these vars
- counts = {"long": [],
- "double": [],
- "void*": []}
+ counts = dict([(type, []) for type in STATE_TYPES])
variables_to_restore = []
for v in vars:
- st = simplified_type(erase_ptr_type(v.concretetype))
+ st = storage_type(self.lltypemap(v))
if st is not None: # ignore the Voids
varname = self.expr(v)
- # XXX hackish: the name of the field in the structure is
- # computed from the 1st letter of the 'st' type, counting
- # from 0 for each of the 'st' types independently
+ # The name of the field in the structure is computed from
+ # the prefix of the 'st' type, counting from 0 for each
+ # of the 'st' types independently
variables_to_restore.append((v, '%s%d' % (
- st[0], len(counts[st]))))
- counts[st].append('(%s)%s' % (st, varname))
- structname = stacklessdata.get_frame_type(len(counts["long"]),
- len(counts["double"]),
- len(counts["void*"]))
+ st.prefix, len(counts[st]))))
+ counts[st].append('(%s)%s' % (st.ctype, varname))
+ structname = stacklessdata.get_frame_type([len(counts[st]) for st in STATE_TYPES])
# reorder the vars according to their type
- vars = counts["long"] + counts["double"] + counts["void*"]
+ vars = sum([counts[st] for st in STATE_TYPES],[])
# generate the 'save:' line, e.g.
# save_0: return (int) save_frame_1(0, (long) n);
savelabel = 'save_%d' % len(self.savelines)
- arguments = ['%d' % stacklessdata.globalstatecounter] + vars
- stacklessdata.globalstatecounter += 1
+
+ # The globally unique number for our state
+ # is the total number of saved states so far
+ globalstatecounter = len(stacklessdata.decode_table) + len(self.savelines)
+
+ arguments = ['%d' % globalstatecounter] + vars
+
savecall = 'save_%s(%s);' % (structname, ', '.join(arguments))
- retvar = self.graph.getreturnvar()
- if retvar.concretetype is lltype.Void:
- savecall += ' return;'
- else:
- retvartype = self.lltypename(retvar)
- savecall = 'return (%s) %s' % (cdecl(retvartype, ''),
- savecall)
+ savecall += ' return %s;' % self.error_return_value()
self.savelines.append('%s: %s' % (savelabel, savecall))
# generate the resume block, e.g.
@@ -238,9 +233,9 @@
varname, cdecl(vartype, ''), structname, fieldname))
retvarname = self.expr(op.result)
retvartype = self.lltypename(op.result)
- retvarst = simplified_type(erase_ptr_type(op.result.concretetype))
+ retvarst = storage_type(self.lltypemap(op.result))
if retvarst is not None:
- globalretvalvarname = RETVALVARS[retvarst]
+ globalretvalvarname = retvarst.global_name
lines.append('%s = (%s) %s;' % (
retvarname, cdecl(retvartype, ''), globalretvalvarname))
lines.append('goto %s;' % (resumelabel,))
@@ -248,17 +243,18 @@
# add the checks for the unwinding case just after the directcall
# in the source
- unwind_check = "if (slp_frame_stack_bottom) goto %s;" % (savelabel,)
+ unwind_check = "if (slp_frame_stack_bottom)\n\tgoto %s;" % (savelabel,)
exception_check = (super(SlpFunctionCodeGenerator, self)
.check_directcall_result(op, err))
- return '%s\n %s:\n\t%s' % (unwind_check,
- resumelabel,
- exception_check)
+ return '%s\n %s:\n%s' % (unwind_check,
+ resumelabel,
+ exception_check)
-def erase_ptr_type(T):
+def signature_type(T):
"""Return T unless it's a pointer type, in which case we return a general
basic pointer type.
+ The returned type must have the same behaviour when put on the C stack.
"""
if isinstance(T, lltype.Ptr):
return Address
@@ -266,20 +262,55 @@
return T
-def simplified_type(T):
+class StateVariableType:
+ def __init__(self, ctype, prefix, global_name):
+ self.ctype = ctype
+ self.prefix = prefix
+ self.global_name = global_name
+
+STATE_TYPES = [
+ StateVariableType('long', 'l', 'slp_retval_long'),
+ StateVariableType('void*', 'p', 'slp_retval_voidptr'),
+ StateVariableType('double', 'd', 'slp_retval_double'),
+ ]
+
+def storage_type(T):
+ """Return the type used to save values of this type
+ """
if T is lltype.Void:
return None
elif T is lltype.Float:
- return "double"
- elif T is Address:
- return "void*"
+ return STATE_TYPES[ 2 ]
+ elif T is Address or isinstance(T, lltype.Ptr):
+ return STATE_TYPES[ 1 ]
elif isinstance(T, lltype.Primitive):
- return "long" # large enough for all other primitives
+ return STATE_TYPES[ 0 ] # long is large enough for all other primitives
else:
raise Exception("don't know about %r" % (T,))
-RETVALVARS = {
- "double": "slp_retval_double",
- "long" : "slp_retval_long",
- "void*" : "slp_retval_voidptr",
- }
+def variables_to_save_across_op(block, opindex):
+ # variable lifetime detection:
+ # 1) find all variables that are produced before the operation
+ produced = {}
+ for v in block.inputargs:
+ produced[v] = True
+ for op1 in block.operations[:opindex]:
+ produced[op1.result] = True
+ # 2) find all variables that are used by or after the operation
+ consumed = {}
+ for op1 in block.operations[opindex:]:
+ for v in op1.args:
+ if isinstance(v, Variable):
+ consumed[v] = True
+ if isinstance(block.exitswitch, Variable):
+ consumed[block.exitswitch] = True
+ for link in block.exits:
+ for v in link.args:
+ if isinstance(v, Variable):
+ consumed[v] = True
+ # 3) variables that are atomic and not consumed after the operation
+ # don't have to have their lifetime extended; that leaves only
+ # the ones that are not atomic or consumed.
+ for v in produced:
+ if v in consumed or not v.concretetype._is_atomic():
+ yield v
Modified: pypy/branch/hl-backend/pypy/translator/c/test/test_annotated.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/test/test_annotated.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/test/test_annotated.py Fri Oct 14 17:44:56 2005
@@ -1,5 +1,5 @@
import autopath
-import py
+import py, sys
from pypy.translator.tool.cbuild import skip_missing_compiler
from pypy.translator.translator import Translator
@@ -167,13 +167,13 @@
assert fn(-4.5) == 92.125
assert fn(4.5) == 90.125
- def test_recursion_detection(self):
- def f(n=int, accum=int):
- if n == 0:
- return accum
- else:
- return f(n-1, accum*n)
+ def test_memoryerror(self):
+ def f(i=int):
+ lst = [0]*i
+ lst[-1] = 5
+ return lst[0]
fn = self.getcompiled(f)
- assert fn(7, 1) == 5040
- py.test.skip("recursion detection: in-progress")
- py.test.raises(RuntimeError, fn, -1, 0)
+ assert fn(1) == 5
+ assert fn(2) == 0
+ py.test.raises(MemoryError, fn, sys.maxint//2+1)
+ py.test.raises(MemoryError, fn, sys.maxint)
Modified: pypy/branch/hl-backend/pypy/translator/c/test/test_extfunc.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/test/test_extfunc.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/test/test_extfunc.py Fri Oct 14 17:44:56 2005
@@ -23,14 +23,18 @@
f1 = compile(does_stuff, [])
t0 = time.clock()
t1 = f1()
- t0 = (t0 + time.clock()) / 2.0
- correct = t0 - t1
- # now we can compare!
- t0 = time.clock()
- t1 = f1() + correct
- assert type(t1) is float
t2 = time.clock()
- assert t0 <= t1 <= t2
+ t3 = f1()
+ t4 = time.clock()
+ t5 = f1()
+ t6 = time.clock()
+ # time.clock() and t1() might have a different notion of zero, so
+ # we can only subtract two numbers returned by the same function.
+ assert 0 <= t2-t0
+ assert 0 <= t3-t1 <= t4-t0
+ assert 0 <= t4-t2 <= t5-t1 <= t6-t0
+ assert 0 <= t5-t3 <= t6-t2
+ assert 0 <= t6-t4
def test_time_sleep():
def does_nothing():
Modified: pypy/branch/hl-backend/pypy/translator/c/test/test_lladdresses.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/test/test_lladdresses.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/test/test_lladdresses.py Fri Oct 14 17:44:56 2005
@@ -71,4 +71,18 @@
res = fc()
assert res
-
+def test_pointer_comparison():
+ def f():
+ result = 0
+ for addr1 in [raw_malloc(1), NULL]:
+ addr2 = addr1 + 1
+ result = result * 2 + int(addr1 == addr2)
+ result = result * 2 + int(addr1 != addr2)
+ result = result * 2 + int(addr1 < addr2)
+ result = result * 2 + int(addr1 <= addr2)
+ result = result * 2 + int(addr1 > addr2)
+ result = result * 2 + int(addr1 >= addr2)
+ return result
+ fc = compile(f, [])
+ res = fc()
+ assert res == int('011100' * 2, 2)
Modified: pypy/branch/hl-backend/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/test/test_standalone.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/test/test_standalone.py Fri Oct 14 17:44:56 2005
@@ -1,8 +1,8 @@
from pypy.translator.translator import Translator
-from pypy.translator.tool.cbuild import build_executable
+from pypy.translator.tool.cbuild import build_executable
from pypy.annotation.model import SomeList, SomeString
from pypy.annotation.listdef import ListDef
-from pypy.rpython.objectmodel import stack_frames_depth
+from pypy.rpython.objectmodel import stack_unwind, stack_frames_depth, stack_too_big
import os
@@ -14,19 +14,19 @@
for s in argv:
os.write(1, " '" + str(s) + "'\n")
return 0
-
+
t = Translator(entry_point)
s_list_of_strings = SomeList(ListDef(None, SomeString()))
t.annotate([s_list_of_strings])
t.specialize()
cbuilder = t.cbuilder(standalone=True)
cbuilder.generate_source()
- cbuilder.compile()
+ cbuilder.compile()
data = cbuilder.cmdexec('hi there')
assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''')
-def test_stack_unwind():
+def test_stack_depth():
def g1():
"just to check Void special cases around the code"
def g2(ignored):
@@ -64,6 +64,64 @@
data = wrap_stackless_function(fn)
assert data.strip() == '10'
+def test_stackless_manytimes():
+ def f(n):
+ if n > 0:
+ stack_frames_depth()
+ res = f(n-1)
+ else:
+ res = stack_frames_depth(), 1
+ return res
+
+ def fn():
+ count0, _ = f(0)
+ count10, _ = f(100)
+ return count10 - count0
+
+ data = wrap_stackless_function(fn)
+ assert data.strip() == '100'
+
+def test_stackless_arguments():
+ def f(n, d, t):
+ if n > 0:
+ res = f(n-1, d, t)
+ else:
+ res = stack_frames_depth(), d, t
+ return res
+
+ def fn():
+ count0, d, t = f(0, 5.5, (1, 2))
+ count10, d, t = f(10, 5.5, (1, 2))
+ return "[" + str(count10 - count0) + ", " + str(d) + ", " + str(t[0]) + ", " + str(t[1]) + "]"
+
+ data = wrap_stackless_function(fn)
+ assert eval(data) == [10, 5.5, 1, 2]
+
+
+def test_stack_too_big():
+ def f1():
+ return stack_too_big()
+ def f2():
+ return lst[1]()
+ def f3():
+ return lst[2]()
+ def f4():
+ return lst[3]()
+ def f5():
+ return lst[4]()
+ lst = [None,f1,f2,f3,f4,f5]
+
+ def f(n):
+ if lst[5]():
+ return n
+ return f(n)+1
+
+ def fn():
+ return f(0)
+ data = wrap_stackless_function(fn)
+ assert int(data.strip()) > 500
+
+
def wrap_stackless_function(fn):
def entry_point(argv):
@@ -72,10 +130,29 @@
t = Translator(entry_point)
s_list_of_strings = SomeList(ListDef(None, SomeString()))
- t.annotate([s_list_of_strings])
+ ann = t.annotate([s_list_of_strings])
t.specialize()
cbuilder = t.cbuilder(standalone=True)
cbuilder.stackless = True
cbuilder.generate_source()
- cbuilder.compile()
+ cbuilder.compile()
return cbuilder.cmdexec('')
+
+def test_stack_unwind():
+ def f():
+ stack_unwind()
+ return 42
+
+ data = wrap_stackless_function(f)
+ assert int(data.strip()) == 42
+
+def test_auto_stack_unwind():
+ def f(n):
+ if n == 1:
+ return 1
+ return (n+f(n-1)) % 1291
+
+ def fn():
+ return f(10**6)
+ data = wrap_stackless_function(fn)
+ assert int(data.strip()) == 704
Modified: pypy/branch/hl-backend/pypy/translator/c/test/test_typed.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/c/test/test_typed.py (original)
+++ pypy/branch/hl-backend/pypy/translator/c/test/test_typed.py Fri Oct 14 17:44:56 2005
@@ -1,5 +1,6 @@
import autopath
import sys
+import py
from py.test import raises
from pypy.translator.translator import Translator
from pypy.translator.test import snippet
@@ -398,3 +399,13 @@
f = self.getcompiled(fn)
for args in [2, 7, 0], [7, 2, 0], [10, 50, 7], [50, -10, -3]:
assert f(*args) == intmask(fn(*args))
+
+ def test_recursion_detection(self):
+ def f(n=int, accum=int):
+ if n == 0:
+ return accum
+ else:
+ return f(n-1, accum*n)
+ fn = self.getcompiled(f)
+ assert fn(7, 1) == 5040
+ py.test.raises(RuntimeError, fn, -1, 0)
Modified: pypy/branch/hl-backend/pypy/translator/goal/bench-windows.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/goal/bench-windows.py (original)
+++ pypy/branch/hl-backend/pypy/translator/goal/bench-windows.py Fri Oct 14 17:44:56 2005
@@ -78,7 +78,7 @@
CREATIONFLAGS = win32con.HIGH_PRIORITY_CLASS
print "configured to run under high priority"
-BENCH_EXECONFIG = 'bench_windows_exe.txt'
+BENCH_EXECONFIG = '_bench_windows_exe.txt'
bench_exe = None
def reference(progname):
@@ -103,16 +103,22 @@
size += os.path.getsize(win32api.GetModuleFileName(int(dll)))
return ver, size
-def run_pystone(executable=reference('python'), n=0):
- argstr = PYSTONE_CMD % (str(n) and n or '')
- txt = run_cmd('%s -c "%s"' % (executable, argstr))
+def run_pystone(executable=reference('python'), n=0, rpy=False):
+ if rpy:
+ txt = run_cmd('%s pystone' % executable)
+ else:
+ argstr = PYSTONE_CMD % (str(n) and n or '')
+ txt = run_cmd('%s -c "%s"' % (executable, argstr))
res = get_result(txt, PYSTONE_PATTERN)
print res
return res
-def run_richards(executable=reference('python'), n=20):
- argstr = RICHARDS_CMD % n
- txt = run_cmd('%s -c "%s"' % (executable, argstr))
+def run_richards(executable=reference('python'), n=20, rpy=False):
+ if rpy:
+ txt = run_cmd('%s richards' % executable)
+ else:
+ argstr = RICHARDS_CMD % n
+ txt = run_cmd('%s -c "%s"' % (executable, argstr))
res = get_result(txt, RICHARDS_PATTERN)
print res
return res
@@ -122,7 +128,7 @@
exes.sort()
return exes
-STAT_FILE = 'bench_windows.dump'
+STAT_FILE = '_bench_windows.dump'
def load_stats(statfile=STAT_FILE):
try:
dic = pickle.load(file(statfile, 'rb'))
@@ -134,9 +140,11 @@
pickle.dump(dic, file(statfile, 'wb'))
HEADLINE = '''\
-executable richards pystone size (MB)'''
+executable richards pystone size (MB)'''
FMT = '''\
-%-27s''' + '%5d %5.1fx %7.1f %5.1fx %5.2f'
+%-27s''' + '%5d %5.1fx' + ' %9.1f %5.1fx %5.3f'
+FMT2 = '''\
+%-27s''' + '%5.3f %5.1f/' + ' %9.1f %5.1f/ %5.3f'
def main():
print 'getting the richards reference'
@@ -149,25 +157,30 @@
exename = os.path.splitext(exe)[0]
mtime = os.path.getmtime(exe)
size = os.path.getsize(exe)
+ rpy = size < 500000
key = md5.new(file(exe,'rb').read()).digest()
if key in prior:
print 'skipped', exename
resdic[key] = prior[key][:2] + (exename, mtime, size)
else:
- resdic[key] = (run_richards(exe, 2), run_pystone(exe, 20000),
+ resdic[key] = (run_richards(exe, 2,rpy), run_pystone(exe, 20000, rpy),
exename, mtime, size)
prior[key] = resdic[key] # save result, temporarily
save_stats(prior)
save_stats(resdic) # save cleaned result
- res = [ (mtime, exe, size, rich, stone)
+ res = [ (stone / rich, exe, size, rich, stone)
for rich, stone, exe, mtime, size in resdic.values()]
version, size = run_version_size()
- res.append( (9e9, 'python %s' % version, size, ref_rich, ref_stone) )
+ res.append( (1.0, 'python %s' % version, size, ref_rich, ref_stone) )
res.sort()
print HEADLINE
- for mtime, exe, size, rich, stone in res:
- print FMT % (exe, rich, rich / ref_rich, stone, ref_stone / stone,
- size / float(1024 * 1024))
+ for speed2, exe, size, rich, stone in res:
+ if speed2 <= 1.0:
+ print FMT % (exe, rich, rich / ref_rich, stone, ref_stone / stone,
+ size / float(1024 * 1024))
+ else:
+ print FMT2 % (exe, rich, ref_rich / rich, stone, stone / ref_stone,
+ size / float(1024 * 1024))
if __name__ == '__main__':
main()
Modified: pypy/branch/hl-backend/pypy/translator/goal/driver.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/goal/driver.py (original)
+++ pypy/branch/hl-backend/pypy/translator/goal/driver.py Fri Oct 14 17:44:56 2005
@@ -16,6 +16,7 @@
DEFAULT_OPTIONS = optparse.Values(defaults={
'gc': 'ref',
+ 'stackless': False,
'debug': True,
'insist': False,
'backend': 'c',
@@ -189,6 +190,7 @@
gcpolicy = gc.NoneGcPolicy
cbuilder = translator.cbuilder(standalone=standalone, gcpolicy=gcpolicy)
+ cbuilder.stackless = opt.stackless
c_source_filename = cbuilder.generate_source()
self.log.info("written: %s" % (c_source_filename,))
self.cbuilder = cbuilder
Modified: pypy/branch/hl-backend/pypy/translator/goal/targetnopstandalone.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/goal/targetnopstandalone.py (original)
+++ pypy/branch/hl-backend/pypy/translator/goal/targetnopstandalone.py Fri Oct 14 17:44:56 2005
@@ -1,3 +1,12 @@
+"""
+A simple standalone target.
+
+The target below specifies None as the argument types list.
+This is a case treated specially in driver.py . If the list
+of input types is empty, it is meant to be a list of strings,
+actually implementing argv of the executable.
+"""
+
import os, sys
def debug(msg):
@@ -6,11 +15,10 @@
# __________ Entry point __________
def entry_point(argv):
- debug("done!")
+ debug("hello world")
return 0
# _____ Define and setup target ___
def target(*args):
return entry_point, None
-
Modified: pypy/branch/hl-backend/pypy/translator/goal/targetrichards.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/goal/targetrichards.py (original)
+++ pypy/branch/hl-backend/pypy/translator/goal/targetrichards.py Fri Oct 14 17:44:56 2005
@@ -1,7 +1,9 @@
from pypy.translator.goal import richards
+from pypy.translator.tool.taskengine import SimpleTaskEngine
entry_point = richards.entry_point
+
# _____ Define and setup target ___
def target(*args):
@@ -18,3 +20,34 @@
richards.main(iterations=5)
+class Tasks(SimpleTaskEngine):
+
+ def task_annotate(self):
+ pass
+ task_annotate.task_deps = []
+
+ def task
+
+
+""" sketch of tasks for translation:
+
+annotate: # includes annotation and annotatation simplifications
+
+rtype: annotate
+
+backendoptimisations: rtype # make little sense otherwise
+
+source_llvm: backendoptimisations, rtype, annotate
+
+source_c: ?backendoptimisations, ?rtype, ?annotate
+
+compile_c : source_c
+
+compile_llvm: source_llvm
+
+run_c: compile_c
+
+run_llvm: compile_llvm
+
+"""
+
Modified: pypy/branch/hl-backend/pypy/translator/goal/translate_pypy.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/goal/translate_pypy.py (original)
+++ pypy/branch/hl-backend/pypy/translator/goal/translate_pypy.py Fri Oct 14 17:44:56 2005
@@ -49,6 +49,7 @@
'1_backend': [OPT(('-b', '--backend'), "Backend", ['c', 'llvm'])],
'2_gc': [OPT(('--gc',), "Garbage collector", ['boehm', 'ref', 'none'])],
+ '3_stackless': [OPT(('--stackless',), "Stackless code generation", True)],
},
@@ -97,6 +98,7 @@
'gc': 'boehm',
'backend': 'c',
+ 'stackless': False,
'batch': False,
'text': False,
Modified: pypy/branch/hl-backend/pypy/translator/js/arraynode.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/arraynode.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/arraynode.py Fri Oct 14 17:44:56 2005
@@ -39,14 +39,14 @@
# ______________________________________________________________________
# entry points from genllvm
#
- def writedatatypedecl(self, codewriter):
- codewriter.arraydef(self.ref,
- 'int',
- self.db.repr_type(self.arraytype))
-
- def writedecl(self, codewriter):
- # declaration for constructor
- codewriter.declare(self.constructor_decl)
+ #def writedatatypedecl(self, codewriter):
+ # codewriter.arraydef(self.ref,
+ # 'int',
+ # self.db.repr_type(self.arraytype))
+
+ #def writedecl(self, codewriter):
+ # # declaration for constructor
+ # codewriter.declare(self.constructor_decl)
class VoidArrayTypeNode(LLVMNode):
@@ -58,9 +58,9 @@
self.array = array
self.ref = "arraytype_Void"
- def writedatatypedecl(self, codewriter):
- td = "%s = type { int }" % self.ref
- codewriter.append(td)
+ #def writedatatypedecl(self, codewriter):
+ # td = "%s = type { int }" % self.ref
+ # codewriter.append(td)
class ArrayNode(ConstantLLVMNode):
""" An arraynode. Elements can be
@@ -91,6 +91,12 @@
if p is not None:
self.db.prepare_constant(lltype.typeOf(p), p)
+ def writedecl(self, codewriter):
+ if self.arraytype is lltype.Char: #or use seperate nodetype
+ codewriter.declare(self.ref + ' = new String()')
+ else:
+ codewriter.declare(self.ref + ' = new Array()')
+
def get_length(self):
""" returns logical length of array """
items = self.value.items
@@ -109,21 +115,22 @@
return "{ int, [%s x %s] }" % (arraylen, typeval)
def get_ref(self):
+ return self.ref
#typeval = self.db.repr_type(lltype.typeOf(self.value))
#ref = "cast (%s* %s to %s*)" % (self.get_typerepr(), self.ref, typeval)
- p, c = lltype.parentlink(self.value)
- assert p is None, "child arrays are NOT needed by rtyper"
+ #p, c = lltype.parentlink(self.value)
+ #assert p is None, "child arrays are NOT needed by rtyper"
#return ref
- return self.ref
def get_pbcref(self, toptr):
- ref = self.ref
- p, c = lltype.parentlink(self.value)
- assert p is None, "child arrays are NOT needed by rtyper"
-
- fromptr = "%s*" % self.get_typerepr()
- ref = "cast(%s %s to %s)" % (fromptr, ref, toptr)
- return ref
+ return self.ref
+ #ref = self.ref
+ #p, c = lltype.parentlink(self.value)
+ #assert p is None, "child arrays are NOT needed by rtyper"
+ #
+ #fromptr = "%s*" % self.get_typerepr()
+ #ref = "cast(%s %s to %s)" % (fromptr, ref, toptr)
+ #return ref
def get_childref(self, index):
return "getelementptr(%s* %s, int 0, uint 1, int %s)" %(
@@ -156,9 +163,6 @@
def get_arrayvalue(self):
items = self.value.items
item_length = len(items)
- if item_length == 0 or items[-1] != chr(0):
- items = items + [chr(0)]
- item_length += 1
s = []
for c in items:
if ord(c) in StrArrayNode.printables:
@@ -166,7 +170,7 @@
else:
s.append("\\%02x" % ord(c))
- r = 'c"%s"' % "".join(s)
+ r = '"%s"' % "".join(s)
return item_length, r
class VoidArrayNode(ConstantLLVMNode):
Modified: pypy/branch/hl-backend/pypy/translator/js/codewriter.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/codewriter.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/codewriter.py Fri Oct 14 17:44:56 2005
@@ -11,13 +11,18 @@
def __init__(self, f, js):
self.f = f
self.js = js
+ self._skip_closeblock = False
def append(self, line, indentation_level=4):
if indentation_level:
s = self.tabstring * indentation_level
else:
s = ''
- self.f.write(s + line + '\n')
+ if not line or line[-1] in '{:};' or line.lstrip()[:2] == '//':
+ eol = '\n'
+ else:
+ eol = ';\n'
+ self.f.write(s + line + eol)
def comment(self, line, indentation_level=4):
self.append("// " + line, indentation_level)
@@ -30,10 +35,15 @@
def label(self, name):
self.append("case %d:" % name, 3)
- openblock = label
+
+ def openblock(self, name):
+ self.append("case %d:" % name, 3)
+ self._currentblock = name
def closeblock(self):
- self.append('continue')
+ if not self._skip_closeblock:
+ self.append('break')
+ self._skip_closeblock = False
def globalinstance(self, name, typeanddata):
#self.append('%s = %s' % (name, typeanddata[1:].split('{')[1][:-1]), 0)
@@ -44,32 +54,61 @@
self.llvm(line, 0)
def structdef(self, name, typereprs):
- self.llvm("%s = type { %s }" %(name, ", ".join(typereprs)), 0)
+ #self.llvm("%s = type { %s }" %(name, ", ".join(typereprs)), 0)
+ pass
def arraydef(self, name, lentype, typerepr):
- self.llvm("%s = type { %s, [0 x %s] }" % (name, lentype, typerepr), 0)
+ #self.llvm("%s = type { %s, [0 x %s] }" % (name, lentype, typerepr), 0)
+ pass
def funcdef(self, name, rettyperepr, argtypereprs):
- self.llvm("%s = type %s (%s)" % (name, rettyperepr,
- ", ".join(argtypereprs)), 0)
+ #self.llvm("%s = type %s (%s)" % (name, rettyperepr,
+ # ", ".join(argtypereprs)), 0)
+ pass
def declare(self, decl):
- #self.llvm("declare %s" % decl, 0)
- pass
+ self.append(decl, 0)
def startimpl(self):
#self.llvm("implementation", 0)
pass
- def br_uncond(self, blockname):
- self.append('prevblock = block')
- self.append('block = %d' % blockname)
- #self.llvm("br label %s" %(blockname,))
-
- def br(self, cond, blockname_false, blockname_true):
- self.append('prevblock = block')
- self.append('block = %s ? %d : %d' % (cond, blockname_true, blockname_false))
- #self.llvm("br bool %s, label %s, label %s" % (cond, blockname_true, blockname_false))
+ def _goto_block(self, block, indentation_level=4):
+ if block == self._currentblock + 1:
+ self._skip_closeblock = True
+ else:
+ self.append('block = ' + str(block), indentation_level)
+ self.append('break', indentation_level)
+
+ def _phi(self, targetblock, exit, indentation_level=4):
+ #self.comment('target.inputargs=%s, args=%s, targetblock=%d' % (exit.target.inputargs, exit.args, targetblock), indentation_level)
+ for i, exitarg in enumerate(exit.args):
+ dest = str(exit.target.inputargs[i])
+ #src = str(exitarg)
+ src = str(self.js.db.repr_arg(exitarg))
+ if src == 'False':
+ src = 'false'
+ elif src == 'True':
+ src = 'true'
+ elif src == 'None':
+ src = 'undefined'
+ if dest != src:
+ self.append('%s = %s' % (dest, src), indentation_level)
+
+ def br_uncond(self, block, exit):
+ self._phi(block, exit)
+ self._goto_block(block)
+ self._skip_closeblock = True
+
+ def br(self, cond, block_false, exit_false, block_true, exit_true):
+ self.append('if (%s) {' % cond)
+ self._phi(block_true, exit_true, 5)
+ self._goto_block(block_true, 5)
+ self.append('} else {')
+ self._phi(block_false, exit_false, 5)
+ self._goto_block(block_false, 5)
+ self.append('}')
+ self._skip_closeblock = True
def switch(self, intty, cond, defaultdest, value_label):
labels = ''
@@ -84,6 +123,10 @@
self.blocks = blocks
usedvars = {} #XXX could probably be limited to inputvars
for block in blocks:
+ if block != blocks[0]: #don't double startblock inputargs
+ for inputarg in block.inputargs:
+ targetvar = self.js.db.repr_arg(inputarg)
+ usedvars[targetvar] = True
for op in block.operations:
targetvar = self.js.db.repr_arg(op.result)
usedvars[targetvar] = True
@@ -91,49 +134,20 @@
self.append("function %s {" % self.decl, 0)
if usedvars:
self.append("var %s" % ', '.join(usedvars.keys()), 1)
- self.append("var block = 0", 1)
- self.append("while (block != undefined) {", 1)
+ self.append("for (var block = 0;;) {", 1)
self.append("switch (block) {", 2)
def closefunc(self):
- self.append("} // end of switch (block)", 2)
- self.append("} // end of while (block != undefined)", 1)
- self.append("} // end of function %s" % self.decl, 0)
+ self.append("}", 2)
+ self.append("}", 1)
+ self.append("};", 0)
def ret(self, type_, ref):
if type_ == 'void':
self.append("return")
else:
self.append("return " + ref)
-
- def phi(self, targetvar, type_, refs, blocknames):
- assert refs and len(refs) == len(blocknames), "phi node requires blocks"
- #mergelist = ", ".join(
- # ["[%s, %s]" % item
- # for item in zip(refs, blocknames)])
- #s = "%s = phi %s %s" % (targetvar, type_, mergelist)
- #self.llvm(s)
- all_refs_identical = True
- for ref in refs:
- if ref != refs[0]:
- all_refs_identical = False
- break
- if all_refs_identical:
- if targetvar != refs[0]:
- self.append('%s = %s' % (targetvar, refs[0]))
- else:
- if len(blocknames) == 1:
- self.append('%s = %s' % (targetvar, refs[i]))
- else:
- n = 0
- for i, blockname in enumerate(blocknames):
- if targetvar != refs[i]:
- if n > 0:
- s = 'else '
- else:
- s = ''
- self.append('%sif (prevblock == %d) %s = %s' % (s, blockname, targetvar, refs[i]))
- n += 1
+ self._skip_closeblock = True
def binaryop(self, name, targetvar, type_, ref1, ref2):
self.append("%(targetvar)s = %(ref1)s %(name)s %(ref2)s" % locals())
@@ -155,10 +169,10 @@
self.append('%s = %s(%s)' % (targetvar, functionref, args))
def cast(self, targetvar, fromtype, fromvar, targettype):
- self.comment('codewriter cast 1 targettype=%(targettype)s, targetvar=%(targetvar)s, fromtype=%(fromtype)s, fromvar=%(fromvar)s' % locals())
+ #self.comment('codewriter cast 1 targettype=%(targettype)s, targetvar=%(targetvar)s, fromtype=%(fromtype)s, fromvar=%(fromvar)s' % locals())
if fromtype == 'void' and targettype == 'void':
return
- self.comment('codewriter cast 2')
+ #self.comment('codewriter cast 2')
if targettype == fromtype:
self.append("%(targetvar)s = %(fromvar)s" % locals())
elif targettype in ('int','uint',):
Modified: pypy/branch/hl-backend/pypy/translator/js/database.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/database.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/database.py Fri Oct 14 17:44:56 2005
@@ -213,7 +213,7 @@
return self.obj2node.itervalues()
# __________________________________________________________
- # Representing variables and constants in LLVM source code
+ # Representing variables and constants in Javascript source code
def repr_arg(self, arg):
if isinstance(arg, Constant):
@@ -242,7 +242,7 @@
if isinstance(type_, lltype.Primitive):
return self.primitives[type_]
elif isinstance(type_, lltype.Ptr):
- return self.repr_type(type_.TO) + '*'
+ return '' #self.repr_type(type_.TO) + 'XXX*'
else:
raise TypeError("cannot represent %r" %(type_,))
@@ -260,7 +260,8 @@
type_ = lltype.typeOf(value)
if isinstance(type_, lltype.Primitive):
repr = self.primitive_to_str(type_, value)
- return None, "%s %s" % (self.repr_type(type_), repr)
+ return None, repr
+ #return None, "%s %s" % (self.repr_type(type_), repr)
elif isinstance(type_, lltype.Ptr):
toptr = self.repr_type(type_)
@@ -333,13 +334,13 @@
# __________________________________________________________
# Other helpers
- def is_function_ptr(self, arg):
- if isinstance(arg, (Constant, Variable)):
- arg = arg.concretetype
- if isinstance(arg, lltype.Ptr):
- if isinstance(arg.TO, lltype.FuncType):
- return True
- return False
+ #def is_function_ptr(self, arg):
+ # if isinstance(arg, (Constant, Variable)):
+ # arg = arg.concretetype
+ # if isinstance(arg, lltype.Ptr):
+ # if isinstance(arg.TO, lltype.FuncType):
+ # return True
+ # return False
def get_childref(self, parent, child):
node = self.obj2node[parent]
Modified: pypy/branch/hl-backend/pypy/translator/js/funcnode.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/funcnode.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/funcnode.py Fri Oct 14 17:44:56 2005
@@ -22,7 +22,7 @@
self.db = db
assert isinstance(type_, lltype.FuncType)
self.type_ = type_
- self.ref = self.make_ref('%functiontype', '')
+ self.ref = self.make_ref('functiontype', '')
def __str__(self):
return "<FuncTypeNode %r>" % self.ref
@@ -31,10 +31,10 @@
self.db.prepare_type(self.type_.RESULT)
self.db.prepare_type_multi(self.type_._trueargs())
- def writedatatypedecl(self, codewriter):
- returntype = self.db.repr_type(self.type_.RESULT)
- inputargtypes = [self.db.repr_type(a) for a in self.type_._trueargs()]
- codewriter.funcdef(self.ref, returntype, inputargtypes)
+ #def writedatatypedecl(self, codewriter):
+ # returntype = self.db.repr_type(self.type_.RESULT)
+ # inputargtypes = [self.db.repr_type(a) for a in self.type_._trueargs()]
+ # codewriter.funcdef(self.ref, returntype, inputargtypes)
class FuncNode(ConstantLLVMNode):
__slots__ = "db value ref graph blockindex".split()
@@ -42,14 +42,15 @@
def __init__(self, db, value):
self.db = db
self.value = value
- self.ref = self.make_ref('pypy_', value.graph.name)
+ pypy_prefix = '' #pypy_
+ self.ref = self.make_ref(pypy_prefix, value.graph.name)
self.graph = value.graph
self.db.genllvm.exceptionpolicy.transform(self.db.translator, self.graph)
#remove_exception_mallocs(self.db.translator, self.graph, self.ref)
#merge_mallocs(self.db.translator, self.graph, self.ref)
- remove_double_links(self.db.translator, self.graph)
+ #remove_double_links(self.db.translator, self.graph)
def __str__(self):
return "<FuncNode %r>" %(self.ref,)
@@ -76,8 +77,8 @@
# ______________________________________________________________________
# main entry points from genllvm
- def writedecl(self, codewriter):
- codewriter.declare(self.getdecl())
+ #def writedecl(self, codewriter):
+ # codewriter.declare(self.getdecl())
def writeimpl(self, codewriter):
graph = self.graph
@@ -145,30 +146,30 @@
return self.ref + "(%s)" % ", ".join(inputargs)
def write_block(self, codewriter, block):
- self.write_block_phi_nodes(codewriter, block)
+ #self.write_block_phi_nodes(codewriter, block)
self.write_block_operations(codewriter, block)
self.write_block_branches(codewriter, block)
- def get_phi_data(self, block):
- data = []
- entrylinks = mkentrymap(self.graph)[block]
- entrylinks = [x for x in entrylinks if x.prevblock is not None]
- inputargs = self.db.repr_arg_multi(block.inputargs)
- inputargtypes = self.db.repr_arg_type_multi(block.inputargs)
- for i, (arg, type_) in enumerate(zip(inputargs, inputargtypes)):
- names = self.db.repr_arg_multi([link.args[i] for link in entrylinks])
- blocknames = [self.blockindex[link.prevblock] for link in entrylinks]
- for i, link in enumerate(entrylinks): #XXX refactor into a transformation
- if link.prevblock.exitswitch == Constant(last_exception) and \
- link.prevblock.exits[0].target != block:
- blocknames[i] += '_exception_found_branchto_' + self.blockindex[block]
- data.append( (arg, type_, names, blocknames) )
- return data
-
- def write_block_phi_nodes(self, codewriter, block):
- for arg, type_, names, blocknames in self.get_phi_data(block):
- if type_ != "void":
- codewriter.phi(arg, type_, names, blocknames)
+ #def get_phi_data(self, block):
+ # data = []
+ # entrylinks = mkentrymap(self.graph)[block]
+ # entrylinks = [x for x in entrylinks if x.prevblock is not None]
+ # inputargs = self.db.repr_arg_multi(block.inputargs)
+ # inputargtypes = self.db.repr_arg_type_multi(block.inputargs)
+ # for i, (arg, type_) in enumerate(zip(inputargs, inputargtypes)):
+ # names = self.db.repr_arg_multi([link.args[i] for link in entrylinks])
+ # blocknames = [self.blockindex[link.prevblock] for link in entrylinks]
+ # for i, link in enumerate(entrylinks): #XXX refactor into a transformation
+ # if link.prevblock.exitswitch == Constant(last_exception) and \
+ # link.prevblock.exits[0].target != block:
+ # blocknames[i] += '_exception_found_branchto_' + self.blockindex[block]
+ # data.append( (arg, type_, names, blocknames) )
+ # return data
+ #
+ #def write_block_phi_nodes(self, codewriter, block):
+ # for arg, type_, names, blocknames in self.get_phi_data(block):
+ # if type_ != "void":
+ # codewriter.phi(arg, type_, names, blocknames)
def write_block_branches(self, codewriter, block):
#assert len(block.exits) <= 2 #more exits are possible (esp. in combination with exceptions)
@@ -176,11 +177,12 @@
#codewriter.comment('FuncNode(ConstantLLVMNode) *last_exception* write_block_branches @%s@' % str(block.exits))
return
if len(block.exits) == 1:
- codewriter.br_uncond(self.blockindex[block.exits[0].target])
+ codewriter.br_uncond(self.blockindex[block.exits[0].target], block.exits[0])
elif len(block.exits) == 2:
cond = self.db.repr_arg(block.exitswitch)
- codewriter.br(cond, self.blockindex[block.exits[0].target],
- self.blockindex[block.exits[1].target])
+ codewriter.br(cond,
+ self.blockindex[block.exits[0].target], block.exits[0],
+ self.blockindex[block.exits[1].target], block.exits[1])
def write_block_operations(self, codewriter, block):
opwriter = OpWriter(self.db, codewriter, self, block)
@@ -212,7 +214,7 @@
def write_returnblock(self, codewriter, block):
assert len(block.inputargs) == 1
- self.write_block_phi_nodes(codewriter, block)
+ #self.write_block_phi_nodes(codewriter, block)
inputargtype = self.db.repr_arg_type(block.inputargs[0])
inputarg = self.db.repr_arg(block.inputargs[0])
codewriter.ret(inputargtype, inputarg)
Modified: pypy/branch/hl-backend/pypy/translator/js/js.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/js.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/js.py Fri Oct 14 17:44:56 2005
@@ -4,6 +4,7 @@
http://webreference.com/programming/javascript/
http://mochikit.com/
http://www.mozilla.org/js/spidermonkey/
+ svn co http://codespeak.net/svn/kupu/trunk/ecmaunit
'''
#import os
@@ -77,7 +78,7 @@
# codewriter.comment("External Function Declarations")
# codewriter.append(llexterns_header)
- codewriter.comment("Type Declarations", 0)
+ #codewriter.comment("Type Declarations", 0)
#for c_name, obj in extern_decls:
# if isinstance(obj, lltype.LowLevelType):
# if isinstance(obj, lltype.Ptr):
@@ -85,33 +86,33 @@
# l = "%%%s = type %s" % (c_name, self.db.repr_type(obj))
# codewriter.append(l)
+ codewriter.comment("Function Implementation", 0)
+ for typ_decl in self.db.getnodes():
+ typ_decl.writeimpl(codewriter)
+
+ codewriter.comment("Forward Declarations", 0)
+ #for typ_decl in self.db.getnodes():
+ # typ_decl.writedatatypedecl(codewriter)
for typ_decl in self.db.getnodes():
- typ_decl.writedatatypedecl(codewriter)
+ typ_decl.writedecl(codewriter)
codewriter.comment("Global Data", 0)
for typ_decl in self.db.getnodes():
typ_decl.writeglobalconstants(codewriter)
- codewriter.comment("Function Prototypes", 0)
+ #codewriter.comment("Function Prototypes", 0)
#codewriter.append(extdeclarations)
#codewriter.append(self.gcpolicy.declarations())
- for typ_decl in self.db.getnodes():
- typ_decl.writedecl(codewriter)
-
- codewriter.comment("Function Implementation", 0)
- codewriter.startimpl()
-
- for typ_decl in self.db.getnodes():
- typ_decl.writeimpl(codewriter)
+ pypy_prefix = '' #pypy_
#codewriter.append(self.exceptionpolicy.llvmcode(self.entrynode))
#
## XXX we need to create our own main() that calls the actual entry_point function
- #if entryfunc_name == 'pypy_entry_point': #XXX just to get on with translate_pypy
+ #if entryfunc_name == pypy_prefix + 'entry_point': #XXX just to get on with translate_pypy
# extfuncnode.ExternalFuncNode.used_external_functions['%main'] = True
#
- #elif entryfunc_name == 'pypy_main_noargs': #XXX just to get on with bpnn & richards
+ #elif entryfunc_name == pypy_prefix + 'main_noargs': #XXX just to get on with bpnn & richards
# extfuncnode.ExternalFuncNode.used_external_functions['%main_noargs'] = True
#
#for f in support_functions:
@@ -134,7 +135,7 @@
graph = self.db.obj2node[entry_point].graph
startblock = graph.startblock
args = ','.join(['arguments[%d]' % i for i,v in enumerate(startblock.inputargs)])
- self.wrappertemplate = "load('%s'); print(pypy_%s(%%s))" % (self.filename, graph.name)
+ self.wrappertemplate = "load('%s'); print(%s%s(%%s))" % (self.filename, pypy_prefix, graph.name)
#codewriter.newline()
#codewriter.comment("Wrapper code for the Javascript CLI", 0)
Modified: pypy/branch/hl-backend/pypy/translator/js/node.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/node.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/node.py Fri Oct 14 17:44:56 2005
@@ -32,10 +32,10 @@
pass
# __________________ before "implementation" ____________________
- def writedatatypedecl(self, codewriter):
- """ write out declare names of data types
- (structs/arrays/function pointers)
- """
+ #def writedatatypedecl(self, codewriter):
+ # """ write out declare names of data types
+ # (structs/arrays/function pointers)
+ # """
def writeglobalconstants(self, codewriter):
""" write out global values. """
Modified: pypy/branch/hl-backend/pypy/translator/js/opaquenode.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/opaquenode.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/opaquenode.py Fri Oct 14 17:44:56 2005
@@ -7,7 +7,7 @@
assert isinstance(opaquetype, lltype.OpaqueType)
self.db = db
self.opaquetype = opaquetype
- self.ref = "%%opaquetype.%s" % (opaquetype.tag)
+ self.ref = "opaquetype." + opaquetype.tag
def __str__(self):
return "<OpaqueNode %r>" %(self.ref,)
@@ -15,9 +15,9 @@
# ______________________________________________________________________
# main entry points from genllvm
- def writedatatypedecl(self, codewriter):
- # XXX Dummy - not sure what what we want
- codewriter.funcdef(self.ref, 'sbyte*', ['sbyte *'])
+ #def writedatatypedecl(self, codewriter):
+ # # XXX Dummy - not sure what what we want
+ # codewriter.funcdef(self.ref, 'sbyte*', ['sbyte *'])
class OpaqueNode(ConstantLLVMNode):
Modified: pypy/branch/hl-backend/pypy/translator/js/opwriter.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/opwriter.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/opwriter.py Fri Oct 14 17:44:56 2005
@@ -212,7 +212,7 @@
targettype = self.db.repr_arg_type(op.result)
fromvar = self.db.repr_arg(op.args[0])
fromtype = self.db.repr_arg_type(op.args[0])
- self.codewriter.comment(op.opname)
+ self.codewriter.comment('next line='+op.opname)
self.codewriter.cast(targetvar, fromtype, fromvar, targettype)
same_as = cast_primitive
@@ -254,8 +254,8 @@
functionref = self.db.repr_arg(op_args[0])
argrefs = self.db.repr_arg_multi(op_args[1:])
argtypes = self.db.repr_arg_type_multi(op_args[1:])
- if self.db.is_function_ptr(op.result):
- returntype = "%s (%s)*" % (returntype, ", ".join(argtypes))
+ #if self.db.is_function_ptr(op.result):
+ # returntype = "%s (%s)*" % (returntype, ", ".join(argtypes))
self.codewriter.call(targetvar,returntype,functionref,argrefs,argtypes)
def last_exception_type_ptr(self, op):
@@ -297,8 +297,8 @@
block_label = self.node.blockindex[self.block]
exc_label = block_label + '_exception_handling'
- if self.db.is_function_ptr(op.result): #use longhand form
- returntype = "%s (%s)*" % (returntype, ", ".join(argtypes))
+ #if self.db.is_function_ptr(op.result): #use longhand form
+ # returntype = "%s (%s)*" % (returntype, ", ".join(argtypes))
self.codewriter.call(targetvar, returntype, functionref, argrefs,
argtypes, none_label, exc_label)
@@ -407,35 +407,27 @@
def getfield(self, op):
tmpvar = self.db.repr_tmpvar()
struct, structtype = self.db.repr_argwithtype(op.args[0])
- index = self._getindexhelper(op.args[1].value, op.args[0].concretetype.TO)
targetvar = self.db.repr_arg(op.result)
targettype = self.db.repr_arg_type(op.result)
if targettype != "void":
- assert index != -1
- self.codewriter.getelementptr(tmpvar, structtype, struct,
- ("uint", index))
- self.codewriter.load(targetvar, targettype, tmpvar)
+ self.codewriter.append('%s = %s.%s' % (targetvar, struct, op.args[1].value)) #XXX move to codewriter
else:
self._skipped(op)
def getsubstruct(self, op):
struct, structtype = self.db.repr_argwithtype(op.args[0])
- index = self._getindexhelper(op.args[1].value, op.args[0].concretetype.TO)
+ #index = self._getindexhelper(op.args[1].value, op.args[0].concretetype.TO)
targetvar = self.db.repr_arg(op.result)
- targettype = self.db.repr_arg_type(op.result)
- assert targettype != "void"
- self.codewriter.getelementptr(targetvar, structtype,
- struct, ("uint", index))
+ #targettype = self.db.repr_arg_type(op.result)
+ #assert targettype != "void"
+ self.codewriter.append('%s = %s.%s' % (targetvar, struct, op.args[1].value)) #XXX move to codewriter
+ #self.codewriter.getelementptr(targetvar, structtype, struct, ("uint", index))
def setfield(self, op):
- tmpvar = self.db.repr_tmpvar()
struct, structtype = self.db.repr_argwithtype(op.args[0])
- index = self._getindexhelper(op.args[1].value, op.args[0].concretetype.TO)
valuevar, valuetype = self.db.repr_argwithtype(op.args[2])
if valuetype != "void":
- self.codewriter.getelementptr(tmpvar, structtype, struct,
- ("uint", index))
- self.codewriter.store(valuetype, valuevar, tmpvar)
+ self.codewriter.append('%s.%s = %s' % (struct, op.args[1].value, valuevar)) #XXX move to codewriter
else:
self._skipped(op)
@@ -479,8 +471,9 @@
def getarraysize(self, op):
array, arraytype = self.db.repr_argwithtype(op.args[0])
- tmpvar = self.db.repr_tmpvar()
- self.codewriter.getelementptr(tmpvar, arraytype, array, ("uint", 0))
+ #tmpvar = self.db.repr_tmpvar()
+ #self.codewriter.getelementptr(tmpvar, arraytype, array, ("uint", 0))
targetvar = self.db.repr_arg(op.result)
- targettype = self.db.repr_arg_type(op.result)
- self.codewriter.load(targetvar, targettype, tmpvar)
+ #targettype = self.db.repr_arg_type(op.result)
+ #self.codewriter.load(targetvar, targettype, tmpvar)
+ self.codewriter.append('%s = %s.length' % (targetvar, array)) #XXX move to codewriter
Modified: pypy/branch/hl-backend/pypy/translator/js/structnode.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/structnode.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/structnode.py Fri Oct 14 17:44:56 2005
@@ -5,6 +5,11 @@
log = log.structnode
+def _rename_reserved_keyword(name):
+ if name in 'if then else function for while witch continue break super int bool Array String Struct Number'.split():
+ name += '_'
+ return name
+
class StructTypeNode(LLVMNode):
__slots__ = "db struct ref name".split()
@@ -32,9 +37,9 @@
# ______________________________________________________________________
# main entry points from genllvm
- def writedatatypedecl(self, codewriter):
- fields_types = [self.db.repr_type(f) for f in self._fields()]
- codewriter.structdef(self.ref, fields_types)
+ #def writedatatypedecl(self, codewriter):
+ # fields_types = [self.db.repr_type(f) for f in self._fields()]
+ # codewriter.structdef(self.ref, fields_types)
class StructVarsizeTypeNode(StructTypeNode):
__slots__ = "constructor_ref constructor_decl".split()
@@ -53,9 +58,9 @@
# ______________________________________________________________________
# main entry points from genllvm
- def writedecl(self, codewriter):
- # declaration for constructor
- codewriter.declare(self.constructor_decl)
+ #def writedecl(self, codewriter):
+ # # declaration for constructor
+ # codewriter.declare(self.constructor_decl)
def writeimpl(self, codewriter):
log.writeimpl(self.ref)
@@ -83,7 +88,7 @@
self.db = db
self.value = value
self.structtype = self.value._TYPE
- prefix = '%structinstance.'
+ prefix = 'structinstance_'
name = str(value).split()[1]
self.ref = self.make_ref(prefix, name)
self._get_ref_cache = None
@@ -112,24 +117,26 @@
p, c = lltype.parentlink(self.value)
if p is not None:
self.db.prepare_constant(lltype.typeOf(p), p)
-
+
+ def writedecl(self, codewriter):
+ codewriter.declare(self.ref + ' = new Object()')
+
def get_typerepr(self):
return self.db.repr_type(self.structtype)
def get_childref(self, index):
- pos = 0
- found = False
- for name in self.structtype._names_without_voids():
- if name == index:
- found = True
- break
- pos += 1
- #Structure types require uint constants!
- #see: http://llvm.cs.uiuc.edu/docs/LangRef.html#i_getelementptr
- return "getelementptr(%s* %s, int 0, uint %s)" %(
- self.get_typerepr(),
- self.get_ref(),
- pos)
+ return self.get_ref() #XXX what to do with index?
+ #pos = 0
+ #found = False
+ #for name in self.structtype._names_without_voids():
+ # if name == index:
+ # found = True
+ # break
+ # pos += 1
+ #return "getelementptr(%s* %s, int 0, uint %s)" %(
+ # self.get_typerepr(),
+ # self.get_ref(),
+ # pos)
def get_ref(self):
""" Returns a reference as used for operations in blocks. """
@@ -146,12 +153,20 @@
def get_pbcref(self, toptr):
""" Returns a reference as used per pbc. """
return self.get_ref()
-
+
def constantvalue(self):
""" Returns the constant representation for this node. """
- values = self._getvalues()
- all_values = ",\n ".join(values)
- return "%s {\n %s\n }\n" % (self.get_typerepr(), all_values)
+ vars = []
+ for i, value in enumerate(self._getvalues()):
+ name = self._get_types[i][0]
+ name = _rename_reserved_keyword(name)
+ var = (name, str(value))
+ vars.append(var)
+ return "({%s})" % ", ".join(["%s:%s" % var for var in vars])
+
+ #values = self._getvalues()
+ #all_values = ",\n ".join(values)
+ #return "%s {\n %s\n }\n" % (self.get_typerepr(), all_values)
class StructVarsizeNode(StructNode):
@@ -206,22 +221,24 @@
return result
def get_ref(self):
- if self._get_ref_cache:
- return self._get_ref_cache
- ref = super(StructVarsizeNode, self).get_ref()
- typeval = self.db.repr_type(lltype.typeOf(self.value))
- ref = "cast (%s* %s to %s*)" % (self.get_typerepr(),
- ref,
- typeval)
- self._get_ref_cache = ref
- return ref
+ return self.ref
+ #if self._get_ref_cache:
+ # return self._get_ref_cache
+ #ref = super(StructVarsizeNode, self).get_ref()
+ #typeval = self.db.repr_type(lltype.typeOf(self.value))
+ #ref = "cast (%s* %s to %s*)" % (self.get_typerepr(),
+ # ref,
+ # typeval)
+ #self._get_ref_cache = ref
+ #return ref
def get_pbcref(self, toptr):
""" Returns a reference as used per pbc. """
- ref = self.ref
- p, c = lltype.parentlink(self.value)
- assert p is None, "child arrays are NOT needed by rtyper"
- fromptr = "%s*" % self.get_typerepr()
- refptr = "getelementptr (%s %s, int 0)" % (fromptr, ref)
- ref = "cast(%s %s to %s)" % (fromptr, refptr, toptr)
- return ref
+ return self.ref
+ #ref = self.ref
+ #p, c = lltype.parentlink(self.value)
+ #assert p is None, "child arrays are NOT needed by rtyper"
+ #fromptr = "%s*" % self.get_typerepr()
+ #refptr = "getelementptr (%s %s, int 0)" % (fromptr, ref)
+ #ref = "cast(%s %s to %s)" % (fromptr, refptr, toptr)
+ #return ref
Modified: pypy/branch/hl-backend/pypy/translator/js/test/test_genllvm1.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/js/test/test_genllvm1.py (original)
+++ pypy/branch/hl-backend/pypy/translator/js/test/test_genllvm1.py Fri Oct 14 17:44:56 2005
@@ -28,7 +28,7 @@
def test_ackermann(self):
f = compile_function(llvmsnippet.ackermann, [int, int])
- for i in range(10):
+ for i in range(7): #>7 js error: too much recursion?!?
assert f(0, i) == i + 1
assert f(1, i) == i + 2
assert f(2, i) == 2 * i + 3
Modified: pypy/branch/hl-backend/pypy/translator/llvm/build_llvm_module.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/llvm/build_llvm_module.py (original)
+++ pypy/branch/hl-backend/pypy/translator/llvm/build_llvm_module.py Fri Oct 14 17:44:56 2005
@@ -82,13 +82,19 @@
use_gcc = True
profile = False
+ cleanup = False
+
+ if sys.platform == 'darwin':
+ gc_libs_path = '-L/sw/lib -ldl'
+ else:
+ gc_libs_path = '-static'
cmds = ["llvm-as < %s.ll | opt %s -f -o %s.bc" % (b, OPTIMIZATION_SWITCHES, b)]
if not use_gcc:
cmds.append("llc %s %s.bc -f -o %s.s" % (genllvm.exceptionpolicy.llc_options(), b, b))
cmds.append("as %s.s -o %s.o" % (b, b))
if exe_name:
- cmd = "gcc %s.o %s -lm -ldl -pipe -o %s" % (b, gc_libs, exe_name)
+ cmd = "gcc %s.o %s %s -lm -pipe -o %s" % (b, gc_libs_path, gc_libs, exe_name)
cmds.append(cmd)
object_files.append("%s.o" % b)
else:
@@ -100,13 +106,13 @@
else:
cmd += ' -fomit-frame-pointer'
cmds.append(cmd)
- cmd = "gcc %s.o %s -lm -ldl -pipe -o %s" % (b, gc_libs, exe_name)
+ cmd = "gcc %s.o %s %s -lm -pipe -o %s" % (b, gc_libs_path, gc_libs, exe_name)
if profile:
cmd += ' -pg'
cmds.append(cmd)
source_files.append("%s.c" % b)
- if exe_name and not profile:
+ if cleanup and exe_name and not profile:
cmds.append('strip ' + exe_name)
upx = os.popen('which upx').read()
if upx: #compress file even further
Modified: pypy/branch/hl-backend/pypy/translator/llvm/externs2ll.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/llvm/externs2ll.py (original)
+++ pypy/branch/hl-backend/pypy/translator/llvm/externs2ll.py Fri Oct 14 17:44:56 2005
@@ -1,4 +1,5 @@
import os
+import sys
import types
import urllib
@@ -11,10 +12,20 @@
def get_ll(ccode, function_names):
+ filename = str(udir.join("ccode.c"))
+ f = open(filename, "w")
+ f.write(ccode)
+ f.close()
- # goto codespeak and compile our c code
- request = urllib.urlencode({'ccode':ccode})
- llcode = urllib.urlopen('http://codespeak.net/pypy/llvm-gcc.cgi', request).read()
+ if os.popen('which llvm-gcc').read(): #local llvm CFE available
+ #log('using local llvm-gcc')
+ plain = filename[:-2]
+ os.system("llvm-gcc -S %s.c -o %s.ll 2>&1" % (plain, plain))
+ llcode = open(plain + '.ll').read()
+ else: #as fallback use remove CFE. XXX local and remote should be similar machines!
+ #log('falling back on remote llvm-gcc')
+ request = urllib.urlencode({'ccode':ccode}) # goto codespeak and compile our c code
+ llcode = urllib.urlopen('http://codespeak.net/pypy/llvm-gcc.cgi', request).read()
# strip lines
ll_lines = []
@@ -134,13 +145,14 @@
include_files.append(j(j(os.path.dirname(extfunc.__file__), "src"), f + ".h"))
for f in include_files:
- ccode.append(open(f).read())
+ s = open(f).read()
+ if f.find('genexterns.c'):
+ if sys.platform == 'darwin':
+ python_h = '"/System/Library/Frameworks/Python.framework/Versions/2.3/include/python2.3/Python.h"'
+ else:
+ python_h = '<python2.3/Python.h>'
+ s = s.replace('__PYTHON_H__', python_h)
+ ccode.append(s)
ccode = "".join(ccode)
- if debug:
- filename = udir.join("ccode.c")
- f = open(str(filename), "w")
- f.write(ccode)
- f.close()
-
return get_ll(ccode, function_names + support_functions)
Modified: pypy/branch/hl-backend/pypy/translator/llvm/gc.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/llvm/gc.py (original)
+++ pypy/branch/hl-backend/pypy/translator/llvm/gc.py Fri Oct 14 17:44:56 2005
@@ -25,7 +25,8 @@
gcpolicy = gcpolicy or 'boehm'
from os.path import exists
- boehm_on_path = exists('/usr/lib/libgc.so') or exists('/usr/lib/libgc.a')
+ boehm_on_path = exists('/usr/lib/libgc.so') or exists('/usr/lib/libgc.a') or \
+ exists('/sw/lib/libgc.so') or exists('/sw/lib/libgc.a')
if gcpolicy == 'boehm' and not boehm_on_path:
log.gc.WARNING('warning: Boehm GC libary not found in /usr/lib, falling back on no gc')
gcpolicy = 'none'
Modified: pypy/branch/hl-backend/pypy/translator/llvm/module/genexterns.c
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/llvm/module/genexterns.c (original)
+++ pypy/branch/hl-backend/pypy/translator/llvm/module/genexterns.c Fri Oct 14 17:44:56 2005
@@ -19,7 +19,9 @@
#include <errno.h>
#include <locale.h>
#include <ctype.h>
-#include <python2.3/Python.h>
+
+//the placeholder in the next line gets replaced by the actual python.h path
+#include __PYTHON_H__
// Do this manually from python :-(
//#include "ll_os.h"
Modified: pypy/branch/hl-backend/pypy/translator/transform.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/transform.py (original)
+++ pypy/branch/hl-backend/pypy/translator/transform.py Fri Oct 14 17:44:56 2005
@@ -14,7 +14,7 @@
from pypy.translator.annrpython import CannotSimplify
from pypy.annotation import model as annmodel
from pypy.annotation.specialize import MemoTable
-
+from pypy.rpython.objectmodel import stack_check
def checkgraphs(self, blocks):
seen = {}
@@ -187,6 +187,30 @@
else:
op.opname = intern('call_specialcase')
+def insert_stackcheck(ann):
+ from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles
+ edges = []
+ for callposition, (caller, callee) in ann.translator.callgraph.items():
+ edge = Edge(caller, callee)
+ edge.callposition = callposition
+ edges.append(edge)
+ edgedict = make_edge_dict(edges)
+ for edge in break_cycles(edgedict, edgedict):
+ caller = edge.source
+ _, _, call_tag = edge.callposition
+ if call_tag:
+ _, caller_block, _ = call_tag
+ else:
+ ann.warning("cycle detected but no information on where to insert "
+ "stack_check()")
+ continue
+ # caller block found, insert stack_check()
+ v = Variable()
+ # push annotation on v
+ ann.setbinding(v, annmodel.SomeImpossibleValue())
+ unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v)
+ caller_block.operations.insert(0, unwind_op)
+
default_extra_passes = [
transform_specialization,
transform_allocate,
Modified: pypy/branch/hl-backend/pypy/translator/translator.py
==============================================================================
--- pypy/branch/hl-backend/pypy/translator/translator.py (original)
+++ pypy/branch/hl-backend/pypy/translator/translator.py Fri Oct 14 17:44:56 2005
@@ -329,11 +329,11 @@
self.frozen = True
return genllvm.genllvm(self, really_compile=really_compile, standalone=standalone, optimize=optimize, exe_name=exe_name, gcpolicy=gcpolicy)
- def asmcompile(self, processor='ppc'):
+ def asmcompile(self, processor='virt'):
from pypy.translator.asm import genasm
- assert processor == 'ppc', 'only ppc asm-generation supported for now'
+ assert processor in ['ppc', 'virt', 'virtfinite']
assert self.rtyper is not None, 'must specialize'
- return genasm.genasm(self)
+ return genasm.genasm(self, processor)
def call(self, *args):
"""Calls underlying Python function."""
More information about the Pypy-commit
mailing list