[pypy-commit] pypy remove-PYPY_NOT_MAIN_FILE: hg merge default
amauryfa
noreply at buildbot.pypy.org
Tue Oct 2 23:07:33 CEST 2012
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: remove-PYPY_NOT_MAIN_FILE
Changeset: r57752:403594295483
Date: 2012-10-02 23:07 +0200
http://bitbucket.org/pypy/pypy/changeset/403594295483/
Log: hg merge default
diff too long, truncating to 2000 out of 2395 lines
diff --git a/pypy/doc/arm.rst b/pypy/doc/arm.rst
--- a/pypy/doc/arm.rst
+++ b/pypy/doc/arm.rst
@@ -23,7 +23,7 @@
The tools required to cross translate from a Linux based host to an ARM based Linux target are:
-- A checkout of PyPy's arm-backend-2 branch.
+- A checkout of PyPy (default branch).
- The GCC ARM cross compiler (on Ubuntu it is the ``gcc-arm-linux-gnueabi package``) but other toolchains should also work.
- Scratchbox 2, a cross-compilation engine (``scratchbox2`` Ubuntu package).
- A 32-bit PyPy or Python.
@@ -147,4 +147,4 @@
return 0
def target(*args):
- return main, None
\ No newline at end of file
+ return main, None
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -115,13 +115,16 @@
which data structures would be more appropriate? For example, a dict
implemented as a hash table will suffer "stm collisions" in all threads
whenever one thread writes anything to it; but there could be other
- implementations.
+ implementations. Maybe alternate strategies can be implemented at the
+ level of the Python interpreter (see list/dict strategies,
+ ``pypy/objspace/std/{list,dict}object.py``).
* More generally, there is the idea that we would need some kind of
"debugger"-like tool to "debug" things that are not bugs, but stm
conflicts. How would this tool look like to the end Python
programmers? Like a profiler? Or like a debugger with breakpoints
- on aborted transactions?
+ on aborted transactions? It would probably be all app-level, with
+ a few hooks e.g. for transaction conflicts.
* Find good ways to have libraries using internally threads and atomics,
but not exposing threads to the user. Right now there is a rough draft
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -18,6 +18,7 @@
.. branch: numpypy_count_nonzero
.. branch: numpy-refactor
Remove numpy lazy evaluation and simplify everything
+.. branch: numpy-reintroduce-jit-drivers
.. branch: numpy-fancy-indexing
Support for array[array-of-ints] in numpy
.. branch: even-more-jit-hooks
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -474,7 +474,7 @@
if f_type == F_BLOCK_LOOP:
self.emit_jump(ops.CONTINUE_LOOP, block, True)
break
- if self.frame_blocks[i][0] == F_BLOCK_FINALLY_END:
+ if f_type == F_BLOCK_FINALLY_END:
self.error("'continue' not supported inside 'finally' " \
"clause",
cont)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -208,11 +208,11 @@
def int_w(self, space):
raise OperationError(space.w_TypeError,
typed_unwrap_error_msg(space, "integer", self))
-
+
def uint_w(self, space):
raise OperationError(space.w_TypeError,
typed_unwrap_error_msg(space, "integer", self))
-
+
def bigint_w(self, space):
raise OperationError(space.w_TypeError,
typed_unwrap_error_msg(space, "integer", self))
@@ -292,8 +292,6 @@
"""Base class for the interpreter-level implementations of object spaces.
http://pypy.readthedocs.org/en/latest/objspace.html"""
- full_exceptions = True # full support for exceptions (normalization & more)
-
def __init__(self, config=None):
"NOT_RPYTHON: Basic initialization of objects."
self.fromcache = InternalSpaceCache(self).getorbuild
@@ -1124,13 +1122,9 @@
def exception_is_valid_obj_as_class_w(self, w_obj):
if not self.isinstance_w(w_obj, self.w_type):
return False
- if not self.full_exceptions:
- return True
return self.is_true(self.issubtype(w_obj, self.w_BaseException))
def exception_is_valid_class_w(self, w_cls):
- if not self.full_exceptions:
- return True
return self.is_true(self.issubtype(w_cls, self.w_BaseException))
def exception_getclass(self, w_obj):
@@ -1381,7 +1375,7 @@
if not self.is_true(self.isinstance(w_obj, self.w_str)):
raise OperationError(self.w_TypeError,
self.wrap('argument must be a string'))
- return self.str_w(w_obj)
+ return self.str_w(w_obj)
def unicode_w(self, w_obj):
return w_obj.unicode_w(self)
@@ -1702,7 +1696,7 @@
'ValueError',
'ZeroDivisionError',
]
-
+
if sys.platform.startswith("win"):
ObjSpace.ExceptionTable += ['WindowsError']
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -45,11 +45,6 @@
def async(self, space):
"Check if this is an exception that should better not be caught."
- if not space.full_exceptions:
- # flow objspace does not support such exceptions and more
- # importantly, raises KeyboardInterrupt if you try to access
- # space.w_KeyboardInterrupt
- return False
return (self.match(space, space.w_SystemExit) or
self.match(space, space.w_KeyboardInterrupt))
@@ -166,9 +161,7 @@
# Or 'Class' can also be an old-style class and 'inst' an old-style
# instance of it.
#
- # Note that 'space.full_exceptions' is set to False by the flow
- # object space; in this case we must assume that we are in a
- # non-advanced case, and ignore the advanced cases. Old-style
+ # The flow object space only deals with non-advanced case. Old-style
# classes and instances *are* advanced.
#
# input (w_type, w_value)... becomes... advanced case?
@@ -183,9 +176,8 @@
#
w_type = self.w_type
w_value = self.get_w_value(space)
- if space.full_exceptions:
- while space.is_true(space.isinstance(w_type, space.w_tuple)):
- w_type = space.getitem(w_type, space.wrap(0))
+ while space.is_true(space.isinstance(w_type, space.w_tuple)):
+ w_type = space.getitem(w_type, space.wrap(0))
if space.exception_is_valid_obj_as_class_w(w_type):
# this is for all cases of the form (Class, something)
@@ -199,8 +191,7 @@
# raise Type, Instance: let etype be the exact type of value
w_type = w_valuetype
else:
- if space.full_exceptions and space.is_true(
- space.isinstance(w_value, space.w_tuple)):
+ if space.is_true(space.isinstance(w_value, space.w_tuple)):
# raise Type, tuple: assume the tuple contains the
# constructor args
w_value = space.call(w_type, w_value)
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -944,14 +944,6 @@
def appcaller(space, *args_w):
if not isinstance(space, ObjSpace):
raise TypeError("first argument must be a space instance.")
- # redirect if the space handles this specially
- # XXX can this be factored a bit less flow space dependently?
- if hasattr(space, 'specialcases'):
- sc = space.specialcases
- if ApplevelClass in sc:
- ret_w = sc[ApplevelClass](space, self, name, args_w)
- if ret_w is not None: # it was RPython
- return ret_w
# the last argument can be an Arguments
w_func = self.wget(space, name)
if not args_w:
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -223,7 +223,7 @@
return next_instr
if opcode == self.opcodedesc.JUMP_ABSOLUTE.index:
- return self.jump_absolute(oparg, next_instr, ec)
+ return self.jump_absolute(oparg, ec)
if we_are_translated():
for opdesc in unrolling_all_opcode_descs:
@@ -557,7 +557,7 @@
w_type = self.popvalue()
operror = OperationError(w_type, w_value)
operror.normalize_exception(space)
- if not space.full_exceptions or space.is_w(w_traceback, space.w_None):
+ if space.is_w(w_traceback, space.w_None):
# common case
raise operror
else:
@@ -858,7 +858,8 @@
def YIELD_VALUE(self, oparg, next_instr):
raise Yield
- def jump_absolute(self, jumpto, next_instr, ec):
+ def jump_absolute(self, jumpto, ec):
+ # this function is overridden by pypy.module.pypyjit.interp_jit
check_nonneg(jumpto)
return jumpto
@@ -944,21 +945,9 @@
def WITH_CLEANUP(self, oparg, next_instr):
# see comment in END_FINALLY for stack state
- # This opcode changed a lot between CPython versions
- if (self.pycode.magic >= 0xa0df2ef
- # Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
- or self.pycode.magic >= 0xa0df2d1):
- # implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
- w_unroller = self.popvalue()
- w_exitfunc = self.popvalue()
- self.pushvalue(w_unroller)
- elif self.pycode.magic >= 0xa0df28c:
- # Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
- w_exitfunc = self.popvalue()
- w_unroller = self.peekvalue(0)
- else:
- raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
-
+ w_unroller = self.popvalue()
+ w_exitfunc = self.popvalue()
+ self.pushvalue(w_unroller)
unroller = self.space.interpclass_w(w_unroller)
is_app_exc = (unroller is not None and
isinstance(unroller, SApplicationException))
@@ -1192,10 +1181,6 @@
def nomoreblocks(self):
raise BytecodeCorruption("misplaced bytecode - should not return")
- # NB. for the flow object space, the state_(un)pack_variables methods
- # give a way to "pickle" and "unpickle" the SuspendedUnroller by
- # enumerating the Variables it contains.
-
class SReturnValue(SuspendedUnroller):
"""Signals a 'return' statement.
Argument is the wrapped object to return."""
@@ -1206,12 +1191,6 @@
def nomoreblocks(self):
return self.w_returnvalue
- def state_unpack_variables(self, space):
- return [self.w_returnvalue]
- def state_pack_variables(space, w_returnvalue):
- return SReturnValue(w_returnvalue)
- state_pack_variables = staticmethod(state_pack_variables)
-
class SApplicationException(SuspendedUnroller):
"""Signals an application-level exception
(i.e. an OperationException)."""
@@ -1226,13 +1205,6 @@
"""Signals a 'break' statement."""
_immutable_ = True
kind = 0x04
-
- def state_unpack_variables(self, space):
- return []
- def state_pack_variables(space):
- return SBreakLoop.singleton
- state_pack_variables = staticmethod(state_pack_variables)
-
SBreakLoop.singleton = SBreakLoop()
class SContinueLoop(SuspendedUnroller):
@@ -1243,12 +1215,6 @@
def __init__(self, jump_to):
self.jump_to = jump_to
- def state_unpack_variables(self, space):
- return [space.wrap(self.jump_to)]
- def state_pack_variables(space, w_jump_to):
- return SContinueLoop(space.int_w(w_jump_to))
- state_pack_variables = staticmethod(state_pack_variables)
-
class FrameBlock(object):
"""Abstract base class for frame blocks from the blockstack,
@@ -1303,7 +1269,9 @@
# and jump to the beginning of the loop, stored in the
# exception's argument
frame.append_block(self)
- return r_uint(unroller.jump_to)
+ jumpto = unroller.jump_to
+ ec = frame.space.getexecutioncontext()
+ return r_uint(frame.jump_absolute(jumpto, ec))
else:
# jump to the end of the loop
self.cleanupstack(frame)
@@ -1323,8 +1291,7 @@
self.cleanupstack(frame)
assert isinstance(unroller, SApplicationException)
operationerr = unroller.operr
- if frame.space.full_exceptions:
- operationerr.normalize_exception(frame.space)
+ operationerr.normalize_exception(frame.space)
# the stack setup is slightly different than in CPython:
# instead of the traceback, we store the unroller object,
# wrapped.
@@ -1356,8 +1323,7 @@
_immutable_ = True
def handle(self, frame, unroller):
- if (frame.space.full_exceptions and
- isinstance(unroller, SApplicationException)):
+ if isinstance(unroller, SApplicationException):
unroller.operr.normalize_exception(frame.space)
return FinallyBlock.handle(self, frame, unroller)
diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -131,13 +131,13 @@
def get_latest_value_float(self, index):
"""Returns the value for the index'th argument to the
last executed operation (from 'fail_args' if it was a guard,
- or from 'args' if it was a FINISH). Returns a float."""
+ or from 'args' if it was a FINISH). Returns a FLOATSTORAGE."""
raise NotImplementedError
def get_latest_value_ref(self, index):
"""Returns the value for the index'th argument to the
last executed operation (from 'fail_args' if it was a guard,
- or from 'args' if it was a FINISH). Returns a ptr or an obj."""
+ or from 'args' if it was a FINISH). Returns a GCREF."""
raise NotImplementedError
def get_latest_value_count(self):
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -981,7 +981,7 @@
assert strlenaddr == cast(BVoidP, strlen)
def test_read_variable():
- if sys.platform == 'win32':
+ if sys.platform == 'win32' or sys.platform == 'darwin':
py.test.skip("untested")
BVoidP = new_pointer_type(new_void_type())
ll = find_and_load_library('c')
@@ -989,7 +989,7 @@
assert stderr == cast(BVoidP, _testfunc(8))
def test_read_variable_as_unknown_length_array():
- if sys.platform == 'win32':
+ if sys.platform == 'win32' or sys.platform == 'darwin':
py.test.skip("untested")
BCharP = new_pointer_type(new_primitive_type("char"))
BArray = new_array_type(BCharP, None)
@@ -999,7 +999,7 @@
# ^^ and not 'char[]', which is basically not allowed and would crash
def test_write_variable():
- if sys.platform == 'win32':
+ if sys.platform == 'win32' or sys.platform == 'darwin':
py.test.skip("untested")
BVoidP = new_pointer_type(new_void_type())
ll = find_and_load_library('c')
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
--- a/pypy/module/micronumpy/arrayimpl/concrete.py
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -244,6 +244,7 @@
def setitem_index(self, space, index, value):
self.setitem(self._lookup_by_unwrapped_index(space, index), value)
+ @jit.unroll_safe
def _single_item_index(self, space, w_idx):
""" Return an index of single item if possible, otherwise raises
IndexError
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -9,8 +9,8 @@
from pypy.interpreter.error import OperationError
from pypy.module.micronumpy import interp_boxes
from pypy.module.micronumpy.interp_dtype import get_dtype_cache
-from pypy.module.micronumpy.interp_numarray import (Scalar, BaseArray,
- scalar_w, W_NDimArray, array)
+from pypy.module.micronumpy.base import W_NDimArray
+from pypy.module.micronumpy.interp_numarray import array
from pypy.module.micronumpy.interp_arrayops import where
from pypy.module.micronumpy import interp_ufuncs
from pypy.rlib.objectmodel import specialize, instantiate
@@ -147,7 +147,8 @@
def is_true(self, w_obj):
assert isinstance(w_obj, BoolObject)
- return w_obj.boolval
+ return False
+ #return w_obj.boolval
def is_w(self, w_obj, w_what):
return w_obj is w_what
@@ -274,7 +275,7 @@
if isinstance(w_index, FloatObject):
w_index = IntObject(int(w_index.floatval))
w_val = self.expr.execute(interp)
- assert isinstance(arr, BaseArray)
+ assert isinstance(arr, W_NDimArray)
arr.descr_setitem(interp.space, w_index, w_val)
def __repr__(self):
@@ -302,11 +303,11 @@
w_rhs = self.rhs.wrap(interp.space)
else:
w_rhs = self.rhs.execute(interp)
- if not isinstance(w_lhs, BaseArray):
+ if not isinstance(w_lhs, W_NDimArray):
# scalar
dtype = get_dtype_cache(interp.space).w_float64dtype
- w_lhs = scalar_w(interp.space, dtype, w_lhs)
- assert isinstance(w_lhs, BaseArray)
+ w_lhs = W_NDimArray.new_scalar(interp.space, dtype, w_lhs)
+ assert isinstance(w_lhs, W_NDimArray)
if self.name == '+':
w_res = w_lhs.descr_add(interp.space, w_rhs)
elif self.name == '*':
@@ -314,17 +315,16 @@
elif self.name == '-':
w_res = w_lhs.descr_sub(interp.space, w_rhs)
elif self.name == '->':
- assert not isinstance(w_rhs, Scalar)
if isinstance(w_rhs, FloatObject):
w_rhs = IntObject(int(w_rhs.floatval))
- assert isinstance(w_lhs, BaseArray)
+ assert isinstance(w_lhs, W_NDimArray)
w_res = w_lhs.descr_getitem(interp.space, w_rhs)
else:
raise NotImplementedError
- if (not isinstance(w_res, BaseArray) and
+ if (not isinstance(w_res, W_NDimArray) and
not isinstance(w_res, interp_boxes.W_GenericBox)):
dtype = get_dtype_cache(interp.space).w_float64dtype
- w_res = scalar_w(interp.space, dtype, w_res)
+ w_res = W_NDimArray.new_scalar(interp.space, dtype, w_res)
return w_res
def __repr__(self):
@@ -416,7 +416,7 @@
def execute(self, interp):
arr = self.args[0].execute(interp)
- if not isinstance(arr, BaseArray):
+ if not isinstance(arr, W_NDimArray):
raise ArgumentNotAnArray
if self.name in SINGLE_ARG_FUNCTIONS:
if len(self.args) != 1 and self.name != 'sum':
@@ -440,20 +440,21 @@
elif self.name == "unegative":
neg = interp_ufuncs.get(interp.space).negative
w_res = neg.call(interp.space, [arr])
+ elif self.name == "cos":
+ cos = interp_ufuncs.get(interp.space).cos
+ w_res = cos.call(interp.space, [arr])
elif self.name == "flat":
w_res = arr.descr_get_flatiter(interp.space)
elif self.name == "tostring":
arr.descr_tostring(interp.space)
w_res = None
- elif self.name == "count_nonzero":
- w_res = arr.descr_count_nonzero(interp.space)
else:
assert False # unreachable code
elif self.name in TWO_ARG_FUNCTIONS:
if len(self.args) != 2:
raise ArgumentMismatch
arg = self.args[1].execute(interp)
- if not isinstance(arg, BaseArray):
+ if not isinstance(arg, W_NDimArray):
raise ArgumentNotAnArray
if self.name == "dot":
w_res = arr.descr_dot(interp.space, arg)
@@ -466,9 +467,9 @@
raise ArgumentMismatch
arg1 = self.args[1].execute(interp)
arg2 = self.args[2].execute(interp)
- if not isinstance(arg1, BaseArray):
+ if not isinstance(arg1, W_NDimArray):
raise ArgumentNotAnArray
- if not isinstance(arg2, BaseArray):
+ if not isinstance(arg2, W_NDimArray):
raise ArgumentNotAnArray
if self.name == "where":
w_res = where(interp.space, arr, arg1, arg2)
@@ -476,7 +477,7 @@
assert False
else:
raise WrongFunctionName
- if isinstance(w_res, BaseArray):
+ if isinstance(w_res, W_NDimArray):
return w_res
if isinstance(w_res, FloatObject):
dtype = get_dtype_cache(interp.space).w_float64dtype
@@ -488,7 +489,7 @@
dtype = w_res.get_dtype(interp.space)
else:
dtype = None
- return scalar_w(interp.space, dtype, w_res)
+ return W_NDimArray.new_scalar(interp.space, dtype, w_res)
_REGEXES = [
('-?[\d\.]+', 'number'),
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -129,6 +129,8 @@
self._prepare_array_index(space, w_index)
shape = res_shape + self.get_shape()[len(indexes):]
res = W_NDimArray.from_shape(shape, self.get_dtype(), self.get_order())
+ if not res.get_size():
+ return res
return loop.getitem_array_int(space, self, res, iter_shape, indexes,
prefix)
@@ -514,7 +516,7 @@
if self.get_size() == 0:
raise OperationError(space.w_ValueError,
space.wrap("Can't call %s on zero-size arrays" % op_name))
- return space.wrap(loop.argmin_argmax(op_name, self))
+ return space.wrap(getattr(loop, 'arg' + op_name)(self))
return func_with_new_name(impl, "reduce_arg%s_impl" % op_name)
descr_argmax = _reduce_argmax_argmin_impl("max")
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -258,7 +258,7 @@
return out
shape = shape_agreement(space, w_obj.get_shape(), out,
broadcast_down=False)
- return loop.call1(shape, self.func, self.name, calc_dtype, res_dtype,
+ return loop.call1(shape, self.func, calc_dtype, res_dtype,
w_obj, out)
@@ -322,7 +322,7 @@
return out
new_shape = shape_agreement(space, w_lhs.get_shape(), w_rhs)
new_shape = shape_agreement(space, new_shape, out, broadcast_down=False)
- return loop.call2(new_shape, self.func, self.name, calc_dtype,
+ return loop.call2(new_shape, self.func, calc_dtype,
res_dtype, w_lhs, w_rhs, out)
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -1,21 +1,34 @@
""" This file is the main run loop as well as evaluation loops for various
-signatures
+operations. This is the place to look for all the computations that iterate
+over all the array elements.
"""
-from pypy.rlib.objectmodel import specialize
from pypy.rlib.rstring import StringBuilder
from pypy.rlib import jit
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.module.micronumpy.base import W_NDimArray
-def call2(shape, func, name, calc_dtype, res_dtype, w_lhs, w_rhs, out):
+call2_driver = jit.JitDriver(name='numpy_call2',
+ greens = ['shapelen', 'func', 'calc_dtype',
+ 'res_dtype'],
+ reds = ['shape', 'w_lhs', 'w_rhs', 'out',
+ 'left_iter', 'right_iter', 'out_iter'])
+
+def call2(shape, func, calc_dtype, res_dtype, w_lhs, w_rhs, out):
if out is None:
out = W_NDimArray.from_shape(shape, res_dtype)
left_iter = w_lhs.create_iter(shape)
right_iter = w_rhs.create_iter(shape)
out_iter = out.create_iter(shape)
+ shapelen = len(shape)
while not out_iter.done():
+ call2_driver.jit_merge_point(shapelen=shapelen, func=func,
+ calc_dtype=calc_dtype, res_dtype=res_dtype,
+ shape=shape, w_lhs=w_lhs, w_rhs=w_rhs,
+ out=out,
+ left_iter=left_iter, right_iter=right_iter,
+ out_iter=out_iter)
w_left = left_iter.getitem().convert_to(calc_dtype)
w_right = right_iter.getitem().convert_to(calc_dtype)
out_iter.setitem(func(calc_dtype, w_left, w_right).convert_to(
@@ -25,30 +38,56 @@
out_iter.next()
return out
-def call1(shape, func, name, calc_dtype, res_dtype, w_obj, out):
+call1_driver = jit.JitDriver(name='numpy_call1',
+ greens = ['shapelen', 'func', 'calc_dtype',
+ 'res_dtype'],
+ reds = ['shape', 'w_obj', 'out', 'obj_iter',
+ 'out_iter'])
+
+def call1(shape, func, calc_dtype, res_dtype, w_obj, out):
if out is None:
out = W_NDimArray.from_shape(shape, res_dtype)
obj_iter = w_obj.create_iter(shape)
out_iter = out.create_iter(shape)
+ shapelen = len(shape)
while not out_iter.done():
+ call1_driver.jit_merge_point(shapelen=shapelen, func=func,
+ calc_dtype=calc_dtype, res_dtype=res_dtype,
+ shape=shape, w_obj=w_obj, out=out,
+ obj_iter=obj_iter, out_iter=out_iter)
elem = obj_iter.getitem().convert_to(calc_dtype)
out_iter.setitem(func(calc_dtype, elem).convert_to(res_dtype))
out_iter.next()
obj_iter.next()
return out
+setslice_driver = jit.JitDriver(name='numpy_setslice',
+ greens = ['shapelen', 'dtype'],
+ reds = ['target', 'source', 'target_iter',
+ 'source_iter'])
+
def setslice(shape, target, source):
# note that unlike everything else, target and source here are
# array implementations, not arrays
target_iter = target.create_iter(shape)
source_iter = source.create_iter(shape)
dtype = target.dtype
+ shapelen = len(shape)
while not target_iter.done():
+ setslice_driver.jit_merge_point(shapelen=shapelen, dtype=dtype,
+ target=target, source=source,
+ target_iter=target_iter,
+ source_iter=source_iter)
target_iter.setitem(source_iter.getitem().convert_to(dtype))
target_iter.next()
source_iter.next()
return target
+reduce_driver = jit.JitDriver(name='numpy_reduce',
+ greens = ['shapelen', 'func', 'done_func',
+ 'calc_dtype', 'identity'],
+ reds = ['obj', 'obj_iter', 'cur_value'])
+
def compute_reduce(obj, calc_dtype, func, done_func, identity):
obj_iter = obj.create_iter(obj.get_shape())
if identity is None:
@@ -56,7 +95,12 @@
obj_iter.next()
else:
cur_value = identity.convert_to(calc_dtype)
+ shapelen = len(obj.get_shape())
while not obj_iter.done():
+ reduce_driver.jit_merge_point(shapelen=shapelen, func=func,
+ calc_dtype=calc_dtype, identity=identity,
+ done_func=done_func, obj=obj,
+ obj_iter=obj_iter, cur_value=cur_value)
rval = obj_iter.getitem().convert_to(calc_dtype)
if done_func is not None and done_func(calc_dtype, rval):
return rval
@@ -70,6 +114,11 @@
arr_iter.setitem(box)
arr_iter.next()
+where_driver = jit.JitDriver(name='numpy_where',
+ greens = ['shapelen', 'dtype', 'arr_dtype'],
+ reds = ['shape', 'arr', 'x', 'y','arr_iter', 'out',
+ 'x_iter', 'y_iter', 'iter', 'out_iter'])
+
def where(out, shape, arr, x, y, dtype):
out_iter = out.create_iter(shape)
arr_iter = arr.create_iter(shape)
@@ -83,7 +132,13 @@
iter = y_iter
else:
iter = x_iter
+ shapelen = len(shape)
while not iter.done():
+ where_driver.jit_merge_point(shapelen=shapelen, shape=shape,
+ dtype=dtype, iter=iter, x_iter=x_iter,
+ y_iter=y_iter, arr_iter=arr_iter,
+ arr=arr, x=x, y=y, arr_dtype=arr_dtype,
+ out_iter=out_iter, out=out)
w_cond = arr_iter.getitem()
if arr_dtype.itemtype.bool(w_cond):
w_val = x_iter.getitem().convert_to(dtype)
@@ -96,12 +151,24 @@
y_iter.next()
return out
+axis_reduce__driver = jit.JitDriver(name='numpy_axis_reduce',
+ greens=['shapelen', 'func', 'dtype',
+ 'identity'],
+ reds=['axis', 'arr', 'out', 'shape',
+ 'out_iter', 'arr_iter'])
+
def do_axis_reduce(shape, func, arr, dtype, axis, out, identity):
out_iter = out.create_axis_iter(arr.get_shape(), axis)
arr_iter = arr.create_iter(arr.get_shape())
if identity is not None:
identity = identity.convert_to(dtype)
+ shapelen = len(shape)
while not out_iter.done():
+ axis_reduce__driver.jit_merge_point(shapelen=shapelen, func=func,
+ dtype=dtype, identity=identity,
+ axis=axis, arr=arr, out=out,
+ shape=shape, out_iter=out_iter,
+ arr_iter=arr_iter)
w_val = arr_iter.getitem().convert_to(dtype)
if out_iter.first_line:
if identity is not None:
@@ -114,23 +181,41 @@
out_iter.next()
return out
- at specialize.arg(0)
-def argmin_argmax(op_name, arr):
- result = 0
- idx = 1
- dtype = arr.get_dtype()
- iter = arr.create_iter(arr.get_shape())
- cur_best = iter.getitem()
- iter.next()
- while not iter.done():
- w_val = iter.getitem()
- new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
- if dtype.itemtype.ne(new_best, cur_best):
- result = idx
- cur_best = new_best
+
+def _new_argmin_argmax(op_name):
+ arg_driver = jit.JitDriver(name='numpy_' + op_name,
+ greens = ['shapelen', 'dtype'],
+ reds = ['result', 'idx', 'cur_best', 'arr',
+ 'iter'])
+
+ def argmin_argmax(arr):
+ result = 0
+ idx = 1
+ dtype = arr.get_dtype()
+ iter = arr.create_iter(arr.get_shape())
+ cur_best = iter.getitem()
iter.next()
- idx += 1
- return result
+ shapelen = len(arr.get_shape())
+ while not iter.done():
+ arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype,
+ result=result, idx=idx,
+ cur_best=cur_best, arr=arr, iter=iter)
+ w_val = iter.getitem()
+ new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
+ if dtype.itemtype.ne(new_best, cur_best):
+ result = idx
+ cur_best = new_best
+ iter.next()
+ idx += 1
+ return result
+ return argmin_argmax
+argmin = _new_argmin_argmax('min')
+argmax = _new_argmin_argmax('max')
+
+# note that shapelen == 2 always
+dot_driver = jit.JitDriver(name = 'numpy_dot',
+ greens = ['dtype'],
+ reds = ['outi', 'lefti', 'righti', 'result'])
def multidim_dot(space, left, right, result, dtype, right_critical_dim):
''' assumes left, right are concrete arrays
@@ -157,6 +242,8 @@
lefti = left.create_dot_iter(broadcast_shape, left_skip)
righti = right.create_dot_iter(broadcast_shape, right_skip)
while not outi.done():
+ dot_driver.jit_merge_point(dtype=dtype, outi=outi, lefti=lefti,
+ righti=righti, result=result)
lval = lefti.getitem().convert_to(dtype)
rval = righti.getitem().convert_to(dtype)
outval = outi.getitem().convert_to(dtype)
@@ -168,21 +255,45 @@
lefti.next()
return result
+count_all_true_driver = jit.JitDriver(name = 'numpy_count',
+ greens = ['shapelen', 'dtype'],
+ reds = ['s', 'iter'])
+
def count_all_true(arr):
s = 0
if arr.is_scalar():
return arr.get_dtype().itemtype.bool(arr.get_scalar_value())
iter = arr.create_iter()
+ shapelen = len(arr.get_shape())
+ dtype = arr.get_dtype()
while not iter.done():
+ count_all_true_driver.jit_merge_point(shapelen=shapelen, iter=iter,
+ s=s, dtype=dtype)
s += iter.getitem_bool()
iter.next()
return s
+getitem_filter_driver = jit.JitDriver(name = 'numpy_getitem_bool',
+ greens = ['shapelen', 'arr_dtype',
+ 'index_dtype'],
+ reds = ['res', 'index_iter', 'res_iter',
+ 'arr_iter'])
+
def getitem_filter(res, arr, index):
res_iter = res.create_iter()
index_iter = index.create_iter()
arr_iter = arr.create_iter()
+ shapelen = len(arr.get_shape())
+ arr_dtype = arr.get_dtype()
+ index_dtype = index.get_dtype()
+ # XXX length of shape of index as well?
while not index_iter.done():
+ getitem_filter_driver.jit_merge_point(shapelen=shapelen,
+ index_dtype=index_dtype,
+ arr_dtype=arr_dtype,
+ res=res, index_iter=index_iter,
+ res_iter=res_iter,
+ arr_iter=arr_iter)
if index_iter.getitem_bool():
res_iter.setitem(arr_iter.getitem())
res_iter.next()
@@ -190,31 +301,63 @@
arr_iter.next()
return res
+setitem_filter_driver = jit.JitDriver(name = 'numpy_setitem_bool',
+ greens = ['shapelen', 'arr_dtype',
+ 'index_dtype'],
+ reds = ['index_iter', 'value_iter',
+ 'arr_iter'])
+
def setitem_filter(arr, index, value):
arr_iter = arr.create_iter()
index_iter = index.create_iter()
value_iter = value.create_iter()
+ shapelen = len(arr.get_shape())
+ index_dtype = index.get_dtype()
+ arr_dtype = arr.get_dtype()
while not index_iter.done():
+ setitem_filter_driver.jit_merge_point(shapelen=shapelen,
+ index_dtype=index_dtype,
+ arr_dtype=arr_dtype,
+ index_iter=index_iter,
+ value_iter=value_iter,
+ arr_iter=arr_iter)
if index_iter.getitem_bool():
arr_iter.setitem(value_iter.getitem())
value_iter.next()
arr_iter.next()
index_iter.next()
+flatiter_getitem_driver = jit.JitDriver(name = 'numpy_flatiter_getitem',
+ greens = ['dtype'],
+ reds = ['step', 'ri', 'res',
+ 'base_iter'])
+
def flatiter_getitem(res, base_iter, step):
ri = res.create_iter()
+ dtype = res.get_dtype()
while not ri.done():
+ flatiter_getitem_driver.jit_merge_point(dtype=dtype,
+ base_iter=base_iter,
+ ri=ri, res=res, step=step)
ri.setitem(base_iter.getitem())
base_iter.next_skip_x(step)
ri.next()
return res
+flatiter_setitem_driver = jit.JitDriver(name = 'numpy_flatiter_setitem',
+ greens = ['dtype'],
+ reds = ['length', 'step', 'arr_iter',
+ 'val_iter'])
+
def flatiter_setitem(arr, val, start, step, length):
dtype = arr.get_dtype()
arr_iter = arr.create_iter()
val_iter = val.create_iter()
arr_iter.next_skip_x(start)
while length > 0:
+ flatiter_setitem_driver.jit_merge_point(dtype=dtype, length=length,
+ step=step, arr_iter=arr_iter,
+ val_iter=val_iter)
arr_iter.setitem(val_iter.getitem().convert_to(dtype))
# need to repeat i_nput values until all assignments are done
arr_iter.next_skip_x(step)
@@ -223,10 +366,16 @@
# WTF numpy?
val_iter.reset()
+fromstring_driver = jit.JitDriver(name = 'numpy_fromstring',
+ greens = ['itemsize', 'dtype'],
+ reds = ['i', 's', 'ai'])
+
def fromstring_loop(a, dtype, itemsize, s):
i = 0
ai = a.create_iter()
while not ai.done():
+ fromstring_driver.jit_merge_point(dtype=dtype, s=s, ai=ai, i=i,
+ itemsize=itemsize)
val = dtype.itemtype.runpack_str(s[i*itemsize:i*itemsize + itemsize])
ai.setitem(val)
ai.next()
@@ -274,12 +423,25 @@
else:
self._done = True
+ @jit.unroll_safe
def get_index(self, space):
return [space.wrap(i) for i in self.indexes]
+getitem_int_driver = jit.JitDriver(name = 'numpy_getitem_int',
+ greens = ['shapelen', 'indexlen', 'dtype'],
+ reds = ['arr', 'res', 'iter', 'indexes_w',
+ 'prefix_w'])
+
def getitem_array_int(space, arr, res, iter_shape, indexes_w, prefix_w):
+ shapelen = len(iter_shape)
+ indexlen = len(indexes_w)
+ dtype = arr.get_dtype()
iter = PureShapeIterator(iter_shape, indexes_w)
while not iter.done():
+ getitem_int_driver.jit_merge_point(shapelen=shapelen, indexlen=indexlen,
+ dtype=dtype, arr=arr, res=res,
+ iter=iter, indexes_w=indexes_w,
+ prefix_w=prefix_w)
# prepare the index
index_w = [None] * len(indexes_w)
for i in range(len(indexes_w)):
@@ -293,10 +455,22 @@
iter.next()
return res
+setitem_int_driver = jit.JitDriver(name = 'numpy_setitem_int',
+ greens = ['shapelen', 'indexlen', 'dtype'],
+ reds = ['arr', 'iter', 'indexes_w',
+ 'prefix_w', 'val_arr'])
+
def setitem_array_int(space, arr, iter_shape, indexes_w, val_arr,
prefix_w):
+ shapelen = len(iter_shape)
+ indexlen = len(indexes_w)
+ dtype = arr.get_dtype()
iter = PureShapeIterator(iter_shape, indexes_w)
while not iter.done():
+ setitem_int_driver.jit_merge_point(shapelen=shapelen, indexlen=indexlen,
+ dtype=dtype, arr=arr,
+ iter=iter, indexes_w=indexes_w,
+ prefix_w=prefix_w, val_arr=val_arr)
# prepare the index
index_w = [None] * len(indexes_w)
for i in range(len(indexes_w)):
diff --git a/pypy/module/micronumpy/test/test_compile.py b/pypy/module/micronumpy/test/test_compile.py
--- a/pypy/module/micronumpy/test/test_compile.py
+++ b/pypy/module/micronumpy/test/test_compile.py
@@ -1,6 +1,5 @@
+
import py
-py.test.skip("this is going away")
-
from pypy.module.micronumpy.compile import (numpy_compile, Assignment,
ArrayConstant, FloatConstant, Operator, Variable, RangeConstant, Execute,
FunctionCall, FakeSpace)
@@ -136,7 +135,7 @@
r
"""
interp = self.run(code)
- assert interp.results[0].value.value == 15
+ assert interp.results[0].get_scalar_value().value == 15
def test_sum2(self):
code = """
@@ -145,7 +144,7 @@
sum(b)
"""
interp = self.run(code)
- assert interp.results[0].value.value == 30 * (30 - 1)
+ assert interp.results[0].get_scalar_value().value == 30 * (30 - 1)
def test_array_write(self):
@@ -164,7 +163,7 @@
b = a + a
min(b)
""")
- assert interp.results[0].value.value == -24
+ assert interp.results[0].get_scalar_value().value == -24
def test_max(self):
interp = self.run("""
@@ -173,7 +172,7 @@
b = a + a
max(b)
""")
- assert interp.results[0].value.value == 256
+ assert interp.results[0].get_scalar_value().value == 256
def test_slice(self):
interp = self.run("""
@@ -265,6 +264,7 @@
assert interp.results[0].value == 3
def test_take(self):
+ py.test.skip("unsupported")
interp = self.run("""
a = |10|
b = take(a, [1, 1, 3, 2])
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -1519,7 +1519,7 @@
assert (a == [1, 1]).all()
def test_int_array_index(self):
- from numpypy import array, arange
+ from numpypy import array, arange, zeros
b = arange(10)[array([3, 2, 1, 5])]
assert (b == [3, 2, 1, 5]).all()
raises(IndexError, "arange(10)[array([10])]")
@@ -1528,6 +1528,7 @@
a = arange(1)
a[[0, 0]] += 1
assert a[0] == 1
+ assert (zeros(1)[[]] == []).all()
def test_int_array_index_setitem(self):
from numpypy import array, arange, zeros
@@ -1999,6 +2000,7 @@
def test_int_array_index(self):
from _numpypy import array
+ assert (array([])[[]] == []).all()
a = array([[1, 2], [3, 4], [5, 6]])
assert (a[slice(0, 3), [0, 0]] == [[1, 1], [3, 3], [5, 5]]).all()
assert (a[array([0, 2]), slice(0, 2)] == [[1, 2], [5, 6]]).all()
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -4,18 +4,12 @@
"""
import py
-py.test.skip("this is going away")
-
from pypy.jit.metainterp import pyjitpl
from pypy.jit.metainterp.test.support import LLJitMixin
from pypy.jit.metainterp.warmspot import reset_stats
from pypy.module.micronumpy import interp_boxes
-from pypy.module.micronumpy.compile import (FakeSpace,
- IntObject, Parser, InterpreterState)
-from pypy.module.micronumpy.interp_numarray import (W_NDimArray,
- BaseArray, W_FlatIterator)
-from pypy.rlib.nonconst import NonConstant
-
+from pypy.module.micronumpy.compile import FakeSpace, Parser, InterpreterState
+from pypy.module.micronumpy.base import W_NDimArray
class TestNumpyJIt(LLJitMixin):
graph = None
@@ -51,11 +45,8 @@
if not len(interp.results):
raise Exception("need results")
w_res = interp.results[-1]
- if isinstance(w_res, BaseArray):
- concr = w_res.get_concrete_or_scalar()
- sig = concr.find_sig()
- frame = sig.create_frame(concr)
- w_res = sig.eval(frame, concr)
+ if isinstance(w_res, W_NDimArray):
+ w_res = w_res.create_iter().getitem()
if isinstance(w_res, interp_boxes.W_Float64Box):
return w_res.value
if isinstance(w_res, interp_boxes.W_Int64Box):
@@ -73,6 +64,7 @@
self.__class__.graph = graph
reset_stats()
pyjitpl._warmrunnerdesc.memory_manager.alive_loops.clear()
+ py.test.skip("don't run for now")
return self.interp.eval_graph(self.graph, [i])
def define_add():
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -79,7 +79,7 @@
except ExitFrame:
return self.popvalue()
- def jump_absolute(self, jumpto, _, ec=None):
+ def jump_absolute(self, jumpto, ec):
if we_are_jitted():
#
# assume that only threads are using the bytecode counter
diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py
--- a/pypy/module/pypyjit/test_pypy_c/test_exception.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py
@@ -95,7 +95,6 @@
def test_continue_in_finally(self):
# check that 'continue' inside a try:finally: block is correctly
# detected as closing a loop
- py.test.skip("is this case important?")
def f(n):
i = 0
while 1:
@@ -110,10 +109,9 @@
assert log.result == 2001
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
- i40 = int_add_ovf(i31, 1)
- guard_no_overflow(descr=...)
- i41 = int_lt(i40, i33)
- guard_true(i41, descr=...)
+ i3 = int_lt(i1, i2)
+ guard_true(i3, descr=...)
+ i4 = int_add(i1, 1)
--TICK--
jump(..., descr=...)
""")
diff --git a/pypy/objspace/flow/bytecode.py b/pypy/objspace/flow/bytecode.py
--- a/pypy/objspace/flow/bytecode.py
+++ b/pypy/objspace/flow/bytecode.py
@@ -1,7 +1,8 @@
"""
Bytecode handling classes and functions for use by the flow space.
"""
-from pypy.interpreter.pycode import PyCode, BytecodeCorruption
+from pypy.interpreter.pycode import (PyCode, BytecodeCorruption, cpython_magic,
+ cpython_code_signature)
from pypy.tool.stdlib_opcode import (host_bytecode_spec, EXTENDED_ARG,
HAVE_ARGUMENT)
from pypy.interpreter.astcompiler.consts import CO_GENERATOR
@@ -12,6 +13,57 @@
"""
opnames = host_bytecode_spec.method_names
+ def __init__(self, space, argcount, nlocals, stacksize, flags,
+ code, consts, names, varnames, filename,
+ name, firstlineno, lnotab, freevars, cellvars,
+ hidden_applevel=False, magic=cpython_magic):
+ """Initialize a new code object"""
+ self.space = space
+ self.co_name = name
+ assert nlocals >= 0
+ self.co_argcount = argcount
+ self.co_nlocals = nlocals
+ self.co_stacksize = stacksize
+ self.co_flags = flags
+ self.co_code = code
+ self.co_consts_w = consts
+ self.co_names_w = [space.wrap(aname) for aname in names]
+ self.co_varnames = varnames
+ self.co_freevars = freevars
+ self.co_cellvars = cellvars
+ self.co_filename = filename
+ self.co_name = name
+ self.co_firstlineno = firstlineno
+ self.co_lnotab = lnotab
+ self.hidden_applevel = hidden_applevel
+ self.magic = magic
+ self._signature = cpython_code_signature(self)
+ self._initialize()
+
+ def _initialize(self):
+ # Precompute what arguments need to be copied into cellvars
+ self._args_as_cellvars = []
+
+ if self.co_cellvars:
+ argcount = self.co_argcount
+ assert argcount >= 0 # annotator hint
+ if self.co_flags & CO_VARARGS:
+ argcount += 1
+ if self.co_flags & CO_VARKEYWORDS:
+ argcount += 1
+ # Cell vars could shadow already-set arguments.
+ # See comment in PyCode._initialize()
+ argvars = self.co_varnames
+ cellvars = self.co_cellvars
+ for i in range(len(cellvars)):
+ cellname = cellvars[i]
+ for j in range(argcount):
+ if cellname == argvars[j]:
+ # argument j has the same name as the cell var i
+ while len(self._args_as_cellvars) <= i:
+ self._args_as_cellvars.append(-1) # pad
+ self._args_as_cellvars[i] = j
+
def read(self, pos):
"""
Decode the instruction starting at position ``next_instr``.
diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -1,19 +1,17 @@
import collections
-import sys
from pypy.tool.error import source_lines
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.pytraceback import PyTraceback
from pypy.interpreter import pyframe
from pypy.interpreter.nestedscope import Cell
-from pypy.interpreter.pycode import CO_OPTIMIZED, CO_NEWLOCALS
+from pypy.interpreter.pycode import CO_NEWLOCALS
from pypy.interpreter.argument import ArgumentsForTranslation
-from pypy.interpreter.pyopcode import (Return, Yield, SuspendedUnroller,
- SReturnValue, SApplicationException, BytecodeCorruption,
- RaiseWithExplicitTraceback)
-from pypy.objspace.flow.model import *
+from pypy.interpreter.pyopcode import Return, BytecodeCorruption
+from pypy.objspace.flow.model import (Constant, Variable, Block, Link,
+ UnwrapException, SpaceOperation, FunctionGraph, c_last_exception)
from pypy.objspace.flow.framestate import (FrameState, recursively_unflatten,
recursively_flatten)
from pypy.objspace.flow.bytecode import HostCode
+from pypy.objspace.flow.specialcase import (rpython_print_item,
+ rpython_print_newline)
class FlowingError(Exception):
""" Signals invalid RPython in the function being analysed"""
@@ -27,16 +25,14 @@
msg += source_lines(self.frame.graph, None, offset=self.frame.last_instr)
return "\n".join(msg)
-
class StopFlowing(Exception):
pass
-class FSException(OperationError):
- def __init__(self, w_type, w_value, tb=None):
+class FSException(Exception):
+ def __init__(self, w_type, w_value):
assert w_type is not None
self.w_type = w_type
self.w_value = w_value
- self._application_traceback = tb
def get_w_value(self, _):
return self.w_value
@@ -44,45 +40,6 @@
def __str__(self):
return '[%s: %s]' % (self.w_type, self.w_value)
- def normalize_exception(self, space):
- """Normalize the OperationError. In other words, fix w_type and/or
- w_value to make sure that the __class__ of w_value is exactly w_type.
- """
- w_type = self.w_type
- w_value = self.w_value
- if space.exception_is_valid_obj_as_class_w(w_type):
- # this is for all cases of the form (Class, something)
- if space.is_w(w_value, space.w_None):
- # raise Type: we assume we have to instantiate Type
- w_value = space.call_function(w_type)
- w_type = self._exception_getclass(space, w_value)
- else:
- w_valuetype = space.exception_getclass(w_value)
- if space.exception_issubclass_w(w_valuetype, w_type):
- # raise Type, Instance: let etype be the exact type of value
- w_type = w_valuetype
- else:
- # raise Type, X: assume X is the constructor argument
- w_value = space.call_function(w_type, w_value)
- w_type = self._exception_getclass(space, w_value)
-
- else:
- # the only case left here is (inst, None), from a 'raise inst'.
- w_inst = w_type
- w_instclass = self._exception_getclass(space, w_inst)
- if not space.is_w(w_value, space.w_None):
- raise FSException(space.w_TypeError,
- space.wrap("instance exception may not "
- "have a separate value"))
- w_value = w_inst
- w_type = w_instclass
-
- self.w_type = w_type
- self.w_value = w_value
-
-class OperationThatShouldNotBePropagatedError(FSException):
- pass
-
class ImplicitOperationError(FSException):
pass
@@ -262,6 +219,20 @@
# ____________________________________________________________
+compare_method = [
+ "cmp_lt", # "<"
+ "cmp_le", # "<="
+ "cmp_eq", # "=="
+ "cmp_ne", # "!="
+ "cmp_gt", # ">"
+ "cmp_ge", # ">="
+ "cmp_in",
+ "cmp_not_in",
+ "cmp_is",
+ "cmp_is_not",
+ "cmp_exc_match",
+ ]
+
class FlowSpaceFrame(pyframe.CPythonFrame):
def __init__(self, space, func, constargs=None):
@@ -497,38 +468,68 @@
res = getattr(self, methodname)(oparg, next_instr)
if res is not None:
next_instr = res
- except OperationThatShouldNotBePropagatedError, e:
- raise Exception(
- 'found an operation that always raises %s: %s' % (
- self.space.unwrap(e.w_type).__name__,
- self.space.unwrap(e.w_value)))
except FSException, operr:
- self.attach_traceback(operr)
next_instr = self.handle_operation_error(operr)
- except RaiseWithExplicitTraceback, e:
- next_instr = self.handle_operation_error(e.operr)
return next_instr
- def attach_traceback(self, operr):
- if self.pycode.hidden_applevel:
- return
- tb = operr.get_traceback()
- tb = PyTraceback(self.space, self, self.last_instr, tb)
- operr.set_traceback(tb)
-
def handle_operation_error(self, operr):
- block = self.unrollstack(SFlowException.kind)
+ block = self.unrollstack(SApplicationException.kind)
if block is None:
- # no handler found for the exception
- # try to preserve the CPython-level traceback
- import sys
- tb = sys.exc_info()[2]
- raise operr, None, tb
+ raise operr
else:
- unroller = SFlowException(operr)
+ unroller = SApplicationException(operr)
next_instr = block.handle(self, unroller)
return next_instr
+ def BAD_OPCODE(self, _, next_instr):
+ raise FlowingError(self, "This operation is not RPython")
+
+ def BREAK_LOOP(self, oparg, next_instr):
+ return self.unrollstack_and_jump(SBreakLoop.singleton)
+
+ def CONTINUE_LOOP(self, startofloop, next_instr):
+ unroller = SContinueLoop(startofloop)
+ return self.unrollstack_and_jump(unroller)
+
+ def cmp_lt(self, w_1, w_2):
+ return self.space.lt(w_1, w_2)
+
+ def cmp_le(self, w_1, w_2):
+ return self.space.le(w_1, w_2)
+
+ def cmp_eq(self, w_1, w_2):
+ return self.space.eq(w_1, w_2)
+
+ def cmp_ne(self, w_1, w_2):
+ return self.space.ne(w_1, w_2)
+
+ def cmp_gt(self, w_1, w_2):
+ return self.space.gt(w_1, w_2)
+
+ def cmp_ge(self, w_1, w_2):
+ return self.space.ge(w_1, w_2)
+
+ def cmp_in(self, w_1, w_2):
+ return self.space.contains(w_2, w_1)
+
+ def cmp_not_in(self, w_1, w_2):
+ return self.space.not_(self.space.contains(w_2, w_1))
+
+ def cmp_is(self, w_1, w_2):
+ return self.space.is_(w_1, w_2)
+
+ def cmp_is_not(self, w_1, w_2):
+ return self.space.not_(self.space.is_(w_1, w_2))
+
+ def cmp_exc_match(self, w_1, w_2):
+ return self.space.newbool(self.space.exception_match(w_1, w_2))
+
+ def COMPARE_OP(self, testnum, next_instr):
+ w_2 = self.popvalue()
+ w_1 = self.popvalue()
+ w_result = getattr(self, compare_method[testnum])(w_1, w_2)
+ self.pushvalue(w_result)
+
def RAISE_VARARGS(self, nbargs, next_instr):
space = self.space
if nbargs == 0:
@@ -538,7 +539,7 @@
# re-raising an implicit operation makes it an explicit one
operr = FSException(operr.w_type, operr.w_value)
self.last_exception = operr
- raise RaiseWithExplicitTraceback(operr)
+ raise operr
else:
raise FSException(space.w_TypeError,
space.wrap("raise: no active exception to re-raise"))
@@ -550,8 +551,7 @@
w_value = self.popvalue()
if 1:
w_type = self.popvalue()
- operror = FSException(w_type, w_value)
- operror.normalize_exception(space)
+ operror = space.exc_from_raise(w_type, w_value)
raise operror
def IMPORT_NAME(self, nameindex, next_instr):
@@ -580,17 +580,45 @@
return next_instr # now inside a 'finally' block
def END_FINALLY(self, oparg, next_instr):
- unroller = self.end_finally()
- if isinstance(unroller, SuspendedUnroller):
- # go on unrolling the stack
- block = self.unrollstack(unroller.kind)
- if block is None:
- w_result = unroller.nomoreblocks()
- self.pushvalue(w_result)
- raise Return
- else:
- next_instr = block.handle(self, unroller)
- return next_instr
+ # unlike CPython, there are two statically distinct cases: the
+ # END_FINALLY might be closing an 'except' block or a 'finally'
+ # block. In the first case, the stack contains three items:
+ # [exception type we are now handling]
+ # [exception value we are now handling]
+ # [wrapped SApplicationException]
+ # In the case of a finally: block, the stack contains only one
+ # item (unlike CPython which can have 1, 2 or 3 items):
+ # [wrapped subclass of SuspendedUnroller]
+ w_top = self.popvalue()
+ if w_top == self.space.w_None:
+ # finally: block with no unroller active
+ return
+ try:
+ unroller = self.space.unwrap(w_top)
+ except UnwrapException:
+ pass
+ else:
+ if isinstance(unroller, SuspendedUnroller):
+ # case of a finally: block
+ return self.unroll_finally(unroller)
+ # case of an except: block. We popped the exception type
+ self.popvalue() # Now we pop the exception value
+ unroller = self.space.unwrap(self.popvalue())
+ return self.unroll_finally(unroller)
+
+ def unroll_finally(self, unroller):
+ # go on unrolling the stack
+ block = self.unrollstack(unroller.kind)
+ if block is None:
+ w_result = unroller.nomoreblocks()
+ self.pushvalue(w_result)
+ raise Return
+ else:
+ return block.handle(self, unroller)
+
+ def POP_BLOCK(self, oparg, next_instr):
+ block = self.pop_block()
+ block.cleanupstack(self) # the block knows how to clean up the value stack
def JUMP_ABSOLUTE(self, jumpto, next_instr):
return jumpto
@@ -603,11 +631,48 @@
# isn't popped straightaway.
self.pushvalue(None)
+ PRINT_EXPR = BAD_OPCODE
+ PRINT_ITEM_TO = BAD_OPCODE
+ PRINT_NEWLINE_TO = BAD_OPCODE
+
+ def PRINT_ITEM(self, oparg, next_instr):
+ w_item = self.popvalue()
+ w_s = self.space.do_operation('str', w_item)
+ self.space.appcall(rpython_print_item, w_s)
+
+ def PRINT_NEWLINE(self, oparg, next_instr):
+ self.space.appcall(rpython_print_newline)
+
+ def FOR_ITER(self, jumpby, next_instr):
+ w_iterator = self.peekvalue()
+ try:
+ w_nextitem = self.space.next(w_iterator)
+ except FSException, e:
+ if not self.space.exception_match(e.w_type, self.space.w_StopIteration):
+ raise
+ # iterator exhausted
+ self.popvalue()
+ next_instr += jumpby
+ else:
+ self.pushvalue(w_nextitem)
+ return next_instr
+
+ def SETUP_LOOP(self, offsettoend, next_instr):
+ block = LoopBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
+ def SETUP_EXCEPT(self, offsettoend, next_instr):
+ block = ExceptBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
+ def SETUP_FINALLY(self, offsettoend, next_instr):
+ block = FinallyBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
def SETUP_WITH(self, offsettoend, next_instr):
# A simpler version than the 'real' 2.7 one:
# directly call manager.__enter__(), don't use special lookup functions
# which don't make sense on the RPython type system.
- from pypy.interpreter.pyopcode import WithBlock
w_manager = self.peekvalue()
w_exit = self.space.getattr(w_manager, self.space.wrap("__exit__"))
self.settopvalue(w_exit)
@@ -616,10 +681,47 @@
self.lastblock = block
self.pushvalue(w_result)
+ def WITH_CLEANUP(self, oparg, next_instr):
+ # Note: RPython context managers receive None in lieu of tracebacks
+ # and cannot suppress the exception.
+ # This opcode changed a lot between CPython versions
+ if (self.pycode.magic >= 0xa0df2ef
+ # Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
+ or self.pycode.magic >= 0xa0df2d1):
+ # implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
+ w_unroller = self.popvalue()
+ w_exitfunc = self.popvalue()
+ self.pushvalue(w_unroller)
+ elif self.pycode.magic >= 0xa0df28c:
+ # Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
+ w_exitfunc = self.popvalue()
+ w_unroller = self.peekvalue(0)
+ else:
+ raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
+
+ unroller = self.space.unwrap(w_unroller)
+ w_None = self.space.w_None
+ if isinstance(unroller, SApplicationException):
+ operr = unroller.operr
+ # The annotator won't allow to merge exception types with None.
+ # Replace it with the exception value...
+ self.space.call_function(w_exitfunc,
+ operr.w_value, operr.w_value, w_None)
+ else:
+ self.space.call_function(w_exitfunc, w_None, w_None, w_None)
+
def LOAD_GLOBAL(self, nameindex, next_instr):
w_result = self.space.find_global(self.w_globals, self.getname_u(nameindex))
self.pushvalue(w_result)
+ def LOAD_ATTR(self, nameindex, next_instr):
+ "obj.attributename"
+ w_obj = self.popvalue()
+ w_attributename = self.getname_w(nameindex)
+ w_value = self.space.getattr(w_obj, w_attributename)
+ self.pushvalue(w_value)
+ LOOKUP_METHOD = LOAD_ATTR
+
def BUILD_LIST_FROM_ARG(self, _, next_instr):
# This opcode was added with pypy-1.8. Here is a simpler
# version, enough for annotation.
@@ -647,23 +749,173 @@
def argument_factory(self, *args):
return ArgumentsForTranslation(self.space, *args)
- def call_contextmanager_exit_function(self, w_func, w_typ, w_val, w_tb):
- if w_typ is not self.space.w_None:
- # The annotator won't allow to merge exception types with None.
- # Replace it with the exception value...
- w_typ = w_val
- self.space.call_function(w_func, w_typ, w_val, w_tb)
- # Return None so that the flow space statically knows that we didn't
- # swallow the exception
- return self.space.w_None
-
### Frame blocks ###
-class SFlowException(SApplicationException):
- """Flowspace override for SApplicationException"""
+class SuspendedUnroller(object):
+ """Abstract base class for interpreter-level objects that
+ instruct the interpreter to change the control flow and the
+ block stack.
+
+ The concrete subclasses correspond to the various values WHY_XXX
+ values of the why_code enumeration in ceval.c:
+
+ WHY_NOT, OK, not this one :-)
+ WHY_EXCEPTION, SApplicationException
+ WHY_RERAISE, implemented differently, see Reraise
+ WHY_RETURN, SReturnValue
+ WHY_BREAK, SBreakLoop
+ WHY_CONTINUE, SContinueLoop
+ WHY_YIELD not needed
+ """
+ def nomoreblocks(self):
+ raise BytecodeCorruption("misplaced bytecode - should not return")
+
+ # NB. for the flow object space, the state_(un)pack_variables methods
+ # give a way to "pickle" and "unpickle" the SuspendedUnroller by
+ # enumerating the Variables it contains.
+
+class SReturnValue(SuspendedUnroller):
+ """Signals a 'return' statement.
+ Argument is the wrapped object to return."""
+ kind = 0x01
+ def __init__(self, w_returnvalue):
+ self.w_returnvalue = w_returnvalue
+
+ def nomoreblocks(self):
+ return self.w_returnvalue
+
+ def state_unpack_variables(self, space):
+ return [self.w_returnvalue]
+
+ @staticmethod
+ def state_pack_variables(space, w_returnvalue):
+ return SReturnValue(w_returnvalue)
+
+class SApplicationException(SuspendedUnroller):
+ """Signals an application-level exception
+ (i.e. an OperationException)."""
+ kind = 0x02
+ def __init__(self, operr):
+ self.operr = operr
+
+ def nomoreblocks(self):
+ raise self.operr
+
def state_unpack_variables(self, space):
return [self.operr.w_type, self.operr.w_value]
@staticmethod
def state_pack_variables(space, w_type, w_value):
- return SFlowException(FSException(w_type, w_value))
+ return SApplicationException(FSException(w_type, w_value))
+
+class SBreakLoop(SuspendedUnroller):
+ """Signals a 'break' statement."""
+ kind = 0x04
+
+ def state_unpack_variables(self, space):
+ return []
+
+ @staticmethod
+ def state_pack_variables(space):
+ return SBreakLoop.singleton
+
+SBreakLoop.singleton = SBreakLoop()
+
+class SContinueLoop(SuspendedUnroller):
+ """Signals a 'continue' statement.
+ Argument is the bytecode position of the beginning of the loop."""
+ kind = 0x08
+ def __init__(self, jump_to):
+ self.jump_to = jump_to
+
+ def state_unpack_variables(self, space):
+ return [space.wrap(self.jump_to)]
+
+ @staticmethod
+ def state_pack_variables(space, w_jump_to):
+ return SContinueLoop(space.int_w(w_jump_to))
+
+
+class FrameBlock(object):
+ """Abstract base class for frame blocks from the blockstack,
+ used by the SETUP_XXX and POP_BLOCK opcodes."""
+
+ def __init__(self, frame, handlerposition, previous):
+ self.handlerposition = handlerposition
+ self.valuestackdepth = frame.valuestackdepth
+ self.previous = previous # this makes a linked list of blocks
+
+ def __eq__(self, other):
+ return (self.__class__ is other.__class__ and
+ self.handlerposition == other.handlerposition and
+ self.valuestackdepth == other.valuestackdepth)
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __hash__(self):
+ return hash((self.handlerposition, self.valuestackdepth))
+
+ def cleanupstack(self, frame):
+ frame.dropvaluesuntil(self.valuestackdepth)
+
+ def handle(self, frame, unroller):
+ raise NotImplementedError
+
+class LoopBlock(FrameBlock):
+ """A loop block. Stores the end-of-loop pointer in case of 'break'."""
+
+ _opname = 'SETUP_LOOP'
+ handling_mask = SBreakLoop.kind | SContinueLoop.kind
+
+ def handle(self, frame, unroller):
+ if isinstance(unroller, SContinueLoop):
+ # re-push the loop block without cleaning up the value stack,
+ # and jump to the beginning of the loop, stored in the
+ # exception's argument
+ frame.append_block(self)
+ return unroller.jump_to
+ else:
+ # jump to the end of the loop
+ self.cleanupstack(frame)
+ return self.handlerposition
+
+class ExceptBlock(FrameBlock):
+ """An try:except: block. Stores the position of the exception handler."""
+
+ _opname = 'SETUP_EXCEPT'
+ handling_mask = SApplicationException.kind
+
+ def handle(self, frame, unroller):
+ # push the exception to the value stack for inspection by the
+ # exception handler (the code after the except:)
+ self.cleanupstack(frame)
+ assert isinstance(unroller, SApplicationException)
+ operationerr = unroller.operr
+ # the stack setup is slightly different than in CPython:
+ # instead of the traceback, we store the unroller object,
+ # wrapped.
+ frame.pushvalue(frame.space.wrap(unroller))
+ frame.pushvalue(operationerr.get_w_value(frame.space))
+ frame.pushvalue(operationerr.w_type)
+ frame.last_exception = operationerr
+ return self.handlerposition # jump to the handler
+
+class FinallyBlock(FrameBlock):
+ """A try:finally: block. Stores the position of the exception handler."""
+
+ _opname = 'SETUP_FINALLY'
+ handling_mask = -1 # handles every kind of SuspendedUnroller
+
+ def handle(self, frame, unroller):
+ # any abnormal reason for unrolling a finally: triggers the end of
+ # the block unrolling and the entering the finally: handler.
+ self.cleanupstack(frame)
+ frame.pushvalue(frame.space.wrap(unroller))
+ return self.handlerposition # jump to the handler
+
+
+class WithBlock(FinallyBlock):
+
+ def handle(self, frame, unroller):
+ return FinallyBlock.handle(self, frame, unroller)
diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py
--- a/pypy/objspace/flow/framestate.py
+++ b/pypy/objspace/flow/framestate.py
@@ -1,4 +1,3 @@
-from pypy.interpreter.pyopcode import SuspendedUnroller
from pypy.rlib.unroll import SpecTag
from pypy.objspace.flow.model import *
@@ -106,6 +105,7 @@
UNPICKLE_TAGS = {}
def recursively_flatten(space, lst):
+ from pypy.objspace.flow.flowcontext import SuspendedUnroller
i = 0
while i < len(lst):
item = lst[i]
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -1,14 +1,14 @@
# ______________________________________________________________________
import __builtin__
import sys
-import operator
import types
-from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
-from pypy.interpreter import pyframe, argument
-from pypy.objspace.flow.model import *
+from pypy.interpreter.baseobjspace import ObjSpace
+from pypy.interpreter.argument import ArgumentsForTranslation
+from pypy.objspace.flow.model import (Constant, Variable, WrapException,
+ UnwrapException, checkgraph, SpaceOperation)
from pypy.objspace.flow import operation
from pypy.objspace.flow.flowcontext import (FlowSpaceFrame, fixeggblocks,
- OperationThatShouldNotBePropagatedError, FSException, FlowingError)
+ FSException, FlowingError)
from pypy.objspace.flow.specialcase import SPECIAL_CASES
from pypy.rlib.unroll import unrolling_iterable, _unroller
from pypy.rlib import rstackovf, rarithmetic
@@ -38,47 +38,32 @@
}
# ______________________________________________________________________
-class FlowObjSpace(ObjSpace):
+class FlowObjSpace(object):
"""NOT_RPYTHON.
The flow objspace space is used to produce a flow graph by recording
the space operations that the interpreter generates when it interprets
(the bytecode of) some function.
"""
+ w_None = Constant(None)
+ builtin = Constant(__builtin__)
+ sys = Constant(sys)
+ w_False = Constant(False)
+ w_True = Constant(True)
+ w_type = Constant(type)
+ w_tuple = Constant(tuple)
+ for exc in [KeyError, ValueError, IndexError, StopIteration,
+ AssertionError, TypeError, AttributeError, ImportError]:
+ clsname = exc.__name__
+ locals()['w_' + clsname] = Constant(exc)
- full_exceptions = False
- FrameClass = FlowSpaceFrame
+ # the following exceptions should not show up
+ # during flow graph construction
+ w_NameError = None
+ w_UnboundLocalError = None
- def initialize(self):
- self.w_None = Constant(None)
- self.builtin = Constant(__builtin__)
- self.sys = Constant(sys)
- self.w_False = Constant(False)
- self.w_True = Constant(True)
- self.w_type = Constant(type)
- self.w_tuple = Constant(tuple)
- for exc in [KeyError, ValueError, IndexError, StopIteration,
- AssertionError, TypeError, AttributeError, ImportError]:
- clsname = exc.__name__
- setattr(self, 'w_'+clsname, Constant(exc))
- # the following exceptions are the ones that should not show up
- # during flow graph construction; they are triggered by
- # non-R-Pythonic constructs or real bugs like typos.
- for exc in [NameError, UnboundLocalError]:
- clsname = exc.__name__
- setattr(self, 'w_'+clsname, None)
- self.specialcases = SPECIAL_CASES.copy()
- #self.make_builtins()
- #self.make_sys()
- # w_str is needed because cmp_exc_match of frames checks against it,
- # as string exceptions are deprecated
- self.w_str = Constant(str)
- # objects which should keep their SomeObjectness
- self.not_really_const = NOT_REALLY_CONST
-
- # disable superclass methods
- enter_cache_building_mode = None
- leave_cache_building_mode = None
- createcompiler = None
+ specialcases = SPECIAL_CASES
+ # objects which should keep their SomeObjectness
+ not_really_const = NOT_REALLY_CONST
def is_w(self, w_one, w_two):
return self.is_true(self.is_(w_one, w_two))
@@ -103,6 +88,12 @@
def newslice(self, w_start, w_stop, w_step):
return self.do_operation('newslice', w_start, w_stop, w_step)
+ def newbool(self, b):
+ if b:
+ return self.w_True
+ else:
+ return self.w_False
+
def wrap(self, obj):
if isinstance(obj, (Variable, Constant)):
raise TypeError("already wrapped: " + repr(obj))
@@ -167,53 +158,77 @@
raise UnwrapException
return obj
- def interpclass_w(self, w_obj):
- obj = self.unwrap(w_obj)
- if isinstance(obj, Wrappable):
- return obj
- return None
+ def exception_issubclass_w(self, w_cls1, w_cls2):
+ return self.is_true(self.issubtype(w_cls1, w_cls2))
- def _check_constant_interp_w_or_w_None(self, RequiredClass, w_obj):
+ def _exception_match(self, w_exc_type, w_check_class):
+ """Helper for exception_match
+
+ Handles the base case where w_check_class is a constant exception
+ type.
"""
- WARNING: this implementation is not complete at all. It's just enough
- to be used by end_finally() inside pyopcode.py.
- """
- return w_obj == self.w_None or (isinstance(w_obj, Constant) and
- isinstance(w_obj.value, RequiredClass))
-
- def getexecutioncontext(self):
- return self.frame
+ if self.is_w(w_exc_type, w_check_class):
+ return True # fast path (also here to handle string exceptions)
+ try:
+ return self.exception_issubclass_w(w_exc_type, w_check_class)
+ except FSException, e:
+ if e.match(self, self.w_TypeError): # string exceptions maybe
+ return False
+ raise
def exception_match(self, w_exc_type, w_check_class):
+ """Checks if the given exception type matches 'w_check_class'."""
try:
check_class = self.unwrap(w_check_class)
except UnwrapException:
- raise Exception, "non-constant except guard"
+ raise FlowingError(self.frame, "Non-constant except guard.")
if check_class in (NotImplementedError, AssertionError):
raise FlowingError(self.frame,
"Catching %s is not valid in RPython" % check_class.__name__)
if not isinstance(check_class, tuple):
# the simple case
- return ObjSpace.exception_match(self, w_exc_type, w_check_class)
+ return self._exception_match(w_exc_type, w_check_class)
# special case for StackOverflow (see rlib/rstackovf.py)
if check_class == rstackovf.StackOverflow:
w_real_class = self.wrap(rstackovf._StackOverflow)
- return ObjSpace.exception_match(self, w_exc_type, w_real_class)
+ return self._exception_match(w_exc_type, w_real_class)
# checking a tuple of classes
for w_klass in self.fixedview(w_check_class):
if self.exception_match(w_exc_type, w_klass):
return True
return False
- def getconstclass(space, w_cls):
- try:
- ecls = space.unwrap(w_cls)
- except UnwrapException:
- pass
+ def exc_from_raise(self, w_type, w_value):
+ """
+ Create a wrapped exception from the arguments of a raise statement.
+
+ Returns an FSException object whose w_value is an instance of w_type.
+ """
+ if self.isinstance_w(w_type, self.w_type):
+ # this is for all cases of the form (Class, something)
+ if self.is_w(w_value, self.w_None):
+ # raise Type: we assume we have to instantiate Type
+ w_value = self.call_function(w_type)
+ w_type = self.type(w_value)
+ else:
+ w_valuetype = self.type(w_value)
+ if self.exception_issubclass_w(w_valuetype, w_type):
+ # raise Type, Instance: let etype be the exact type of value
+ w_type = w_valuetype
+ else:
+ # raise Type, X: assume X is the constructor argument
+ w_value = self.call_function(w_type, w_value)
+ w_type = self.type(w_value)
else:
- if isinstance(ecls, (type, types.ClassType)):
- return ecls
- return None
+ # the only case left here is (inst, None), from a 'raise inst'.
+ w_inst = w_type
+ w_instclass = self.type(w_inst)
+ if not self.is_w(w_value, self.w_None):
+ raise FSException(self.w_TypeError, self.wrap(
+ "instance exception may not have a separate value"))
+ w_value = w_inst
+ w_type = w_instclass
+ return FSException(w_type, w_value)
def build_flow(self, func, constargs={}, tweak_for_generator=True):
"""
@@ -232,7 +247,7 @@
def fixedview(self, w_tuple, expected_length=None):
return self.unpackiterable(w_tuple, expected_length)
- listview = fixedview
+ listview = fixedview_unroll = fixedview
More information about the pypy-commit
mailing list