[pypy-svn] r78047 - in pypy/trunk/pypy: . annotation annotation/test config doc/config jit/backend/llgraph jit/backend/llsupport jit/backend/llsupport/test jit/backend/test jit/backend/x86/test jit/codewriter jit/codewriter/test jit/metainterp jit/metainterp/optimizeopt jit/metainterp/test jit/tl module/_ffi module/_rawffi module/_rawffi/test module/pypyjit module/pypyjit/test rlib rlib/test rpython rpython/lltypesystem rpython/test translator/c/test

antocuni at codespeak.net antocuni at codespeak.net
Mon Oct 18 16:45:19 CEST 2010


Author: antocuni
Date: Mon Oct 18 16:45:16 2010
New Revision: 78047

Added:
   pypy/trunk/pypy/doc/config/objspace.usemodules._ffi.txt
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/doc/config/objspace.usemodules._ffi.txt
   pypy/trunk/pypy/jit/backend/llsupport/ffisupport.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/jit/backend/llsupport/ffisupport.py
   pypy/trunk/pypy/jit/backend/llsupport/test/test_ffisupport.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/jit/backend/llsupport/test/test_ffisupport.py
   pypy/trunk/pypy/jit/metainterp/optimizeopt/fficall.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/jit/metainterp/optimizeopt/fficall.py
   pypy/trunk/pypy/jit/metainterp/test/test_fficall.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/jit/metainterp/test/test_fficall.py
   pypy/trunk/pypy/jit/metainterp/test/test_optimizefficall.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/jit/metainterp/test/test_optimizefficall.py
   pypy/trunk/pypy/module/_ffi/
      - copied from r78044, pypy/branch/jitffi/pypy/module/_ffi/
   pypy/trunk/pypy/rlib/clibffi.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/rlib/clibffi.py
   pypy/trunk/pypy/rlib/libffi.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/rlib/libffi.py
   pypy/trunk/pypy/rlib/test/test_clibffi.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/rlib/test/test_clibffi.py
   pypy/trunk/pypy/rlib/test/test_libffi.py
      - copied unchanged from r78044, pypy/branch/jitffi/pypy/rlib/test/test_libffi.py
Modified:
   pypy/trunk/pypy/   (props changed)
   pypy/trunk/pypy/annotation/model.py
   pypy/trunk/pypy/annotation/test/test_model.py
   pypy/trunk/pypy/config/pypyoption.py
   pypy/trunk/pypy/jit/backend/llgraph/llimpl.py
   pypy/trunk/pypy/jit/backend/llgraph/runner.py
   pypy/trunk/pypy/jit/backend/llsupport/descr.py
   pypy/trunk/pypy/jit/backend/llsupport/llmodel.py
   pypy/trunk/pypy/jit/backend/test/runner_test.py
   pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py
   pypy/trunk/pypy/jit/backend/x86/test/test_ztranslation.py
   pypy/trunk/pypy/jit/codewriter/effectinfo.py
   pypy/trunk/pypy/jit/codewriter/jtransform.py
   pypy/trunk/pypy/jit/codewriter/support.py
   pypy/trunk/pypy/jit/codewriter/test/test_effectinfo.py
   pypy/trunk/pypy/jit/metainterp/executor.py
   pypy/trunk/pypy/jit/metainterp/optimize_nopspec.py   (props changed)
   pypy/trunk/pypy/jit/metainterp/optimizeopt/__init__.py
   pypy/trunk/pypy/jit/metainterp/optimizeopt/virtualize.py
   pypy/trunk/pypy/jit/metainterp/resoperation.py
   pypy/trunk/pypy/jit/metainterp/test/test_loop_nopspec.py   (props changed)
   pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/trunk/pypy/jit/metainterp/warmstate.py
   pypy/trunk/pypy/jit/tl/jittest.py   (props changed)
   pypy/trunk/pypy/jit/tl/pypyjit.py
   pypy/trunk/pypy/jit/tl/pypyjit_child.py
   pypy/trunk/pypy/module/_rawffi/__init__.py
   pypy/trunk/pypy/module/_rawffi/callback.py
   pypy/trunk/pypy/module/_rawffi/interp_rawffi.py
   pypy/trunk/pypy/module/_rawffi/structure.py
   pypy/trunk/pypy/module/_rawffi/test/test__rawffi.py
   pypy/trunk/pypy/module/pypyjit/policy.py
   pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py
   pypy/trunk/pypy/rlib/jit.py
   pypy/trunk/pypy/rlib/test/test_jit.py
   pypy/trunk/pypy/rlib/test/test_rdynload.py
   pypy/trunk/pypy/rpython/lltypesystem/lltype.py
   pypy/trunk/pypy/rpython/rpbc.py
   pypy/trunk/pypy/rpython/test/test_rclass.py
   pypy/trunk/pypy/translator/c/test/test_newgc.py
Log:
merge the jitffi branch: it provides a new jit-friendly rlib.libffi module,
and an app-level _ffi module which exposes it.



Modified: pypy/trunk/pypy/annotation/model.py
==============================================================================
--- pypy/trunk/pypy/annotation/model.py	(original)
+++ pypy/trunk/pypy/annotation/model.py	Mon Oct 18 16:45:16 2010
@@ -574,11 +574,11 @@
         
 NUMBER = object()
 annotation_to_ll_map = [
+    (SomeSingleFloat(), lltype.SingleFloat),
     (s_None, lltype.Void),   # also matches SomeImpossibleValue()
     (s_Bool, lltype.Bool),
     (SomeInteger(knowntype=r_ulonglong), NUMBER),    
     (SomeFloat(), lltype.Float),
-    (SomeSingleFloat(), lltype.SingleFloat),
     (SomeChar(), lltype.Char),
     (SomeUnicodeCodePoint(), lltype.UniChar),
     (SomeAddress(), llmemory.Address),

Modified: pypy/trunk/pypy/annotation/test/test_model.py
==============================================================================
--- pypy/trunk/pypy/annotation/test/test_model.py	(original)
+++ pypy/trunk/pypy/annotation/test/test_model.py	Mon Oct 18 16:45:16 2010
@@ -128,7 +128,7 @@
     assert isinstance(s_p, SomeOOInstance) and s_p.ootype == C
 
 def test_annotation_to_lltype():
-    from pypy.rlib.rarithmetic import r_uint
+    from pypy.rlib.rarithmetic import r_uint, r_singlefloat
     s_i = SomeInteger()
     s_pos = SomeInteger(nonneg=True)
     s_1 = SomeInteger(nonneg=True); s_1.const = 1
@@ -151,6 +151,9 @@
     C = ootype.Instance('C', ROOT, {})
     ref = SomeOOInstance(C)
     assert annotation_to_lltype(ref) == C
+    s_singlefloat = SomeSingleFloat()
+    s_singlefloat.const = r_singlefloat(0.0)
+    assert annotation_to_lltype(s_singlefloat) == lltype.SingleFloat
     
 def test_ll_union():
     PS1 = lltype.Ptr(lltype.GcStruct('s'))

Modified: pypy/trunk/pypy/config/pypyoption.py
==============================================================================
--- pypy/trunk/pypy/config/pypyoption.py	(original)
+++ pypy/trunk/pypy/config/pypyoption.py	Mon Oct 18 16:45:16 2010
@@ -73,9 +73,9 @@
     }
 
 module_import_dependencies = {
-    # no _rawffi if importing pypy.rlib.libffi raises ImportError
+    # no _rawffi if importing pypy.rlib.clibffi raises ImportError
     # or CompilationError
-    "_rawffi"   : ["pypy.rlib.libffi"],
+    "_rawffi"   : ["pypy.rlib.clibffi"],
 
     "zlib"      : ["pypy.rlib.rzlib"],
     "bz2"       : ["pypy.module.bz2.interp_bz2"],

Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py	Mon Oct 18 16:45:16 2010
@@ -10,7 +10,7 @@
                                          BoxInt, BoxPtr, BoxObj, BoxFloat,
                                          REF, INT, FLOAT)
 from pypy.jit.codewriter import heaptracker
-from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr
+from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.module.support import LLSupport, OOSupport
 from pypy.rpython.llinterp import LLException
@@ -305,12 +305,12 @@
     loop = _from_opaque(loop)
     loop.operations.append(Operation(opnum))
 
-def compile_add_descr(loop, ofs, type):
+def compile_add_descr(loop, ofs, type, arg_types):
     from pypy.jit.backend.llgraph.runner import Descr
     loop = _from_opaque(loop)
     op = loop.operations[-1]
     assert isinstance(type, str) and len(type) == 1
-    op.descr = Descr(ofs, type)
+    op.descr = Descr(ofs, type, arg_types=arg_types)
 
 def compile_add_loop_token(loop, descr):
     if we_are_translated():
@@ -801,7 +801,7 @@
             else:
                 raise TypeError(x)
         try:
-            return _do_call_common(func, args_in_order)
+            return _do_call_common(func, args_in_order, calldescr)
         except LLException, lle:
             _last_exception = lle
             d = {'v': None,
@@ -1018,6 +1018,9 @@
     if isinstance(TYPE, lltype.Ptr):
         if isinstance(x, (int, long, llmemory.AddressAsInt)):
             x = llmemory.cast_int_to_adr(x)
+        if TYPE is rffi.VOIDP:
+            # assume that we want a "C-style" cast, without typechecking the value
+            return rffi.cast(TYPE, x)
         return llmemory.cast_adr_to_ptr(x, TYPE)
     elif TYPE == llmemory.Address:
         if isinstance(x, (int, long, llmemory.AddressAsInt)):
@@ -1411,10 +1414,26 @@
 def do_call_pushfloat(x):
     _call_args_f.append(x)
 
-def _do_call_common(f, args_in_order=None):
+kind2TYPE = {
+    'i': lltype.Signed,
+    'f': lltype.Float,
+    'v': lltype.Void,
+    }
+
+def _do_call_common(f, args_in_order=None, calldescr=None):
     ptr = llmemory.cast_int_to_adr(f).ptr
-    FUNC = lltype.typeOf(ptr).TO
-    ARGS = FUNC.ARGS
+    PTR = lltype.typeOf(ptr)
+    if PTR == rffi.VOIDP:
+        # it's a pointer to a C function, so we don't have a precise
+        # signature: create one from the descr
+        ARGS = map(kind2TYPE.get, calldescr.arg_types)
+        RESULT = kind2TYPE[calldescr.typeinfo]
+        FUNC = lltype.FuncType(ARGS, RESULT)
+        func_to_call = rffi.cast(lltype.Ptr(FUNC), ptr)
+    else:
+        FUNC = PTR.TO
+        ARGS = FUNC.ARGS
+        func_to_call = ptr._obj._callable
     args = cast_call_args(ARGS, _call_args_i, _call_args_r, _call_args_f,
                           args_in_order)
     del _call_args_i[:]
@@ -1426,7 +1445,7 @@
         result = llinterp.eval_graph(ptr._obj.graph, args)
         # ^^^ may raise, in which case we get an LLException
     else:
-        result = ptr._obj._callable(*args)
+        result = func_to_call(*args)
     return result
 
 def do_call_void(f):

Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/trunk/pypy/jit/backend/llgraph/runner.py	Mon Oct 18 16:45:16 2010
@@ -154,7 +154,7 @@
             llimpl.compile_add(c, op.getopnum())
             descr = op.getdescr()
             if isinstance(descr, Descr):
-                llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo)
+                llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo, descr.arg_types)
             if isinstance(descr, history.LoopToken) and op.getopnum() != rop.JUMP:
                 llimpl.compile_add_loop_token(c, descr)
             if self.is_oo and isinstance(descr, (OODescr, MethDescr)):
@@ -297,6 +297,18 @@
         return self.getdescr(0, token[0], extrainfo=extrainfo,
                              arg_types=''.join(arg_types))
 
+    def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo=None):
+        from pypy.jit.backend.llsupport.ffisupport import get_ffi_type_kind
+        arg_types = []
+        for arg in ffi_args:
+            kind = get_ffi_type_kind(arg)
+            if kind != history.VOID:
+                arg_types.append(kind)
+        reskind = get_ffi_type_kind(ffi_result)
+        return self.getdescr(0, reskind, extrainfo=extrainfo,
+                             arg_types=''.join(arg_types))
+
+
     def grab_exc_value(self):
         return llimpl.grab_exc_value()
 

Modified: pypy/trunk/pypy/jit/backend/llsupport/descr.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llsupport/descr.py	(original)
+++ pypy/trunk/pypy/jit/backend/llsupport/descr.py	Mon Oct 18 16:45:16 2010
@@ -307,6 +307,21 @@
     _return_type = history.INT
     call_stub = staticmethod(lambda func, args_i, args_r, args_f: 0)
 
+class DynamicIntCallDescr(BaseIntCallDescr):
+    """
+    calldescr that works for every integer type, by explicitly passing it the
+    size of the result. Used only by get_call_descr_dynamic
+    """
+    _clsname = 'DynamicIntCallDescr'
+
+    def __init__(self, arg_classes, result_size, extrainfo=None):
+        BaseIntCallDescr.__init__(self, arg_classes, extrainfo)
+        self._result_size = result_size
+
+    def get_result_size(self, translate_support_code):
+        return self._result_size
+
+
 class NonGcPtrCallDescr(BaseIntCallDescr):
     _clsname = 'NonGcPtrCallDescr'
     def get_result_size(self, translate_support_code):

Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llsupport/llmodel.py	(original)
+++ pypy/trunk/pypy/jit/backend/llsupport/llmodel.py	Mon Oct 18 16:45:16 2010
@@ -17,6 +17,7 @@
 from pypy.jit.backend.llsupport.descr import get_call_descr
 from pypy.jit.backend.llsupport.descr import BaseIntCallDescr, GcPtrCallDescr
 from pypy.jit.backend.llsupport.descr import FloatCallDescr, VoidCallDescr
+from pypy.jit.backend.llsupport.ffisupport import get_call_descr_dynamic
 from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
 
 
@@ -231,6 +232,9 @@
     def calldescrof(self, FUNC, ARGS, RESULT, extrainfo=None):
         return get_call_descr(self.gc_ll_descr, ARGS, RESULT, extrainfo)
 
+    def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo=None):
+        return get_call_descr_dynamic(ffi_args, ffi_result, extrainfo)
+
     def get_overflow_error(self):
         ovf_vtable = self.cast_adr_to_int(self._ovf_error_vtable)
         ovf_inst = lltype.cast_opaque_ptr(llmemory.GCREF,

Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/trunk/pypy/jit/backend/test/runner_test.py	Mon Oct 18 16:45:16 2010
@@ -421,6 +421,7 @@
             assert x == 3.5 - 42
 
     def test_call(self):
+        from pypy.rlib.libffi import types
 
         def func_int(a, b):
             return a + b
@@ -428,23 +429,31 @@
             return chr(ord(c) + ord(c1))
 
         functions = [
-            (func_int, lltype.Signed, 655360),
-            (func_int, rffi.SHORT, 1213),
-            (func_char, lltype.Char, 12)
+            (func_int, lltype.Signed, types.sint, 655360),
+            (func_int, rffi.SHORT, types.sint16, 1213),
+            (func_char, lltype.Char, types.uchar, 12)
             ]
 
-        for func, TP, num in functions:
+        for func, TP, ffi_type, num in functions:
             cpu = self.cpu
             #
             FPTR = self.Ptr(self.FuncType([TP, TP], TP))
             func_ptr = llhelper(FPTR, func)
             FUNC = deref(FPTR)
-            calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
             funcbox = self.get_funcbox(cpu, func_ptr)
+            # first, try it with the "normal" calldescr
+            calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
             res = self.execute_operation(rop.CALL,
                                          [funcbox, BoxInt(num), BoxInt(num)],
                                          'int', descr=calldescr)
             assert res.value == 2 * num
+            # then, try it with the dynamic calldescr
+            dyn_calldescr = cpu.calldescrof_dynamic([ffi_type, ffi_type], ffi_type)
+            res = self.execute_operation(rop.CALL,
+                                         [funcbox, BoxInt(num), BoxInt(num)],
+                                         'int', descr=dyn_calldescr)
+            assert res.value == 2 * num
+            
 
         if cpu.supports_floats:
             def func(f0, f1, f2, f3, f4, f5, f6, i0, i1, f7, f8, f9):
@@ -507,6 +516,23 @@
                                          'int', descr=calldescr)
             assert res.value == func_ints(*args)
 
+    def test_call_to_c_function(self):
+        from pypy.rlib.libffi import CDLL, types, ArgChain
+        libc = CDLL('libc.so.6')
+        c_tolower = libc.getpointer('tolower', [types.uchar], types.sint)
+        argchain = ArgChain().arg(ord('A'))
+        assert c_tolower.call(argchain, rffi.INT) == ord('a')
+
+        func_adr = llmemory.cast_ptr_to_adr(c_tolower.funcsym)
+        funcbox = ConstInt(heaptracker.adr2int(func_adr))
+        calldescr = self.cpu.calldescrof_dynamic([types.uchar], types.sint)
+        res = self.execute_operation(rop.CALL,
+                                     [funcbox, BoxInt(ord('A'))],
+                                     'int',
+                                     descr=calldescr)
+        assert res.value == ord('a')
+
+
     def test_field_basic(self):
         t_box, T_box = self.alloc_instance(self.T)
         fielddescr = self.cpu.fielddescrof(self.S, 'value')

Modified: pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py	Mon Oct 18 16:45:16 2010
@@ -191,6 +191,33 @@
     def run_orig(self, name, n, x):
         self.main_allfuncs(name, n, x)
 
+    def define_libffi_workaround(cls):
+        # XXX: this is a workaround for a bug in database.py.  It seems that
+        # the problem is triggered by optimizeopt/fficall.py, and in
+        # particular by the ``cast_base_ptr_to_instance(Func, llfunc)``: in
+        # these tests, that line is the only place where libffi.Func is
+        # referenced.
+        #
+        # The problem occurs because the gctransformer tries to annotate a
+        # low-level helper to call the __del__ of libffi.Func when it's too
+        # late.
+        #
+        # This workaround works by forcing the annotator (and all the rest of
+        # the toolchain) to see libffi.Func in a "proper" context, not just as
+        # the target of cast_base_ptr_to_instance.  Note that the function
+        # below is *never* called by any actual test, it's just annotated.
+        #
+        from pypy.rlib.libffi import get_libc_name, CDLL, types, ArgChain
+        libc_name = get_libc_name()
+        def f(n, x, *args):
+            libc = CDLL(libc_name)
+            ptr = libc.getpointer('labs', [types.slong], types.slong)
+            chain = ArgChain()
+            chain.arg(n)
+            n = ptr.call(chain, lltype.Signed)
+            return (n, x) + args
+        return None, f, None
+
     def define_compile_framework_1(cls):
         # a moving GC.  Supports malloc_varsize_nonmovable.  Simple test, works
         # without write_barriers and root stack enumeration.

Modified: pypy/trunk/pypy/jit/backend/x86/test/test_ztranslation.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_ztranslation.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_ztranslation.py	Mon Oct 18 16:45:16 2010
@@ -1,4 +1,4 @@
-import py, os
+import py, os, sys
 from pypy.tool.udir import udir
 from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL, unroll_parameters
 from pypy.rlib.jit import PARAMETERS, dont_look_inside
@@ -63,8 +63,32 @@
                 if k - abs(j):  raise ValueError
                 if k - abs(-j): raise ValueError
             return total * 10
+        #
+        from pypy.rpython.lltypesystem import lltype, rffi
+        from pypy.rlib.libffi import types, CDLL, ArgChain
+        from pypy.rlib.test.test_libffi import get_libm_name
+        libm_name = get_libm_name(sys.platform)
+        jitdriver2 = JitDriver(greens=[], reds = ['i', 'func', 'res', 'x'])
+        def libffi_stuff(i, j):
+            lib = CDLL(libm_name)
+            func = lib.getpointer('fabs', [types.double], types.double)
+            res = 0.0
+            x = float(j)
+            while i > 0:
+                jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x)
+                jitdriver2.can_enter_jit(i=i, res=res, func=func, x=x)
+                func = hint(func, promote=True)
+                argchain = ArgChain()
+                argchain.arg(x)
+                res = func.call(argchain, rffi.DOUBLE)
+                i -= 1
+            return res
+        #
+        def main(i, j):
+            return f(i, j) + libffi_stuff(i, j)
+        expected = f(40, -49)
         res = self.meta_interp(f, [40, -49])
-        assert res == f(40, -49)
+        assert res == expected
 
     def test_direct_assembler_call_translates(self):
         class Thing(object):

Modified: pypy/trunk/pypy/jit/codewriter/effectinfo.py
==============================================================================
--- pypy/trunk/pypy/jit/codewriter/effectinfo.py	(original)
+++ pypy/trunk/pypy/jit/codewriter/effectinfo.py	Mon Oct 18 16:45:16 2010
@@ -19,7 +19,7 @@
     OS_NONE                     = 0    # normal case, no oopspec
     OS_ARRAYCOPY                = 1    # "list.ll_arraycopy"
     OS_STR2UNICODE              = 2    # "str.str2unicode"
-
+    #
     OS_STR_CONCAT               = 22   # "stroruni.concat"
     OS_STR_SLICE                = 23   # "stroruni.slice"
     OS_STR_EQUAL                = 24   # "stroruni.equal"
@@ -30,7 +30,7 @@
     OS_STREQ_NONNULL_CHAR       = 29   # s1 == char  (assert s1!=NULL)
     OS_STREQ_CHECKNULL_CHAR     = 30   # s1!=NULL and s1==char
     OS_STREQ_LENGTHOK           = 31   # s1 == s2    (assert len(s1)==len(s2))
-
+    #
     OS_UNI_CONCAT               = 42   #
     OS_UNI_SLICE                = 43   #
     OS_UNI_EQUAL                = 44   #
@@ -42,6 +42,10 @@
     OS_UNIEQ_CHECKNULL_CHAR     = 50   #   STR, in the same order)
     OS_UNIEQ_LENGTHOK           = 51   #
     _OS_offset_uni              = OS_UNI_CONCAT - OS_STR_CONCAT
+    #
+    OS_LIBFFI_PREPARE           = 60
+    OS_LIBFFI_PUSH_ARG          = 61
+    OS_LIBFFI_CALL              = 62
 
     def __new__(cls, readonly_descrs_fields,
                 write_descrs_fields, write_descrs_arrays,

Modified: pypy/trunk/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/trunk/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/trunk/pypy/jit/codewriter/jtransform.py	Mon Oct 18 16:45:16 2010
@@ -320,6 +320,8 @@
             prepare = self._handle_str2unicode_call
         elif oopspec_name.startswith('virtual_ref'):
             prepare = self._handle_virtual_ref_call
+        elif oopspec_name.startswith('libffi_'):
+            prepare = self._handle_libffi_call
         else:
             prepare = self.prepare_builtin_call
         try:
@@ -1030,8 +1032,10 @@
     # ----------
     # Strings and Unicodes.
 
-    def _handle_oopspec_call(self, op, args, oopspecindex):
+    def _handle_oopspec_call(self, op, args, oopspecindex, extraeffect=None):
         calldescr = self.callcontrol.getcalldescr(op, oopspecindex)
+        if extraeffect:
+            calldescr.get_extra_info().extraeffect = extraeffect
         if isinstance(op.args[0].value, str):
             pass  # for tests only
         else:
@@ -1132,6 +1136,23 @@
                                           vrefinfo.JIT_VIRTUAL_REF)
         return SpaceOperation(oopspec_name, list(args), op.result)
 
+    # -----------
+    # rlib.libffi
+
+    def _handle_libffi_call(self, op, oopspec_name, args):
+        if oopspec_name == 'libffi_prepare_call':
+            oopspecindex = EffectInfo.OS_LIBFFI_PREPARE
+            extraeffect = EffectInfo.EF_CANNOT_RAISE
+        elif oopspec_name.startswith('libffi_push_'):
+            oopspecindex = EffectInfo.OS_LIBFFI_PUSH_ARG
+            extraeffect = EffectInfo.EF_CANNOT_RAISE
+        elif oopspec_name.startswith('libffi_call_'):
+            oopspecindex = EffectInfo.OS_LIBFFI_CALL
+            extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
+        else:
+            assert False, 'unsupported oopspec: %s' % oopspec_name
+        return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)
+
     def rewrite_op_jit_force_virtual(self, op):
         return self._do_builtin_call(op)
 

Modified: pypy/trunk/pypy/jit/codewriter/support.py
==============================================================================
--- pypy/trunk/pypy/jit/codewriter/support.py	(original)
+++ pypy/trunk/pypy/jit/codewriter/support.py	Mon Oct 18 16:45:16 2010
@@ -1,5 +1,5 @@
 import sys
-from pypy.rpython.lltypesystem import lltype, rclass
+from pypy.rpython.lltypesystem import lltype, rclass, rffi
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython import rlist
 from pypy.rpython.lltypesystem import rstr as ll_rstr, rdict as ll_rdict
@@ -8,6 +8,7 @@
 from pypy.rpython.ootypesystem import rdict as oo_rdict
 from pypy.rpython.llinterp import LLInterpreter
 from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
 from pypy.translator.simplify import get_funcobj
 from pypy.translator.unsimplify import split_block
 from pypy.objspace.flow.model import Constant
@@ -217,6 +218,33 @@
     else:
         return x
 
+
+# libffi support
+# --------------
+
+def func(llfunc):
+    from pypy.rlib.libffi import Func
+    return cast_base_ptr_to_instance(Func, llfunc)
+
+def _ll_1_libffi_prepare_call(llfunc):
+    return func(llfunc)._prepare()
+
+def _ll_4_libffi_push_int(llfunc, value, ll_args, i):
+    return func(llfunc)._push_int(value, ll_args, i)
+
+def _ll_4_libffi_push_float(llfunc, value, ll_args, i):
+    return func(llfunc)._push_float(value, ll_args, i)
+
+def _ll_3_libffi_call_int(llfunc, funcsym, ll_args):
+    return func(llfunc)._do_call(funcsym, ll_args, rffi.LONG)
+
+def _ll_3_libffi_call_float(llfunc, funcsym, ll_args):
+    return func(llfunc)._do_call(funcsym, ll_args, rffi.DOUBLE)
+
+def _ll_3_libffi_call_void(llfunc, funcsym, ll_args):
+    return func(llfunc)._do_call(funcsym, ll_args, lltype.Void)
+
+
 # in the following calls to builtins, the JIT is allowed to look inside:
 inline_calls_to = [
     ('int_floordiv_ovf_zer', [lltype.Signed, lltype.Signed], lltype.Signed),

Modified: pypy/trunk/pypy/jit/codewriter/test/test_effectinfo.py
==============================================================================
--- pypy/trunk/pypy/jit/codewriter/test/test_effectinfo.py	(original)
+++ pypy/trunk/pypy/jit/codewriter/test/test_effectinfo.py	Mon Oct 18 16:45:16 2010
@@ -1,7 +1,8 @@
 from pypy.rpython.lltypesystem.rclass import OBJECT
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.ootypesystem import ootype
-from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze
+from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze,\
+    EffectInfo
 
 class FakeCPU:
     def fielddescrof(self, T, fieldname):
@@ -9,6 +10,14 @@
     def arraydescrof(self, A):
         return ('arraydescr', A)
 
+def test_no_oopspec_duplicate():
+    # check that all the various EffectInfo.OS_* have unique values
+    oopspecs = set()
+    for name, value in EffectInfo.__dict__.iteritems():
+        if name.startswith('OS_'):
+            assert value not in oopspecs
+            oopspecs.add(value)
+
 def test_include_read_field():
     S = lltype.GcStruct("S", ("a", lltype.Signed))
     effects = frozenset([("readstruct", lltype.Ptr(S), "a")])

Modified: pypy/trunk/pypy/jit/metainterp/executor.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/executor.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/executor.py	Mon Oct 18 16:45:16 2010
@@ -80,6 +80,9 @@
 do_call_loopinvariant = do_call
 do_call_may_force = do_call
 
+def do_call_c(cpu, metainterp, argboxes, descr):
+    raise NotImplementedError("Should never be called directly")
+
 def do_getarrayitem_gc(cpu, _, arraybox, indexbox, arraydescr):
     array = arraybox.getref_base()
     index = indexbox.getint()

Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt/__init__.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/optimizeopt/__init__.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/optimizeopt/__init__.py	Mon Oct 18 16:45:16 2010
@@ -3,6 +3,7 @@
 from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds
 from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize
 from pypy.jit.metainterp.optimizeopt.heap import OptHeap
+from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall
 from pypy.jit.metainterp.optimizeopt.string import OptString
 
 def optimize_loop_1(metainterp_sd, loop, virtuals=True):
@@ -16,6 +17,7 @@
                      OptVirtualize(),
                      OptString(),
                      OptHeap(),
+                     OptFfiCall(),
                     ]
     optimizer = Optimizer(metainterp_sd, loop, optimizations, virtuals)
     optimizer.propagate_all_forward()

Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt/virtualize.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/optimizeopt/virtualize.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/optimizeopt/virtualize.py	Mon Oct 18 16:45:16 2010
@@ -134,6 +134,11 @@
         fielddescrs = self._get_field_descr_list()
         return modifier.make_virtual(self.known_class, fielddescrs)
 
+    def __repr__(self):
+        cls_name = self.known_class.value.adr.ptr._obj._TYPE._name
+        field_names = [field.name for field in self._fields]
+        return "<VirtualValue cls=%s fields=%s>" % (cls_name, field_names)
+
 class VStructValue(AbstractVirtualStructValue):
 
     def __init__(self, optimizer, structdescr, keybox, source_op=None):

Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/resoperation.py	Mon Oct 18 16:45:16 2010
@@ -463,7 +463,7 @@
 
     '_CANRAISE_FIRST', # ----- start of can_raise operations -----
     'CALL/*d',
-    'CALL_ASSEMBLER/*d',
+    'CALL_ASSEMBLER/*d',  # call already compiled assembler
     'CALL_MAY_FORCE/*d',
     'CALL_LOOPINVARIANT/*d',
     #'OOSEND',                     # ootype operation

Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py	Mon Oct 18 16:45:16 2010
@@ -132,14 +132,21 @@
 # ____________________________________________________________
 
 def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}):
-    print '-'*20, 'Comparing lists', '-'*20
+    # try to use the full width of the terminal to display the list
+    # unfortunately, does not work with the default capture method of py.test
+    # (which is fd), you you need to use either -s or --capture=sys, else you
+    # get the standard 80 columns width
+    totwidth = py.io.get_terminal_width()
+    width = totwidth / 2 - 1
+    print ' Comparing lists '.center(totwidth, '-')
+    print '%s| %s' % ('optimized'.center(width), 'expected'.center(width))
     for op1, op2 in zip(oplist1, oplist2):
         txt1 = str(op1)
         txt2 = str(op2)
         while txt1 or txt2:
-            print '%-39s| %s' % (txt1[:39], txt2[:39])
-            txt1 = txt1[39:]
-            txt2 = txt2[39:]
+            print '%s| %s' % (txt1[:width].ljust(width), txt2[:width])
+            txt1 = txt1[width:]
+            txt2 = txt2[width:]
         assert op1.getopnum() == op2.getopnum()
         assert op1.numargs() == op2.numargs()
         for i in range(op1.numargs()):
@@ -262,6 +269,10 @@
         expected = self.parse(optops)
         print '\n'.join([str(o) for o in loop.operations])
         self.assert_equal(loop, expected)
+        return loop
+
+
+class OptimizeOptTest(BaseTestOptimizeOpt):
 
     def test_simple(self):
         ops = """
@@ -2643,7 +2654,7 @@
             ''', rop.GUARD_TRUE)
 
 
-class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin):
+class TestLLtype(OptimizeOptTest, LLtypeMixin):
 
     def test_residual_call_does_not_invalidate_caches(self):
         ops = """
@@ -4533,7 +4544,7 @@
         # can be raised by ll_str2unicode()
 
 
-##class TestOOtype(BaseTestOptimizeOpt, OOtypeMixin):
+##class TestOOtype(OptimizeOptTest, OOtypeMixin):
 
 ##    def test_instanceof(self):
 ##        ops = """

Modified: pypy/trunk/pypy/jit/metainterp/warmstate.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/warmstate.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/warmstate.py	Mon Oct 18 16:45:16 2010
@@ -1,5 +1,5 @@
 import sys
-from pypy.rpython.lltypesystem import lltype, llmemory, rstr
+from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance
 from pypy.rpython.annlowlevel import cast_object_to_ptr
@@ -24,7 +24,11 @@
     """
     INPUT = lltype.typeOf(x)
     if INPUT is lltype.Signed:
-        return lltype.cast_primitive(TYPE, x)    # XXX missing: Ptr(non-gc)
+        if isinstance(TYPE, lltype.Ptr) and TYPE.TO._gckind == 'raw':
+            # non-gc pointer
+            return rffi.cast(TYPE, x)
+        else:
+            return lltype.cast_primitive(TYPE, x)
     elif INPUT is lltype.Float:
         assert TYPE is lltype.Float
         return x

Modified: pypy/trunk/pypy/jit/tl/pypyjit.py
==============================================================================
--- pypy/trunk/pypy/jit/tl/pypyjit.py	(original)
+++ pypy/trunk/pypy/jit/tl/pypyjit.py	Mon Oct 18 16:45:16 2010
@@ -40,6 +40,9 @@
 config.objspace.usemodules.array = True
 config.objspace.usemodules._weakref = False
 config.objspace.usemodules._sre = False
+#
+config.objspace.usemodules._ffi = True
+#
 set_pypy_opt_level(config, level='jit')
 config.objspace.std.withinlineddict = True
 

Modified: pypy/trunk/pypy/jit/tl/pypyjit_child.py
==============================================================================
--- pypy/trunk/pypy/jit/tl/pypyjit_child.py	(original)
+++ pypy/trunk/pypy/jit/tl/pypyjit_child.py	Mon Oct 18 16:45:16 2010
@@ -16,7 +16,7 @@
     interp.heap.malloc_nonmovable = returns_null     # XXX
 
     from pypy.jit.backend.llgraph.runner import LLtypeCPU
-    LLtypeCPU.supports_floats = False    # for now
+    #LLtypeCPU.supports_floats = False    # for now
     apply_jit(interp, graph, LLtypeCPU)
 
 

Modified: pypy/trunk/pypy/module/_rawffi/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/_rawffi/__init__.py	(original)
+++ pypy/trunk/pypy/module/_rawffi/__init__.py	Mon Oct 18 16:45:16 2010
@@ -1,5 +1,5 @@
 
-""" Low-level interface to libffi
+""" Low-level interface to clibffi
 """
 
 from pypy.interpreter.mixedmodule import MixedModule
@@ -39,11 +39,11 @@
         if hasattr(interp_rawffi, 'check_HRESULT'):
             Module.interpleveldefs['check_HRESULT'] = 'interp_rawffi.check_HRESULT'
 
-        from pypy.rlib import libffi
+        from pypy.rlib import clibffi
         for name in ['FUNCFLAG_STDCALL', 'FUNCFLAG_CDECL', 'FUNCFLAG_PYTHONAPI',
                      ]:
-            if hasattr(libffi, name):
-                Module.interpleveldefs[name] = "space.wrap(%r)" % getattr(libffi, name)
+            if hasattr(clibffi, name):
+                Module.interpleveldefs[name] = "space.wrap(%r)" % getattr(clibffi, name)
                 
         super(Module, cls).buildloaders()
     buildloaders = classmethod(buildloaders)

Modified: pypy/trunk/pypy/module/_rawffi/callback.py
==============================================================================
--- pypy/trunk/pypy/module/_rawffi/callback.py	(original)
+++ pypy/trunk/pypy/module/_rawffi/callback.py	Mon Oct 18 16:45:16 2010
@@ -8,8 +8,8 @@
 from pypy.module._rawffi.array import get_elem, push_elem
 from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \
      wrap_value, unwrap_value, unwrap_truncate_int
-from pypy.rlib.libffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL
-from pypy.rlib.libffi import ffi_type_void
+from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL
+from pypy.rlib.clibffi import ffi_type_void
 from pypy.module._rawffi.tracker import tracker
 from pypy.interpreter.error import OperationError
 from pypy.interpreter import gateway

Modified: pypy/trunk/pypy/module/_rawffi/interp_rawffi.py
==============================================================================
--- pypy/trunk/pypy/module/_rawffi/interp_rawffi.py	(original)
+++ pypy/trunk/pypy/module/_rawffi/interp_rawffi.py	Mon Oct 18 16:45:16 2010
@@ -5,7 +5,7 @@
 from pypy.interpreter.gateway import interp2app, NoneNotWrapped
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 
-from pypy.rlib.libffi import *
+from pypy.rlib.clibffi import *
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rlib.unroll import unrolling_iterable
 

Modified: pypy/trunk/pypy/module/_rawffi/structure.py
==============================================================================
--- pypy/trunk/pypy/module/_rawffi/structure.py	(original)
+++ pypy/trunk/pypy/module/_rawffi/structure.py	Mon Oct 18 16:45:16 2010
@@ -15,7 +15,7 @@
 from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value
 from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length
 from pypy.module._rawffi.interp_rawffi import size_alignment
-from pypy.rlib import libffi
+from pypy.rlib import clibffi
 from pypy.rlib.rarithmetic import intmask, r_uint
 
 def unpack_fields(space, w_fields):
@@ -104,14 +104,14 @@
     descr_fieldoffset.unwrap_spec = ['self', ObjSpace, str]
 
     # get the corresponding ffi_type
-    ffi_struct = lltype.nullptr(libffi.FFI_STRUCT_P.TO)
+    ffi_struct = lltype.nullptr(clibffi.FFI_STRUCT_P.TO)
 
     def get_basic_ffi_type(self):
         if not self.ffi_struct:
             # Repeated fields are delicate.  Consider for example
             #     struct { int a[5]; }
             # or  struct { struct {int x;} a[5]; }
-            # Seeing no corresponding doc in libffi, let's just repeat
+            # Seeing no corresponding doc in clibffi, let's just repeat
             # the field 5 times...
             fieldtypes = []
             for name, tp in self.fields:
@@ -122,7 +122,7 @@
                 while count + basic_size <= total_size:
                     fieldtypes.append(basic_ffi_type)
                     count += basic_size
-            self.ffi_struct = libffi.make_struct_ffitype_e(self.size,
+            self.ffi_struct = clibffi.make_struct_ffitype_e(self.size,
                                                            self.alignment,
                                                            fieldtypes)
         return self.ffi_struct.ffistruct

Modified: pypy/trunk/pypy/module/_rawffi/test/test__rawffi.py
==============================================================================
--- pypy/trunk/pypy/module/_rawffi/test/test__rawffi.py	(original)
+++ pypy/trunk/pypy/module/_rawffi/test/test__rawffi.py	Mon Oct 18 16:45:16 2010
@@ -191,7 +191,7 @@
     prepare_c_example = staticmethod(prepare_c_example)
     
     def setup_class(cls):
-        from pypy.rlib.libffi import get_libc_name
+        from pypy.rlib.clibffi import get_libc_name
         space = gettestobjspace(usemodules=('_rawffi', 'struct'))
         cls.space = space
         cls.w_lib_name = space.wrap(cls.prepare_c_example())

Modified: pypy/trunk/pypy/module/pypyjit/policy.py
==============================================================================
--- pypy/trunk/pypy/module/pypyjit/policy.py	(original)
+++ pypy/trunk/pypy/module/pypyjit/policy.py	Mon Oct 18 16:45:16 2010
@@ -11,7 +11,7 @@
         if '.' in modname:
             modname, _ = modname.split('.', 1)
         if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions',
-                       'imp', 'sys', 'array']:
+                       'imp', 'sys', 'array', '_ffi']:
             return True
         return False
 

Modified: pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py	(original)
+++ pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py	Mon Oct 18 16:45:16 2010
@@ -79,8 +79,11 @@
 
 
 class PyPyCJITTests(object):
-    def run_source(self, source, expected_max_ops, *testcases):
+    def run_source(self, source, expected_max_ops, *testcases, **kwds):
         assert isinstance(expected_max_ops, int)
+        threshold = kwds.pop('threshold', 3)
+        if kwds:
+            raise TypeError, 'Unsupported keyword arguments: %s' % kwds.keys()
         source = py.code.Source(source)
         filepath = self.tmpdir.join('case%d.py' % self.counter)
         logfilepath = filepath.new(ext='.log')
@@ -92,7 +95,7 @@
             import sys
             try: # make the file runnable by CPython
                 import pypyjit
-                pypyjit.set_param(threshold=3)
+                pypyjit.set_param(threshold=%d)
             except ImportError:
                 pass
 
@@ -102,7 +105,7 @@
                 print >> sys.stderr, 'got:', repr(result)
                 assert result == expected
                 assert type(result) is type(expected)
-        """)
+        """ % threshold)
         for testcase in testcases * 2:
             print >> f, "check(%r, %r)" % testcase
         print >> f, "print 'OK :-)'"
@@ -123,6 +126,7 @@
         if self.total_ops > expected_max_ops:
             assert 0, "too many operations: got %d, expected maximum %d" % (
                 self.total_ops, expected_max_ops)
+        return result
 
     def parse_loops(self, opslogfile):
         from pypy.jit.metainterp.test.oparser import parse
@@ -1134,6 +1138,39 @@
             return sa
         ''', 88, ([], 1997001))
 
+    def test__ffi_call(self):
+        from pypy.rlib.test.test_libffi import get_libm_name
+        libm_name = get_libm_name(sys.platform)
+        out = self.run_source('''
+        def main():
+            from _ffi import CDLL, types
+            libm = CDLL('%(libm_name)s')
+            pow = libm.getfunc('pow', [types.double, types.double],
+                               types.double)
+            print pow.getaddr()
+            i = 0
+            res = 0
+            while i < 2000:
+                res += pow(2, 3)
+                i += 1
+            return res
+        ''' % locals(),
+                              76, ([], 8.0*2000), threshold=1000)
+        pow_addr = int(out.splitlines()[0])
+        ops = self.get_by_bytecode('CALL_FUNCTION')
+        assert len(ops) == 2 # we get two loops, because of specialization
+        call_function = ops[0]
+        last_ops = [op.getopname() for op in call_function[-5:]]
+        assert last_ops == ['force_token',
+                            'setfield_gc',
+                            'call_may_force',
+                            'guard_not_forced',
+                            'guard_no_exception']
+        call = call_function[-3]
+        assert call.getarg(0).value == pow_addr
+        assert call.getarg(1).value == 2.0
+        assert call.getarg(2).value == 3.0
+
     # test_circular
 
 class AppTestJIT(PyPyCJITTests):

Modified: pypy/trunk/pypy/rlib/jit.py
==============================================================================
--- pypy/trunk/pypy/rlib/jit.py	(original)
+++ pypy/trunk/pypy/rlib/jit.py	Mon Oct 18 16:45:16 2010
@@ -77,6 +77,12 @@
         return result
     return decorator
 
+def oopspec(spec):
+    def decorator(func):
+        func.oopspec = spec
+        return func
+    return decorator
+
 class Entry(ExtRegistryEntry):
     _about_ = hint
 

Modified: pypy/trunk/pypy/rlib/test/test_jit.py
==============================================================================
--- pypy/trunk/pypy/rlib/test/test_jit.py	(original)
+++ pypy/trunk/pypy/rlib/test/test_jit.py	Mon Oct 18 16:45:16 2010
@@ -1,10 +1,16 @@
 import py
 from pypy.rlib.jit import hint, we_are_jitted, JitDriver, purefunction_promote
-from pypy.rlib.jit import JitHintError
+from pypy.rlib.jit import JitHintError, oopspec
 from pypy.translator.translator import TranslationContext, graphof
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
 from pypy.rpython.lltypesystem import lltype
 
+def test_oopspec():
+    @oopspec('foobar')
+    def fn():
+        pass
+    assert fn.oopspec == 'foobar'
+    
 class BaseTestJIT(BaseRtypingTest):
     def test_hint(self):
         def f():

Modified: pypy/trunk/pypy/rlib/test/test_rdynload.py
==============================================================================
--- pypy/trunk/pypy/rlib/test/test_rdynload.py	(original)
+++ pypy/trunk/pypy/rlib/test/test_rdynload.py	Mon Oct 18 16:45:16 2010
@@ -1,5 +1,5 @@
 from pypy.rlib.rdynload import *
-from pypy.rlib.libffi import get_libc_name
+from pypy.rlib.clibffi import get_libc_name
 from pypy.rpython.lltypesystem import rffi, lltype
 import py
 

Modified: pypy/trunk/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/lltype.py	Mon Oct 18 16:45:16 2010
@@ -794,6 +794,8 @@
             return llmemory.cast_adr_to_ptr(value, TGT)
     elif TGT == llmemory.Address and isinstance(ORIG, Ptr):
         return llmemory.cast_ptr_to_adr(value)
+    elif TGT == Signed and isinstance(ORIG, Ptr) and ORIG.TO._gckind == 'raw':
+        return llmemory.cast_adr_to_int(llmemory.cast_ptr_to_adr(value), 'symbolic')
     raise TypeError("don't know how to cast from %r to %r" % (ORIG, TGT))
 
 

Modified: pypy/trunk/pypy/rpython/rpbc.py
==============================================================================
--- pypy/trunk/pypy/rpython/rpbc.py	(original)
+++ pypy/trunk/pypy/rpython/rpbc.py	Mon Oct 18 16:45:16 2010
@@ -256,6 +256,8 @@
     def convert_const(self, value):
         if isinstance(value, types.MethodType) and value.im_self is None:
             value = value.im_func   # unbound method -> bare function
+        elif isinstance(value, staticmethod):
+            value = value.__get__(42) # hackish, get the function wrapped by staticmethod
         if self.lowleveltype is Void:
             return None
         if value is None:

Modified: pypy/trunk/pypy/rpython/test/test_rclass.py
==============================================================================
--- pypy/trunk/pypy/rpython/test/test_rclass.py	(original)
+++ pypy/trunk/pypy/rpython/test/test_rclass.py	Mon Oct 18 16:45:16 2010
@@ -319,6 +319,17 @@
         res = self.interpret(f, [])
         assert res == 42
 
+    def test_staticmethod2(self):
+        class A(object):
+            f = staticmethod(lambda x, y: x*y)
+        class B(A):
+            f = staticmethod(lambda x, y: x+y)
+        def f():
+            b = B()
+            return b.f(6, 7)
+        res = self.interpret(f, [])
+        assert res == 13
+
     def test_is(self):
         class A: pass
         class B(A): pass

Modified: pypy/trunk/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/trunk/pypy/translator/c/test/test_newgc.py	Mon Oct 18 16:45:16 2010
@@ -624,13 +624,13 @@
         os.unlink(self.filename)
 
     def define_callback_with_collect(cls):
-        from pypy.rlib.libffi import ffi_type_pointer, cast_type_to_ffitype,\
+        from pypy.rlib.clibffi import ffi_type_pointer, cast_type_to_ffitype,\
              CDLL, ffi_type_void, CallbackFuncPtr, ffi_type_sint
         from pypy.rpython.lltypesystem import rffi, ll2ctypes
         import gc
         ffi_size_t = cast_type_to_ffitype(rffi.SIZE_T)
 
-        from pypy.rlib.libffi import get_libc_name
+        from pypy.rlib.clibffi import get_libc_name
 
         def callback(ll_args, ll_res, stuff):
             gc.collect()



More information about the Pypy-commit mailing list