[pypy-commit] pypy result-in-resops: some progress on resop specialization
fijal
noreply at buildbot.pypy.org
Tue Jul 24 16:17:50 CEST 2012
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: result-in-resops
Changeset: r56422:3b467df21f17
Date: 2012-07-24 13:14 +0200
http://bitbucket.org/pypy/pypy/changeset/3b467df21f17/
Log: some progress on resop specialization
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -9,7 +9,7 @@
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.llinterp import LLInterpreter
from pypy.jit.metainterp import history
-from pypy.jit.metainterp.history import REF, INT, FLOAT, STRUCT
+from pypy.jit.metainterp.resoperation import REF, INT, FLOAT, STRUCT
from pypy.jit.metainterp.warmstate import unwrap
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.backend import model
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -9,7 +9,7 @@
from pypy.conftest import option
from pypy.tool.sourcetools import func_with_new_name
-from pypy.jit.metainterp.resoperation import ResOperation, rop, get_deep_immutable_oplist
+from pypy.jit.metainterp.resoperation import rop, get_deep_immutable_oplist
from pypy.jit.metainterp.history import TreeLoop, Box, History, JitCellToken, TargetToken
from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt
from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const, ConstInt
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -5,10 +5,11 @@
from pypy.rlib.rarithmetic import ovfcheck, r_longlong, is_valid_int
from pypy.rlib.rtimer import read_timestamp
from pypy.rlib.unroll import unrolling_iterable
-from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr
-from pypy.jit.metainterp.history import INT, REF, FLOAT, VOID, AbstractDescr
+from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr,\
+ AbstractDescr
+from pypy.jit.metainterp.resoperation import INT, REF, FLOAT, VOID
from pypy.jit.metainterp import resoperation
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop, create_resop
from pypy.jit.metainterp.blackhole import BlackholeInterpreter, NULL
from pypy.jit.codewriter import longlong
@@ -333,6 +334,7 @@
name = 'bhimpl_' + key.lower()
if hasattr(BlackholeInterpreter, name):
func = make_execute_function_with_boxes(
+ value,
key.lower(),
getattr(BlackholeInterpreter, name).im_func)
if func is not None:
@@ -366,7 +368,7 @@
#raise AssertionError("missing %r" % (key,))
return execute_by_num_args
-def make_execute_function_with_boxes(name, func):
+def make_execute_function_with_boxes(opnum, name, func):
# Make a wrapper for 'func'. The func is a simple bhimpl_xxx function
# from the BlackholeInterpreter class. The wrapper is a new function
# that receives and returns boxed values.
@@ -383,7 +385,6 @@
if func.resulttype not in ('i', 'r', 'f', None):
return None
argtypes = unrolling_iterable(func.argtypes)
- resulttype = func.resulttype
#
def do(cpu, _, *args):
newargs = ()
@@ -405,12 +406,11 @@
assert not args
#
result = func(*newargs)
- ResOperation(opnum, orig_args, result, )
+ if has_descr:
+ return create_resop(opnum, orig_args[:-1], result, orig_args[-1])
+ else:
+ return create_resop(opnum, orig_args, result)
#
- if resulttype == 'i': return BoxInt(result)
- if resulttype == 'r': return BoxPtr(result)
- if resulttype == 'f': return BoxFloat(result)
- return None
#
do.func_name = 'do_' + name
return do
diff --git a/pypy/jit/metainterp/heapcache.py b/pypy/jit/metainterp/heapcache.py
--- a/pypy/jit/metainterp/heapcache.py
+++ b/pypy/jit/metainterp/heapcache.py
@@ -50,11 +50,12 @@
def _output_indirection(self, box):
return self.output_indirections.get(box, box)
- def invalidate_caches(self, opnum, descr, argboxes):
- self.mark_escaped(opnum, argboxes)
- self.clear_caches(opnum, descr, argboxes)
+ def invalidate_caches(self, op):
+ self.mark_escaped(op)
+ self.clear_caches(op)
- def mark_escaped(self, opnum, argboxes):
+ def mark_escaped(self, op):
+ opnum = op.getopnum()
if opnum == rop.SETFIELD_GC:
assert len(argboxes) == 2
box, valuebox = argboxes
@@ -77,23 +78,22 @@
opnum != rop.MARK_OPAQUE_PTR and
opnum != rop.PTR_EQ and
opnum != rop.PTR_NE):
- idx = 0
- for box in argboxes:
- # setarrayitem_gc don't escape its first argument
- if not (idx == 0 and opnum in [rop.SETARRAYITEM_GC]):
- self._escape(box)
- idx += 1
+ op.foreach_arg(self._escape)
- def _escape(self, box):
- if box in self.new_boxes:
- self.new_boxes[box] = False
- if box in self.dependencies:
- deps = self.dependencies[box]
- del self.dependencies[box]
+ def _escape(self, opnum, idx, source):
+ # setarrayitem_gc don't escape its first argument
+ if idx == 0 and opnum == rop.SETARRAYITEM_GC:
+ return
+ if source in self.new_boxes:
+ self.new_boxes[source] = False
+ if source in self.dependencies:
+ deps = self.dependencies[source]
+ del self.dependencies[source]
for dep in deps:
self._escape(dep)
- def clear_caches(self, opnum, descr, argboxes):
+ def clear_caches(self, op):
+ opnum = op.getopnum()
if (opnum == rop.SETFIELD_GC or
opnum == rop.SETARRAYITEM_GC or
opnum == rop.SETFIELD_RAW or
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -8,19 +8,14 @@
from pypy.conftest import option
-from pypy.jit.metainterp.resoperation import ResOperation, rop, AbstractValue
+from pypy.jit.metainterp.resoperation import rop, AbstractValue, INT, REF,\
+ FLOAT
+
from pypy.jit.codewriter import heaptracker, longlong
import weakref
# ____________________________________________________________
-INT = 'i'
-REF = 'r'
-FLOAT = 'f'
-STRUCT = 's'
-HOLE = '_'
-VOID = 'v'
-
FAILARGS_LIMIT = 1000
def getkind(TYPE, supports_floats=True,
@@ -152,6 +147,9 @@
def __repr__(self):
return 'Const(%s)' % self._getrepr_()
+ def is_constant(self):
+ return True
+
class ConstInt(Const):
type = INT
@@ -799,10 +797,8 @@
self.inputargs = None
self.operations = []
- def record(self, opnum, argboxes, resbox, descr=None):
- op = ResOperation(opnum, argboxes, resbox, descr)
+ def record(self, op):
self.operations.append(op)
- return op
def substitute_operation(self, position, opnum, argboxes, descr=None):
resbox = self.operations[position].result
diff --git a/pypy/jit/metainterp/optimizeopt/earlyforce.py b/pypy/jit/metainterp/optimizeopt/earlyforce.py
--- a/pypy/jit/metainterp/optimizeopt/earlyforce.py
+++ b/pypy/jit/metainterp/optimizeopt/earlyforce.py
@@ -1,6 +1,6 @@
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
from pypy.jit.metainterp.optimizeopt.vstring import VAbstractStringValue
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
class OptEarlyForce(Optimization):
def propagate_forward(self, op):
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ b/pypy/jit/metainterp/optimizeopt/fficall.py
@@ -1,7 +1,7 @@
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
from pypy.rlib import clibffi, libffi
from pypy.rlib.debug import debug_print
from pypy.rlib.libffi import Func
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -4,7 +4,7 @@
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY
from pypy.jit.metainterp.history import ConstInt, Const
from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
from pypy.rlib.objectmodel import we_are_translated
diff --git a/pypy/jit/metainterp/optimizeopt/intutils.py b/pypy/jit/metainterp/optimizeopt/intutils.py
--- a/pypy/jit/metainterp/optimizeopt/intutils.py
+++ b/pypy/jit/metainterp/optimizeopt/intutils.py
@@ -1,6 +1,6 @@
from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, maxint, is_valid_int
from pypy.rlib.objectmodel import we_are_translated
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop, create_resop
from pypy.jit.metainterp.history import BoxInt, ConstInt
MAXINT = maxint
MININT = -maxint - 1
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -6,7 +6,7 @@
IntLowerBound, MININT, MAXINT
from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
args_dict)
-from pypy.jit.metainterp.resoperation import rop, ResOperation, AbstractResOp
+from pypy.jit.metainterp.resoperation import rop, AbstractResOp
from pypy.jit.metainterp.typesystem import llhelper, oohelper
from pypy.tool.pairtype import extendabletype
from pypy.rlib.debug import debug_start, debug_stop, debug_print
diff --git a/pypy/jit/metainterp/optimizeopt/pure.py b/pypy/jit/metainterp/optimizeopt/pure.py
--- a/pypy/jit/metainterp/optimizeopt/pure.py
+++ b/pypy/jit/metainterp/optimizeopt/pure.py
@@ -1,5 +1,5 @@
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, REMOVED
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
args_dict)
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -4,8 +4,7 @@
from pypy.jit.metainterp.optimizeopt.intutils import IntBound
from pypy.jit.metainterp.optimizeopt.optimizer import *
from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method
-from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop,
- ResOperation)
+from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop)
from pypy.rlib.rarithmetic import highest_bit
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -1,6 +1,6 @@
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.history import TargetToken, JitCellToken
class OptSimplify(Optimization):
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -7,7 +7,7 @@
from pypy.jit.metainterp.optimizeopt.optimizer import *
from pypy.jit.metainterp.optimizeopt.generalize import KillHugeIntBounds
from pypy.jit.metainterp.inliner import Inliner
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.resume import Snapshot
import sys, os
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -4,7 +4,7 @@
from pypy.jit.metainterp.optimizeopt import optimizer
from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
descrlist_dict, sort_descrs)
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp.optimizeopt.optimizer import OptValue
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -8,7 +8,7 @@
from pypy.jit.metainterp.history import BoxInt, ConstInt, BoxPtr, Const
from pypy.jit.metainterp.optimize import InvalidLoop
from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.debug import debug_start, debug_stop, debug_print
from pypy.rlib.objectmodel import we_are_translated
diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -5,7 +5,7 @@
from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
from pypy.jit.metainterp.optimizeopt.optimizer import llhelper, REMOVED
from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
from pypy.rlib.objectmodel import specialize, we_are_translated
from pypy.rlib.unroll import unrolling_iterable
from pypy.rpython import annlowlevel
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -9,7 +9,8 @@
from pypy.jit.metainterp import history, compile, resume
from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat
from pypy.jit.metainterp.history import Box, TargetToken
-from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp.resoperation import rop, create_resop
+from pypy.jit.metainterp import resoperation
from pypy.jit.metainterp import executor
from pypy.jit.metainterp.logger import Logger
from pypy.jit.metainterp.jitprof import EmptyProfiler
@@ -164,8 +165,10 @@
assert not oldbox.same_box(b)
- def make_result_of_lastop(self, resultbox):
- got_type = resultbox.type
+ def make_result_of_lastop(self, resultop):
+ got_type = resultop.type
+ if got_type == resoperation.VOID:
+ return
# XXX disabled for now, conflicts with str_guard_value
#if not we_are_translated():
# typeof = {'i': history.INT,
@@ -173,14 +176,14 @@
# 'f': history.FLOAT}
# assert typeof[self.jitcode._resulttypes[self.pc]] == got_type
target_index = ord(self.bytecode[self.pc-1])
- if got_type == history.INT:
- self.registers_i[target_index] = resultbox
- elif got_type == history.REF:
+ if got_type == resoperation.INT:
+ self.registers_i[target_index] = resultop
+ elif got_type == resoperation.REF:
#debug_print(' ->',
# llmemory.cast_ptr_to_adr(resultbox.getref_base()))
- self.registers_r[target_index] = resultbox
- elif got_type == history.FLOAT:
- self.registers_f[target_index] = resultbox
+ self.registers_r[target_index] = resultop
+ elif got_type == resoperation.FLOAT:
+ self.registers_f[target_index] = resultop
else:
raise AssertionError("bad result box type")
@@ -1299,6 +1302,7 @@
@specialize.arg(1)
def execute_varargs(self, opnum, argboxes, descr, exc, pure):
+ xxx
self.metainterp.clear_exception()
resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes,
descr=descr)
@@ -1468,10 +1472,10 @@
# store this information for fastpath of call_assembler
# (only the paths that can actually be taken)
for jd in self.jitdrivers_sd:
- name = {history.INT: 'int',
- history.REF: 'ref',
- history.FLOAT: 'float',
- history.VOID: 'void'}[jd.result_type]
+ name = {resoperation.INT: 'int',
+ resoperation.REF: 'ref',
+ resoperation.FLOAT: 'float',
+ resoperation.VOID: 'void'}[jd.result_type]
tokens = getattr(self, 'loop_tokens_done_with_this_frame_%s' % name)
jd.portal_finishtoken = tokens[0].finishdescr
num = self.cpu.get_fail_descr_number(tokens[0].finishdescr)
@@ -1651,14 +1655,14 @@
self.aborted_tracing(stb.reason)
sd = self.staticdata
result_type = self.jitdriver_sd.result_type
- if result_type == history.VOID:
+ if result_type == resoperation.VOID:
assert resultbox is None
raise sd.DoneWithThisFrameVoid()
- elif result_type == history.INT:
+ elif result_type == resoperation.INT:
raise sd.DoneWithThisFrameInt(resultbox.getint())
- elif result_type == history.REF:
+ elif result_type == resoperation.REF:
raise sd.DoneWithThisFrameRef(self.cpu, resultbox.getref_base())
- elif result_type == history.FLOAT:
+ elif result_type == resoperation.FLOAT:
raise sd.DoneWithThisFrameFloat(resultbox.getfloatstorage())
else:
assert False
@@ -1727,12 +1731,10 @@
# execute the operation
profiler = self.staticdata.profiler
profiler.count_ops(opnum)
- resbox = executor.execute(self.cpu, self, opnum, descr, *argboxes)
- if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST:
- return self._record_helper_pure(opnum, resbox, descr, *argboxes)
- else:
- return self._record_helper_nonpure_varargs(opnum, resbox, descr,
- list(argboxes))
+ resop = executor.execute(self.cpu, self, opnum, descr, *argboxes)
+ if not resop.is_constant():
+ self._record(resop)
+ return resop
@specialize.arg(1)
def execute_and_record_varargs(self, opnum, argboxes, descr=None):
@@ -1751,15 +1753,6 @@
resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes)
return resbox
- def _record_helper_pure(self, opnum, resbox, descr, *argboxes):
- canfold = self._all_constants(*argboxes)
- if canfold:
- resbox = resbox.constbox() # ensure it is a Const
- return resbox
- else:
- resbox = resbox.nonconstbox() # ensure it is a Box
- return self._record_helper_nonpure_varargs(opnum, resbox, descr, list(argboxes))
-
def _record_helper_pure_varargs(self, opnum, resbox, descr, argboxes):
canfold = self._all_constants_varargs(argboxes)
if canfold:
@@ -1783,6 +1776,18 @@
self.attach_debug_info(op)
return resbox
+ def _record(self, resop):
+ opnum = resop.getopnum()
+ if (rop._OVF_FIRST <= opnum <= rop._OVF_LAST and
+ self.last_exc_value_box is None and
+ resop.all_constant_args()):
+ return resop.constbox()
+ profiler = self.staticdata.profiler
+ profiler.count_ops(opnum, Counters.RECORDED_OPS)
+ self.heapcache.invalidate_caches(resop)
+ self.history.record(resop)
+ self.attach_debug_info(resop)
+ return resop
def attach_debug_info(self, op):
if (not we_are_translated() and op is not None
@@ -2157,17 +2162,17 @@
# temporarily put a JUMP to a pseudo-loop
sd = self.staticdata
result_type = self.jitdriver_sd.result_type
- if result_type == history.VOID:
+ if result_type == resoperation.VOID:
assert exitbox is None
exits = []
loop_tokens = sd.loop_tokens_done_with_this_frame_void
- elif result_type == history.INT:
+ elif result_type == resoperation.INT:
exits = [exitbox]
loop_tokens = sd.loop_tokens_done_with_this_frame_int
- elif result_type == history.REF:
+ elif result_type == resoperation.REF:
exits = [exitbox]
loop_tokens = sd.loop_tokens_done_with_this_frame_ref
- elif result_type == history.FLOAT:
+ elif result_type == resoperation.FLOAT:
exits = [exitbox]
loop_tokens = sd.loop_tokens_done_with_this_frame_float
else:
@@ -2175,7 +2180,7 @@
# FIXME: kill TerminatingLoopToken?
# FIXME: can we call compile_trace?
token = loop_tokens[0].finishdescr
- self.history.record(rop.FINISH, exits, None, descr=token)
+ self.history.record(create_resop(rop.FINISH, exits, None, descr=token))
target_token = compile.compile_trace(self, self.resumekey)
if target_token is not token:
compile.giveup()
@@ -2635,30 +2640,23 @@
if self.debug:
print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))),
try:
- resultbox = unboundmethod(self, *args)
+ resultop = unboundmethod(self, *args)
except Exception, e:
if self.debug:
print '-> %s!' % e.__class__.__name__
raise
- if num_return_args == 0:
- if self.debug:
- print
- assert resultbox is None
- else:
- if self.debug:
- print '-> %r' % (resultbox,)
- assert argcodes[next_argcode] == '>'
- result_argcode = argcodes[next_argcode + 1]
- assert resultbox.type == {'i': history.INT,
- 'r': history.REF,
- 'f': history.FLOAT}[result_argcode]
+ if self.debug:
+ print resultop
+ assert argcodes[next_argcode] == '>'
+ result_argcode = argcodes[next_argcode + 1]
+ assert resultop.type == {'i': resoperation.INT,
+ 'r': resoperation.REF,
+ 'f': resoperation.FLOAT,
+ 'v': resoperation.VOID}[result_argcode]
else:
- resultbox = unboundmethod(self, *args)
+ resultop = unboundmethod(self, *args)
#
- if resultbox is not None:
- self.make_result_of_lastop(resultbox)
- elif not we_are_translated():
- assert self._result_argcode in 'v?'
+ self.make_result_of_lastop(resultop)
#
unboundmethod = getattr(MIFrame, 'opimpl_' + name).im_func
argtypes = unrolling_iterable(unboundmethod.argtypes)
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -4,9 +4,22 @@
from pypy.jit.codewriter import longlong
from pypy.rlib.objectmodel import compute_identity_hash
+INT = 'i'
+REF = 'r'
+FLOAT = 'f'
+STRUCT = 's'
+VOID = 'v'
+
@specialize.arg(0)
-def ResOperation(opnum, args, result, descr=None):
+def create_resop(opnum, args, result, descr=None):
cls = opclasses[opnum]
+ assert cls.NUMARGS == -1
+ if cls.is_always_pure():
+ for arg in args:
+ if not arg.is_constant():
+ break
+ else:
+ return cls.wrap_constant(result)
if result is None:
op = cls()
else:
@@ -17,6 +30,84 @@
op.setdescr(descr)
return op
+ at specialize.arg(0)
+def create_resop_0(opnum, result, descr=None):
+ cls = opclasses[opnum]
+ assert cls.NUMARGS == 0
+ if result is None:
+ op = cls()
+ else:
+ op = cls(result)
+ if descr is not None:
+ assert isinstance(op, ResOpWithDescr)
+ op.setdescr(descr)
+ return op
+
+ at specialize.arg(0)
+def create_resop_1(opnum, arg0, result, descr=None):
+ cls = opclasses[opnum]
+ assert cls.NUMARGS == 1
+ if cls.is_always_pure():
+ if arg0.is_constant():
+ return cls.wrap_constant(result)
+ if result is None:
+ op = cls()
+ else:
+ op = cls(result)
+ op._arg0 = arg0
+ if descr is not None:
+ assert isinstance(op, ResOpWithDescr)
+ op.setdescr(descr)
+ return op
+
+ at specialize.arg(0)
+def create_resop_2(opnum, arg0, arg1, result, descr=None):
+ cls = opclasses[opnum]
+ assert cls.NUMARGS == 2
+ if cls.is_always_pure():
+ if arg0.is_constant() and arg1.is_constant():
+ return cls.wrap_constant(result)
+ if result is None:
+ op = cls()
+ else:
+ op = cls(result)
+ op._arg0 = arg0
+ op._arg1 = arg1
+ if descr is not None:
+ assert isinstance(op, ResOpWithDescr)
+ op.setdescr(descr)
+ return op
+
+ at specialize.arg(0)
+def create_resop_3(opnum, arg0, arg1, arg2, result, descr=None):
+ cls = opclasses[opnum]
+ assert cls.NUMARGS == 3
+ if cls.is_always_pure():
+ if arg0.is_constant() and arg1.is_constant() and arg2.is_constant():
+ return cls.wrap_constant(result)
+ if result is None:
+ op = cls()
+ else:
+ op = cls(result)
+ op._arg0 = arg0
+ op._arg1 = arg1
+ op._arg2 = arg2
+ if descr is not None:
+ assert isinstance(op, ResOpWithDescr)
+ op.setdescr(descr)
+ return op
+
+def copy_and_change(self, opnum, args=None, result=None, descr=None):
+ "shallow copy: the returned operation is meant to be used in place of self"
+ if args is None:
+ args = self.getarglist()
+ if result is None:
+ result = self.result
+ if descr is None:
+ descr = self.getdescr()
+ newop = ResOperation(opnum, args, result, descr)
+ return newop
+
class AbstractValue(object):
__slots__ = ()
@@ -72,6 +163,9 @@
def same_box(self, other):
return self is other
+ def is_constant(self):
+ return False
+
class AbstractResOp(AbstractValue):
"""The central ResOperation class, representing one operation."""
@@ -80,8 +174,9 @@
pc = 0
opnum = 0
- def getopnum(self):
- return self.opnum
+ @classmethod
+ def getopnum(cls):
+ return cls.opnum
# methods implemented by the arity mixins
# ---------------------------------------
@@ -118,6 +213,9 @@
def getdescr(self):
return None
+ def getdescrclone(self):
+ return None
+
def setdescr(self, descr):
raise NotImplementedError
@@ -127,28 +225,6 @@
# common methods
# --------------
- def copy_and_change(self, opnum, args=None, result=None, descr=None):
- "shallow copy: the returned operation is meant to be used in place of self"
- if args is None:
- args = self.getarglist()
- if result is None:
- result = self.result
- if descr is None:
- descr = self.getdescr()
- newop = ResOperation(opnum, args, result, descr)
- return newop
-
- def clone(self):
- args = self.getarglist()
- descr = self.getdescr()
- if descr is not None:
- descr = descr.clone_if_mutable()
- op = ResOperation(self.getopnum(), args[:], self.result, descr)
- if not we_are_translated():
- op.name = self.name
- op.pc = self.pc
- return op
-
def __repr__(self):
try:
return self.repr()
@@ -176,56 +252,71 @@
return '%s%s%s(%s, descr=%r)' % (prefix, sres, self.getopname(),
', '.join([str(a) for a in args]), descr)
- def getopname(self):
+ @classmethod
+ def getopname(cls):
try:
- return opname[self.getopnum()].lower()
+ return opname[cls.getopnum()].lower()
except KeyError:
- return '<%d>' % self.getopnum()
+ return '<%d>' % cls.getopnum()
- def is_guard(self):
- return rop._GUARD_FIRST <= self.getopnum() <= rop._GUARD_LAST
+ @classmethod
+ def is_guard(cls):
+ return rop._GUARD_FIRST <= cls.getopnum() <= rop._GUARD_LAST
- def is_foldable_guard(self):
- return rop._GUARD_FOLDABLE_FIRST <= self.getopnum() <= rop._GUARD_FOLDABLE_LAST
+ @classmethod
+ def is_foldable_guard(cls):
+ return rop._GUARD_FOLDABLE_FIRST <= cls.getopnum() <= rop._GUARD_FOLDABLE_LAST
- def is_guard_exception(self):
- return (self.getopnum() == rop.GUARD_EXCEPTION or
- self.getopnum() == rop.GUARD_NO_EXCEPTION)
+ @classmethod
+ def is_guard_exception(cls):
+ return (cls.getopnum() == rop.GUARD_EXCEPTION or
+ cls.getopnum() == rop.GUARD_NO_EXCEPTION)
- def is_guard_overflow(self):
- return (self.getopnum() == rop.GUARD_OVERFLOW or
- self.getopnum() == rop.GUARD_NO_OVERFLOW)
+ @classmethod
+ def is_guard_overflow(cls):
+ return (cls.getopnum() == rop.GUARD_OVERFLOW or
+ cls.getopnum() == rop.GUARD_NO_OVERFLOW)
- def is_always_pure(self):
- return rop._ALWAYS_PURE_FIRST <= self.getopnum() <= rop._ALWAYS_PURE_LAST
+ @classmethod
+ def is_always_pure(cls):
+ return rop._ALWAYS_PURE_FIRST <= cls.getopnum() <= rop._ALWAYS_PURE_LAST
- def has_no_side_effect(self):
- return rop._NOSIDEEFFECT_FIRST <= self.getopnum() <= rop._NOSIDEEFFECT_LAST
+ @classmethod
+ def has_no_side_effect(cls):
+ return rop._NOSIDEEFFECT_FIRST <= cls.getopnum() <= rop._NOSIDEEFFECT_LAST
- def can_raise(self):
- return rop._CANRAISE_FIRST <= self.getopnum() <= rop._CANRAISE_LAST
+ @classmethod
+ def can_raise(cls):
+ return rop._CANRAISE_FIRST <= cls.getopnum() <= rop._CANRAISE_LAST
- def is_malloc(self):
+ @classmethod
+ def is_malloc(cls):
# a slightly different meaning from can_malloc
- return rop._MALLOC_FIRST <= self.getopnum() <= rop._MALLOC_LAST
+ return rop._MALLOC_FIRST <= cls.getopnum() <= rop._MALLOC_LAST
- def can_malloc(self):
- return self.is_call() or self.is_malloc()
+ @classmethod
+ def can_malloc(cls):
+ return cls.is_call() or cls.is_malloc()
- def is_call(self):
- return rop._CALL_FIRST <= self.getopnum() <= rop._CALL_LAST
+ @classmethod
+ def is_call(cls):
+ return rop._CALL_FIRST <= cls.getopnum() <= rop._CALL_LAST
- def is_ovf(self):
- return rop._OVF_FIRST <= self.getopnum() <= rop._OVF_LAST
+ @classmethod
+ def is_ovf(cls):
+ return rop._OVF_FIRST <= cls.getopnum() <= rop._OVF_LAST
- def is_comparison(self):
- return self.is_always_pure() and self.returns_bool_result()
+ @classmethod
+ def is_comparison(cls):
+ return cls.is_always_pure() and cls.returns_bool_result()
- def is_final(self):
- return rop._FINAL_FIRST <= self.getopnum() <= rop._FINAL_LAST
+ @classmethod
+ def is_final(cls):
+ return rop._FINAL_FIRST <= cls.getopnum() <= rop._FINAL_LAST
- def returns_bool_result(self):
- opnum = self.getopnum()
+ @classmethod
+ def returns_bool_result(cls):
+ opnum = cls.getopnum()
if we_are_translated():
assert opnum >= 0
elif opnum < 0:
@@ -234,12 +325,17 @@
class ResOpNone(object):
_mixin_ = True
+ type = VOID
def __init__(self):
pass # no return value
+ def getresult(self):
+ return None
+
class ResOpInt(object):
_mixin_ = True
+ type = INT
def __init__(self, intval):
assert isinstance(intval, int)
@@ -247,9 +343,16 @@
def getint(self):
return self.intval
+ getresult = getint
+
+ @staticmethod
+ def wrap_constant(intval):
+ from pypy.jit.metainterp.history import ConstInt
+ return ConstInt(intval)
class ResOpFloat(object):
_mixin_ = True
+ type = FLOAT
def __init__(self, floatval):
#assert isinstance(floatval, float)
@@ -258,9 +361,16 @@
def getfloatstorage(self):
return self.floatval
+ getresult = getfloatstorage
+
+ @staticmethod
+ def wrap_constant(floatval):
+ from pypy.jit.metainterp.history import ConstFloat
+ return ConstFloat(floatval)
class ResOpPointer(object):
_mixin_ = True
+ type = REF
def __init__(self, pval):
assert typeOf(pval) == GCREF
@@ -268,6 +378,12 @@
def getref_base(self):
return self.pval
+ getresult = getref_base
+
+ @staticmethod
+ def wrap_constant(pval):
+ from pypy.jit.metainterp.history import ConstPtr
+ return ConstPtr(pval)
# ===================
# Top of the hierachy
@@ -283,6 +399,9 @@
def getdescr(self):
return self._descr
+ def getdescrclone(self):
+ return self._descr.clone_if_mutable()
+
def setdescr(self, descr):
# for 'call', 'new', 'getfield_gc'...: the descr is a prebuilt
# instance provided by the backend holding details about the type
@@ -312,16 +431,6 @@
def setfailargs(self, fail_args):
self._fail_args = fail_args
- def copy_and_change(self, opnum, args=None, result=None, descr=None):
- newop = AbstractResOp.copy_and_change(self, opnum, args, result, descr)
- newop.setfailargs(self.getfailargs())
- return newop
-
- def clone(self):
- newop = AbstractResOp.clone(self)
- newop.setfailargs(self.getfailargs())
- return newop
-
# ============
# arity mixins
# ============
@@ -329,6 +438,8 @@
class NullaryOp(object):
_mixin_ = True
+ NUMARGS = 0
+
def initarglist(self, args):
assert len(args) == 0
@@ -344,11 +455,21 @@
def setarg(self, i, box):
raise IndexError
+ def foreach_arg(self, func):
+ pass
+
+ def clone(self):
+ r = create_resop_0(self.opnum, self.getresult(), self.getdescrclone())
+ if self.is_guard():
+ r.setfailargs(self.getfailargs())
+ return r
class UnaryOp(object):
_mixin_ = True
_arg0 = None
+ NUMARGS = 1
+
def initarglist(self, args):
assert len(args) == 1
self._arg0, = args
@@ -371,12 +492,24 @@
else:
raise IndexError
+ @specialize.arg(1)
+ def foreach_arg(self, func):
+ func(self.getopnum(), 0, self._arg0)
+
+ def clone(self):
+ r = create_resop_1(self.opnum, self._arg0, self.getresult(),
+ self.getdescrclone())
+ if self.is_guard():
+ r.setfailargs(self.getfailargs())
+ return r
class BinaryOp(object):
_mixin_ = True
_arg0 = None
_arg1 = None
+ NUMARGS = 2
+
def initarglist(self, args):
assert len(args) == 2
self._arg0, self._arg1 = args
@@ -403,6 +536,18 @@
def getarglist(self):
return [self._arg0, self._arg1]
+ @specialize.arg(1)
+ def foreach_arg(self, func):
+ func(self.getopnum(), 0, self._arg0)
+ func(self.getopnum(), 1, self._arg1)
+
+ def clone(self):
+ r = create_resop_2(self.opnum, self._arg0, self._arg1,
+ self.getresult(), self.getdescrclone())
+ if self.is_guard():
+ r.setfailargs(self.getfailargs())
+ return r
+
class TernaryOp(object):
_mixin_ = True
@@ -410,6 +555,8 @@
_arg1 = None
_arg2 = None
+ NUMARGS = 3
+
def initarglist(self, args):
assert len(args) == 3
self._arg0, self._arg1, self._arg2 = args
@@ -440,10 +587,24 @@
else:
raise IndexError
+ @specialize.arg(1)
+ def foreach_arg(self, func):
+ func(self.getopnum(), 0, self._arg0)
+ func(self.getopnum(), 1, self._arg1)
+ func(self.getopnum(), 2, self._arg2)
+
+ def clone(self):
+ assert not self.is_guard()
+ return create_resop_3(self.opnum, self._arg0, self._arg1, self._arg2,
+ self.getresult(), self.getdescrclone())
+
+
class N_aryOp(object):
_mixin_ = True
_args = None
+ NUMARGS = -1
+
def initarglist(self, args):
self._args = args
@@ -459,6 +620,16 @@
def setarg(self, i, box):
self._args[i] = box
+ @specialize.arg(1)
+ def foreach_arg(self, func):
+ for i, arg in enumerate(self._args):
+ func(self.getopnum(), i, arg)
+
+ def clone(self):
+ assert not self.is_guard()
+ return create_resop(self.opnum, self._args[:], self.getresult(),
+ self.getdescrclone())
+
# ____________________________________________________________
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -1,7 +1,7 @@
import sys, os
from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind
from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat
-from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE
+from pypy.jit.metainterp.resoperation import INT, REF, FLOAT
from pypy.jit.metainterp.history import AbstractDescr
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp import jitprof
diff --git a/pypy/jit/metainterp/test/test_resoperation.py b/pypy/jit/metainterp/test/test_resoperation.py
--- a/pypy/jit/metainterp/test/test_resoperation.py
+++ b/pypy/jit/metainterp/test/test_resoperation.py
@@ -2,6 +2,19 @@
from pypy.jit.metainterp import resoperation as rop
from pypy.jit.metainterp.history import AbstractDescr
+class FakeBox(object):
+ def __init__(self, v):
+ self.v = v
+
+ def __eq__(self, other):
+ return self.v == other.v
+
+ def __ne__(self, other):
+ return not self == other
+
+ def is_constant(self):
+ return False
+
def test_arity_mixins():
cases = [
(0, rop.NullaryOp),
@@ -55,19 +68,20 @@
def test_instantiate():
from pypy.rpython.lltypesystem import lltype, llmemory
- op = rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 15)
- assert op.getarglist() == ['a', 'b']
+ op = rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 15)
+ assert op.getarglist() == [FakeBox('a'), FakeBox('b')]
assert op.getint() == 15
mydescr = AbstractDescr()
- op = rop.ResOperation(rop.rop.CALL_f, ['a', 'b'], 15.5, descr=mydescr)
- assert op.getarglist() == ['a', 'b']
+ op = rop.create_resop(rop.rop.CALL_f, [FakeBox('a'),
+ FakeBox('b')], 15.5, descr=mydescr)
+ assert op.getarglist() == [FakeBox('a'), FakeBox('b')]
assert op.getfloat() == 15.5
assert op.getdescr() is mydescr
- op = rop.ResOperation(rop.rop.CALL_p, ['a', 'b'],
+ op = rop.create_resop(rop.rop.CALL_p, [FakeBox('a'), FakeBox('b')],
lltype.nullptr(llmemory.GCREF.TO), descr=mydescr)
- assert op.getarglist() == ['a', 'b']
+ assert op.getarglist() == [FakeBox('a'), FakeBox('b')]
assert not op.getref_base()
assert op.getdescr() is mydescr
@@ -76,15 +90,51 @@
mydescr = AbstractDescr()
p = lltype.malloc(llmemory.GCREF.TO)
- assert rop.ResOperation(rop.rop.NEW, [], p).can_malloc()
- call = rop.ResOperation(rop.rop.CALL_i, ['a', 'b'], 3, descr=mydescr)
+ assert rop.create_resop_0(rop.rop.NEW, p).can_malloc()
+ call = rop.create_resop(rop.rop.CALL_i, [FakeBox('a'),
+ FakeBox('b')], 3, descr=mydescr)
assert call.can_malloc()
- assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 3).can_malloc()
+ assert not rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'),
+ FakeBox('b'), 3).can_malloc()
def test_get_deep_immutable_oplist():
- ops = [rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 3)]
+ ops = [rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 3)]
newops = rop.get_deep_immutable_oplist(ops)
py.test.raises(TypeError, "newops.append('foobar')")
py.test.raises(TypeError, "newops[0] = 'foobar'")
py.test.raises(AssertionError, "newops[0].setarg(0, 'd')")
py.test.raises(AssertionError, "newops[0].setdescr('foobar')")
+
+def test_clone():
+ mydescr = AbstractDescr()
+ op = rop.create_resop_0(rop.rop.GUARD_NO_EXCEPTION, None, descr=mydescr)
+ op.setfailargs([3])
+ op2 = op.clone()
+ assert not op2 is op
+ assert op2.getresult() is None
+ assert op2.getfailargs() is op.getfailargs()
+ op = rop.create_resop_1(rop.rop.INT_IS_ZERO, FakeBox('a'), 1)
+ op2 = op.clone()
+ assert op2 is not op
+ assert op2._arg0 == FakeBox('a')
+ assert op2.getint() == 1
+ op = rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 1)
+ op2 = op.clone()
+ assert op2 is not op
+ assert op2._arg0 == FakeBox('a')
+ assert op2._arg1 == FakeBox('b')
+ assert op2.getint() == 1
+ op = rop.create_resop_3(rop.rop.STRSETITEM, FakeBox('a'), FakeBox('b'),
+ FakeBox('c'), None)
+ op2 = op.clone()
+ assert op2 is not op
+ assert op2._arg0 == FakeBox('a')
+ assert op2._arg1 == FakeBox('b')
+ assert op2._arg2 == FakeBox('c')
+ assert op2.getresult() is None
+ op = rop.create_resop(rop.rop.CALL_i, [FakeBox('a'), FakeBox('b'),
+ FakeBox('c')], 13, descr=mydescr)
+ op2 = op.clone()
+ assert op2 is not op
+ assert op2._args == [FakeBox('a'), FakeBox('b'), FakeBox('c')]
+ assert op2.getint() == 13
More information about the pypy-commit
mailing list