[pypy-svn] r64662 - in pypy/branch/pyjitpl5/pypy/jit: backend/llgraph backend/minimal backend/x86 metainterp

benjamin at codespeak.net benjamin at codespeak.net
Sat Apr 25 02:55:49 CEST 2009


Author: benjamin
Date: Sat Apr 25 02:55:49 2009
New Revision: 64662

Modified:
   pypy/branch/pyjitpl5/pypy/jit/backend/llgraph/runner.py
   pypy/branch/pyjitpl5/pypy/jit/backend/minimal/runner.py
   pypy/branch/pyjitpl5/pypy/jit/backend/x86/runner.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/history.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py
Log:
implement serialization of prebuilt AbstractValues for space in the binary

At the moment, only simple ConstInt can be serialized

I refactored out jitcode decoding from MIFrame


Modified: pypy/branch/pyjitpl5/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llgraph/runner.py	Sat Apr 25 02:55:49 2009
@@ -234,6 +234,9 @@
     def cast_int_to_adr(self, int):
         return llimpl.cast_int_to_adr(self.memo_cast, int)
 
+    def unserialize_prebuilt(self, const_type, decoder):
+        pass
+
 
 
 class LLtypeCPU(BaseCPU):

Modified: pypy/branch/pyjitpl5/pypy/jit/backend/minimal/runner.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/minimal/runner.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/minimal/runner.py	Sat Apr 25 02:55:49 2009
@@ -39,6 +39,9 @@
     def compile_operations(self, loop):
         pass
 
+    def unserialize_prebuilt(self, const_type, decoder):
+        pass
+
     def execute_operations(self, loop, valueboxes):
         if DEBUG:
             print "execute_operations: starting", loop

Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/runner.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/runner.py	Sat Apr 25 02:55:49 2009
@@ -609,6 +609,9 @@
             counter += 1
         return counter, basesize, ptr
 
+    def unserialize_prebuilt(self, const_type, decoder):
+        pass
+
     def calldescrof(self, functype, argtypes, resulttype):
         if resulttype is lltype.Void:
             size = 0

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py	Sat Apr 25 02:55:49 2009
@@ -6,7 +6,7 @@
 from pypy.rlib import objectmodel
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.jit import _we_are_jitted
-from pypy.jit.metainterp.history import Const, getkind
+from pypy.rlib.rarithmetic import intmask
 from pypy.jit.metainterp import heaptracker, support, history
 from pypy.tool.udir import udir
 from pypy.translator.simplify import get_funcobj, get_functype
@@ -30,18 +30,82 @@
         self.called_from = called_from
         self.graph = graph
 
-    def setup(self, code, constants):
+    def setup(self, code, constant_code, unserialized):
         self.code = code
-        self.constants = constants
+        self.serialized_constants = constant_code
+        self.unserialized_constants = unserialized
+        self.constants = None
+
+    def ensure_constants(self, cpu):
+        if self.constants is None:
+            self.constants = []
+            decoder = JitCodeDecoder(self.serialized_constants)
+            const_code_len = len(self.serialized_constants)
+            unserialized_index = 0
+            while decoder.pc < const_code_len:
+                const_type = decoder.load_int()
+                if const_type == history.CONST_NOT_SERIALIZED:
+                    const = self.unserialized_constants[unserialized_index]
+                    unserialized_index += 1
+                else:
+                    const = history.unserialize_prebuilt(const_type, decoder, cpu)
+                self.constants.append(const)
+        return self.constants
 
     def __repr__(self):
         return '<JitCode %r>' % (getattr(self, 'name', '?'),)
 
-    def dump(self, file=None):
+    def dump(self, cpu, file=None):
+        self.ensure_constants(cpu)
         import dump
         dump.dump_bytecode(self, file=file)
         print >> file
 
+
+class JitCodeDecoder(object):
+
+    def __init__(self, bytecode):
+        self.bytecode = bytecode
+        self.pc = 0
+
+    def load_int(self):
+        pc = self.pc
+        result = ord(self.bytecode[pc])
+        self.pc = pc + 1
+        if result > 0x7F:
+            result = self._load_larger_int(result)
+        return result
+
+    def _load_larger_int(self, result):    # slow path
+        result = result & 0x7F
+        shift = 7
+        pc = self.pc
+        while 1:
+            byte = ord(self.bytecode[pc])
+            pc += 1
+            result += (byte & 0x7F) << shift
+            shift += 7
+            if not byte & 0x80:
+                break
+        self.pc = pc
+        return intmask(result)
+    _load_larger_int._dont_inline_ = True
+
+    def load_3byte(self):
+        pc = self.pc
+        result = (((ord(self.bytecode[pc + 0])) << 16) |
+                  ((ord(self.bytecode[pc + 1])) <<  8) |
+                  ((ord(self.bytecode[pc + 2])) <<  0))
+        self.pc = pc + 3
+        return result
+
+    def load_bool(self):
+        pc = self.pc
+        result = ord(self.bytecode[pc])
+        self.pc = pc + 1
+        return bool(result)
+
+
 class IndirectCallset(history.AbstractValue):
     def __init__(self, codewriter, graphs):
         keys = []
@@ -228,7 +292,7 @@
 ##                                                            [TP], OF)
 ##                insert_func, _ = support.builtin_func_for_spec(rtyper,
 ##                      'list.insert', [TP, lltype.Signed, OF], lltype.Void)
-            tp = getkind(OF)
+            tp = history.getkind(OF)
 ##            if isinstance(TP.TO, lltype.GcStruct):
 ##                ld = ListDescr(history.ConstAddr(getfunc.value, self.cpu),
 ##                               history.ConstAddr(setfunc.value, self.cpu),
@@ -282,24 +346,40 @@
         code = assemble(labelpos, self.codewriter.metainterp_sd,
                         self.assembler)
         self.resolve_switch_targets(labelpos)
-        self.bytecode.setup(code, self.constants)
+        const_code, consts = self.serialize_constants()
+        self.bytecode.setup(code, const_code, consts)
 
         self.bytecode._source = self.assembler
         self.bytecode._metainterp_sd = self.codewriter.metainterp_sd
         self.bytecode._labelpos = labelpos
         if self.debug:
-            self.bytecode.dump()
+            self.bytecode.dump(self.cpu)
         else:
             print repr(self.bytecode)
             dir = udir.ensure("jitcodes", dir=1)
-            self.bytecode.dump(open(str(dir.join(self.bytecode.name)), "w"))
+            self.bytecode.dump(self.cpu,
+                               open(str(dir.join(self.bytecode.name)), "w"))
+
+    def serialize_constants(self):
+        code = []
+        unserialized = []
+        for const in self.constants:
+            try:
+                as_bytecode = const.serialize()
+            except history.Unserializable:
+                code.append(history.CONST_NOT_SERIALIZED)
+                unserialized.append(const)
+            else:
+                code.extend(as_bytecode)
+        bytecode = assemble_constant_code(code)
+        return bytecode, unserialized
 
     def const_position(self, constvalue):
         """Generate a constant of the given value.
         Returns its index in the list self.positions[].
         """
         if constvalue is _we_are_jitted: constvalue = True
-        const = Const._new(constvalue, self.cpu)
+        const = history.Const._new(constvalue, self.cpu)
         return self.get_position(const)
 
     def get_position(self, x):
@@ -1158,6 +1238,17 @@
             break
     return result
 
+def assemble_constant_code(assembler):
+    result = []
+    for arg in assembler:
+        if isinstance(arg, bool):
+            result.append(chr(int(arg)))
+        elif isinstance(arg, int):
+            result.extend(encode_int(arg))
+        else:
+            raise AssertionError("not simple enough %s" % arg)
+    return "".join(result)
+
 def assemble(labelpos, metainterp_sd, assembler):
     result = []
     for arg in assembler:

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/history.py	Sat Apr 25 02:55:49 2009
@@ -101,6 +101,9 @@
     def sort_key(self):
         raise NotImplementedError
 
+    def serialize(self):
+        raise Unserializable
+
 class AbstractDescr(AbstractValue):
     def handle_fail_op(self, metainterp, fail_op):
         raise NotImplementedError
@@ -116,6 +119,18 @@
     def get_jitcode_for_class(self, oocls):
         return self.jitcodes[oocls]
 
+class Unserializable(Exception):
+    pass
+
+CONST_TYPE_INT = 1
+CONST_TYPE_ADDR = 2
+CONST_NOT_SERIALIZED = 100
+
+def unserialize_prebuilt(const_type, decoder, cpu):
+    if const_type == CONST_TYPE_INT:
+        return ConstInt(decoder.load_int())
+    return cpu.unserialize_prebuilt(const_type, decoder)
+
 
 class Const(AbstractValue):
     __slots__ = ()
@@ -148,6 +163,17 @@
     def constbox(self):
         return self
 
+    def serialize(self):
+        """
+        NOT_RPYTHON
+        Convert this constant into a list of strings for JIT bytecode.
+        """
+        # A useful generic implementation.
+        try:
+            return (self.const_type, self.value)
+        except AttributeError:
+            raise Unserializable
+
     def __repr__(self):
         return 'Const(%s)' % self._getrepr_()
 
@@ -178,6 +204,7 @@
 
 class ConstInt(Const):
     type = INT
+    const_type = CONST_TYPE_INT
     _attrs_ = ('value',)
 
     def __init__(self, value):
@@ -196,6 +223,11 @@
     def getint(self):
         return self.value
 
+    def serialize(self):
+        if isinstance(self.value, Symbolic):
+            raise Unserializable
+        return super(ConstInt, self).serialize()
+
     def getaddr(self, cpu):
         return cpu.cast_int_to_adr(self.value)
 

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py	Sat Apr 25 02:55:49 2009
@@ -119,57 +119,17 @@
 # ____________________________________________________________
 
 
-class MIFrame(object):
+class MIFrame(codewriter.JitCodeDecoder):
 
     def __init__(self, metainterp, jitcode):
         assert isinstance(jitcode, codewriter.JitCode)
         self.metainterp = metainterp
         self.jitcode = jitcode
-        self.bytecode = jitcode.code
-        self.constants = jitcode.constants
+        codewriter.JitCodeDecoder.__init__(self, jitcode.code)
+        self.constants = jitcode.ensure_constants(self.metainterp.cpu)
         self.exception_target = -1
         self.name = jitcode.name # purely for having name attribute
 
-    # ------------------------------
-    # Decoding of the JitCode
-
-    def load_int(self):
-        pc = self.pc
-        result = ord(self.bytecode[pc])
-        self.pc = pc + 1
-        if result > 0x7F:
-            result = self._load_larger_int(result)
-        return result
-
-    def _load_larger_int(self, result):    # slow path
-        result = result & 0x7F
-        shift = 7
-        pc = self.pc
-        while 1:
-            byte = ord(self.bytecode[pc])
-            pc += 1
-            result += (byte & 0x7F) << shift
-            shift += 7
-            if not byte & 0x80:
-                break
-        self.pc = pc
-        return intmask(result)
-    _load_larger_int._dont_inline_ = True
-
-    def load_3byte(self):
-        pc = self.pc
-        result = (((ord(self.bytecode[pc + 0])) << 16) |
-                  ((ord(self.bytecode[pc + 1])) <<  8) |
-                  ((ord(self.bytecode[pc + 2])) <<  0))
-        self.pc = pc + 3
-        return result
-
-    def load_bool(self):
-        pc = self.pc
-        result = ord(self.bytecode[pc])
-        self.pc = pc + 1
-        return bool(result)
-
     def getenv(self, i):
         assert i >= 0
         j = i >> 1



More information about the Pypy-commit mailing list