[pypy-svn] r47333 - in pypy/dist/pypy/rpython: . lltypesystem lltypesystem/test

arigo at codespeak.net arigo at codespeak.net
Tue Oct 9 12:26:32 CEST 2007


Author: arigo
Date: Tue Oct  9 12:26:31 2007
New Revision: 47333

Modified:
   pypy/dist/pypy/rpython/extfunc.py
   pypy/dist/pypy/rpython/llinterp.py
   pypy/dist/pypy/rpython/lltypesystem/llarena.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_llarena.py
Log:
Annotate and translate the arena functions.
Extended the register_external() logic so that if we specify both
llimpl and llfakeimpl, the latter is called by the llinterpreter
and the former is translated to C.


Modified: pypy/dist/pypy/rpython/extfunc.py
==============================================================================
--- pypy/dist/pypy/rpython/extfunc.py	(original)
+++ pypy/dist/pypy/rpython/extfunc.py	Tue Oct  9 12:26:31 2007
@@ -191,6 +191,8 @@
                 '_name': self.name,
                 '_safe_not_sandboxed': self.safe_not_sandboxed,
                 }
+            if hasattr(self, fake_method_name):
+                impl._llfnobjattrs_['_fakeimpl'] = fakeimpl
             obj = rtyper.getannmixlevel().delayedfunction(
                 impl, signature_args, hop.s_result)
         else:

Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Tue Oct  9 12:26:31 2007
@@ -439,8 +439,12 @@
 
     def invoke_callable_with_pyexceptions(self, fptr, *args):
         obj = self.llinterpreter.typer.type_system.deref(fptr)
+        if hasattr(obj, '_fakeimpl'):
+            f = obj._fakeimpl
+        else:
+            f = obj._callable
         try:
-            return obj._callable(*args)
+            return f(*args)
         except LLException, e:
             raise
         except Exception, e:
@@ -606,6 +610,8 @@
 
     def perform_call(self, f, ARGS, args):
         fobj = self.llinterpreter.typer.type_system.deref(f)
+        if hasattr(fobj, '_fakeimpl'):
+            return self.invoke_callable_with_pyexceptions(f, *args)
         has_callable = getattr(fobj, '_callable', None) is not None
         if has_callable and getattr(fobj._callable, 'suggested_primitive', False):
                 return self.invoke_callable_with_pyexceptions(f, *args)

Modified: pypy/dist/pypy/rpython/lltypesystem/llarena.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llarena.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/llarena.py	Tue Oct  9 12:26:31 2007
@@ -169,11 +169,10 @@
 
 # ____________________________________________________________
 #
-# Public interface: arena_malloc(), arena_free() and arena_reset()
-# which directly correspond to lloperations.  Although the operations
-# are similar to raw_malloc(), raw_free() and raw_memclear(), the
-# backend can choose a different implementation for arenas, one that
-# is more suited to very large chunks of memory.
+# Public interface: arena_malloc(), arena_free(), arena_reset()
+# are similar to raw_malloc(), raw_free() and raw_memclear(), but
+# work with fakearenaaddresses on which arbitrary arithmetic is
+# possible even on top of the llinterpreter.
 
 def arena_malloc(nbytes, zero):
     """Allocate and return a new arena, optionally zero-initialized."""
@@ -201,3 +200,80 @@
     this is used to know what type of lltype object to allocate."""
     assert isinstance(addr, fakearenaaddress)
     addr.arena.allocate_object(addr.offset, size)
+
+# ____________________________________________________________
+#
+# Translation support: the functions above turn into the code below.
+# We can tweak these implementations to be more suited to very large
+# chunks of memory.
+
+import os, sys
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rpython.extfunc import register_external
+
+if os.name == 'posix':
+    READ_MAX = (sys.maxint//4) + 1    # upper bound on reads to avoid surprises
+    os_read = rffi.llexternal('read',
+                              [rffi.INT, llmemory.Address, rffi.SIZE_T],
+                              rffi.SIZE_T)
+
+    def clear_large_memory_chunk(baseaddr, size):
+        # on Linux at least, reading from /dev/zero is the fastest way
+        # to clear arenas, because the kernel knows that it doesn't
+        # need to even allocate the pages before they are used
+        try:
+            fd = os.open('/dev/zero', os.O_RDONLY, 0644)
+        except OSError:
+            pass
+        else:
+            while size > 0:
+                count = os_read(fd, baseaddr, min(READ_MAX, size))
+                count = rffi.cast(lltype.Signed, count)
+                if count < 0:
+                    break
+                size -= count
+                baseaddr += count
+            os.close(fd)
+
+        if size > 0:     # reading from /dev/zero failed, fallback
+            llmemory.raw_memclear(baseaddr, size)
+
+else:
+    # XXX any better implementation on Windows?
+    clear_large_memory_chunk = llmemory.raw_memclear
+
+
+def llimpl_arena_malloc(nbytes, zero):
+    addr = llmemory.raw_malloc(nbytes)
+    if zero:
+        clear_large_memory_chunk(addr, nbytes)
+    return addr
+register_external(arena_malloc, [int, bool], llmemory.Address,
+                  'll_arena.arena_malloc',
+                  llimpl=llimpl_arena_malloc,
+                  llfakeimpl=arena_malloc,
+                  sandboxsafe=True)
+
+def llimpl_arena_free(arena_addr):
+    llmemory.raw_free(arena_addr)
+register_external(arena_free, [llmemory.Address], None, 'll_arena.arena_free',
+                  llimpl=llimpl_arena_free,
+                  llfakeimpl=arena_free,
+                  sandboxsafe=True)
+
+def llimpl_arena_reset(arena_addr, myarenasize, zero):
+    if zero:
+        clear_large_memory_chunk(arena_addr, myarenasize)
+register_external(arena_reset, [llmemory.Address, int, bool], None,
+                  'll_arena.arena_reset',
+                  llimpl=llimpl_arena_reset,
+                  llfakeimpl=arena_reset,
+                  sandboxsafe=True)
+
+def llimpl_arena_reserve(addr, size):
+    pass
+register_external(arena_reserve, [llmemory.Address, int], None,
+                  'll_arena.arena_reserve',
+                  llimpl=llimpl_arena_reserve,
+                  llfakeimpl=arena_reserve,
+                  sandboxsafe=True)

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_llarena.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_llarena.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_llarena.py	Tue Oct  9 12:26:31 2007
@@ -2,7 +2,7 @@
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.lltypesystem.llmemory import cast_adr_to_ptr
 from pypy.rpython.lltypesystem.llarena import arena_malloc, arena_reset
-from pypy.rpython.lltypesystem.llarena import arena_reserve
+from pypy.rpython.lltypesystem.llarena import arena_reserve, arena_free
 from pypy.rpython.lltypesystem.llarena import ArenaError
 
 def test_arena():
@@ -106,13 +106,32 @@
     assert lt(a, b+19)
 
 
+SX = lltype.Struct('S', ('x',lltype.Signed))
+
 def test_look_inside_object():
-    S = lltype.Struct('S', ('x',lltype.Signed))
-    SPTR = lltype.Ptr(S)
-    a = arena_malloc(50, False)
+    SPTR = lltype.Ptr(SX)
+    myarenasize = 50
+    a = arena_malloc(myarenasize, False)
     b = a + 4
-    arena_reserve(b, llmemory.sizeof(S))
-    (b + llmemory.offsetof(S, 'x')).signed[0] = 123
+    arena_reserve(b, llmemory.sizeof(SX))
+    (b + llmemory.offsetof(SX, 'x')).signed[0] = 123
     assert llmemory.cast_adr_to_ptr(b, SPTR).x == 123
     llmemory.cast_adr_to_ptr(b, SPTR).x += 1
-    assert (b + llmemory.offsetof(S, 'x')).signed[0] == 124
+    assert (b + llmemory.offsetof(SX, 'x')).signed[0] == 124
+    arena_reset(a, myarenasize, True)
+    arena_reserve(b, llmemory.sizeof(SX))
+    assert llmemory.cast_adr_to_ptr(b, SPTR).x == 0
+    arena_free(a)
+    return 42
+
+
+def test_llinterpreted():
+    from pypy.rpython.test.test_llinterp import interpret
+    res = interpret(test_look_inside_object, [])
+    assert res == 42
+
+def test_compiled():
+    from pypy.translator.c.test.test_genc import compile
+    fn = compile(test_look_inside_object, [])
+    res = fn()
+    assert res == 42



More information about the Pypy-commit mailing list