[prev in list] [next in list] [prev in thread] [next in thread]
List: pypy-svn
Subject: [pypy-commit] pypy default: (ronan, Edd reviewing) hg merge less-stringly-ops
From: rlamy <noreply () buildbot ! pypy ! org>
Date: 2013-08-31 14:39:29
Message-ID: 20130831143929.C6CE41C0205 () cobra ! cs ! uni-duesseldorf ! de
[Download RAW message or body]
Author: Ronan Lamy <ronan.lamy@gmail.com>
Branch:
Changeset: r66725:1f657fecc55c
Date: 2013-08-31 15:36 +0100
http://bitbucket.org/pypy/pypy/changeset/1f657fecc55c/
Log: (ronan, Edd reviewing) hg merge less-stringly-ops
Use subclasses of SpaceOperation instead of SpaceOperator objects.
Random cleanups in flowspace.
diff too long, truncating to 2000 out of 2520 lines
diff --git a/rpython/annotator/argument.py b/rpython/annotator/argument.py
--- a/rpython/annotator/argument.py
+++ b/rpython/annotator/argument.py
@@ -25,7 +25,7 @@
return [Ellipsis]
raise CallPatternTooComplex("'*' argument must be SomeTuple")
- def is_true(self, s_tup):
+ def bool(self, s_tup):
assert isinstance(s_tup, SomeTuple)
return bool(s_tup.items)
@@ -208,7 +208,7 @@
args_w = data_args_w[:need_cnt]
for argname, w_arg in zip(argnames[need_cnt:], data_args_w[need_cnt:]):
unfiltered_kwds_w[argname] = w_arg
- assert not space.is_true(data_w_stararg)
+ assert not space.bool(data_w_stararg)
else:
stararg_w = space.unpackiterable(data_w_stararg)
args_w = data_args_w + stararg_w
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -688,7 +688,7 @@
fn, block, i = self.position_key
op = block.operations[i]
if opname is not None:
- assert op.opname == opname or op.opname in opname
+ assert op.opname == opname
if arity is not None:
assert len(op.args) == arity
if pos is not None:
diff --git a/rpython/annotator/builtin.py b/rpython/annotator/builtin.py
--- a/rpython/annotator/builtin.py
+++ b/rpython/annotator/builtin.py
@@ -94,7 +94,7 @@
def builtin_bool(s_obj):
- return s_obj.is_true()
+ return s_obj.bool()
def builtin_int(s_obj, s_base=None):
if isinstance(s_obj, SomeInteger):
diff --git a/rpython/annotator/test/test_annrpython.py \
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -1490,7 +1490,7 @@
s = a.build_types(snippet.prime, [int])
assert s.knowntype == bool
- def test_and_is_true_coalesce(self):
+ def test_and_bool_coalesce(self):
def f(a,b,c,d,e):
x = a and b
if x:
@@ -1500,7 +1500,7 @@
s = a.build_types(f, [int, str, a.bookkeeper.immutablevalue(1.0), \
a.bookkeeper.immutablevalue('d'), a.bookkeeper.immutablevalue('e')])
assert s == annmodel.SomeTuple([annmodel.SomeChar(), \
a.bookkeeper.immutablevalue(1.0)])
- def test_is_true_coalesce2(self):
+ def test_bool_coalesce2(self):
def f(a,b,a1,b1,c,d,e):
x = (a or b) and (a1 or b1)
if x:
@@ -1514,7 +1514,7 @@
assert s == annmodel.SomeTuple([annmodel.SomeChar(),
a.bookkeeper.immutablevalue(1.0)])
- def test_is_true_coalesce_sanity(self):
+ def test_bool_coalesce_sanity(self):
def f(a):
while a:
pass
diff --git a/rpython/annotator/test/test_argument.py \
b/rpython/annotator/test/test_argument.py
--- a/rpython/annotator/test/test_argument.py
+++ b/rpython/annotator/test/test_argument.py
@@ -7,7 +7,7 @@
def newtuple(self, items):
return tuple(items)
- def is_true(self, obj):
+ def bool(self, obj):
return bool(obj)
def unpackiterable(self, it):
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -20,10 +20,10 @@
def immutablevalue(x):
return getbookkeeper().immutablevalue(x)
-UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'delattr',
+UNARY_OPERATIONS = set(['len', 'bool', 'getattr', 'setattr', 'delattr',
'simple_call', 'call_args', 'str', 'repr',
'iter', 'next', 'invert', 'type', 'issubtype',
- 'pos', 'neg', 'nonzero', 'abs', 'hex', 'oct',
+ 'pos', 'neg', 'abs', 'hex', 'oct',
'ord', 'int', 'float', 'long',
'hash', 'id', # <== not supported any more
'getslice', 'setslice', 'delslice',
@@ -57,7 +57,7 @@
def len(obj):
return SomeInteger(nonneg=True)
- def is_true_behavior(obj, s):
+ def bool_behavior(obj, s):
if obj.is_immutable_constant():
s.const = bool(obj.const)
else:
@@ -65,13 +65,13 @@
if s_len.is_immutable_constant():
s.const = s_len.const > 0
- def is_true(s_obj):
+ def bool(s_obj):
r = SomeBool()
- s_obj.is_true_behavior(r)
+ s_obj.bool_behavior(r)
bk = getbookkeeper()
knowntypedata = {}
- op = bk._find_current_op(opname=("is_true", "nonzero"), arity=1)
+ op = bk._find_current_op(opname="bool", arity=1)
arg = op.args[0]
s_nonnone_obj = s_obj
if s_obj.can_be_none():
@@ -80,9 +80,6 @@
r.set_knowntypedata(knowntypedata)
return r
- def nonzero(obj):
- return obj.is_true()
-
def hash(obj):
raise AnnotatorError("cannot use hash() in RPython")
@@ -176,7 +173,7 @@
abs = neg
- def is_true(self):
+ def bool(self):
if self.is_immutable_constant():
return getbookkeeper().immutablevalue(bool(self.const))
return s_Bool
@@ -208,7 +205,7 @@
abs_ovf = _clone(abs, [OverflowError])
class __extend__(SomeBool):
- def is_true(self):
+ def bool(self):
return self
def invert(self):
@@ -667,7 +664,7 @@
# create or update the attribute in clsdef
clsdef.generalize_attr(attr, s_value)
- def is_true_behavior(ins, s):
+ def bool_behavior(ins, s):
if not ins.can_be_None:
s.const = True
@@ -736,7 +733,7 @@
d = [desc.bind_under(classdef, name) for desc in pbc.descriptions]
return SomePBC(d, can_be_None=pbc.can_be_None)
- def is_true_behavior(pbc, s):
+ def bool_behavior(pbc, s):
if pbc.isNone():
s.const = False
elif not pbc.can_be_None:
@@ -797,7 +794,7 @@
v = p.ll_ptrtype._example()(*llargs)
return ll_to_annotation(v)
- def is_true(p):
+ def bool(p):
return s_Bool
class __extend__(SomeLLADTMeth):
@@ -831,5 +828,5 @@
llmemory.supported_access_types[s_attr.const])
getattr.can_only_throw = []
- def is_true(s_addr):
+ def bool(s_addr):
return s_Bool
diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py
--- a/rpython/flowspace/bytecode.py
+++ b/rpython/flowspace/bytecode.py
@@ -3,6 +3,7 @@
"""
from rpython.tool.stdlib_opcode import host_bytecode_spec
from opcode import EXTENDED_ARG, HAVE_ARGUMENT
+import opcode
from rpython.flowspace.argument import Signature
from rpython.flowspace.flowcontext import BytecodeCorruption
@@ -83,10 +84,10 @@
Returns (next_instr, opname, oparg).
"""
co_code = self.co_code
- opcode = ord(co_code[pos])
+ opnum = ord(co_code[pos])
next_instr = pos + 1
- if opcode >= HAVE_ARGUMENT:
+ if opnum >= HAVE_ARGUMENT:
lo = ord(co_code[next_instr])
hi = ord(co_code[next_instr+1])
next_instr += 2
@@ -94,16 +95,18 @@
else:
oparg = 0
- while opcode == EXTENDED_ARG:
- opcode = ord(co_code[next_instr])
- if opcode < HAVE_ARGUMENT:
+ while opnum == EXTENDED_ARG:
+ opnum = ord(co_code[next_instr])
+ if opnum < HAVE_ARGUMENT:
raise BytecodeCorruption
lo = ord(co_code[next_instr+1])
hi = ord(co_code[next_instr+2])
next_instr += 3
oparg = (oparg * 65536) | (hi * 256) | lo
- opname = self.opnames[opcode]
+ if opnum in opcode.hasjrel:
+ oparg += next_instr
+ opname = self.opnames[opnum]
return next_instr, opname, oparg
@property
diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py
--- a/rpython/flowspace/flowcontext.py
+++ b/rpython/flowspace/flowcontext.py
@@ -9,19 +9,16 @@
from rpython.tool.stdlib_opcode import host_bytecode_spec
from rpython.flowspace.argument import CallSpec
from rpython.flowspace.model import (Constant, Variable, Block, Link,
- c_last_exception, SpaceOperation)
+ c_last_exception, SpaceOperation, const)
from rpython.flowspace.framestate import (FrameState, recursively_unflatten,
recursively_flatten)
from rpython.flowspace.specialcase import (rpython_print_item,
rpython_print_newline)
-from rpython.flowspace.operation import op
class FlowingError(Exception):
""" Signals invalid RPython in the function being analysed"""
- def __init__(self, frame, msg):
- super(FlowingError, self).__init__(msg)
- self.frame = frame
+ frame = None
def __str__(self):
msg = ["\n"]
@@ -133,7 +130,7 @@
def append(self, operation):
raise NotImplementedError
- def guessbool(self, frame, w_condition, **kwds):
+ def guessbool(self, frame, w_condition):
raise AssertionError("cannot guessbool(%s)" % (w_condition,))
@@ -215,7 +212,7 @@
[str(s) for s in self.listtoreplay[self.index:]]))
self.index += 1
- def guessbool(self, frame, w_condition, **kwds):
+ def guessbool(self, frame, w_condition):
assert self.index == len(self.listtoreplay)
frame.recorder = self.nextreplayer
return self.booloutcome
@@ -309,7 +306,7 @@
def unsupportedoperation(OPCODE, msg):
def UNSUPPORTED(self, *ignored):
- raise FlowingError(self, "%s is not RPython" % (msg,))
+ raise FlowingError("%s is not RPython" % (msg,))
UNSUPPORTED.func_name = OPCODE
return UNSUPPORTED
@@ -351,7 +348,7 @@
if closure is None:
self.closure = []
else:
- self.closure = [self.space.wrap(c.cell_contents) for c in closure]
+ self.closure = [const(c.cell_contents) for c in closure]
assert len(self.closure) == len(self.pycode.co_freevars)
def init_locals_stack(self, code):
@@ -412,21 +409,7 @@
self.locals_stack_w[:len(items_w)] = items_w
self.dropvaluesuntil(len(items_w))
- def unrollstack(self, unroller_kind):
- while self.blockstack:
- block = self.blockstack.pop()
- if (block.handling_mask & unroller_kind) != 0:
- return block
- block.cleanupstack(self)
- return None
-
- def unrollstack_and_jump(self, unroller):
- block = self.unrollstack(unroller.kind)
- if block is None:
- raise BytecodeCorruption("misplaced bytecode - should not return")
- return block.handle(self, unroller)
-
- def getstate(self):
+ def getstate(self, next_pos):
# getfastscope() can return real None, for undefined locals
data = self.save_locals_stack()
if self.last_exception is None:
@@ -435,42 +418,46 @@
else:
data.append(self.last_exception.w_type)
data.append(self.last_exception.w_value)
- recursively_flatten(self.space, data)
- return FrameState(data, self.blockstack[:], self.last_instr)
+ recursively_flatten(data)
+ return FrameState(data, self.blockstack[:], next_pos)
def setstate(self, state):
""" Reset the frame to the given state. """
data = state.mergeable[:]
- recursively_unflatten(self.space, data)
+ recursively_unflatten(data)
self.restore_locals_stack(data[:-2]) # Nones == undefined locals
if data[-2] == Constant(None):
assert data[-1] == Constant(None)
self.last_exception = None
else:
self.last_exception = FSException(data[-2], data[-1])
- self.last_instr = state.next_instr
self.blockstack = state.blocklist[:]
- def guessbool(self, w_condition, **kwds):
- return self.recorder.guessbool(self, w_condition, **kwds)
+ def guessbool(self, w_condition):
+ if isinstance(w_condition, Constant):
+ return w_condition.value
+ return self.recorder.guessbool(self, w_condition)
def do_operation(self, name, *args_w):
+ spaceop = SpaceOperation(name, args_w, Variable())
+ self.record(spaceop)
+ return spaceop.result
+
+ def record(self, spaceop):
recorder = self.recorder
if getattr(recorder, 'final_state', None) is not None:
self.mergeblock(recorder.crnt_block, recorder.final_state)
raise StopFlowing
- spaceop = SpaceOperation(name, args_w, Variable())
spaceop.offset = self.last_instr
recorder.append(spaceop)
- return spaceop.result
- def do_operation_with_implicit_exceptions(self, name, *args_w):
- w_result = self.do_operation(name, *args_w)
- oper = getattr(op, name)
- self.handle_implicit_exceptions(oper.canraise)
- return w_result
+ def do_op(self, op):
+ self.record(op)
+ if op.canraise:
+ self.guessexception(op.canraise)
+ return op.result
- def handle_implicit_exceptions(self, exceptions):
+ def guessexception(self, exceptions, force=False):
"""
Catch possible exceptions implicitly.
@@ -479,9 +466,12 @@
even if the interpreter re-raises the exception, it will not be the
same ImplicitOperationError instance internally.
"""
- if not exceptions:
+ if not force and not any(isinstance(block, (ExceptBlock, FinallyBlock))
+ for block in self.blockstack):
+ # The implicit exception wouldn't be caught and would later get
+ # removed, so don't bother creating it.
return
- return self.recorder.guessexception(self, *exceptions)
+ self.recorder.guessexception(self, *exceptions)
def build_flow(self):
graph = self.graph
@@ -493,11 +483,12 @@
def record_block(self, block):
self.setstate(block.framestate)
+ next_pos = block.framestate.next_instr
self.recorder = block.make_recorder()
try:
while True:
- self.last_instr = self.handle_bytecode(self.last_instr)
- self.recorder.final_state = self.getstate()
+ next_pos = self.handle_bytecode(next_pos)
+ self.recorder.final_state = self.getstate(next_pos)
except ImplicitOperationError, e:
if isinstance(e.w_type, Constant):
@@ -525,6 +516,11 @@
link = Link([w_result], self.graph.returnblock)
self.recorder.crnt_block.closeblock(link)
+ except FlowingError as exc:
+ if exc.frame is None:
+ exc.frame = self
+ raise
+
self.recorder = None
def mergeblock(self, currentblock, currentstate):
@@ -578,27 +574,23 @@
break
def handle_bytecode(self, next_instr):
+ self.last_instr = next_instr
next_instr, methodname, oparg = self.pycode.read(next_instr)
try:
- res = getattr(self, methodname)(oparg, next_instr)
+ res = getattr(self, methodname)(oparg)
return res if res is not None else next_instr
except FSException, operr:
return self.handle_operation_error(operr)
def handle_operation_error(self, operr):
- block = self.unrollstack(SApplicationException.kind)
- if block is None:
- raise operr
- else:
- unroller = SApplicationException(operr)
- next_instr = block.handle(self, unroller)
- return next_instr
+ unroller = SApplicationException(operr)
+ return unroller.unroll(self)
def getlocalvarname(self, index):
return self.pycode.co_varnames[index]
def getconstant_w(self, index):
- return self.space.wrap(self.pycode.consts[index])
+ return const(self.pycode.consts[index])
def getname_u(self, index):
return self.pycode.names[index]
@@ -606,15 +598,15 @@
def getname_w(self, index):
return Constant(self.pycode.names[index])
- def BAD_OPCODE(self, _, next_instr):
- raise FlowingError(self, "This operation is not RPython")
+ def BAD_OPCODE(self, _):
+ raise FlowingError("This operation is not RPython")
- def BREAK_LOOP(self, oparg, next_instr):
- return self.unrollstack_and_jump(SBreakLoop.singleton)
+ def BREAK_LOOP(self, oparg):
+ return SBreakLoop.singleton.unroll(self)
- def CONTINUE_LOOP(self, startofloop, next_instr):
+ def CONTINUE_LOOP(self, startofloop):
unroller = SContinueLoop(startofloop)
- return self.unrollstack_and_jump(unroller)
+ return unroller.unroll(self)
def cmp_lt(self, w_1, w_2):
return self.space.lt(w_1, w_2)
@@ -649,13 +641,13 @@
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):
+ def COMPARE_OP(self, testnum):
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):
+ def RAISE_VARARGS(self, nbargs):
space = self.space
if nbargs == 0:
if self.last_exception is not None:
@@ -679,31 +671,26 @@
operror = space.exc_from_raise(w_type, w_value)
raise operror
- def IMPORT_NAME(self, nameindex, next_instr):
+ def IMPORT_NAME(self, nameindex):
space = self.space
modulename = self.getname_u(nameindex)
- glob = space.unwrap(self.w_globals)
- fromlist = space.unwrap(self.popvalue())
+ glob = self.w_globals.value
+ fromlist = self.popvalue().value
level = self.popvalue().value
w_obj = space.import_name(modulename, glob, None, fromlist, level)
self.pushvalue(w_obj)
- def IMPORT_FROM(self, nameindex, next_instr):
+ def IMPORT_FROM(self, nameindex):
w_name = self.getname_w(nameindex)
w_module = self.peekvalue()
self.pushvalue(self.space.import_from(w_module, w_name))
- def RETURN_VALUE(self, oparg, next_instr):
+ def RETURN_VALUE(self, oparg):
w_returnvalue = self.popvalue()
- block = self.unrollstack(SReturnValue.kind)
- if block is None:
- raise Return(w_returnvalue)
- else:
- unroller = SReturnValue(w_returnvalue)
- next_instr = block.handle(self, unroller)
- return next_instr # now inside a 'finally' block
+ unroller = SReturnValue(w_returnvalue)
+ return unroller.unroll(self)
- def END_FINALLY(self, oparg, next_instr):
+ def END_FINALLY(self, oparg):
# 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:
@@ -719,29 +706,21 @@
return
elif isinstance(w_top, SuspendedUnroller):
# case of a finally: block
- return self.unroll_finally(w_top)
+ return w_top.unroll(self)
else:
# case of an except: block. We popped the exception type
self.popvalue() # Now we pop the exception value
unroller = self.popvalue()
- return self.unroll_finally(unroller)
+ return unroller.unroll(self)
- def unroll_finally(self, unroller):
- # go on unrolling the stack
- block = self.unrollstack(unroller.kind)
- if block is None:
- unroller.nomoreblocks()
- else:
- return block.handle(self, unroller)
-
- def POP_BLOCK(self, oparg, next_instr):
+ def POP_BLOCK(self, oparg):
block = self.blockstack.pop()
block.cleanupstack(self) # the block knows how to clean up the value stack
- def JUMP_ABSOLUTE(self, jumpto, next_instr):
+ def JUMP_ABSOLUTE(self, jumpto):
return jumpto
- def YIELD_VALUE(self, _, next_instr):
+ def YIELD_VALUE(self, _):
assert self.pycode.is_generator
w_result = self.popvalue()
self.do_operation('yield', w_result)
@@ -753,67 +732,60 @@
PRINT_ITEM_TO = BAD_OPCODE
PRINT_NEWLINE_TO = BAD_OPCODE
- def PRINT_ITEM(self, oparg, next_instr):
+ def PRINT_ITEM(self, oparg):
w_item = self.popvalue()
w_s = self.do_operation('str', w_item)
self.space.appcall(rpython_print_item, w_s)
- def PRINT_NEWLINE(self, oparg, next_instr):
+ def PRINT_NEWLINE(self, oparg):
self.space.appcall(rpython_print_newline)
- def JUMP_FORWARD(self, jumpby, next_instr):
- next_instr += jumpby
- return next_instr
+ def JUMP_FORWARD(self, target):
+ return target
- def JUMP_IF_FALSE(self, stepby, next_instr):
+ def JUMP_IF_FALSE(self, target):
# Python <= 2.6 only
w_cond = self.peekvalue()
- if not self.space.is_true(w_cond):
- next_instr += stepby
- return next_instr
+ if not self.guessbool(self.space.bool(w_cond)):
+ return target
- def JUMP_IF_TRUE(self, stepby, next_instr):
+ def JUMP_IF_TRUE(self, target):
# Python <= 2.6 only
w_cond = self.peekvalue()
- if self.space.is_true(w_cond):
- next_instr += stepby
- return next_instr
+ if self.guessbool(self.space.bool(w_cond)):
+ return target
- def POP_JUMP_IF_FALSE(self, target, next_instr):
+ def POP_JUMP_IF_FALSE(self, target):
w_value = self.popvalue()
- if not self.space.is_true(w_value):
+ if not self.guessbool(self.space.bool(w_value)):
return target
- return next_instr
- def POP_JUMP_IF_TRUE(self, target, next_instr):
+ def POP_JUMP_IF_TRUE(self, target):
w_value = self.popvalue()
- if self.space.is_true(w_value):
+ if self.guessbool(self.space.bool(w_value)):
return target
- return next_instr
- def JUMP_IF_FALSE_OR_POP(self, target, next_instr):
+ def JUMP_IF_FALSE_OR_POP(self, target):
w_value = self.peekvalue()
- if not self.space.is_true(w_value):
+ if not self.guessbool(self.space.bool(w_value)):
return target
self.popvalue()
- return next_instr
- def JUMP_IF_TRUE_OR_POP(self, target, next_instr):
+ def JUMP_IF_TRUE_OR_POP(self, target):
w_value = self.peekvalue()
- if self.space.is_true(w_value):
+ if self.guessbool(self.space.bool(w_value)):
return target
self.popvalue()
- return next_instr
- def JUMP_IF_NOT_DEBUG(self, target, next_instr):
- return next_instr
+ def JUMP_IF_NOT_DEBUG(self, target):
+ pass
- def GET_ITER(self, oparg, next_instr):
+ def GET_ITER(self, oparg):
w_iterable = self.popvalue()
w_iterator = self.space.iter(w_iterable)
self.pushvalue(w_iterator)
- def FOR_ITER(self, jumpby, next_instr):
+ def FOR_ITER(self, target):
w_iterator = self.peekvalue()
try:
w_nextitem = self.space.next(w_iterator)
@@ -822,36 +794,35 @@
raise
# iterator exhausted
self.popvalue()
- next_instr += jumpby
+ return target
else:
self.pushvalue(w_nextitem)
- return next_instr
- def SETUP_LOOP(self, offsettoend, next_instr):
- block = LoopBlock(self, next_instr + offsettoend)
+ def SETUP_LOOP(self, target):
+ block = LoopBlock(self, target)
self.blockstack.append(block)
- def SETUP_EXCEPT(self, offsettoend, next_instr):
- block = ExceptBlock(self, next_instr + offsettoend)
+ def SETUP_EXCEPT(self, target):
+ block = ExceptBlock(self, target)
self.blockstack.append(block)
- def SETUP_FINALLY(self, offsettoend, next_instr):
- block = FinallyBlock(self, next_instr + offsettoend)
+ def SETUP_FINALLY(self, target):
+ block = FinallyBlock(self, target)
self.blockstack.append(block)
- def SETUP_WITH(self, offsettoend, next_instr):
+ def SETUP_WITH(self, target):
# 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.
w_manager = self.peekvalue()
- w_exit = self.space.getattr(w_manager, self.space.wrap("__exit__"))
+ w_exit = self.space.getattr(w_manager, const("__exit__"))
self.settopvalue(w_exit)
w_result = self.space.call_method(w_manager, "__enter__")
- block = WithBlock(self, next_instr + offsettoend)
+ block = WithBlock(self, target)
self.blockstack.append(block)
self.pushvalue(w_result)
- def WITH_CLEANUP(self, oparg, next_instr):
+ def WITH_CLEANUP(self, oparg):
# Note: RPython context managers receive None in lieu of tracebacks
# and cannot suppress the exception.
# This opcode changed a lot between CPython versions
@@ -873,22 +844,22 @@
else:
self.space.call_function(w_exitfunc, w_None, w_None, w_None)
- def LOAD_FAST(self, varindex, next_instr):
+ def LOAD_FAST(self, varindex):
w_value = self.locals_stack_w[varindex]
if w_value is None:
- raise FlowingError(self, "Local variable referenced before assignment")
+ raise FlowingError("Local variable referenced before assignment")
self.pushvalue(w_value)
- def LOAD_CONST(self, constindex, next_instr):
+ def LOAD_CONST(self, constindex):
w_const = self.getconstant_w(constindex)
self.pushvalue(w_const)
- def LOAD_GLOBAL(self, nameindex, next_instr):
+ def LOAD_GLOBAL(self, nameindex):
w_result = self.space.find_global(self.w_globals, self.getname_u(nameindex))
self.pushvalue(w_result)
LOAD_NAME = LOAD_GLOBAL
- def LOAD_ATTR(self, nameindex, next_instr):
+ def LOAD_ATTR(self, nameindex):
"obj.attributename"
w_obj = self.popvalue()
w_attributename = self.getname_w(nameindex)
@@ -896,29 +867,29 @@
self.pushvalue(w_value)
LOOKUP_METHOD = LOAD_ATTR
- def LOAD_DEREF(self, varindex, next_instr):
+ def LOAD_DEREF(self, varindex):
self.pushvalue(self.closure[varindex])
- def STORE_FAST(self, varindex, next_instr):
+ def STORE_FAST(self, varindex):
w_newvalue = self.popvalue()
assert w_newvalue is not None
self.locals_stack_w[varindex] = w_newvalue
- def STORE_GLOBAL(self, nameindex, next_instr):
+ def STORE_GLOBAL(self, nameindex):
varname = self.getname_u(nameindex)
- raise FlowingError(self,
- "Attempting to modify global variable %r." % (varname))
+ raise FlowingError(
+ "Attempting to modify global variable %r." % (varname))
- def POP_TOP(self, oparg, next_instr):
+ def POP_TOP(self, oparg):
self.popvalue()
- def ROT_TWO(self, oparg, next_instr):
+ def ROT_TWO(self, oparg):
w_1 = self.popvalue()
w_2 = self.popvalue()
self.pushvalue(w_1)
self.pushvalue(w_2)
- def ROT_THREE(self, oparg, next_instr):
+ def ROT_THREE(self, oparg):
w_1 = self.popvalue()
w_2 = self.popvalue()
w_3 = self.popvalue()
@@ -926,7 +897,7 @@
self.pushvalue(w_3)
self.pushvalue(w_2)
- def ROT_FOUR(self, oparg, next_instr):
+ def ROT_FOUR(self, oparg):
w_1 = self.popvalue()
w_2 = self.popvalue()
w_3 = self.popvalue()
@@ -936,11 +907,11 @@
self.pushvalue(w_3)
self.pushvalue(w_2)
- def DUP_TOP(self, oparg, next_instr):
+ def DUP_TOP(self, oparg):
w_1 = self.peekvalue()
self.pushvalue(w_1)
- def DUP_TOPX(self, itemcount, next_instr):
+ def DUP_TOPX(self, itemcount):
delta = itemcount - 1
while True:
itemcount -= 1
@@ -958,7 +929,7 @@
for OPCODE, op in _unsupported_ops:
locals()[OPCODE] = unsupportedoperation(OPCODE, op)
- def BUILD_LIST_FROM_ARG(self, _, next_instr):
+ def BUILD_LIST_FROM_ARG(self, _):
# This opcode was added with pypy-1.8. Here is a simpler
# version, enough for annotation.
last_val = self.popvalue()
@@ -967,14 +938,14 @@
def call_function(self, oparg, w_star=None, w_starstar=None):
if w_starstar is not None:
- raise FlowingError(self, "Dict-unpacking is not RPython")
+ raise FlowingError("Dict-unpacking is not RPython")
n_arguments = oparg & 0xff
n_keywords = (oparg >> 8) & 0xff
keywords = {}
for _ in range(n_keywords):
w_value = self.popvalue()
w_key = self.popvalue()
- key = self.space.str_w(w_key)
+ key = w_key.value
keywords[key] = w_value
arguments = self.popvalues(n_arguments)
args = CallSpec(arguments, keywords, w_star, w_starstar)
@@ -982,37 +953,37 @@
w_result = self.space.call_args(w_function, args)
self.pushvalue(w_result)
- def CALL_FUNCTION(self, oparg, next_instr):
+ def CALL_FUNCTION(self, oparg):
self.call_function(oparg)
CALL_METHOD = CALL_FUNCTION
- def CALL_FUNCTION_VAR(self, oparg, next_instr):
+ def CALL_FUNCTION_VAR(self, oparg):
w_varargs = self.popvalue()
self.call_function(oparg, w_varargs)
- def CALL_FUNCTION_KW(self, oparg, next_instr):
+ def CALL_FUNCTION_KW(self, oparg):
w_varkw = self.popvalue()
self.call_function(oparg, None, w_varkw)
- def CALL_FUNCTION_VAR_KW(self, oparg, next_instr):
+ def CALL_FUNCTION_VAR_KW(self, oparg):
w_varkw = self.popvalue()
w_varargs = self.popvalue()
self.call_function(oparg, w_varargs, w_varkw)
- def MAKE_FUNCTION(self, numdefaults, next_instr):
+ def MAKE_FUNCTION(self, numdefaults):
w_codeobj = self.popvalue()
defaults = self.popvalues(numdefaults)
fn = self.space.newfunction(w_codeobj, self.w_globals, defaults)
self.pushvalue(fn)
- def STORE_ATTR(self, nameindex, next_instr):
+ def STORE_ATTR(self, nameindex):
"obj.attributename = newvalue"
w_attributename = self.getname_w(nameindex)
w_obj = self.popvalue()
w_newvalue = self.popvalue()
self.space.setattr(w_obj, w_attributename, w_newvalue)
- def UNPACK_SEQUENCE(self, itemcount, next_instr):
+ def UNPACK_SEQUENCE(self, itemcount):
w_iterable = self.popvalue()
items = self.space.unpack_sequence(w_iterable, itemcount)
for w_item in reversed(items):
@@ -1023,18 +994,18 @@
w_result = self.space.getslice(w_obj, w_start, w_end)
self.pushvalue(w_result)
- def SLICE_0(self, oparg, next_instr):
+ def SLICE_0(self, oparg):
self.slice(self.space.w_None, self.space.w_None)
- def SLICE_1(self, oparg, next_instr):
+ def SLICE_1(self, oparg):
w_start = self.popvalue()
self.slice(w_start, self.space.w_None)
- def SLICE_2(self, oparg, next_instr):
+ def SLICE_2(self, oparg):
w_end = self.popvalue()
self.slice(self.space.w_None, w_end)
- def SLICE_3(self, oparg, next_instr):
+ def SLICE_3(self, oparg):
w_end = self.popvalue()
w_start = self.popvalue()
self.slice(w_start, w_end)
@@ -1044,18 +1015,18 @@
w_newvalue = self.popvalue()
self.space.setslice(w_obj, w_start, w_end, w_newvalue)
- def STORE_SLICE_0(self, oparg, next_instr):
+ def STORE_SLICE_0(self, oparg):
self.storeslice(self.space.w_None, self.space.w_None)
- def STORE_SLICE_1(self, oparg, next_instr):
+ def STORE_SLICE_1(self, oparg):
w_start = self.popvalue()
self.storeslice(w_start, self.space.w_None)
- def STORE_SLICE_2(self, oparg, next_instr):
+ def STORE_SLICE_2(self, oparg):
w_end = self.popvalue()
self.storeslice(self.space.w_None, w_end)
- def STORE_SLICE_3(self, oparg, next_instr):
+ def STORE_SLICE_3(self, oparg):
w_end = self.popvalue()
w_start = self.popvalue()
self.storeslice(w_start, w_end)
@@ -1064,23 +1035,23 @@
w_obj = self.popvalue()
self.space.delslice(w_obj, w_start, w_end)
- def DELETE_SLICE_0(self, oparg, next_instr):
+ def DELETE_SLICE_0(self, oparg):
self.deleteslice(self.space.w_None, self.space.w_None)
- def DELETE_SLICE_1(self, oparg, next_instr):
+ def DELETE_SLICE_1(self, oparg):
w_start = self.popvalue()
self.deleteslice(w_start, self.space.w_None)
- def DELETE_SLICE_2(self, oparg, next_instr):
+ def DELETE_SLICE_2(self, oparg):
w_end = self.popvalue()
self.deleteslice(self.space.w_None, w_end)
- def DELETE_SLICE_3(self, oparg, next_instr):
+ def DELETE_SLICE_3(self, oparg):
w_end = self.popvalue()
w_start = self.popvalue()
self.deleteslice(w_start, w_end)
- def LIST_APPEND(self, oparg, next_instr):
+ def LIST_APPEND(self, oparg):
w = self.popvalue()
if sys.version_info < (2, 7):
v = self.popvalue()
@@ -1088,27 +1059,27 @@
v = self.peekvalue(oparg - 1)
self.space.call_method(v, 'append', w)
- def DELETE_FAST(self, varindex, next_instr):
+ def DELETE_FAST(self, varindex):
if self.locals_stack_w[varindex] is None:
varname = self.getlocalvarname(varindex)
message = "local variable '%s' referenced before assignment"
raise UnboundLocalError(message, varname)
self.locals_stack_w[varindex] = None
- def STORE_MAP(self, oparg, next_instr):
+ def STORE_MAP(self, oparg):
w_key = self.popvalue()
w_value = self.popvalue()
w_dict = self.peekvalue()
self.space.setitem(w_dict, w_key, w_value)
- def STORE_SUBSCR(self, oparg, next_instr):
+ def STORE_SUBSCR(self, oparg):
"obj[subscr] = newvalue"
w_subscr = self.popvalue()
w_obj = self.popvalue()
w_newvalue = self.popvalue()
self.space.setitem(w_obj, w_subscr, w_newvalue)
- def BUILD_SLICE(self, numargs, next_instr):
+ def BUILD_SLICE(self, numargs):
if numargs == 3:
w_step = self.popvalue()
elif numargs == 2:
@@ -1120,23 +1091,23 @@
w_slice = self.space.newslice(w_start, w_end, w_step)
self.pushvalue(w_slice)
- def DELETE_SUBSCR(self, oparg, next_instr):
+ def DELETE_SUBSCR(self, oparg):
"del obj[subscr]"
w_subscr = self.popvalue()
w_obj = self.popvalue()
self.space.delitem(w_obj, w_subscr)
- def BUILD_TUPLE(self, itemcount, next_instr):
+ def BUILD_TUPLE(self, itemcount):
items = self.popvalues(itemcount)
w_tuple = self.space.newtuple(items)
self.pushvalue(w_tuple)
- def BUILD_LIST(self, itemcount, next_instr):
+ def BUILD_LIST(self, itemcount):
items = self.popvalues(itemcount)
w_list = self.space.newlist(items)
self.pushvalue(w_list)
- def BUILD_MAP(self, itemcount, next_instr):
+ def BUILD_MAP(self, itemcount):
w_dict = self.space.newdict()
self.pushvalue(w_dict)
@@ -1147,15 +1118,15 @@
# Set literals, set comprehensions
- def BUILD_SET(self, oparg, next_instr):
+ def BUILD_SET(self, oparg):
raise NotImplementedError("BUILD_SET")
- def SET_ADD(self, oparg, next_instr):
+ def SET_ADD(self, oparg):
raise NotImplementedError("SET_ADD")
# Dict comprehensions
- def MAP_ADD(self, oparg, next_instr):
+ def MAP_ADD(self, oparg):
raise NotImplementedError("MAP_ADD")
# Closures
@@ -1182,6 +1153,14 @@
WHY_CONTINUE, SContinueLoop
WHY_YIELD not needed
"""
+ def unroll(self, frame):
+ while frame.blockstack:
+ block = frame.blockstack.pop()
+ if isinstance(self, block.handles):
+ return block.handle(frame, self)
+ block.cleanupstack(frame)
+ return self.nomoreblocks()
+
def nomoreblocks(self):
raise BytecodeCorruption("misplaced bytecode - should not return")
@@ -1192,7 +1171,6 @@
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
@@ -1200,17 +1178,16 @@
def nomoreblocks(self):
raise Return(self.w_returnvalue)
- def state_unpack_variables(self, space):
+ def state_unpack_variables(self):
return [self.w_returnvalue]
@staticmethod
- def state_pack_variables(space, w_returnvalue):
+ def state_pack_variables(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
@@ -1218,22 +1195,21 @@
def nomoreblocks(self):
raise self.operr
- def state_unpack_variables(self, space):
+ def state_unpack_variables(self):
return [self.operr.w_type, self.operr.w_value]
@staticmethod
- def state_pack_variables(space, w_type, w_value):
+ def state_pack_variables(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):
+ def state_unpack_variables(self):
return []
@staticmethod
- def state_pack_variables(space):
+ def state_pack_variables():
return SBreakLoop.singleton
SBreakLoop.singleton = SBreakLoop()
@@ -1241,17 +1217,16 @@
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)]
+ def state_unpack_variables(self):
+ return [const(self.jump_to)]
@staticmethod
- def state_pack_variables(space, w_jump_to):
- return SContinueLoop(space.int_w(w_jump_to))
+ def state_pack_variables(w_jump_to):
+ return SContinueLoop(w_jump_to.value)
class FrameBlock(object):
@@ -1282,8 +1257,7 @@
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
+ handles = (SBreakLoop, SContinueLoop)
def handle(self, frame, unroller):
if isinstance(unroller, SContinueLoop):
@@ -1300,8 +1274,7 @@
class ExceptBlock(FrameBlock):
"""An try:except: block. Stores the position of the exception handler."""
- _opname = 'SETUP_EXCEPT'
- handling_mask = SApplicationException.kind
+ handles = SApplicationException
def handle(self, frame, unroller):
# push the exception to the value stack for inspection by the
@@ -1321,8 +1294,7 @@
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
+ handles = SuspendedUnroller
def handle(self, frame, unroller):
# any abnormal reason for unrolling a finally: triggers the end of
diff --git a/rpython/flowspace/framestate.py b/rpython/flowspace/framestate.py
--- a/rpython/flowspace/framestate.py
+++ b/rpython/flowspace/framestate.py
@@ -106,7 +106,7 @@
UNPICKLE_TAGS = {}
-def recursively_flatten(space, lst):
+def recursively_flatten(lst):
from rpython.flowspace.flowcontext import SuspendedUnroller
i = 0
while i < len(lst):
@@ -114,7 +114,7 @@
if not isinstance(unroller, SuspendedUnroller):
i += 1
else:
- vars = unroller.state_unpack_variables(space)
+ vars = unroller.state_unpack_variables()
key = unroller.__class__, len(vars)
try:
tag = PICKLE_TAGS[key]
@@ -124,12 +124,12 @@
lst[i:i + 1] = [tag] + vars
-def recursively_unflatten(space, lst):
+def recursively_unflatten(lst):
for i in xrange(len(lst) - 1, -1, -1):
item = lst[i]
if item in UNPICKLE_TAGS:
unrollerclass, argcount = UNPICKLE_TAGS[item]
arguments = lst[i + 1:i + 1 + argcount]
del lst[i + 1:i + 1 + argcount]
- unroller = unrollerclass.state_pack_variables(space, *arguments)
+ unroller = unrollerclass.state_pack_variables(*arguments)
lst[i] = unroller
diff --git a/rpython/flowspace/model.py b/rpython/flowspace/model.py
--- a/rpython/flowspace/model.py
+++ b/rpython/flowspace/model.py
@@ -8,7 +8,6 @@
from rpython.tool.uid import uid, Hashable
from rpython.tool.sourcetools import PY_IDENTIFIER, nice_repr_for_func
-from rpython.rlib.rarithmetic import is_valid_int, r_longlong, r_ulonglong, r_uint
"""
@@ -355,6 +354,21 @@
during its construction"""
+# method-wrappers have not enough introspection in CPython
+if hasattr(complex.real.__get__, 'im_self'):
+ type_with_bad_introspection = None # on top of PyPy
+else:
+ type_with_bad_introspection = type(complex.real.__get__)
+
+def const(obj):
+ if isinstance(obj, (Variable, Constant)):
+ raise TypeError("already wrapped: " + repr(obj))
+ # method-wrapper have ill-defined comparison and introspection
+ # to appear in a flow graph
+ if type(obj) is type_with_bad_introspection:
+ raise WrapException
+ return Constant(obj)
+
class SpaceOperation(object):
__slots__ = "opname args result offset".split()
@@ -489,7 +503,8 @@
if not __debug__:
return
try:
-
+ from rpython.rlib.rarithmetic import (is_valid_int, r_longlong,
+ r_ulonglong, r_uint)
vars_previous_blocks = {}
exitblocks = {graph.returnblock: 1, # retval
diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py
--- a/rpython/flowspace/objspace.py
+++ b/rpython/flowspace/objspace.py
@@ -9,9 +9,9 @@
from rpython.flowspace.argument import CallSpec
from rpython.flowspace.model import (Constant, Variable, WrapException,
- UnwrapException, checkgraph)
+ UnwrapException, checkgraph, const)
from rpython.flowspace.bytecode import HostCode
-from rpython.flowspace import operation
+from rpython.flowspace.operation import op
from rpython.flowspace.flowcontext import (FlowSpaceFrame, fixeggblocks,
FSException, FlowingError)
from rpython.flowspace.generator import (tweak_generator_graph,
@@ -20,15 +20,8 @@
from rpython.flowspace.specialcase import SPECIAL_CASES
from rpython.rlib.unroll import unrolling_iterable, _unroller
from rpython.rlib import rstackovf
-from rpython.rlib.rarithmetic import is_valid_int
-# method-wrappers have not enough introspection in CPython
-if hasattr(complex.real.__get__, 'im_self'):
- type_with_bad_introspection = None # on top of PyPy
-else:
- type_with_bad_introspection = type(complex.real.__get__)
-
# the following gives us easy access to declare more for applications:
NOT_REALLY_CONST = {
Constant(sys): {
@@ -74,7 +67,6 @@
(the bytecode of) some function.
"""
w_None = Constant(None)
- builtin = Constant(__builtin__)
sys = Constant(sys)
w_False = Constant(False)
w_True = Constant(True)
@@ -97,9 +89,6 @@
def build_flow(self, func):
return build_flow(func, self)
- def is_w(self, w_one, w_two):
- return self.is_true(self.is_(w_one, w_two))
-
is_ = None # real version added by add_operations()
id = None # real version added by add_operations()
@@ -126,73 +115,36 @@
return self.w_False
def newfunction(self, w_code, w_globals, defaults_w):
- try:
- code = self.unwrap(w_code)
- globals = self.unwrap(w_globals)
- defaults = tuple([self.unwrap(value) for value in defaults_w])
- except UnwrapException:
- raise FlowingError(self.frame, "Dynamically created function must"
+ if not all(isinstance(value, Constant) for value in defaults_w):
+ raise FlowingError("Dynamically created function must"
" have constant default values.")
+ code = w_code.value
+ globals = w_globals.value
+ defaults = tuple([default.value for default in defaults_w])
fn = types.FunctionType(code, globals, code.co_name, defaults)
return Constant(fn)
- def wrap(self, obj):
- if isinstance(obj, (Variable, Constant)):
- raise TypeError("already wrapped: " + repr(obj))
- # method-wrapper have ill-defined comparison and introspection
- # to appear in a flow graph
- if type(obj) is type_with_bad_introspection:
- raise WrapException
- return Constant(obj)
-
def exc_wrap(self, exc):
- w_value = self.wrap(exc)
- w_type = self.wrap(type(exc))
+ w_value = const(exc)
+ w_type = const(type(exc))
return FSException(w_type, w_value)
- def int_w(self, w_obj):
- if isinstance(w_obj, Constant):
- val = w_obj.value
- if not is_valid_int(val):
- raise TypeError("expected integer: " + repr(w_obj))
- return val
- return self.unwrap(w_obj)
-
- def str_w(self, w_obj):
- if isinstance(w_obj, Constant):
- val = w_obj.value
- if type(val) is not str:
- raise TypeError("expected string: " + repr(w_obj))
- return val
- return self.unwrap(w_obj)
-
- def unwrap(self, w_obj):
- if isinstance(w_obj, Variable):
- raise UnwrapException
- elif isinstance(w_obj, Constant):
- return w_obj.value
- else:
- raise TypeError("not wrapped: " + repr(w_obj))
-
- def exception_issubclass_w(self, w_cls1, w_cls2):
- return self.is_true(self.issubtype(w_cls1, w_cls2))
-
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 FlowingError(self.frame, "Non-constant except guard.")
+ frame = self.frame
+ if not isinstance(w_check_class, Constant):
+ raise FlowingError("Non-constant except guard.")
+ check_class = w_check_class.value
if check_class in (NotImplementedError, AssertionError):
- raise FlowingError(self.frame,
+ raise FlowingError(
"Catching %s is not valid in RPython" % check_class.__name__)
if not isinstance(check_class, tuple):
# the simple case
- return self.exception_issubclass_w(w_exc_type, w_check_class)
+ return frame.guessbool(self.issubtype(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 self.exception_issubclass_w(w_exc_type, w_real_class)
+ w_real_class = const(rstackovf._StackOverflow)
+ return frame.guessbool(self.issubtype(w_exc_type, w_real_class))
# checking a tuple of classes
for w_klass in self.unpackiterable(w_check_class):
if self.exception_match(w_exc_type, w_klass):
@@ -205,14 +157,16 @@
Returns an FSException object whose w_value is an instance of w_type.
"""
- if self.isinstance_w(w_arg1, self.w_type):
+ frame = self.frame
+ if frame.guessbool(self.call_function(const(isinstance), w_arg1,
+ self.w_type)):
# this is for all cases of the form (Class, something)
- if self.is_w(w_arg2, self.w_None):
+ if frame.guessbool(self.is_(w_arg2, self.w_None)):
# raise Type: we assume we have to instantiate Type
w_value = self.call_function(w_arg1)
else:
w_valuetype = self.type(w_arg2)
- if self.exception_issubclass_w(w_valuetype, w_arg1):
+ if frame.guessbool(self.issubtype(w_valuetype, w_arg1)):
# raise Type, Instance: let etype be the exact type of value
w_value = w_arg2
else:
@@ -220,7 +174,7 @@
w_value = self.call_function(w_arg1, w_arg2)
else:
# the only case left here is (inst, None), from a 'raise inst'.
- if not self.is_w(w_arg2, self.w_None):
+ if not frame.guessbool(self.is_(w_arg2, self.w_None)):
raise self.exc_wrap(TypeError(
"instance exception may not have a separate value"))
w_value = w_arg1
@@ -230,40 +184,34 @@
def unpackiterable(self, w_iterable):
if isinstance(w_iterable, Constant):
l = w_iterable.value
- return [self.wrap(x) for x in l]
+ return [const(x) for x in l]
else:
raise UnwrapException("cannot unpack a Variable iterable ")
def unpack_sequence(self, w_iterable, expected_length):
if isinstance(w_iterable, Constant):
- l = list(self.unwrap(w_iterable))
+ l = list(w_iterable.value)
if len(l) != expected_length:
raise ValueError
- return [self.wrap(x) for x in l]
+ return [const(x) for x in l]
else:
w_len = self.len(w_iterable)
- w_correct = self.eq(w_len, self.wrap(expected_length))
- if not self.is_true(w_correct):
+ w_correct = self.eq(w_len, const(expected_length))
+ if not self.frame.guessbool(self.bool(w_correct)):
e = self.exc_from_raise(self.w_ValueError, self.w_None)
raise e
- return [self.frame.do_operation('getitem', w_iterable, self.wrap(i))
+ return [self.frame.do_operation('getitem', w_iterable, const(i))
for i in range(expected_length)]
# ____________________________________________________________
def not_(self, w_obj):
- return self.wrap(not self.is_true(w_obj))
-
- def is_true(self, w_obj):
- if w_obj.foldable():
- return bool(w_obj.value)
- w_truthvalue = self.frame.do_operation('is_true', w_obj)
- return self.frame.guessbool(w_truthvalue)
+ return const(not self.frame.guessbool(self.bool(w_obj)))
def iter(self, w_iterable):
if isinstance(w_iterable, Constant):
iterable = w_iterable.value
if isinstance(iterable, unrolling_iterable):
- return self.wrap(iterable.get_unroller())
+ return const(iterable.get_unroller())
w_iter = self.frame.do_operation("iter", w_iterable)
return w_iter
@@ -278,9 +226,9 @@
raise self.exc_wrap(StopIteration())
else:
frame.replace_in_stack(it, next_unroller)
- return self.wrap(v)
+ return const(v)
w_item = frame.do_operation("next", w_iter)
- frame.handle_implicit_exceptions([StopIteration, RuntimeError])
+ frame.guessexception([StopIteration, RuntimeError], force=True)
return w_item
@@ -290,8 +238,7 @@
if w_obj in self.not_really_const:
const_w = self.not_really_const[w_obj]
if w_name not in const_w:
- return self.frame.do_operation_with_implicit_exceptions('getattr',
- w_obj, w_name)
+ return self.frame.do_op(op.getattr(w_obj, w_name))
if w_obj.foldable() and w_name.foldable():
obj, name = w_obj.value, w_name.value
try:
@@ -300,23 +247,19 @@
etype = e.__class__
msg = "getattr(%s, %s) always raises %s: %s" % (
obj, name, etype, e)
- raise FlowingError(self.frame, msg)
+ raise FlowingError(msg)
try:
- return self.wrap(result)
+ return const(result)
except WrapException:
pass
- return self.frame.do_operation_with_implicit_exceptions('getattr',
- w_obj, w_name)
-
- def isinstance_w(self, w_obj, w_type):
- return self.is_true(self.isinstance(w_obj, w_type))
+ return self.frame.do_op(op.getattr(w_obj, w_name))
def import_name(self, name, glob=None, loc=None, frm=None, level=-1):
try:
mod = __import__(name, glob, loc, frm, level)
except ImportError as e:
raise self.exc_wrap(e)
- return self.wrap(mod)
+ return const(mod)
def import_from(self, w_module, w_name):
assert isinstance(w_module, Constant)
@@ -325,16 +268,15 @@
if w_module in self.not_really_const:
const_w = self.not_really_const[w_module]
if w_name not in const_w:
- return self.frame.do_operation_with_implicit_exceptions('getattr',
- w_module, w_name)
+ return self.frame.do_op(op.getattr(w_module, w_name))
try:
- return self.wrap(getattr(w_module.value, w_name.value))
+ return const(getattr(w_module.value, w_name.value))
except AttributeError:
raise self.exc_wrap(ImportError(
"cannot import name '%s'" % w_name.value))
def call_method(self, w_obj, methname, *arg_w):
- w_meth = self.getattr(w_obj, self.wrap(methname))
+ w_meth = self.getattr(w_obj, const(methname))
return self.call_function(w_meth, *arg_w)
def call_function(self, w_func, *args_w):
@@ -343,7 +285,7 @@
def appcall(self, func, *args_w):
"""Call an app-level RPython function directly"""
- w_func = self.wrap(func)
+ w_func = const(func)
return self.frame.do_operation('simple_call', w_func, *args_w)
def call_args(self, w_callable, args):
@@ -351,7 +293,7 @@
fn = w_callable.value
if hasattr(fn, "_flowspace_rewrite_directly_as_"):
fn = fn._flowspace_rewrite_directly_as_
- w_callable = self.wrap(fn)
+ w_callable = const(fn)
try:
sc = self.specialcases[fn] # TypeError if 'fn' not hashable
except (KeyError, TypeError):
@@ -362,7 +304,7 @@
args_w = args.arguments_w + self.unpackiterable(args.w_stararg)
else:
args_w = args.arguments_w
- return sc(self, args_w)
+ return sc(self, *args_w)
if args.keywords or isinstance(args.w_stararg, Variable):
shape, args_w = args.flatten()
@@ -383,79 +325,31 @@
types.TypeType)) and
c.__module__ in ['__builtin__', 'exceptions']):
if c in builtins_exceptions:
- self.frame.handle_implicit_exceptions(builtins_exceptions[c])
+ self.frame.guessexception(builtins_exceptions[c])
return w_res
# *any* exception for non-builtins
- self.frame.handle_implicit_exceptions([Exception])
+ self.frame.guessexception([Exception])
return w_res
def find_global(self, w_globals, varname):
try:
- value = self.unwrap(w_globals)[varname]
+ value = w_globals.value[varname]
except KeyError:
# not in the globals, now look in the built-ins
try:
- value = getattr(self.unwrap(self.builtin), varname)
+ value = getattr(__builtin__, varname)
except AttributeError:
- message = "global name '%s' is not defined" % varname
- raise FlowingError(self.frame, self.wrap(message))
- return self.wrap(value)
+ raise FlowingError("global name '%s' is not defined" % varname)
+ return const(value)
-def make_impure_op(oper):
- def generic_operator(self, *args_w):
- if len(args_w) != oper.arity:
- raise TypeError(oper.name + " got the wrong number of arguments")
- w_result = self.frame.do_operation_with_implicit_exceptions(oper.name, \
*args_w)
- return w_result
+def make_op(cls):
+ def generic_operator(self, *args):
+ return cls(*args).eval(self.frame)
return generic_operator
-def make_op(oper):
- """Add function operation to the flow space."""
- name = oper.name
- func = oper.pyfunc
-
- def generic_operator(self, *args_w):
- assert len(args_w) == oper.arity, name + " got the wrong number of \
arguments"
- args = []
- if all(w_arg.foldable() for w_arg in args_w):
- args = [w_arg.value for w_arg in args_w]
- # All arguments are constants: call the operator now
- try:
- result = func(*args)
- except Exception, e:
- etype = e.__class__
- msg = "%s%r always raises %s: %s" % (
- name, tuple(args), etype, e)
- raise FlowingError(self.frame, msg)
- else:
- # don't try to constant-fold operations giving a 'long'
- # result. The result is probably meant to be sent to
- # an intmask(), but the 'long' constant confuses the
- # annotator a lot.
- if oper.can_overflow and type(result) is long:
- pass
- # don't constant-fold getslice on lists, either
- elif name == 'getslice' and type(result) is list:
- pass
- # otherwise, fine
- else:
- try:
- return self.wrap(result)
- except WrapException:
- # type cannot sanely appear in flow graph,
- # store operation with variable result instead
- pass
- w_result = self.frame.do_operation_with_implicit_exceptions(name, *args_w)
- return w_result
- return generic_operator
-
-for oper in operation.op.__dict__.values():
- if getattr(FlowObjSpace, oper.name, None) is None:
- if oper.pure:
- op_method = make_op(oper)
- else:
- op_method = make_impure_op(oper)
- setattr(FlowObjSpace, oper.name, op_method)
+for cls in op.__dict__.values():
+ if getattr(FlowObjSpace, cls.opname, None) is None:
+ setattr(FlowObjSpace, cls.opname, make_op(cls))
def build_flow(func, space=FlowObjSpace()):
diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py
--- a/rpython/flowspace/operation.py
+++ b/rpython/flowspace/operation.py
@@ -7,53 +7,101 @@
import __future__
import operator
from rpython.tool.sourcetools import compile2
-from rpython.rlib.rarithmetic import ovfcheck
-from rpython.flowspace.model import Constant
+from rpython.flowspace.model import (Constant, WrapException, const, Variable,
+ SpaceOperation)
+from rpython.flowspace.specialcase import register_flow_sc
class _OpHolder(object): pass
op = _OpHolder()
func2op = {}
-class SpaceOperator(object):
- def __init__(self, name, arity, symbol, pyfunc, pure=False,
- can_overflow=False):
- self.name = name
- self.arity = arity
- self.symbol = symbol
- self.pyfunc = pyfunc
- self.pure = pure
- self.can_overflow = can_overflow
- self.canraise = []
+class HLOperation(SpaceOperation):
+ pure = False
+ def __init__(self, *args):
+ if len(args) != self.arity:
+ raise TypeError(self.opname + " got the wrong number of arguments")
+ self.args = list(args)
+ self.result = Variable()
+ self.offset = -1
- def make_sc(self):
- def sc_operator(space, args_w):
- if len(args_w) != self.arity:
- if self is op.pow and len(args_w) == 2:
- args_w = args_w + [Constant(None)]
- elif self is op.getattr and len(args_w) == 3:
+ @classmethod
+ def make_sc(cls):
+ def sc_operator(space, *args_w):
+ if len(args_w) != cls.arity:
+ if cls is op.pow and len(args_w) == 2:
+ args_w = list(args_w) + [Constant(None)]
+ elif cls is op.getattr and len(args_w) == 3:
return space.frame.do_operation('simple_call', \
Constant(getattr), *args_w) else:
raise Exception("should call %r with exactly %d arguments" % (
- self.name, self.arity))
+ cls.opname, cls.arity))
# completely replace the call with the underlying
# operation and its limited implicit exceptions semantic
- return getattr(space, self.name)(*args_w)
+ return getattr(space, cls.opname)(*args_w)
return sc_operator
+ def eval(self, frame):
+ result = self.constfold()
+ if result is not None:
+ return result
+ return frame.do_op(self)
+
+ def constfold(self):
+ return None
+
+class PureOperation(HLOperation):
+ pure = True
+
+ def constfold(self):
+ args = []
+ if all(w_arg.foldable() for w_arg in self.args):
+ args = [w_arg.value for w_arg in self.args]
+ # All arguments are constants: call the operator now
+ try:
+ result = self.pyfunc(*args)
+ except Exception as e:
+ from rpython.flowspace.flowcontext import FlowingError
+ msg = "%s%r always raises %s: %s" % (
+ self.opname, tuple(args), type(e), e)
+ raise FlowingError(msg)
+ else:
+ # don't try to constant-fold operations giving a 'long'
+ # result. The result is probably meant to be sent to
+ # an intmask(), but the 'long' constant confuses the
+ # annotator a lot.
+ if self.can_overflow and type(result) is long:
+ pass
+ # don't constant-fold getslice on lists, either
+ elif self.opname == 'getslice' and type(result) is list:
+ pass
+ # otherwise, fine
+ else:
+ try:
+ return const(result)
+ except WrapException:
+ # type cannot sanely appear in flow graph,
+ # store operation with variable result instead
+ pass
+
def add_operator(name, arity, symbol, pyfunc=None, pure=False, ovf=False):
operator_func = getattr(operator, name, None)
- oper = SpaceOperator(name, arity, symbol, pyfunc, pure, can_overflow=ovf)
- setattr(op, name, oper)
+ base_cls = PureOperation if pure else HLOperation
+ cls = type(name, (base_cls,), {'opname': name, 'arity': arity,
+ 'can_overflow': ovf, 'canraise': []})
+ setattr(op, name, cls)
if pyfunc is not None:
- func2op[pyfunc] = oper
+ func2op[pyfunc] = cls
if operator_func:
- func2op[operator_func] = oper
- if pyfunc is None:
- oper.pyfunc = operator_func
+ func2op[operator_func] = cls
+ if pyfunc is not None:
+ cls.pyfunc = staticmethod(pyfunc)
+ elif operator_func is not None:
+ cls.pyfunc = staticmethod(operator_func)
if ovf:
- ovf_func = lambda *args: ovfcheck(oper.pyfunc(*args))
+ from rpython.rlib.rarithmetic import ovfcheck
+ ovf_func = lambda *args: ovfcheck(cls.pyfunc(*args))
add_operator(name + '_ovf', arity, symbol, pyfunc=ovf_func)
# ____________________________________________________________
@@ -163,7 +211,6 @@
add_operator('is_', 2, 'is', pure=True)
add_operator('id', 1, 'id', pyfunc=id)
add_operator('type', 1, 'type', pyfunc=new_style_type, pure=True)
-add_operator('isinstance', 2, 'isinstance', pyfunc=isinstance, pure=True)
add_operator('issubtype', 2, 'issubtype', pyfunc=issubclass, pure=True) # not for \
old-style classes add_operator('repr', 1, 'repr', pyfunc=repr, pure=True)
add_operator('str', 1, 'str', pyfunc=str, pure=True)
@@ -182,9 +229,9 @@
add_operator('trunc', 1, 'trunc', pyfunc=unsupported)
add_operator('pos', 1, 'pos', pure=True)
add_operator('neg', 1, 'neg', pure=True, ovf=True)
-add_operator('nonzero', 1, 'truth', pyfunc=bool, pure=True)
-op.is_true = op.nonzero
-add_operator('abs' , 1, 'abs', pyfunc=abs, pure=True, ovf=True)
+add_operator('bool', 1, 'truth', pyfunc=bool, pure=True)
+op.is_true = op.nonzero = op.bool # for llinterp
+add_operator('abs', 1, 'abs', pyfunc=abs, pure=True, ovf=True)
add_operator('hex', 1, 'hex', pyfunc=hex, pure=True)
add_operator('oct', 1, 'oct', pyfunc=oct, pure=True)
add_operator('ord', 1, 'ord', pyfunc=ord, pure=True)
@@ -240,10 +287,13 @@
# Other functions that get directly translated to SpaceOperators
func2op[type] = op.type
-func2op[operator.truth] = op.nonzero
+func2op[operator.truth] = op.bool
if hasattr(__builtin__, 'next'):
func2op[__builtin__.next] = op.next
+for fn, oper in func2op.items():
+ register_flow_sc(fn)(oper.make_sc())
+
op_appendices = {
OverflowError: 'ovf',
@@ -266,7 +316,7 @@
oper = getattr(op, name)
lis = oper.canraise
if exc in lis:
- raise ValueError, "your list is causing duplication!"
+ raise ValueError("your list is causing duplication!")
lis.append(exc)
assert exc in op_appendices
diff --git a/rpython/flowspace/specialcase.py b/rpython/flowspace/specialcase.py
--- a/rpython/flowspace/specialcase.py
+++ b/rpython/flowspace/specialcase.py
@@ -1,13 +1,42 @@
-from rpython.flowspace.model import Constant
-from rpython.flowspace.operation import func2op, op
-from rpython.rlib.rarithmetic import r_uint
-from rpython.rlib.objectmodel import we_are_translated
+from rpython.flowspace.model import Constant, const
-def sc_import(space, args_w):
+SPECIAL_CASES = {}
+
+def register_flow_sc(func):
+ """Decorator triggering special-case handling of ``func``.
+
+ When the flow graph builder sees ``func``, it calls the decorated function
+ with ``decorated_func(space, *args_w)``, where ``args_w`` is a sequence of
+ flow objects (Constants or Variables).
+ """
+ def decorate(sc_func):
+ SPECIAL_CASES[func] = sc_func
+ return decorate
+
+@register_flow_sc(__import__)
+def sc_import(space, *args_w):
assert len(args_w) > 0 and len(args_w) <= 5, 'import needs 1 to 5 arguments'
- args = [space.unwrap(arg) for arg in args_w]
+ assert all(isinstance(arg, Constant) for arg in args_w)
+ args = [arg.value for arg in args_w]
return space.import_name(*args)
+@register_flow_sc(locals)
+def sc_locals(_, *args):
+ raise Exception(
+ "A function calling locals() is not RPython. "
+ "Note that if you're translating code outside the PyPy "
+ "repository, a likely cause is that py.test's --assert=rewrite "
+ "mode is getting in the way. You should copy the file "
+ "pytest.ini from the root of the PyPy repository into your "
+ "own project.")
+
+@register_flow_sc(isinstance)
+def sc_isinstance(space, w_instance, w_type):
+ if w_instance.foldable() and w_type.foldable():
+ return const(isinstance(w_instance.value, w_type.value))
+ return space.frame.do_operation('simple_call', const(isinstance),
+ w_instance, w_type)
+
# _________________________________________________________________________
# a simplified version of the basic printing routines, for RPython programs
class StdOutBuffer:
@@ -30,32 +59,3 @@
s = '\n'
import os
os.write(1, s)
-
-# _________________________________________________________________________
-
-def sc_r_uint(space, args_w):
- # special case to constant-fold r_uint(32-bit-constant)
- # (normally, the 32-bit constant is a long, and is not allowed to
- # show up in the flow graphs at all)
- [w_value] = args_w
- if isinstance(w_value, Constant):
- return Constant(r_uint(w_value.value))
- return space.frame.do_operation('simple_call', space.wrap(r_uint), w_value)
-
-def sc_we_are_translated(space, args_w):
- return Constant(True)
-
-def sc_locals(space, args):
- raise Exception(
- "A function calling locals() is not RPython. "
- "Note that if you're translating code outside the PyPy "
- "repository, a likely cause is that py.test's --assert=rewrite "
- "mode is getting in the way. You should copy the file "
- "pytest.ini from the root of the PyPy repository into your "
- "own project.")
-
-SPECIAL_CASES = {__import__: sc_import, r_uint: sc_r_uint,
- we_are_translated: sc_we_are_translated,
- locals: sc_locals}
-for fn, oper in func2op.items():
- SPECIAL_CASES[fn] = oper.make_sc()
diff --git a/rpython/flowspace/test/test_framestate.py \
b/rpython/flowspace/test/test_framestate.py
--- a/rpython/flowspace/test/test_framestate.py
+++ b/rpython/flowspace/test/test_framestate.py
@@ -25,55 +25,55 @@
def test_eq_framestate(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
- fs2 = frame.getstate()
+ fs1 = frame.getstate(0)
+ fs2 = frame.getstate(0)
assert fs1 == fs2
def test_neq_hacked_framestate(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
+ fs1 = frame.getstate(0)
frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable()
- fs2 = frame.getstate()
+ fs2 = frame.getstate(0)
assert fs1 != fs2
def test_union_on_equal_framestates(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
- fs2 = frame.getstate()
+ fs1 = frame.getstate(0)
+ fs2 = frame.getstate(0)
assert fs1.union(fs2) == fs1
def test_union_on_hacked_framestates(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
+ fs1 = frame.getstate(0)
frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable()
- fs2 = frame.getstate()
+ fs2 = frame.getstate(0)
assert fs1.union(fs2) == fs2 # fs2 is more general
assert fs2.union(fs1) == fs2 # fs2 is more general
def test_restore_frame(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
+ fs1 = frame.getstate(0)
frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable()
frame.setstate(fs1)
- assert fs1 == frame.getstate()
+ assert fs1 == frame.getstate(0)
def test_copy(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
+ fs1 = frame.getstate(0)
fs2 = fs1.copy()
assert fs1 == fs2
def test_getvariables(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
+ fs1 = frame.getstate(0)
vars = fs1.getvariables()
assert len(vars) == 1
def test_getoutputargs(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
+ fs1 = frame.getstate(0)
frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable()
- fs2 = frame.getstate()
+ fs2 = frame.getstate(0)
outputargs = fs1.getoutputargs(fs2)
# 'x' -> 'x' is a Variable
# locals_w[n-1] -> locals_w[n-1] is Constant(None)
@@ -81,9 +81,9 @@
def test_union_different_constants(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
+ fs1 = frame.getstate(0)
frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(42)
- fs2 = frame.getstate()
+ fs2 = frame.getstate(0)
fs3 = fs1.union(fs2)
frame.setstate(fs3)
assert isinstance(frame.locals_stack_w[frame.pycode.co_nlocals-1],
@@ -91,7 +91,7 @@
def test_union_spectag(self):
frame = self.getframe(self.func_simple)
- fs1 = frame.getstate()
+ fs1 = frame.getstate(0)
frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(SpecTag())
- fs2 = frame.getstate()
+ fs2 = frame.getstate(0)
assert fs1.union(fs2) is None # UnionError
diff --git a/rpython/flowspace/test/test_objspace.py \
b/rpython/flowspace/test/test_objspace.py
--- a/rpython/flowspace/test/test_objspace.py
+++ b/rpython/flowspace/test/test_objspace.py
@@ -104,7 +104,7 @@
def test_loop(self):
graph = self.codetest(self.loop)
assert self.all_operations(graph) == {'abs': 1,
- 'is_true': 1,
+ 'bool': 1,
'sub': 1}
#__________________________________________________________
@@ -532,7 +532,7 @@
def f(x):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic