[pypy-svn] r55667 - in pypy/branch/eval-loop-experiments: config interpreter interpreter/test
antocuni at codespeak.net
antocuni at codespeak.net
Sun Jun 8 15:56:36 CEST 2008
Author: antocuni
Date: Sun Jun 8 15:56:34 2008
New Revision: 55667
Modified:
pypy/branch/eval-loop-experiments/config/pypyoption.py
pypy/branch/eval-loop-experiments/interpreter/pycode.py
pypy/branch/eval-loop-experiments/interpreter/pyopcode.py
pypy/branch/eval-loop-experiments/interpreter/test/test_interpreter.py
Log:
experimental option that precomputes opcode args and pack the bytecode
to contains only opcodes, not opargs; the intent is to make the
interpreter loop a bit smaller.
The benchmarks are a bit controversial, it's not clear if you win or
loose.
Modified: pypy/branch/eval-loop-experiments/config/pypyoption.py
==============================================================================
--- pypy/branch/eval-loop-experiments/config/pypyoption.py (original)
+++ pypy/branch/eval-loop-experiments/config/pypyoption.py Sun Jun 8 15:56:34 2008
@@ -138,7 +138,11 @@
BoolOption("usepycfiles", "Write and read pyc files when importing",
default=True),
-
+
+ BoolOption("usecodeargs", "store opcodes and opargs in separate lists",
+ default=False,
+ requires=[("objspace.usepycfiles", False)]),
+
BoolOption("honor__builtins__",
"Honor the __builtins__ key of a module dictionary",
default=False),
Modified: pypy/branch/eval-loop-experiments/interpreter/pycode.py
==============================================================================
--- pypy/branch/eval-loop-experiments/interpreter/pycode.py (original)
+++ pypy/branch/eval-loop-experiments/interpreter/pycode.py Sun Jun 8 15:56:34 2008
@@ -11,6 +11,7 @@
from pypy.interpreter.gateway import NoneNotWrapped
from pypy.interpreter.baseobjspace import ObjSpace, W_Root
from pypy.rlib.rarithmetic import intmask
+from pypy.tool import stdlib_opcode
# helper
@@ -65,7 +66,7 @@
self.co_nlocals = nlocals
self.co_stacksize = stacksize
self.co_flags = flags
- self.co_code = code
+ self.precompute_code(code)
self.co_consts_w = consts
self.co_names_w = [space.new_interned_str(aname) for aname in names]
self.co_varnames = varnames
@@ -114,7 +115,53 @@
def signature(self):
return self._signature
-
+
+ def precompute_code(self, code):
+ from pypy.interpreter.pyopcode import decode_opcode
+ if not self.space.config.objspace.usecodeargs:
+ self.co_code = code
+ self.co_codeargs = None
+ return
+
+ next_instr = 0
+ codeargs = []
+ codelist = []
+ orig2new = {} # index in code --> index in codelist
+ new2orig = {} # index in codelist --> index in code
+ while next_instr < len(code):
+ opcode = ord(code[next_instr])
+ orig2new[next_instr] = len(codelist)
+ new2orig[len(codelist)] = next_instr
+ next_instr += 1
+ next_instr, opcode, oparg = decode_opcode(code, next_instr, opcode)
+ codelist.append(chr(opcode))
+ codeargs.append(oparg)
+
+ # sanity check
+ assert len(codelist) == len(codeargs)
+ for i, j in orig2new.iteritems():
+ assert code[i] == codelist[j]
+
+ # recompute target addresses
+ i = 0
+ while i<len(codelist):
+ opcode = ord(codelist[i])
+ if opcode in stdlib_opcode.hasjabs:
+ oparg = codeargs[i]
+ codeargs[i] = orig2new[oparg]
+ elif opcode in stdlib_opcode.hasjrel:
+ oparg = codeargs[i]
+ orig_from = new2orig[i]
+ orig_to = orig_from + oparg + 3
+ new_from = i
+ new_to = orig2new[orig_to]
+ new_offset = new_to - new_from - 1
+ codeargs[i] = new_offset
+ i+=1
+
+ self.co_code = ''.join(codelist)
+ self.co_codeargs = codeargs
+
def _from_code(space, code, hidden_applevel=False):
""" Initialize the code object from a real (CPython) one.
This is just a hack, until we have our own compile.
Modified: pypy/branch/eval-loop-experiments/interpreter/pyopcode.py
==============================================================================
--- pypy/branch/eval-loop-experiments/interpreter/pyopcode.py (original)
+++ pypy/branch/eval-loop-experiments/interpreter/pyopcode.py Sun Jun 8 15:56:34 2008
@@ -60,6 +60,31 @@
unrolling_compare_dispatch_table = unrolling_iterable(
enumerate(compare_dispatch_table))
+def decode_opcode(co_code, next_instr, opcode):
+ if opcode >= HAVE_ARGUMENT:
+ lo = ord(co_code[next_instr])
+ hi = ord(co_code[next_instr+1])
+ next_instr += 2
+ oparg = (hi << 8) | lo
+ hint(opcode, concrete=True)
+ hint(oparg, concrete=True)
+ else:
+ oparg = 0
+
+ while opcode == opcodedesc.EXTENDED_ARG.index:
+ opcode = ord(co_code[next_instr])
+ if opcode < HAVE_ARGUMENT:
+ raise BytecodeCorruption
+ lo = ord(co_code[next_instr+1])
+ hi = ord(co_code[next_instr+2])
+ next_instr += 3
+ oparg = (oparg << 16) | (hi << 8) | lo
+ hint(opcode, concrete=True)
+ hint(oparg, concrete=True)
+
+ return next_instr, opcode, oparg
+decode_opcode._always_inline_ = True
+
class __extend__(pyframe.PyFrame):
"""A PyFrame that knows about interpretation of standard Python opcodes
@@ -73,20 +98,21 @@
next_instr = r_uint(next_instr)
co_code = pycode.co_code
+ co_codeargs = pycode.co_codeargs
try:
while True:
- next_instr = self.handle_bytecode(co_code, next_instr, ec)
+ next_instr = self.handle_bytecode(co_code, co_codeargs, next_instr, ec)
rstack.resume_point("dispatch", self, co_code, ec,
returns=next_instr)
except ExitFrame:
return self.popvalue()
- def handle_bytecode(self, co_code, next_instr, ec):
+ def handle_bytecode(self, co_code, co_codeargs, next_instr, ec):
from pypy.rlib import rstack # for resume points
try:
- next_instr = self.dispatch_bytecode(co_code, next_instr, ec)
+ next_instr = self.dispatch_bytecode(co_code, co_codeargs, next_instr, ec)
rstack.resume_point("handle_bytecode", self, co_code, ec,
returns=next_instr)
except OperationError, operr:
@@ -144,38 +170,25 @@
next_instr = block.handle(self, unroller)
return next_instr
- def dispatch_bytecode(self, co_code, next_instr, ec):
+ def dispatch_bytecode(self, co_code, co_codeargs, next_instr, ec):
space = self.space
while True:
+
self.last_instr = intmask(next_instr)
if not we_are_jitted():
ec.bytecode_trace(self)
next_instr = r_uint(self.last_instr)
opcode = ord(co_code[next_instr])
- next_instr += 1
+
if space.config.objspace.logbytecodes:
space.bytecodecounts[opcode] = space.bytecodecounts.get(opcode, 0) + 1
- if opcode >= HAVE_ARGUMENT:
- lo = ord(co_code[next_instr])
- hi = ord(co_code[next_instr+1])
- next_instr += 2
- oparg = (hi << 8) | lo
+ if space.config.objspace.usecodeargs:
+ oparg = co_codeargs[next_instr]
+ next_instr += 1
else:
- oparg = 0
- hint(opcode, concrete=True)
- hint(oparg, concrete=True)
-
- while opcode == opcodedesc.EXTENDED_ARG.index:
- opcode = ord(co_code[next_instr])
- if opcode < HAVE_ARGUMENT:
- raise BytecodeCorruption
- lo = ord(co_code[next_instr+1])
- hi = ord(co_code[next_instr+2])
- next_instr += 3
- oparg = (oparg << 16) | (hi << 8) | lo
- hint(opcode, concrete=True)
- hint(oparg, concrete=True)
+ next_instr += 1
+ next_instr, opcode, oparg = decode_opcode(co_code, next_instr, opcode)
if opcode == opcodedesc.RETURN_VALUE.index:
w_returnvalue = self.popvalue()
Modified: pypy/branch/eval-loop-experiments/interpreter/test/test_interpreter.py
==============================================================================
--- pypy/branch/eval-loop-experiments/interpreter/test/test_interpreter.py (original)
+++ pypy/branch/eval-loop-experiments/interpreter/test/test_interpreter.py Sun Jun 8 15:56:34 2008
@@ -43,6 +43,16 @@
ec = self.space.getexecutioncontext()
ec.compiler = self.saved_compiler
+ def test_jump(self):
+ code ='''
+ def f(s):
+ if len(s) == 0:
+ return 42
+ return 24
+ '''
+ assert self.codetest(code, 'f', ['']) == 42
+ assert self.codetest(code, 'f', ['x']) == 24
+
def test_exception_trivial(self):
x = self.codetest('''\
def f():
More information about the Pypy-commit
mailing list