[pypy-svn] r76432 - in pypy/branch/x86-64-jit-backend: . lib-python/modified-2.5.2/ctypes lib_pypy/_ctypes lib_pypy/pypy_test pypy/interpreter/astcompiler pypy/interpreter/test pypy/jit/backend/x86 pypy/jit/backend/x86/test pypy/jit/metainterp pypy/jit/metainterp/test pypy/module/__builtin__ pypy/module/_ast pypy/module/_ast/test pypy/objspace/std pypy/objspace/std/test pypy/rlib pypy/rlib/test pypy/rpython/lltypesystem

jcreigh at codespeak.net jcreigh at codespeak.net
Mon Aug 2 17:26:56 CEST 2010


Author: jcreigh
Date: Mon Aug  2 17:26:53 2010
New Revision: 76432

Modified:
   pypy/branch/x86-64-jit-backend/   (props changed)
   pypy/branch/x86-64-jit-backend/lib-python/modified-2.5.2/ctypes/__init__.py
   pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/__init__.py
   pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/array.py
   pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/builtin.py
   pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/primitive.py
   pypy/branch/x86-64-jit-backend/lib_pypy/pypy_test/test_ctypes_support.py
   pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/assemble.py
   pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/codegen.py
   pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/consts.py
   pypy/branch/x86-64-jit-backend/pypy/interpreter/test/test_compiler.py
   pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/assembler.py
   pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/runner.py
   pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/test/test_runner.py
   pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_loop.py
   pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_loop_spec.py
   pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/x86-64-jit-backend/pypy/module/__builtin__/compiling.py
   pypy/branch/x86-64-jit-backend/pypy/module/_ast/__init__.py
   pypy/branch/x86-64-jit-backend/pypy/module/_ast/test/test_ast.py
   pypy/branch/x86-64-jit-backend/pypy/objspace/std/callmethod.py
   pypy/branch/x86-64-jit-backend/pypy/objspace/std/test/test_callmethod.py
   pypy/branch/x86-64-jit-backend/pypy/rlib/objectmodel.py
   pypy/branch/x86-64-jit-backend/pypy/rlib/test/test_objectmodel.py
   pypy/branch/x86-64-jit-backend/pypy/rpython/lltypesystem/rstr.py
Log:
merged changes from trunk through r76430

Modified: pypy/branch/x86-64-jit-backend/lib-python/modified-2.5.2/ctypes/__init__.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/lib-python/modified-2.5.2/ctypes/__init__.py	(original)
+++ pypy/branch/x86-64-jit-backend/lib-python/modified-2.5.2/ctypes/__init__.py	Mon Aug  2 17:26:53 2010
@@ -471,7 +471,7 @@
 
 # functions
 
-from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
+from _ctypes import _memmove_addr, _memset_addr, _cast_addr
 
 ## void *memmove(void *, const void *, size_t);
 memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
@@ -490,24 +490,34 @@
 def cast(obj, typ):
     return _cast(obj, obj, typ)
 
-_string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
+try:
+    from _ctypes import _string_at_addr
+except ImportError:
+    from _ctypes import _string_at
+else:
+    _string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
+
 def string_at(ptr, size=-1):
     """string_at(addr[, size]) -> string
 
     Return the string at addr."""
     return _string_at(ptr, size)
 
+def wstring_at(ptr, size=-1):
+    """wstring_at(addr[, size]) -> string
+
+    Return the string at addr."""
+    return _wstring_at(ptr, size)
+
 try:
     from _ctypes import _wstring_at_addr
 except ImportError:
-    pass
+    try:
+        from _ctypes import _wstring_at
+    except ImportError:
+        del wstring_at
 else:
     _wstring_at = CFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr)
-    def wstring_at(ptr, size=-1):
-        """wstring_at(addr[, size]) -> string
-
-        Return the string at addr."""
-        return _wstring_at(ptr, size)
 
 
 if _os.name in ("nt", "ce"): # COM stuff

Modified: pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/__init__.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/__init__.py	(original)
+++ pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/__init__.py	Mon Aug  2 17:26:53 2010
@@ -7,8 +7,8 @@
 from _ctypes.dll import dlopen
 from _ctypes.structure import Structure
 from _ctypes.array import Array
-from _ctypes.builtin import _memmove_addr, _string_at_addr, _memset_addr,\
-     set_conversion_mode, _wstring_at_addr
+from _ctypes.builtin import _memmove_addr, _string_at, _memset_addr,\
+     set_conversion_mode, _wstring_at
 from _ctypes.union import Union
 
 import os as _os

Modified: pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/array.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/array.py	(original)
+++ pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/array.py	Mon Aug  2 17:26:53 2010
@@ -4,7 +4,6 @@
 from _ctypes.basics import _CData, cdata_from_address, _CDataMeta, sizeof
 from _ctypes.basics import keepalive_key, store_reference, ensure_objects
 from _ctypes.basics import CArgObject
-from _ctypes.builtin import _string_at_addr, _wstring_at_addr
 
 def _create_unicode(buffer, maxlength):
     res = []

Modified: pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/builtin.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/builtin.py	(original)
+++ pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/builtin.py	Mon Aug  2 17:26:53 2010
@@ -8,10 +8,10 @@
 _memmove_addr = _rawffi.get_libc().getaddressindll('memmove')
 _memset_addr = _rawffi.get_libc().getaddressindll('memset')
 
-def _string_at_addr(addr, lgt):
+def _string_at(addr, lgt):
     # address here can be almost anything
     import ctypes
-    arg = ctypes.c_char_p._CData_value(addr)
+    arg = ctypes.c_void_p._CData_value(addr)
     return _rawffi.charp2rawstring(arg, lgt)
 
 def set_conversion_mode(encoding, errors):
@@ -20,9 +20,9 @@
     ConvMode.encoding = encoding
     return old_cm
 
-def _wstring_at_addr(addr, lgt):
+def _wstring_at(addr, lgt):
     import ctypes
-    arg = ctypes.c_wchar_p._CData_value(addr)
+    arg = ctypes.c_void_p._CData_value(addr)
     # XXX purely applevel
     if lgt == -1:
         lgt = sys.maxint

Modified: pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/primitive.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/primitive.py	(original)
+++ pypy/branch/x86-64-jit-backend/lib_pypy/_ctypes/primitive.py	Mon Aug  2 17:26:53 2010
@@ -86,6 +86,8 @@
         return value
     if isinstance(value, _Pointer):
         return cls.from_address(value._buffer.buffer)
+    if isinstance(value, (int, long)):
+        return cls(value)
 
 FROM_PARAM_BY_TYPE = {
     'z': from_param_char_p,
@@ -141,13 +143,13 @@
             result.value = property(_getvalue, _setvalue)
         elif tp == 'Z':
             # c_wchar_p
-            from _ctypes import Array, _Pointer, _wstring_at_addr
+            from _ctypes import Array, _Pointer, _wstring_at
             def _getvalue(self):
                 addr = self._buffer[0]
                 if addr == 0:
                     return None
                 else:
-                    return _wstring_at_addr(addr, -1)
+                    return _wstring_at(addr, -1)
 
             def _setvalue(self, value):
                 if isinstance(value, basestring):
@@ -216,14 +218,14 @@
             SysAllocStringLen = windll.oleaut32.SysAllocStringLen
             SysStringLen = windll.oleaut32.SysStringLen
             SysFreeString = windll.oleaut32.SysFreeString
-            from _ctypes import _wstring_at_addr
+            from _ctypes import _wstring_at
             def _getvalue(self):
                 addr = self._buffer[0]
                 if addr == 0:
                     return None
                 else:
                     size = SysStringLen(addr)
-                    return _wstring_at_addr(addr, size)
+                    return _wstring_at(addr, size)
 
             def _setvalue(self, value):
                 if isinstance(value, basestring):
@@ -254,18 +256,21 @@
     from_address = cdata_from_address
 
     def from_param(self, value):
+        if isinstance(value, self):
+            return value
+        
         from_param_f = FROM_PARAM_BY_TYPE.get(self._type_)
         if from_param_f:
             res = from_param_f(self, value)
             if res is not None:
                 return res
-            
-        if isinstance(value, self):
-            return value
-        try:
-            return self(value)
-        except (TypeError, ValueError):
-            return super(SimpleType, self).from_param(value)
+        else:
+            try:
+                return self(value)
+            except (TypeError, ValueError):
+                pass
+
+        return super(SimpleType, self).from_param(value)
 
     def _CData_output(self, resbuffer, base=None, index=-1):
         output = super(SimpleType, self)._CData_output(resbuffer, base, index)

Modified: pypy/branch/x86-64-jit-backend/lib_pypy/pypy_test/test_ctypes_support.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/lib_pypy/pypy_test/test_ctypes_support.py	(original)
+++ pypy/branch/x86-64-jit-backend/lib_pypy/pypy_test/test_ctypes_support.py	Mon Aug  2 17:26:53 2010
@@ -20,3 +20,14 @@
     assert get_errno() != 0
     set_errno(0)
     assert get_errno() == 0
+
+def test_argument_conversion_and_checks():
+    import ctypes
+    libc = ctypes.cdll.LoadLibrary("libc.so.6")
+    libc.strlen.argtypes = ctypes.c_char_p,
+    libc.strlen.restype = ctypes.c_size_t
+    assert libc.strlen("eggs") == 4
+    
+    # Should raise ArgumentError, not segfault
+    py.test.raises(ctypes.ArgumentError, libc.strlen, False)
+

Modified: pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/assemble.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/assemble.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/assemble.py	Mon Aug  2 17:26:53 2010
@@ -566,22 +566,22 @@
     return (oparg % 256) + 2 * (oparg / 256)
 
 def _compute_CALL_FUNCTION(arg):
-    return _num_args(arg)
+    return -_num_args(arg)
 
 def _compute_CALL_FUNCTION_VAR(arg):
-    return _num_args(arg) - 1
+    return -_num_args(arg) - 1
 
 def _compute_CALL_FUNCTION_KW(arg):
-    return _num_args(arg) - 1
+    return -_num_args(arg) - 1
 
 def _compute_CALL_FUNCTION_VAR_KW(arg):
-    return _num_args(arg) - 2
+    return -_num_args(arg) - 2
 
 def _compute_CALL_LIKELY_BUILTIN(arg):
     return -(arg & 0xFF) + 1
 
 def _compute_CALL_METHOD(arg):
-    return -arg - 1
+    return -_num_args(arg) - 1
 
 
 _stack_effect_computers = {}

Modified: pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/codegen.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/codegen.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/codegen.py	Mon Aug  2 17:26:53 2010
@@ -960,9 +960,12 @@
         elif call_type == 3:
             op = ops.CALL_FUNCTION_VAR_KW
         self.emit_op_arg(op, arg)
+    
+    def _call_has_no_star_args(self, call):
+        return not call.starargs and not call.kwargs
 
     def _call_has_simple_args(self, call):
-        return not call.starargs and not call.kwargs and not call.keywords
+        return self._call_has_no_star_args(call) and not call.keywords
 
     def _optimize_builtin_call(self, call):
         if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \
@@ -988,7 +991,7 @@
 
     def _optimize_method_call(self, call):
         if not self.space.config.objspace.opcodes.CALL_METHOD or \
-                not self._call_has_simple_args(call) or \
+                not self._call_has_no_star_args(call) or \
                 not isinstance(call.func, ast.Attribute):
             return False
         attr_lookup = call.func
@@ -1000,7 +1003,12 @@
             arg_count = len(call.args)
         else:
             arg_count = 0
-        self.emit_op_arg(ops.CALL_METHOD, arg_count)
+        if call.keywords:
+            self.visit_sequence(call.keywords)
+            kwarg_count = len(call.keywords)
+        else:
+            kwarg_count = 0
+        self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count)
         return True
 
     def _listcomp_generator(self, list_name, gens, gen_index, elt):

Modified: pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/consts.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/consts.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/interpreter/astcompiler/consts.py	Mon Aug  2 17:26:53 2010
@@ -18,4 +18,4 @@
 
 PyCF_SOURCE_IS_UTF8 = 0x0100
 PyCF_DONT_IMPLY_DEDENT = 0x0200
-PyCF_AST_ONLY = 0x0400
+PyCF_ONLY_AST = 0x0400

Modified: pypy/branch/x86-64-jit-backend/pypy/interpreter/test/test_compiler.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/interpreter/test/test_compiler.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/interpreter/test/test_compiler.py	Mon Aug  2 17:26:53 2010
@@ -4,6 +4,7 @@
 from pypy.interpreter.pycode import PyCode
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.argument import Arguments
+from pypy.conftest import gettestobjspace
 
 class BaseTestCompiler:
     def setup_method(self, method):
@@ -848,14 +849,38 @@
         
         import StringIO, sys, dis
         s = StringIO.StringIO()
+        out = sys.stdout
         sys.stdout = s
         try:
             dis.dis(code)
         finally:
-            sys.stdout = sys.__stdout__
+            sys.stdout = out
         output = s.getvalue()
         assert "LOAD_GLOBAL" not in output
 
+class AppTestCallMethod(object):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{'objspace.opcodes.CALL_METHOD': True})
+        
+    def test_call_method_kwargs(self):
+        source = """def _f(a):
+            return a.f(a=a)
+        """
+        exec source
+        code = _f.func_code
+        
+        import StringIO, sys, dis
+        s = StringIO.StringIO()
+        out = sys.stdout
+        sys.stdout = s
+        try:
+            dis.dis(code)
+        finally:
+            sys.stdout = out
+        output = s.getvalue()
+        assert "CALL_METHOD" in output
+            
+
 class AppTestExceptions:
     def test_indentation_error(self):
         source = """if 1:

Modified: pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/assembler.py	Mon Aug  2 17:26:53 2010
@@ -1,4 +1,4 @@
-import sys
+import sys, os
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
 from pypy.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT,\
@@ -30,6 +30,7 @@
 from pypy.rlib.debug import debug_print
 from pypy.rlib import rgc
 from pypy.jit.backend.x86.jump import remap_frame_layout
+from pypy.rlib.streamio import open_file_as_stream
 
 # darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0,
 # better safe than sorry
@@ -154,6 +155,7 @@
     mc_size = MachineCodeBlockWrapper.MC_DEFAULT_SIZE
     _float_constants = None
     _regalloc = None
+    _output_loop_log = None
 
     def __init__(self, cpu, translate_support_code=False,
                             failargs_limit=1000):
@@ -168,18 +170,26 @@
         self.fail_boxes_ptr = values_array(llmemory.GCREF, failargs_limit)
         self.fail_boxes_float = values_array(lltype.Float, failargs_limit)
         self.fail_ebp = 0
+        self.loop_run_counter = values_array(lltype.Signed, 10000)
+        self.loop_names = []
+        # if we have 10000 loops, we have some other problems I guess
         self.float_const_neg_addr = 0
         self.float_const_abs_addr = 0
         self.malloc_fixedsize_slowpath1 = 0
         self.malloc_fixedsize_slowpath2 = 0
         self.pending_guard_tokens = []
         self.setup_failure_recovery()
+        self._loop_counter = 0
+        self._debug = False
 
     def leave_jitted_hook(self):
         ptrs = self.fail_boxes_ptr.ar
         llop.gc_assume_young_pointers(lltype.Void,
                                       llmemory.cast_ptr_to_adr(ptrs))
 
+    def set_debug(self, v):
+        self._debug = v
+
     def make_sure_mc_exists(self):
         if self.mc is None:
             # the address of the function called by 'new'
@@ -209,6 +219,22 @@
                 self._build_float_constants()
             if hasattr(gc_ll_descr, 'get_malloc_fixedsize_slowpath_addr'):
                 self._build_malloc_fixedsize_slowpath()
+            s = os.environ.get('PYPYLOG')
+            if s:
+                if s.find(':') != -1:
+                    s = s.split(':')[-1]
+                self.set_debug(True)
+                self._output_loop_log = s + ".count"
+
+    def finish_once(self):
+        if self._debug:
+            output_log = self._output_loop_log
+            assert output_log is not None
+            f = open_file_as_stream(output_log, "w")
+            for i in range(self._loop_counter):
+                f.write(self.loop_names[i] + ":" +
+                        str(self.loop_run_counter.getitem(i)) + "\n")
+            f.close()
 
     def _build_float_constants(self):
         # 44 bytes: 32 bytes for the data, and up to 12 bytes for alignment
@@ -267,9 +293,9 @@
             # Arguments should be unique
             assert len(set(inputargs)) == len(inputargs)
 
+        self.make_sure_mc_exists()
         funcname = self._find_debug_merge_point(operations)
 
-        self.make_sure_mc_exists()
         
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
         arglocs = regalloc.prepare_loop(inputargs, operations, looptoken)
@@ -302,9 +328,9 @@
             # Arguments should be unique
             assert len(set(inputargs)) == len(inputargs)
 
+        self.make_sure_mc_exists()
         funcname = self._find_debug_merge_point(operations)
 
-        self.make_sure_mc_exists()
         arglocs = self.rebuild_faillocs_from_descr(
             faildescr._x86_failure_recovery_bytecode)
         if not we_are_translated():
@@ -357,10 +383,18 @@
         self.mc.done()
 
     def _find_debug_merge_point(self, operations):
+
         for op in operations:
             if op.opnum == rop.DEBUG_MERGE_POINT:
-                return op.args[0]._get_str()
-        return ""
+                funcname = op.args[0]._get_str()
+                break
+        else:
+            funcname = "<loop %d>" % self._loop_counter
+        # invent the counter, so we don't get too confused
+        if self._debug:
+            self.loop_names.append(funcname)
+            self._loop_counter += 1
+        return funcname
         
     def patch_jump_for_descr(self, faildescr, adr_new_target):
         adr_jump_offset = faildescr._x86_adr_jump_offset
@@ -384,6 +418,15 @@
 
     def _assemble(self, regalloc, operations):
         self._regalloc = regalloc
+        if self._debug:
+            # before doing anything, let's increase a counter
+            # we need one register free (a bit of a hack, but whatever)
+            self.mc.PUSH(eax)
+            adr = self.loop_run_counter.get_addr_for_num(self._loop_counter - 1)
+            self.mc.MOV(eax, heap(adr))
+            self.mc.ADD(eax, imm(1))
+            self.mc.MOV(heap(adr), eax)
+            self.mc.POP(eax)
         regalloc.walk_operations(operations)        
         self.mc.done()
         if we_are_translated() or self.cpu.dont_keepalive_stuff:

Modified: pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/runner.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/runner.py	Mon Aug  2 17:26:53 2010
@@ -46,6 +46,7 @@
         self.profile_agent.startup()
 
     def finish_once(self):
+        self.assembler.finish_once()
         self.profile_agent.shutdown()
 
     def compile_loop(self, inputargs, operations, looptoken):

Modified: pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/test/test_runner.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/test/test_runner.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/jit/backend/x86/test/test_runner.py	Mon Aug  2 17:26:53 2010
@@ -9,8 +9,11 @@
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp.executor import execute
 from pypy.jit.backend.test.runner_test import LLtypeBackendTest
+from pypy.jit.metainterp.test.oparser import parse
+from pypy.tool.udir import udir
 import ctypes
 import sys
+import os
 
 CPU = getcpuclass()
 
@@ -453,3 +456,36 @@
             # Really just a sanity check. We're actually interested in
             # whether the test segfaults.
             assert self.cpu.get_latest_value_int(0) == finished.value
+
+
+class TestDebuggingAssembler(object):
+    def setup_method(self, meth):
+        self.pypylog = os.environ.get('PYPYLOG', None)
+        self.logfile = str(udir.join('x86_runner.log'))
+        os.environ['PYPYLOG'] = "mumble:" + self.logfile
+        self.cpu = CPU(rtyper=None, stats=FakeStats())
+
+    def teardown_method(self, meth):
+        if self.pypylog is not None:
+            os.environ['PYPYLOG'] = self.pypylog
+
+    def test_debugger_on(self):
+        loop = """
+        [i0]
+        debug_merge_point('xyz')
+        i1 = int_add(i0, 1)
+        i2 = int_ge(i1, 10)
+        guard_false(i2) []
+        jump(i1)
+        """
+        ops = parse(loop)
+        self.cpu.assembler.set_debug(True)
+        self.cpu.compile_loop(ops.inputargs, ops.operations, ops.token)
+        self.cpu.set_future_value_int(0, 0)
+        self.cpu.execute_token(ops.token)
+        # check debugging info
+        assert self.cpu.assembler.loop_names == ["xyz"]
+        assert self.cpu.assembler.loop_run_counter.getitem(0) == 10
+        self.cpu.finish_once()
+        lines = py.path.local(self.logfile + ".count").readlines()
+        assert lines[0] == 'xyz:10\n'

Modified: pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/optimizeopt.py	Mon Aug  2 17:26:53 2010
@@ -1001,6 +1001,17 @@
             self.make_equal_to(op.result, v1)
         else:
             return self.optimize_default(op)
+    
+    def optimize_INT_ADD(self, op):
+        v1 = self.getvalue(op.args[0])
+        v2 = self.getvalue(op.args[1])
+        # If one side of the op is 0 the result is the other side.
+        if v1.is_constant() and v1.box.getint() == 0:
+            self.make_equal_to(op.result, v2)
+        elif v2.is_constant() and v2.box.getint() == 0:
+            self.make_equal_to(op.result, v1)
+        else:
+            self.optimize_default(op)
 
 
 optimize_ops = _findall(Optimizer, 'optimize_')

Modified: pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_loop.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_loop.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_loop.py	Mon Aug  2 17:26:53 2010
@@ -9,6 +9,10 @@
 
 class LoopTest(object):
     optimizer = OPTIMIZER_SIMPLE
+    automatic_promotion_result = {
+        'int_add' : 6, 'int_gt' : 1, 'guard_false' : 1, 'jump' : 1, 
+        'guard_value' : 3
+    }
 
     def meta_interp(self, f, args, policy=None):
         return ll_meta_interp(f, args, optimizer=self.optimizer,
@@ -477,9 +481,9 @@
         res = self.meta_interp(main_interpreter_loop, [1])
         assert res == main_interpreter_loop(1)
         self.check_loop_count(1)
-        # XXX maybe later optimize guard_value away
-        self.check_loops({'int_add' : 6, 'int_gt' : 1,
-                          'guard_false' : 1, 'jump' : 1, 'guard_value' : 3})
+        # These loops do different numbers of ops based on which optimizer we
+        # are testing with.
+        self.check_loops(self.automatic_promotion_result)
 
     def test_can_enter_jit_outside_main_loop(self):
         myjitdriver = JitDriver(greens=[], reds=['i', 'j', 'a'])

Modified: pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_loop_spec.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_loop_spec.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_loop_spec.py	Mon Aug  2 17:26:53 2010
@@ -5,6 +5,10 @@
 
 class LoopSpecTest(test_loop.LoopTest):
     optimizer = OPTIMIZER_FULL
+    automatic_promotion_result = {
+        'int_add' : 3, 'int_gt' : 1, 'guard_false' : 1, 'jump' : 1, 
+        'guard_value' : 1
+    }
 
     # ====> test_loop.py
 

Modified: pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/jit/metainterp/test/test_optimizeopt.py	Mon Aug  2 17:26:53 2010
@@ -2063,6 +2063,28 @@
         jump(i0)
         """
         self.optimize_loop(ops, 'Not', expected)
+        
+        ops = """
+        [i0]
+        i1 = int_add(i0, 0)
+        jump(i1)
+        """
+        expected = """
+        [i0]
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+        
+        ops = """
+        [i0]
+        i1 = int_add(0, i0)
+        jump(i1)
+        """
+        expected = """
+        [i0]
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
     
     # ----------
 

Modified: pypy/branch/x86-64-jit-backend/pypy/module/__builtin__/compiling.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/module/__builtin__/compiling.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/module/__builtin__/compiling.py	Mon Aug  2 17:26:53 2010
@@ -38,7 +38,7 @@
         str_ = space.str_w(w_source)
 
     ec = space.getexecutioncontext()
-    if flags & ~(ec.compiler.compiler_flags | consts.PyCF_AST_ONLY |
+    if flags & ~(ec.compiler.compiler_flags | consts.PyCF_ONLY_AST |
                  consts.PyCF_DONT_IMPLY_DEDENT | consts.PyCF_SOURCE_IS_UTF8):
         raise OperationError(space.w_ValueError,
                              space.wrap("compile() unrecognized flags"))
@@ -53,7 +53,7 @@
                                         "or 'eval' or 'single'"))
 
     if ast_node is None:
-        if flags & consts.PyCF_AST_ONLY:
+        if flags & consts.PyCF_ONLY_AST:
             mod = ec.compiler.compile_to_ast(str_, filename, mode, flags)
             return space.wrap(mod)
         else:

Modified: pypy/branch/x86-64-jit-backend/pypy/module/_ast/__init__.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/module/_ast/__init__.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/module/_ast/__init__.py	Mon Aug  2 17:26:53 2010
@@ -5,7 +5,7 @@
 class Module(MixedModule):
 
     interpleveldefs = {
-        "PyCF_AST_ONLY" : "space.wrap(%s)" % consts.PyCF_AST_ONLY
+        "PyCF_ONLY_AST" : "space.wrap(%s)" % consts.PyCF_ONLY_AST
         }
     appleveldefs = {}
 

Modified: pypy/branch/x86-64-jit-backend/pypy/module/_ast/test/test_ast.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/module/_ast/test/test_ast.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/module/_ast/test/test_ast.py	Mon Aug  2 17:26:53 2010
@@ -10,7 +10,7 @@
         cls.w_get_ast = cls.space.appexec([], """():
     def get_ast(source, mode="exec"):
         import _ast as ast
-        mod = compile(source, "<test>", mode, ast.PyCF_AST_ONLY)
+        mod = compile(source, "<test>", mode, ast.PyCF_ONLY_AST)
         assert isinstance(mod, ast.mod)
         return mod
     return get_ast""")

Modified: pypy/branch/x86-64-jit-backend/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/objspace/std/callmethod.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/objspace/std/callmethod.py	Mon Aug  2 17:26:53 2010
@@ -12,7 +12,7 @@
 
 from pypy.interpreter import function
 from pypy.objspace.descroperation import object_getattribute
-from pypy.rlib import rstack # for resume points
+from pypy.rlib import jit, rstack # for resume points
 
 # This module exports two extra methods for StdObjSpaceFrame implementing
 # the LOOKUP_METHOD and CALL_METHOD opcodes in an efficient way, as well
@@ -56,16 +56,42 @@
     f.pushvalue(w_value)
     f.pushvalue(None)
 
-def CALL_METHOD(f, nargs, *ignored):
-    # 'nargs' is the argument count excluding the implicit 'self'
-    w_self = f.peekvalue(nargs)
-    w_callable = f.peekvalue(nargs + 1)
-    n = nargs + (w_self is not None)
-    try:
-        w_result = f.space.call_valuestack(w_callable, n, f)
-        rstack.resume_point("CALL_METHOD", f, nargs, returns=w_result)
-    finally:
-        f.dropvalues(nargs + 2)
+ at jit.unroll_safe
+def CALL_METHOD(f, oparg, *ignored):
+    # opargs contains the arg, and kwarg count, excluding the implicit 'self'
+    n_args = oparg & 0xff
+    n_kwargs = (oparg >> 8) & 0xff
+    w_self = f.peekvalue(n_args + (2 * n_kwargs))
+    w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1)
+    n = n_args + (w_self is not None)
+    
+    if not n_kwargs:
+        try:
+            w_result = f.space.call_valuestack(w_callable, n, f)
+            rstack.resume_point("CALL_METHOD_no_kwargs", f, n_args, returns=w_result)
+        finally:
+            f.dropvalues(n_args + 2)
+    else:
+        keywords = [None] * n_kwargs
+        keywords_w = [None] * n_kwargs
+        while True:
+            n_kwargs -= 1
+            if n_kwargs < 0:
+                break
+            w_value = f.popvalue()
+            w_key = f.popvalue()
+            key = f.space.str_w(w_key)
+            keywords[n_kwargs] = key
+            keywords_w[n_kwargs] = w_value
+    
+        arguments = f.popvalues(n)
+        args = f.argument_factory(arguments, keywords, keywords_w, None, None)
+        
+        try:
+            w_result = f.space.call_args(w_callable, args)
+            rstack.resume_point("CALL_METHOD", f, w_self, returns=w_result)
+        finally:
+            f.dropvalues(1 + (w_self is None))
     f.pushvalue(w_result)
 
 

Modified: pypy/branch/x86-64-jit-backend/pypy/objspace/std/test/test_callmethod.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/objspace/std/test/test_callmethod.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/objspace/std/test/test_callmethod.py	Mon Aug  2 17:26:53 2010
@@ -106,6 +106,15 @@
             else:
                 raise Exception("did not raise?")
         """
+    
+    def test_kwargs(self):
+        exec """if 1:
+            class C(object):
+                def f(self, a):
+                    return a + 2
+            
+            assert C().f(a=3) == 5
+        """
 
 
 class AppTestCallMethodWithGetattributeShortcut(AppTestCallMethod):

Modified: pypy/branch/x86-64-jit-backend/pypy/rlib/objectmodel.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/rlib/objectmodel.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/rlib/objectmodel.py	Mon Aug  2 17:26:53 2010
@@ -26,7 +26,7 @@
         by a call result then.
         """
         def decorated_func(func):
-            func._annspecialcase_ = 'specialize:memo()'
+            func._annspecialcase_ = 'specialize:memo'
             return func
         return decorated_func
 
@@ -63,7 +63,7 @@
         for example). Same warnings about exponential behavior apply.
         """
         def decorated_func(func):
-            func._annspecialcase_ = 'specialize:ll()'
+            func._annspecialcase_ = 'specialize:ll'
             return func
 
         return decorated_func
@@ -82,6 +82,17 @@
         
 specialize = _Specialize()
 
+def enforceargs(*args):
+    """ Decorate a function with forcing of RPython-level types on arguments.
+    None means no enforcing.
+
+    XXX shouldn't we also add asserts in function body?
+    """
+    def decorator(f):
+        f._annenforceargs_ = args
+        return f
+    return decorator
+
 # ____________________________________________________________
 
 class Symbolic(object):

Modified: pypy/branch/x86-64-jit-backend/pypy/rlib/test/test_objectmodel.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/rlib/test/test_objectmodel.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/rlib/test/test_objectmodel.py	Mon Aug  2 17:26:53 2010
@@ -404,6 +404,13 @@
 
     assert f._annspecialcase_ == 'specialize:arg(1)'
 
+def test_enforceargs_decorator():
+    @enforceargs(int, str, None)
+    def f(a, b, c):
+        pass
+
+    assert f._annenforceargs_ == (int, str, None)
+
 def getgraph(f, argtypes):
     from pypy.translator.translator import TranslationContext, graphof
     from pypy.translator.backendopt.all import backend_optimizations

Modified: pypy/branch/x86-64-jit-backend/pypy/rpython/lltypesystem/rstr.py
==============================================================================
--- pypy/branch/x86-64-jit-backend/pypy/rpython/lltypesystem/rstr.py	(original)
+++ pypy/branch/x86-64-jit-backend/pypy/rpython/lltypesystem/rstr.py	Mon Aug  2 17:26:53 2010
@@ -2,7 +2,7 @@
 from pypy.tool.pairtype import pairtype
 from pypy.rpython.error import TyperError
 from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated
-from pypy.rlib.objectmodel import _hash_string
+from pypy.rlib.objectmodel import _hash_string, enforceargs
 from pypy.rlib.debug import ll_assert
 from pypy.rlib.jit import purefunction
 from pypy.rpython.robject import PyObjRepr, pyobj_repr
@@ -56,6 +56,7 @@
                 llmemory.itemoffsetof(TP.chars, 0) +
                 llmemory.sizeof(CHAR_TP) * item)
 
+    @enforceargs(None, None, int, int, int)
     def copy_string_contents(src, dst, srcstart, dststart, length):
         assert srcstart >= 0
         assert dststart >= 0



More information about the Pypy-commit mailing list