[pypy-svn] r70326 - in pypy/branch/virtual-forcing: . lib-python lib-python/modified-2.5.2/test pypy pypy/config pypy/doc/config pypy/interpreter pypy/interpreter/test pypy/jit/backend/llsupport pypy/jit/backend/llvm/test pypy/jit/backend/test pypy/jit/backend/x86 pypy/jit/backend/x86/test pypy/jit/metainterp pypy/jit/metainterp/test pypy/lib pypy/lib/app_test pypy/module/__builtin__ pypy/module/__builtin__/test pypy/module/__pypy__ pypy/module/_demo pypy/module/_demo/test pypy/module/exceptions pypy/module/imp pypy/module/imp/test pypy/module/oracle pypy/module/thread pypy/module/zipimport pypy/module/zipimport/test pypy/objspace/flow pypy/objspace/std/test pypy/rlib pypy/rpython pypy/rpython/memory/gctransform pypy/rpython/memory/gctransform/test pypy/rpython/test pypy/rpython/tool pypy/tool pypy/translator pypy/translator/backendopt pypy/translator/backendopt/test pypy/translator/c pypy/translator/c/test pypy/translator/platform pypy/translator/platform/test

arigo at codespeak.net arigo at codespeak.net
Tue Dec 29 10:12:41 CET 2009


Author: arigo
Date: Tue Dec 29 10:12:39 2009
New Revision: 70326

Added:
   pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/test_runpy.py
      - copied unchanged from r70325, pypy/trunk/lib-python/modified-2.5.2/test/test_runpy.py
   pypy/branch/virtual-forcing/pypy/doc/config/objspace.usemodules.imp.txt
      - copied unchanged from r70325, pypy/trunk/pypy/doc/config/objspace.usemodules.imp.txt
   pypy/branch/virtual-forcing/pypy/module/_demo/test/   (props changed)
      - copied from r70325, pypy/trunk/pypy/module/_demo/test/
   pypy/branch/virtual-forcing/pypy/module/imp/   (props changed)
      - copied from r70325, pypy/trunk/pypy/module/imp/
Removed:
   pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/test___all__.py
   pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/test_importhooks.py
   pypy/branch/virtual-forcing/pypy/lib/app_test/test_imp_extra.py
   pypy/branch/virtual-forcing/pypy/lib/imp.py
   pypy/branch/virtual-forcing/pypy/module/__builtin__/app_misc.py
   pypy/branch/virtual-forcing/pypy/module/__builtin__/importing.py
   pypy/branch/virtual-forcing/pypy/module/__builtin__/test/test_import.py
   pypy/branch/virtual-forcing/pypy/module/thread/importlock.py
Modified:
   pypy/branch/virtual-forcing/LICENSE
   pypy/branch/virtual-forcing/lib-python/   (props changed)
   pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/infinite_reload.py
   pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/test_import.py
   pypy/branch/virtual-forcing/pypy/   (props changed)
   pypy/branch/virtual-forcing/pypy/config/pypyoption.py
   pypy/branch/virtual-forcing/pypy/interpreter/baseobjspace.py
   pypy/branch/virtual-forcing/pypy/interpreter/gateway.py
   pypy/branch/virtual-forcing/pypy/interpreter/mixedmodule.py
   pypy/branch/virtual-forcing/pypy/interpreter/module.py
   pypy/branch/virtual-forcing/pypy/interpreter/test/test_gateway.py
   pypy/branch/virtual-forcing/pypy/jit/backend/llsupport/gc.py
   pypy/branch/virtual-forcing/pypy/jit/backend/llvm/test/conftest.py   (props changed)
   pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py
   pypy/branch/virtual-forcing/pypy/jit/backend/x86/assembler.py
   pypy/branch/virtual-forcing/pypy/jit/backend/x86/test/test_gc_integration.py   (props changed)
   pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/effectinfo.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/logger.py   (props changed)
   pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_effectinfo.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_optimizefindnode.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_resume.py
   pypy/branch/virtual-forcing/pypy/lib/app_test/test_runpy.py
   pypy/branch/virtual-forcing/pypy/module/__builtin__/__init__.py
   pypy/branch/virtual-forcing/pypy/module/__pypy__/__init__.py
   pypy/branch/virtual-forcing/pypy/module/_demo/__init__.py
   pypy/branch/virtual-forcing/pypy/module/exceptions/   (props changed)
   pypy/branch/virtual-forcing/pypy/module/imp/test/   (props changed)
   pypy/branch/virtual-forcing/pypy/module/oracle/__init__.py
   pypy/branch/virtual-forcing/pypy/module/oracle/interp_error.py
   pypy/branch/virtual-forcing/pypy/module/thread/__init__.py
   pypy/branch/virtual-forcing/pypy/module/zipimport/__init__.py
   pypy/branch/virtual-forcing/pypy/module/zipimport/interp_zipimport.py
   pypy/branch/virtual-forcing/pypy/module/zipimport/test/test_zipimport.py
   pypy/branch/virtual-forcing/pypy/objspace/flow/flowcontext.py
   pypy/branch/virtual-forcing/pypy/objspace/std/test/test_setobject.py   (props changed)
   pypy/branch/virtual-forcing/pypy/rlib/rgc.py
   pypy/branch/virtual-forcing/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/virtual-forcing/pypy/rpython/memory/gctransform/test/test_framework.py
   pypy/branch/virtual-forcing/pypy/rpython/rptr.py
   pypy/branch/virtual-forcing/pypy/rpython/test/test_rptr.py
   pypy/branch/virtual-forcing/pypy/rpython/tool/rffi_platform.py
   pypy/branch/virtual-forcing/pypy/tool/gcc_cache.py
   pypy/branch/virtual-forcing/pypy/tool/udir.py
   pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_writeanalyze.py
   pypy/branch/virtual-forcing/pypy/translator/backendopt/writeanalyze.py
   pypy/branch/virtual-forcing/pypy/translator/c/gc.py
   pypy/branch/virtual-forcing/pypy/translator/c/test/test_boehm.py
   pypy/branch/virtual-forcing/pypy/translator/c/test/test_refcount.py   (props changed)
   pypy/branch/virtual-forcing/pypy/translator/c/test/test_stackless.py
   pypy/branch/virtual-forcing/pypy/translator/driver.py
   pypy/branch/virtual-forcing/pypy/translator/platform/__init__.py
   pypy/branch/virtual-forcing/pypy/translator/platform/darwin.py
   pypy/branch/virtual-forcing/pypy/translator/platform/posix.py
   pypy/branch/virtual-forcing/pypy/translator/platform/test/test_darwin.py
   pypy/branch/virtual-forcing/pypy/translator/platform/test/test_platform.py
Log:
Merge the changes on trunk, from -r70231:70325.


Modified: pypy/branch/virtual-forcing/LICENSE
==============================================================================
--- pypy/branch/virtual-forcing/LICENSE	(original)
+++ pypy/branch/virtual-forcing/LICENSE	Tue Dec 29 10:12:39 2009
@@ -86,6 +86,7 @@
     Guenter Jantzen
     Dinu Gherman
     Georg Brandl
+    Benjamin Peterson
     Ben Young
     Nicolas Chauvat
     Jean-Paul Calderone

Modified: pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/infinite_reload.py
==============================================================================
--- pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/infinite_reload.py	(original)
+++ pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/infinite_reload.py	Tue Dec 29 10:12:39 2009
@@ -3,8 +3,5 @@
 #  reload()ing. This module is imported by test_import.py:test_infinite_reload
 #  to make sure this doesn't happen any more.
 
-print 1
 import infinite_reload
-print 2
 reload(infinite_reload)
-print 3

Modified: pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/test_import.py
==============================================================================
--- pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/test_import.py	(original)
+++ pypy/branch/virtual-forcing/lib-python/modified-2.5.2/test/test_import.py	Tue Dec 29 10:12:39 2009
@@ -1,4 +1,4 @@
-from test.test_support import TESTFN, TestFailed, check_impl_detail
+from test.test_support import TESTFN, TestFailed
 
 import os
 import random
@@ -56,6 +56,11 @@
         os.unlink(source)
 
     try:
+        #--- the block below is to check that "reload" manages to import
+        #--- the .pyc file alone.  We don't support it in PyPy in the default
+        #--- configuration.
+        return
+
         try:
             reload(mod)
         except ImportError, err:
@@ -238,5 +243,4 @@
     finally:
         sys.path.pop(0)
 
-if check_impl_detail():
-    test_infinite_reload()
+test_infinite_reload()

Modified: pypy/branch/virtual-forcing/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/config/pypyoption.py	(original)
+++ pypy/branch/virtual-forcing/pypy/config/pypyoption.py	Tue Dec 29 10:12:39 2009
@@ -16,7 +16,7 @@
 
 default_modules = essential_modules.copy()
 default_modules.update(dict.fromkeys(
-    ["_codecs", "gc", "_weakref", "marshal", "errno",
+    ["_codecs", "gc", "_weakref", "marshal", "errno", "imp",
      "math", "_sre", "_pickle_support", "operator",
      "parser", "symbol", "token", "_ast", "_random", "__pypy__",
      "_testing"]))

Modified: pypy/branch/virtual-forcing/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/branch/virtual-forcing/pypy/interpreter/baseobjspace.py	Tue Dec 29 10:12:39 2009
@@ -239,6 +239,9 @@
             config = get_pypy_config(translating=False)
         self.config = config
 
+        self.builtin_modules = {}
+        self.reloading_modules = {}
+
         # import extra modules for side-effects
         import pypy.interpreter.nestedscope     # register *_DEREF bytecodes
 
@@ -266,16 +269,22 @@
     def startup(self):
         # To be called before using the space
 
-        # Initialize all builtin modules
+        # Initialize already imported builtin modules
         from pypy.interpreter.module import Module
+        w_modules = self.sys.get('modules')
         for w_modname in self.unpackiterable(
                                 self.sys.get('builtin_module_names')):
+            try:
+                w_mod = self.getitem(w_modules, w_modname)
+            except OperationError, e:
+                if e.match(self, self.w_KeyError):
+                    continue
+                raise
             modname = self.str_w(w_modname)
-            mod = self.interpclass_w(self.getbuiltinmodule(modname))
+            mod = self.interpclass_w(w_mod)
             if isinstance(mod, Module):
-                import time
                 self.timer.start("startup " + modname)
-                mod.startup(self)
+                mod.init(self)
                 self.timer.stop("startup " + modname)
 
     def finish(self):
@@ -283,11 +292,9 @@
         if w_exitfunc is not None:
             self.call_function(w_exitfunc)
         from pypy.interpreter.module import Module
-        for w_modname in self.unpackiterable(
-                                self.sys.get('builtin_module_names')):
-            modname = self.str_w(w_modname)
-            mod = self.interpclass_w(self.getbuiltinmodule(modname))
-            if isinstance(mod, Module):
+        for w_mod in self.builtin_modules.values():
+            mod = self.interpclass_w(w_mod)
+            if isinstance(mod, Module) and mod.startup_called:
                 mod.shutdown(self)
         if self.config.objspace.std.withdictmeasurement:
             from pypy.objspace.std.dictmultiobject import report
@@ -339,14 +346,42 @@
 
         w_name = self.wrap(name)
         w_mod = self.wrap(Module(self, w_name))
-        w_modules = self.sys.get('modules')
-        self.setitem(w_modules, w_name, w_mod)
+        self.builtin_modules[name] = w_mod
         return name
 
-    def getbuiltinmodule(self, name):
+    def getbuiltinmodule(self, name, force_init=False):
         w_name = self.wrap(name)
         w_modules = self.sys.get('modules')
-        return self.getitem(w_modules, w_name)
+        try:
+            w_mod = self.getitem(w_modules, w_name)
+        except OperationError, e:
+            if not e.match(self, self.w_KeyError):
+                raise
+        else:
+            if not force_init:
+                return w_mod
+
+        # If the module is a builtin but not yet imported,
+        # retrieve it and initialize it
+        try:
+            w_mod = self.builtin_modules[name]
+        except KeyError:
+            raise OperationError(
+                self.w_SystemError,
+                self.wrap("getbuiltinmodule() called "
+                          "with non-builtin module %s" % name))
+        else:
+            # Add the module to sys.modules
+            self.setitem(w_modules, w_name, w_mod)
+
+            # And initialize it
+            from pypy.interpreter.module import Module
+            mod = self.interpclass_w(w_mod)
+            if isinstance(mod, Module):
+                self.timer.start("startup " + name)
+                mod.init(self)
+                self.timer.stop("startup " + name)
+            return w_mod
 
     def get_builtinmodule_to_install(self):
         """NOT_RPYTHON"""
@@ -390,26 +425,27 @@
         "NOT_RPYTHON: only for initializing the space."
 
         from pypy.module.exceptions import Module
-        w_name_exceptions = self.wrap('exceptions')
-        self.exceptions_module = Module(self, w_name_exceptions)
+        w_name = self.wrap('exceptions')
+        self.exceptions_module = Module(self, w_name)
+        self.builtin_modules['exceptions'] = self.wrap(self.exceptions_module)
 
         from pypy.module.sys import Module
         w_name = self.wrap('sys')
         self.sys = Module(self, w_name)
-        w_modules = self.sys.get('modules')
-        self.setitem(w_modules, w_name, self.wrap(self.sys))
+        self.builtin_modules['sys'] = self.wrap(self.sys)
 
-        self.setitem(w_modules, w_name_exceptions,
-                     self.wrap(self.exceptions_module))
+        from pypy.module.imp import Module
+        w_name = self.wrap('imp')
+        self.builtin_modules['imp'] = self.wrap(Module(self, w_name))
 
         from pypy.module.__builtin__ import Module
         w_name = self.wrap('__builtin__')
         self.builtin = Module(self, w_name)
         w_builtin = self.wrap(self.builtin)
-        self.setitem(w_modules, w_name, w_builtin)
+        self.builtin_modules['__builtin__'] = self.wrap(w_builtin)
         self.setitem(self.builtin.w_dict, self.wrap('__builtins__'), w_builtin)
 
-        bootstrap_modules = ['sys', '__builtin__', 'exceptions']
+        bootstrap_modules = ['sys', 'imp', '__builtin__', 'exceptions']
         installed_builtin_modules = bootstrap_modules[:]
 
         self.export_builtin_exceptions()
@@ -480,12 +516,11 @@
 
     def setup_builtin_modules(self):
         "NOT_RPYTHON: only for initializing the space."
-        from pypy.interpreter.module import Module
-        for w_modname in self.unpackiterable(self.sys.get('builtin_module_names')):
-            modname = self.unwrap(w_modname)
-            mod = self.getbuiltinmodule(modname)
-            if isinstance(mod, Module):
-                mod.setup_after_space_initialization()
+        self.getbuiltinmodule('sys')
+        self.getbuiltinmodule('imp')
+        self.getbuiltinmodule('__builtin__')
+        for mod in self.builtin_modules.values():
+            mod.setup_after_space_initialization()
 
     def initialize(self):
         """NOT_RPYTHON: Abstract method that should put some minimal

Modified: pypy/branch/virtual-forcing/pypy/interpreter/gateway.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/interpreter/gateway.py	(original)
+++ pypy/branch/virtual-forcing/pypy/interpreter/gateway.py	Tue Dec 29 10:12:39 2009
@@ -386,6 +386,15 @@
     else:
         return typ.__name__ + '_w'
 
+
+def unwrap_spec(*spec):
+    """A decorator which attaches the unwrap_spec attribute."""
+    def decorator(func):
+        func.unwrap_spec = spec
+        return func
+    return decorator
+
+
 class BuiltinCode(eval.Code):
     "The code object implementing a built-in (interpreter-level) hook."
     _immutable_ = True

Modified: pypy/branch/virtual-forcing/pypy/interpreter/mixedmodule.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/interpreter/mixedmodule.py	(original)
+++ pypy/branch/virtual-forcing/pypy/interpreter/mixedmodule.py	Tue Dec 29 10:12:39 2009
@@ -13,7 +13,8 @@
 
     applevel_name = None
     expose__file__attribute = True
-    
+    w_initialdict = None
+
     def __init__(self, space, w_name): 
         """ NOT_RPYTHON """ 
         Module.__init__(self, space, w_name) 
@@ -21,6 +22,13 @@
         self.__class__.buildloaders()
         self.loaders = self.loaders.copy()    # copy from the class to the inst
 
+    def init(self, space):
+        """This is called each time the module is imported or reloaded
+        """
+        if self.w_initialdict is not None:
+            space.call_method(self.w_dict, 'update', self.w_initialdict)
+        Module.init(self, space)
+
     def get_applevel_name(cls):
         """ NOT_RPYTHON """
         if cls.applevel_name is not None:
@@ -82,11 +90,13 @@
             for name in self.loaders: 
                 w_value = self.get(name)  
                 space.setitem(self.w_dict, space.new_interned_str(name), w_value) 
-            self.lazy = False 
+            self.lazy = False
+            self.w_initialdict = space.call_method(self.w_dict, 'items')
         return self.w_dict 
 
     def _freeze_(self):
         self.getdict()
+        self.startup_called = False
         # hint for the annotator: Modules can hold state, so they are
         # not constant
         return False

Modified: pypy/branch/virtual-forcing/pypy/interpreter/module.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/interpreter/module.py	(original)
+++ pypy/branch/virtual-forcing/pypy/interpreter/module.py	Tue Dec 29 10:12:39 2009
@@ -15,22 +15,30 @@
         self.w_dict = w_dict 
         self.w_name = w_name 
         if w_name is not None:
-            space.setitem(w_dict, space.new_interned_str('__name__'), w_name) 
+            space.setitem(w_dict, space.new_interned_str('__name__'), w_name)
+        self.startup_called = False
 
     def setup_after_space_initialization(self):
         """NOT_RPYTHON: to allow built-in modules to do some more setup
         after the space is fully initialized."""
 
+    def init(self, space):
+        """This is called each time the module is imported or reloaded
+        """
+        if not self.startup_called:
+            self.startup_called = True
+            self.startup(space)
+
     def startup(self, space):
-        """This is called at runtime before the space gets uses to allow
-        the module to do initialization at runtime.
+        """This is called at runtime on import to allow the module to
+        do initialization when it is imported for the first time.
         """
 
     def shutdown(self, space):
         """This is called when the space is shut down, just after
-        sys.exitfunc().
+        sys.exitfunc(), if the module has been imported.
         """
-        
+
     def getdict(self):
         return self.w_dict
 

Modified: pypy/branch/virtual-forcing/pypy/interpreter/test/test_gateway.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/interpreter/test/test_gateway.py	(original)
+++ pypy/branch/virtual-forcing/pypy/interpreter/test/test_gateway.py	Tue Dec 29 10:12:39 2009
@@ -520,6 +520,16 @@
         w_res = space.call_obj_args(w_g, w_self, args3)
         assert space.is_true(space.eq(w_res, space.wrap(('g', 'self', 3))))
 
+    def test_unwrap_spec_decorator(self):
+        space = self.space
+        @gateway.unwrap_spec(gateway.ObjSpace, gateway.W_Root, int)
+        def g(space, w_thing, i):
+            return space.newtuple([w_thing, space.wrap(i)])
+        w_g = space.wrap(gateway.interp2app_temp(g))
+        args = argument.Arguments(space, [space.wrap(-1), space.wrap(0)])
+        w_res = space.call_args(w_g, args)
+        assert space.eq_w(w_res, space.wrap((-1, 0)))
+
 
 class TestPassThroughArguments:
     

Modified: pypy/branch/virtual-forcing/pypy/jit/backend/llsupport/gc.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/llsupport/gc.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/llsupport/gc.py	Tue Dec 29 10:12:39 2009
@@ -41,7 +41,7 @@
         GcLLDescription.__init__(self, gcdescr, translator)
         # grab a pointer to the Boehm 'malloc' function
         from pypy.rpython.tool import rffi_platform
-        compilation_info = rffi_platform.check_boehm()
+        compilation_info = rffi_platform.configure_boehm()
 
         # Versions 6.x of libgc needs to use GC_local_malloc().
         # Versions 7.x of libgc removed this function; GC_malloc() has

Modified: pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py	Tue Dec 29 10:12:39 2009
@@ -1,5 +1,5 @@
 
-import py, sys, random
+import py, sys, random, os
 from pypy.jit.metainterp.history import (AbstractFailDescr,
                                          BasicFailDescr,
                                          BoxInt, Box, BoxPtr,
@@ -465,6 +465,29 @@
                                          'float', descr=calldescr)
             assert abs(res.value - 4.6) < 0.0001
 
+    def test_call_stack_alignment(self):
+        # test stack alignment issues, notably for Mac OS/X
+
+        def func_ints(*ints):
+            s = str(ints) + '\n'
+            os.write(1, s)   # don't remove -- crash if the stack is misaligned
+            return sum(ints)
+
+        for nb_args in range(0, 35):
+            cpu = self.cpu
+            TP = lltype.Signed
+            #
+            FPTR = self.Ptr(self.FuncType([TP] * nb_args, TP))
+            func_ptr = llhelper(FPTR, func_ints)
+            FUNC = deref(FPTR)
+            calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+            funcbox = self.get_funcbox(cpu, func_ptr)
+            args = [280-24*i for i in range(nb_args)]
+            res = self.execute_operation(rop.CALL,
+                                         [funcbox] + map(BoxInt, args),
+                                         'int', descr=calldescr)
+            assert res.value == sum(args)
+
     def test_field_basic(self):
         t_box, T_box = self.alloc_instance(self.T)
         fielddescr = self.cpu.fielddescrof(self.S, 'value')

Modified: pypy/branch/virtual-forcing/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/x86/assembler.py	Tue Dec 29 10:12:39 2009
@@ -17,6 +17,7 @@
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.backend.x86.support import values_array
 from pypy.rlib.debug import debug_print
+from pypy.rlib import rgc
 
 # our calling convention - we pass first 6 args in registers
 # and the rest stays on the stack
@@ -27,7 +28,6 @@
 else:
     CALL_ALIGN = 1
 
-
 def align_stack_words(words):
     return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1)
 
@@ -225,13 +225,14 @@
 
     def _patch_stackadjust(self, adr_lea, reserved_depth):
         # patch stack adjustment LEA
-        # possibly align, e.g. for Mac OS X        
         mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 4)
         # Compute the correct offset for the instruction LEA ESP, [EBP-4*words].
         # Given that [EBP] is where we saved EBP, i.e. in the last word
         # of our fixed frame, then the 'words' value is:
         words = (FRAME_FIXED_SIZE - 1) + reserved_depth
-        mc.write(packimm32(-WORD * words))
+        # align, e.g. for Mac OS X        
+        aligned_words = align_stack_words(words+2)-2 # 2 = EIP+EBP
+        mc.write(packimm32(-WORD * aligned_words))
         mc.done()
 
     def _assemble_bootstrap_code(self, inputargs, arglocs):
@@ -403,14 +404,6 @@
                     return self.implement_guard(addr, getattr(self.mc, name))
         return genop_cmp_guard
 
-##    XXX redo me
-##    def align_stack_for_call(self, nargs):
-##        # xxx do something when we don't use push anymore for calls
-##        extra_on_stack = align_stack_words(nargs)
-##        for i in range(extra_on_stack-nargs):
-##            self.mc.PUSH(imm(0))   --- or just use a single SUB(esp, imm)
-##        return extra_on_stack
-
     def _emit_call(self, x, arglocs, start=0, tmp=eax):
         p = 0
         n = len(arglocs)
@@ -957,6 +950,7 @@
             boxes.append(box)
         return boxes
 
+    @rgc.no_collect
     def grab_frame_values(self, bytecode, frame_addr, allregisters):
         # no malloc allowed here!!
         self.fail_ebp = allregisters[16 + ebp.op]
@@ -1021,6 +1015,7 @@
 
     def setup_failure_recovery(self):
 
+        @rgc.no_collect
         def failure_recovery_func(registers):
             # 'registers' is a pointer to a structure containing the
             # original value of the registers, optionally the original

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py	Tue Dec 29 10:12:39 2009
@@ -11,7 +11,7 @@
 from pypy.tool.udir import udir
 from pypy.translator.simplify import get_funcobj, get_functype
 from pypy.translator.backendopt.canraise import RaiseAnalyzer
-from pypy.translator.backendopt.writeanalyze import WriteAnalyzer
+from pypy.translator.backendopt.writeanalyze import ReadWriteAnalyzer
 from pypy.jit.metainterp.typesystem import deref, arrayItem, fieldType
 from pypy.jit.metainterp.effectinfo import effectinfo_from_writeanalyze
 from pypy.jit.metainterp.effectinfo import VirtualizableAnalyzer
@@ -185,7 +185,7 @@
         self.portal_runner_ptr = portal_runner_ptr
         translator = self.rtyper.annotator.translator
         self.raise_analyzer = RaiseAnalyzer(translator)
-        self.write_analyzer = WriteAnalyzer(translator)
+        self.readwrite_analyzer = ReadWriteAnalyzer(translator)
         self.virtualizable_analyzer = VirtualizableAnalyzer(translator)
 
     def make_portal_bytecode(self, graph):
@@ -326,7 +326,7 @@
         # ok
         if consider_effects_of is not None:
             effectinfo = effectinfo_from_writeanalyze(
-                    self.write_analyzer.analyze(consider_effects_of),
+                    self.readwrite_analyzer.analyze(consider_effects_of),
                     self.cpu,
                     self.virtualizable_analyzer.analyze(consider_effects_of))
             calldescr = self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo)

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/effectinfo.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/effectinfo.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/effectinfo.py	Tue Dec 29 10:12:39 2009
@@ -7,13 +7,17 @@
 class EffectInfo(object):
     _cache = {}
 
-    def __new__(cls, write_descrs_fields, write_descrs_arrays,
+    def __new__(cls, readonly_descrs_fields,
+                write_descrs_fields, write_descrs_arrays,
                 forces_virtual_or_virtualizable=False):
-        key = (frozenset(write_descrs_fields), frozenset(write_descrs_arrays),
+        key = (frozenset(readonly_descrs_fields),
+               frozenset(write_descrs_fields),
+               frozenset(write_descrs_arrays),
                forces_virtual_or_virtualizable)
         if key in cls._cache:
             return cls._cache[key]
         result = object.__new__(cls)
+        result.readonly_descrs_fields = readonly_descrs_fields
         result.write_descrs_fields = write_descrs_fields
         result.write_descrs_arrays = write_descrs_arrays
         result.forces_virtual_or_virtualizable= forces_virtual_or_virtualizable
@@ -25,26 +29,39 @@
     from pypy.translator.backendopt.writeanalyze import top_set
     if effects is top_set:
         return None
+    readonly_descrs_fields = []
+    # readonly_descrs_arrays = [] --- not enabled for now
     write_descrs_fields = []
     write_descrs_arrays = []
+
+    def add_struct(descrs_fields, (_, T, fieldname)):
+        T = deref(T)
+        if consider_struct(T, fieldname):
+            descr = cpu.fielddescrof(T, fieldname)
+            descrs_fields.append(descr)
+
+    def add_array(descrs_arrays, (_, T)):
+        ARRAY = deref(T)
+        if consider_array(ARRAY):
+            descr = cpu.arraydescrof(ARRAY)
+            descrs_arrays.append(descr)
+
     for tup in effects:
         if tup[0] == "struct":
-            _, T, fieldname = tup
-            T = deref(T)
-            if not consider_struct(T, fieldname):
-                continue
-            descr = cpu.fielddescrof(T, fieldname)
-            write_descrs_fields.append(descr)
+            add_struct(write_descrs_fields, tup)
+        elif tup[0] == "readstruct":
+            tupw = ("struct",) + tup[1:]
+            if tupw not in effects:
+                add_struct(readonly_descrs_fields, tup)
         elif tup[0] == "array":
-            _, T = tup
-            ARRAY = deref(T)
-            if not consider_array(ARRAY):
-                continue
-            descr = cpu.arraydescrof(ARRAY)
-            write_descrs_arrays.append(descr)
+            add_array(write_descrs_arrays, tup)
+        elif tup[0] == "readarray":
+            pass
         else:
             assert 0
-    return EffectInfo(write_descrs_fields, write_descrs_arrays,
+    return EffectInfo(readonly_descrs_fields,
+                      write_descrs_fields,
+                      write_descrs_arrays,
                       forces_virtual_or_virtualizable)
 
 def consider_struct(TYPE, fieldname):

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py	Tue Dec 29 10:12:39 2009
@@ -161,18 +161,18 @@
         return self.box
 
     def make_virtual_info(self, modifier, fieldnums):
-        vinfo = self._cached_vinfo 
-        if vinfo is not None and resume.tagged_list_eq(
-                vinfo.fieldnums, fieldnums):
+        vinfo = self._cached_vinfo
+        if vinfo is not None and vinfo.equals(fieldnums):
             return vinfo
         vinfo = self._make_virtual(modifier)
-        vinfo.fieldnums = fieldnums
+        vinfo.set_content(fieldnums)
         self._cached_vinfo = vinfo
         return vinfo
 
     def _make_virtual(self, modifier):
         raise NotImplementedError("abstract base")
 
+
 def get_fielddescrlist_cache(cpu):
     if not hasattr(cpu, '_optimizeopt_fielddescrlist_cache'):
         result = descrlist_dict()
@@ -234,7 +234,6 @@
 
     def get_args_for_fail(self, modifier):
         if self.box is None and not modifier.already_seen_virtual(self.keybox):
-            # modifier.already_seen_virtual()
             # checks for recursion: it is False unless
             # we have already seen the very same keybox
             lst = self._get_field_descr_list()
@@ -302,11 +301,9 @@
 
     def get_args_for_fail(self, modifier):
         if self.box is None and not modifier.already_seen_virtual(self.keybox):
-            # modifier.already_seen_virtual()
             # checks for recursion: it is False unless
             # we have already seen the very same keybox
             itemboxes = []
-            const = self.optimizer.new_const_item(self.arraydescr)
             for itemvalue in self._items:
                 itemboxes.append(itemvalue.get_key_box())
             modifier.register_virtual_fields(self.keybox, itemboxes)
@@ -515,6 +512,9 @@
 
     def emit_operation(self, op, must_clone=True):
         self.heap_op_optimizer.emitting_operation(op)
+        self._emit_operation(op, must_clone)
+
+    def _emit_operation(self, op, must_clone=True):
         for i in range(len(op.args)):
             arg = op.args[i]
             if arg in self.values:
@@ -535,10 +535,11 @@
         self.newoperations.append(op)
 
     def store_final_boxes_in_guard(self, op):
+        pendingfields = self.heap_op_optimizer.force_lazy_setfields_for_guard()
         descr = op.descr
         assert isinstance(descr, compile.ResumeGuardDescr)
         modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
-        newboxes = modifier.finish(self.values)
+        newboxes = modifier.finish(self.values, pendingfields)
         if len(newboxes) > self.metainterp_sd.options.failargs_limit: # XXX be careful here
             raise compile.GiveUp
         descr.store_final_boxes(op, newboxes)
@@ -883,11 +884,13 @@
 class HeapOpOptimizer(object):
     def __init__(self, optimizer):
         self.optimizer = optimizer
-        # cached OptValues for each field descr
+        # cached fields:  {descr: {OptValue_instance: OptValue_fieldvalue}}
         self.cached_fields = {}
-
-        # cached OptValues for each field descr
+        # cached array items:  {descr: CachedArrayItems}
         self.cached_arrayitems = {}
+        # lazily written setfields (at most one per descr):  {descr: op}
+        self.lazy_setfields = {}
+        self.lazy_setfields_descrs = []     # keys (at least) of previous dict
 
     def clean_caches(self):
         self.cached_fields.clear()
@@ -895,6 +898,9 @@
 
     def cache_field_value(self, descr, value, fieldvalue, write=False):
         if write:
+            # when seeing a setfield, we have to clear the cache for the same
+            # field on any other structure, just in case they are aliasing
+            # each other
             d = self.cached_fields[descr] = {}
         else:
             d = self.cached_fields.setdefault(descr, {})
@@ -952,8 +958,6 @@
         return None
 
     def emitting_operation(self, op):
-        if op.is_always_pure():
-            return
         if op.has_no_side_effect():
             return
         if op.is_ovf():
@@ -965,10 +969,16 @@
             opnum == rop.SETARRAYITEM_GC or
             opnum == rop.DEBUG_MERGE_POINT):
             return
-        if opnum == rop.CALL:
+        if (opnum == rop.CALL or
+            opnum == rop.CALL_MAY_FORCE):
             effectinfo = op.descr.get_extra_info()
             if effectinfo is not None:
+                # XXX we can get the wrong complexity here, if the lists
+                # XXX stored on effectinfo are large
+                for fielddescr in effectinfo.readonly_descrs_fields:
+                    self.force_lazy_setfield(fielddescr)
                 for fielddescr in effectinfo.write_descrs_fields:
+                    self.force_lazy_setfield(fielddescr)
                     try:
                         del self.cached_fields[fielddescr]
                     except KeyError:
@@ -979,9 +989,73 @@
                     except KeyError:
                         pass
                 return
+            self.force_all_lazy_setfields()
+        elif op.is_final() or (not we_are_translated() and
+                               op.opnum < 0):   # escape() operations
+            self.force_all_lazy_setfields()
         self.clean_caches()
 
+    def force_lazy_setfield(self, descr, before_guard=False):
+        try:
+            op = self.lazy_setfields[descr]
+        except KeyError:
+            return
+        del self.lazy_setfields[descr]
+        self.optimizer._emit_operation(op)
+        #
+        # hackish: reverse the order of the last two operations if it makes
+        # sense to avoid a situation like "int_eq/setfield_gc/guard_true",
+        # which the backend (at least the x86 backend) does not handle well.
+        newoperations = self.optimizer.newoperations
+        if before_guard and len(newoperations) >= 2:
+            lastop = newoperations[-1]
+            prevop = newoperations[-2]
+            # - is_comparison() for cases like "int_eq/setfield_gc/guard_true"
+            # - CALL_MAY_FORCE: "call_may_force/setfield_gc/guard_not_forced"
+            if ((prevop.is_comparison() or prevop.opnum == rop.CALL_MAY_FORCE)
+                and prevop.result not in lastop.args):
+                newoperations[-2] = lastop
+                newoperations[-1] = prevop
+
+    def force_all_lazy_setfields(self):
+        if len(self.lazy_setfields_descrs) > 0:
+            for descr in self.lazy_setfields_descrs:
+                self.force_lazy_setfield(descr)
+            del self.lazy_setfields_descrs[:]
+
+    def force_lazy_setfields_for_guard(self):
+        pendingfields = []
+        for descr in self.lazy_setfields_descrs:
+            try:
+                op = self.lazy_setfields[descr]
+            except KeyError:
+                continue
+            # the only really interesting case that we need to handle in the
+            # guards' resume data is that of a virtual object that is stored
+            # into a field of a non-virtual object.
+            value = self.optimizer.getvalue(op.args[0])
+            assert not value.is_virtual()      # it must be a non-virtual
+            fieldvalue = self.optimizer.getvalue(op.args[1])
+            if fieldvalue.is_virtual():
+                # this is the case that we leave to resume.py
+                pendingfields.append((descr, value.box,
+                                      fieldvalue.get_key_box()))
+            else:
+                self.force_lazy_setfield(descr, before_guard=True)
+        return pendingfields
+
+    def force_lazy_setfield_if_necessary(self, op, value, write=False):
+        try:
+            op1 = self.lazy_setfields[op.descr]
+        except KeyError:
+            if write:
+                self.lazy_setfields_descrs.append(op.descr)
+        else:
+            if self.optimizer.getvalue(op1.args[0]) is not value:
+                self.force_lazy_setfield(op.descr)
+
     def optimize_GETFIELD_GC(self, op, value):
+        self.force_lazy_setfield_if_necessary(op, value)
         # check if the field was read from another getfield_gc just before
         # or has been written to recently
         fieldvalue = self.read_cached_field(op.descr, value)
@@ -996,7 +1070,8 @@
         self.cache_field_value(op.descr, value, fieldvalue)
 
     def optimize_SETFIELD_GC(self, op, value, fieldvalue):
-        self.optimizer.emit_operation(op)
+        self.force_lazy_setfield_if_necessary(op, value, write=True)
+        self.lazy_setfields[op.descr] = op
         # remember the result of future reads of the field
         self.cache_field_value(op.descr, value, fieldvalue, write=True)
 

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py	Tue Dec 29 10:12:39 2009
@@ -95,8 +95,8 @@
 TAGBOX      = 2
 TAGVIRTUAL  = 3
 
-UNASSIGNED = tag(-2 ** 12 - 1, TAGBOX)
-UNASSIGNEDVIRTUAL = tag(-2 ** 12 - 1, TAGVIRTUAL)
+UNASSIGNED = tag(-1<<13, TAGBOX)
+UNASSIGNEDVIRTUAL = tag(-1<<13, TAGVIRTUAL)
 NULLREF = tag(-1, TAGCONST)
 
 
@@ -197,6 +197,7 @@
         return len(self.cached_boxes)
 
     def assign_number_to_box(self, box, boxes):
+        # returns a negative number
         if box in self.cached_boxes:
             num = self.cached_boxes[box]
             boxes[-num-1] = box
@@ -210,6 +211,7 @@
         return len(self.cached_virtuals)
 
     def assign_number_to_virtual(self, box):
+        # returns a negative number
         if box in self.cached_virtuals:
             num = self.cached_virtuals[box]
         else:
@@ -232,8 +234,6 @@
     def __init__(self, storage, memo):
         self.storage = storage
         self.memo = memo
-        #self.virtuals = []
-        #self.vfieldboxes = []
 
     def make_virtual(self, known_class, fielddescrs):
         return VirtualInfo(known_class, fielddescrs)
@@ -254,8 +254,6 @@
         if (isinstance(box, Box) and box not in self.liveboxes_from_env
                                  and box not in self.liveboxes):
             self.liveboxes[box] = UNASSIGNED
-            return True
-        return False
 
     def _register_boxes(self, boxes):
         for box in boxes:
@@ -270,7 +268,7 @@
         _, tagbits = untag(tagged)
         return tagbits == TAGVIRTUAL
 
-    def finish(self, values):
+    def finish(self, values, pending_setfields=[]):
         # compute the numbering
         storage = self.storage
         numb, liveboxes_from_env, v = self.memo.number(values,
@@ -293,16 +291,29 @@
                 value = values[box]
                 value.get_args_for_fail(self)
 
+        for _, box, fieldbox in pending_setfields:
+            self.register_box(box)
+            self.register_box(fieldbox)
+            value = values[fieldbox]
+            value.get_args_for_fail(self)
+
         self._number_virtuals(liveboxes, values, v)
+        self._add_pending_fields(pending_setfields)
 
         storage.rd_consts = self.memo.consts
         dump_storage(storage, liveboxes)
         return liveboxes[:]
 
     def _number_virtuals(self, liveboxes, values, num_env_virtuals):
+        # !! 'liveboxes' is a list that is extend()ed in-place !!
         memo = self.memo
         new_liveboxes = [None] * memo.num_cached_boxes()
         count = 0
+        # So far, self.liveboxes should contain 'tagged' values that are
+        # either UNASSIGNED, UNASSIGNEDVIRTUAL, or a *non-negative* value
+        # with the TAGVIRTUAL.  The following loop removes the UNASSIGNED
+        # and UNASSIGNEDVIRTUAL entries, and replaces them with real
+        # negative values.
         for box, tagged in self.liveboxes.iteritems():
             i, tagbits = untag(tagged)
             if tagbits == TAGBOX:
@@ -317,6 +328,8 @@
                     assert box not in self.liveboxes_from_env
                     index = memo.assign_number_to_virtual(box)
                     self.liveboxes[box] = tag(index, TAGVIRTUAL)
+                else:
+                    assert i >= 0
         new_liveboxes.reverse()
         liveboxes.extend(new_liveboxes)
         nholes = len(new_liveboxes) - count
@@ -353,6 +366,16 @@
                 return True
         return False
 
+    def _add_pending_fields(self, pending_setfields):
+        rd_pendingfields = None
+        if pending_setfields:
+            rd_pendingfields = []
+            for descr, box, fieldbox in pending_setfields:
+                num = self._gettagged(box)
+                fieldnum = self._gettagged(fieldbox)
+                rd_pendingfields.append((descr, num, fieldnum))
+        self.storage.rd_pendingfields = rd_pendingfields
+
     def _gettagged(self, box):
         if isinstance(box, Const):
             return self.memo.getconst(box)
@@ -361,11 +384,16 @@
                 return self.liveboxes_from_env[box]
             return self.liveboxes[box]
 
+
 class AbstractVirtualInfo(object):
     def allocate(self, metainterp):
         raise NotImplementedError
     def setfields(self, metainterp, box, fn_decode_box):
         raise NotImplementedError
+    def equals(self, fieldnums):
+        return tagged_list_eq(self.fieldnums, fieldnums)
+    def set_content(self, fieldnums):
+        self.fieldnums = fieldnums
 
 
 class AbstractVirtualStructInfo(AbstractVirtualInfo):
@@ -473,6 +501,7 @@
         self.liveboxes = liveboxes
         self.cpu = metainterp.cpu
         self._prepare_virtuals(metainterp, storage.rd_virtuals)
+        self._prepare_pendingfields(metainterp, storage.rd_pendingfields)
 
     def _prepare_virtuals(self, metainterp, virtuals):
         if virtuals:
@@ -491,6 +520,16 @@
                     vinfo.setfields(metainterp, self.virtuals[i],
                                     self._decode_box)
 
+    def _prepare_pendingfields(self, metainterp, pendingfields):
+        if pendingfields:
+            if metainterp._already_allocated_resume_virtuals is not None:
+                return
+            for descr, num, fieldnum in pendingfields:
+                box = self._decode_box(num)
+                fieldbox = self._decode_box(fieldnum)
+                metainterp.execute_and_record(rop.SETFIELD_GC,
+                                              descr, box, fieldbox)
+
     def consume_boxes(self):
         numb = self.cur_numb
         assert numb is not None

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_effectinfo.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_effectinfo.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_effectinfo.py	Tue Dec 29 10:12:39 2009
@@ -3,32 +3,77 @@
 from pypy.rpython.ootypesystem import ootype
 from pypy.jit.metainterp.effectinfo import effectinfo_from_writeanalyze
 
+class FakeCPU:
+    def fielddescrof(self, T, fieldname):
+        return ('fielddescr', T, fieldname)
+    def arraydescrof(self, A):
+        return ('arraydescr', A)
+
+def test_include_read_field():
+    S = lltype.GcStruct("S", ("a", lltype.Signed))
+    effects = frozenset([("readstruct", lltype.Ptr(S), "a")])
+    effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+    assert list(effectinfo.readonly_descrs_fields) == [('fielddescr', S, "a")]
+    assert not effectinfo.write_descrs_fields
+    assert not effectinfo.write_descrs_arrays
+
+def test_include_write_field():
+    S = lltype.GcStruct("S", ("a", lltype.Signed))
+    effects = frozenset([("struct", lltype.Ptr(S), "a")])
+    effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+    assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")]
+    assert not effectinfo.readonly_descrs_fields
+    assert not effectinfo.write_descrs_arrays
+
+def test_include_write_array():
+    A = lltype.GcArray(lltype.Signed)
+    effects = frozenset([("array", lltype.Ptr(A))])
+    effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+    assert not effectinfo.readonly_descrs_fields
+    assert not effectinfo.write_descrs_fields
+    assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)]
+
+def test_dont_include_read_and_write_field():
+    S = lltype.GcStruct("S", ("a", lltype.Signed))
+    effects = frozenset([("readstruct", lltype.Ptr(S), "a"),
+                         ("struct", lltype.Ptr(S), "a")])
+    effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+    assert not effectinfo.readonly_descrs_fields
+    assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")]
+    assert not effectinfo.write_descrs_arrays
+
+
 def test_filter_out_typeptr():
     effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_filter_out_array_of_void():
     effects = frozenset([("array", lltype.Ptr(lltype.GcArray(lltype.Void)))])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_filter_out_struct_with_void():
     effects = frozenset([("struct", lltype.Ptr(lltype.GcStruct("x", ("a", lltype.Void))), "a")])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_filter_out_ooarray_of_void():
     effects = frozenset([("array", ootype.Array(ootype.Void))])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_filter_out_instance_with_void():
     effects = frozenset([("struct", ootype.Instance("x", ootype.ROOT, {"a": ootype.Void}), "a")])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_optimizefindnode.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_optimizefindnode.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_optimizefindnode.py	Tue Dec 29 10:12:39 2009
@@ -96,9 +96,15 @@
     onedescr = cpu.fielddescrof(U, 'one')
 
     FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
-    nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], []))
-    writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([adescr], []))
-    writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([adescr], [arraydescr]))
+    plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+    nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+                                    EffectInfo([], [], []))
+    writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+                                  EffectInfo([], [adescr], []))
+    writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+                                      EffectInfo([], [adescr], [arraydescr]))
+    readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+                                 EffectInfo([adescr], [], []))
     mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
                  EffectInfo([], [], forces_virtual_or_virtualizable=True))
 

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_optimizeopt.py	Tue Dec 29 10:12:39 2009
@@ -87,7 +87,10 @@
 
 def test_reuse_vinfo():
     class FakeVInfo(object):
-        pass
+        def set_content(self, fieldnums):
+            self.fieldnums = fieldnums
+        def equals(self, fieldnums):
+            return self.fieldnums == fieldnums
     class FakeVirtualValue(optimizeopt.AbstractVirtualValue):
         def _make_virtual(self, *args):
             return FakeVInfo()
@@ -606,10 +609,10 @@
         p3sub = getfield_gc(p3, descr=nextdescr)
         i3 = getfield_gc(p3sub, descr=valuedescr)
         escape(i3)
+        p1 = new_with_vtable(ConstClass(node_vtable))
         p2sub = new_with_vtable(ConstClass(node_vtable2))
         setfield_gc(p2sub, i1, descr=valuedescr)
         setfield_gc(p2, p2sub, descr=nextdescr)
-        p1 = new_with_vtable(ConstClass(node_vtable))
         jump(i1, p1, p2)
         """
         # The same as test_p123_simple, but in the end the "old" p2 contains
@@ -1293,6 +1296,182 @@
         """
         self.optimize_loop(ops, 'Not, Not', ops)
 
+    def test_duplicate_setfield_1(self):
+        ops = """
+        [p1, i1, i2]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p1, i2, descr=valuedescr)
+        jump(p1, i1, i2)
+        """
+        expected = """
+        [p1, i1, i2]
+        setfield_gc(p1, i2, descr=valuedescr)
+        jump(p1, i1, i2)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+    def test_duplicate_setfield_2(self):
+        ops = """
+        [p1, i1, i3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i2 = getfield_gc(p1, descr=valuedescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        escape(i2)
+        jump(p1, i1, i3)
+        """
+        expected = """
+        [p1, i1, i3]
+        setfield_gc(p1, i3, descr=valuedescr)
+        escape(i1)
+        jump(p1, i1, i3)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+    def test_duplicate_setfield_3(self):
+        ops = """
+        [p1, p2, i1, i3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i2 = getfield_gc(p2, descr=valuedescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        escape(i2)
+        jump(p1, p2, i1, i3)
+        """
+        # potential aliasing of p1 and p2 means that we cannot kill the
+        # the setfield_gc
+        self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+    def test_duplicate_setfield_4(self):
+        ops = """
+        [p1, i1, i2, p3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        #
+        # some operations on which the above setfield_gc cannot have effect
+        i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
+        i4 = getarrayitem_gc(p3, i3, descr=arraydescr)
+        i5 = int_add(i3, i4)
+        setarrayitem_gc(p3, 0, i5, descr=arraydescr)
+        setfield_gc(p1, i4, descr=nextdescr)
+        #
+        setfield_gc(p1, i2, descr=valuedescr)
+        jump(p1, i1, i2, p3)
+        """
+        expected = """
+        [p1, i1, i2, p3]
+        #
+        i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
+        i4 = getarrayitem_gc(p3, i3, descr=arraydescr)
+        i5 = int_add(i3, i4)
+        setarrayitem_gc(p3, 0, i5, descr=arraydescr)
+        #
+        setfield_gc(p1, i2, descr=valuedescr)
+        setfield_gc(p1, i4, descr=nextdescr)
+        jump(p1, i1, i2, p3)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+
+    def test_duplicate_setfield_sideeffects_1(self):
+        ops = """
+        [p1, i1, i2]
+        setfield_gc(p1, i1, descr=valuedescr)
+        escape()
+        setfield_gc(p1, i2, descr=valuedescr)
+        jump(p1, i1, i2)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', ops)
+
+    def test_duplicate_setfield_residual_guard_1(self):
+        ops = """
+        [p1, i1, i2, i3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        guard_true(i3) []
+        i4 = int_neg(i2)
+        setfield_gc(p1, i2, descr=valuedescr)
+        jump(p1, i1, i2, i4)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+    def test_duplicate_setfield_residual_guard_2(self):
+        # the difference with the previous test is that the field value is
+        # a virtual, which we try hard to keep virtual
+        ops = """
+        [p1, i2, i3]
+        p2 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p1, p2, descr=nextdescr)
+        guard_true(i3) []
+        i4 = int_neg(i2)
+        setfield_gc(p1, NULL, descr=nextdescr)
+        jump(p1, i2, i4)
+        """
+        expected = """
+        [p1, i2, i3]
+        guard_true(i3) [p1]
+        i4 = int_neg(i2)
+        setfield_gc(p1, NULL, descr=nextdescr)
+        jump(p1, i2, i4)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+    def test_duplicate_setfield_residual_guard_3(self):
+        ops = """
+        [p1, i2, i3]
+        p2 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p2, i2, descr=valuedescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        guard_true(i3) []
+        i4 = int_neg(i2)
+        setfield_gc(p1, NULL, descr=nextdescr)
+        jump(p1, i2, i4)
+        """
+        expected = """
+        [p1, i2, i3]
+        guard_true(i3) [p1, i2]
+        i4 = int_neg(i2)
+        setfield_gc(p1, NULL, descr=nextdescr)
+        jump(p1, i2, i4)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+    def test_duplicate_setfield_residual_guard_4(self):
+        # test that the setfield_gc does not end up between int_eq and
+        # the following guard_true
+        ops = """
+        [p1, i1, i2, i3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i5 = int_eq(i3, 5)
+        guard_true(i5) []
+        i4 = int_neg(i2)
+        setfield_gc(p1, i2, descr=valuedescr)
+        jump(p1, i1, i2, i4)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+    def test_duplicate_setfield_aliasing(self):
+        # a case where aliasing issues (and not enough cleverness) mean
+        # that we fail to remove any setfield_gc
+        ops = """
+        [p1, p2, i1, i2, i3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, i2, descr=valuedescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        jump(p1, p2, i1, i2, i3)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not, Not', ops)
+
+    def test_duplicate_setfield_guard_value_const(self):
+        ops = """
+        [p1, i1, i2]
+        guard_value(p1, ConstPtr(myptr)) []
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
+        jump(p1, i1, i2)
+        """
+        expected = """
+        [i1, i2]
+        setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
+        jump(i1, i2)
+        """
+        self.optimize_loop(ops, 'Constant(myptr), Not, Not', expected)
+
     def test_duplicate_getarrayitem_1(self):
         ops = """
         [p1]
@@ -1634,6 +1813,14 @@
                 tag = ('virtual', self.namespace[match.group(2)])
             virtuals[pvar] = (tag, None, fieldstext)
         #
+        r2 = re.compile(r"([\w\d()]+)[.](\w+)\s*=\s*([\w\d()]+)")
+        pendingfields = []
+        for match in r2.finditer(text):
+            pvar = match.group(1)
+            pfieldname = match.group(2)
+            pfieldvar = match.group(3)
+            pendingfields.append((pvar, pfieldname, pfieldvar))
+        #
         def _variables_equal(box, varname, strict):
             if varname not in virtuals:
                 if strict:
@@ -1655,11 +1842,21 @@
                 else:
                     virtuals[varname] = tag, box, fieldstext
         #
-        basetext = text[:ends[0]]
+        basetext = text.splitlines()[0]
         varnames = [s.strip() for s in basetext.split(',')]
+        if varnames == ['']:
+            varnames = []
         assert len(boxes) == len(varnames)
         for box, varname in zip(boxes, varnames):
             _variables_equal(box, varname, strict=True)
+        for pvar, pfieldname, pfieldvar in pendingfields:
+            box = oparse.getvar(pvar)
+            fielddescr = self.namespace[pfieldname.strip()]
+            fieldbox = executor.execute(self.cpu,
+                                        rop.GETFIELD_GC,
+                                        fielddescr,
+                                        box)
+            _variables_equal(fieldbox, pfieldvar, strict=True)
         #
         for match in parts:
             pvar = match.group(1)
@@ -1918,6 +2115,57 @@
             where p7v is a node_vtable, valuedescr=iv
             ''')
 
+    def test_expand_fail_lazy_setfield_1(self):
+        self.make_fail_descr()
+        ops = """
+        [p1, i2, i3]
+        p2 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p2, i2, descr=valuedescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        guard_true(i3, descr=fdescr) []
+        i4 = int_neg(i2)
+        setfield_gc(p1, NULL, descr=nextdescr)
+        jump(p1, i2, i4)
+        """
+        expected = """
+        [p1, i2, i3]
+        guard_true(i3, descr=fdescr) [p1, i2]
+        i4 = int_neg(i2)
+        setfield_gc(p1, NULL, descr=nextdescr)
+        jump(p1, i2, i4)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', expected)
+        self.loop.inputargs[0].value = self.nodebox.value
+        self.check_expanded_fail_descr('''
+            p1.nextdescr = p2
+            where p2 is a node_vtable, valuedescr=i2
+            ''')
+
+    def test_expand_fail_lazy_setfield_2(self):
+        self.make_fail_descr()
+        ops = """
+        [i2, i3]
+        p2 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p2, i2, descr=valuedescr)
+        setfield_gc(ConstPtr(myptr), p2, descr=nextdescr)
+        guard_true(i3, descr=fdescr) []
+        i4 = int_neg(i2)
+        setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
+        jump(i2, i4)
+        """
+        expected = """
+        [i2, i3]
+        guard_true(i3, descr=fdescr) [i2]
+        i4 = int_neg(i2)
+        setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
+        jump(i2, i4)
+        """
+        self.optimize_loop(ops, 'Not, Not', expected)
+        self.check_expanded_fail_descr('''
+            ConstPtr(myptr).nextdescr = p2
+            where p2 is a node_vtable, valuedescr=i2
+            ''')
+
 
 class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin):
 
@@ -2031,6 +2279,58 @@
         """
         self.optimize_loop(ops, 'Not, Not, Not', expected)
 
+    def test_residual_call_invalidates_some_read_caches_1(self):
+        ops = """
+        [p1, i1, p2, i2]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, i2, descr=adescr)
+        i3 = call(i1, descr=readadescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        setfield_gc(p2, i3, descr=adescr)
+        jump(p1, i1, p2, i2)
+        """
+        expected = """
+        [p1, i1, p2, i2]
+        setfield_gc(p2, i2, descr=adescr)
+        i3 = call(i1, descr=readadescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        setfield_gc(p2, i3, descr=adescr)
+        jump(p1, i1, p2, i2)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+
+    def test_residual_call_invalidates_some_read_caches_2(self):
+        ops = """
+        [p1, i1, p2, i2]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, i2, descr=adescr)
+        i3 = call(i1, descr=writeadescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        setfield_gc(p2, i3, descr=adescr)
+        jump(p1, i1, p2, i2)
+        """
+        expected = """
+        [p1, i1, p2, i2]
+        setfield_gc(p2, i2, descr=adescr)
+        i3 = call(i1, descr=writeadescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        setfield_gc(p2, i3, descr=adescr)
+        jump(p1, i1, p2, i2)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+
+    def test_residual_call_invalidates_some_read_caches_3(self):
+        ops = """
+        [p1, i1, p2, i2]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, i2, descr=adescr)
+        i3 = call(i1, descr=plaincalldescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        setfield_gc(p2, i3, descr=adescr)
+        jump(p1, i1, p2, i2)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
     def test_vref_nonvirtual(self):
         ops = """
         [p1]

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_resume.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_resume.py	Tue Dec 29 10:12:39 2009
@@ -12,6 +12,8 @@
     rd_frame_info_list = None
     rd_numb = None
     rd_consts = []
+    rd_virtuals = None
+    rd_pendingfields = None
 
 def test_tag():
     assert tag(3, 1) == rffi.r_short(3<<2|1)
@@ -40,6 +42,12 @@
     assert not tagged_list_eq([tag(1, TAGBOX)], [tag(-2, TAGBOX)])
     assert not tagged_list_eq([tag(1, TAGBOX), tag(-2, TAGBOX)], [tag(1, TAGBOX)])
 
+def test_vinfo():
+    v1 = AbstractVirtualInfo()
+    v1.set_content([1, 2, 4])
+    assert v1.equals([1, 2, 4])
+    assert not v1.equals([1, 2, 6])
+
 class MyMetaInterp:
     _already_allocated_resume_virtuals = None
 
@@ -80,7 +88,6 @@
                             tag(0, TAGBOX),
                             tag(1, TAGBOX)])
     storage.rd_numb = numb
-    storage.rd_virtuals = None
 
     b1s, b2s, b3s = [BoxInt(), BoxPtr(), BoxInt()]
     assert b1s != b3s
@@ -103,7 +110,6 @@
                             tag(0, TAGBOX),
                             tag(1, TAGBOX)])
     storage.rd_numb = numb
-    storage.rd_virtuals = None
     b1s, b2s, b3s = [BoxInt(), BoxPtr(), BoxInt()]
     assert b1s != b3s
     reader = ResumeDataReader(storage, [b1s, b2s, b3s], MyMetaInterp())
@@ -125,6 +131,7 @@
         rd_virtuals = [FakeVinfo(), None]
         rd_numb = []
         rd_consts = []
+        rd_pendingfields = None
     class FakeMetainterp(object):
         _already_allocated_resume_virtuals = None
         cpu = None
@@ -968,6 +975,46 @@
     assert ptr.a == 111
     assert ptr.b == lltype.nullptr(LLtypeMixin.NODE)
 
+
+def test_virtual_adder_pending_fields():
+    b2s, b4s = [BoxPtr(), BoxPtr()]
+    storage = Storage()
+    memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
+    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier.liveboxes_from_env = {}
+    modifier.liveboxes = {}
+    modifier.vfieldboxes = {}
+
+    v2 = OptValue(b2s)
+    v4 = OptValue(b4s)
+    modifier.register_box(b2s)
+    modifier.register_box(b4s)
+
+    values = {b4s: v4, b2s: v2}
+    liveboxes = []
+    modifier._number_virtuals(liveboxes, values, 0)
+    assert liveboxes == [b2s, b4s]
+    modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)])
+    storage.rd_consts = memo.consts[:]
+    storage.rd_numb = None
+    # resume
+    demo55.next = lltype.nullptr(LLtypeMixin.NODE)
+    b2t = BoxPtr(demo55o)
+    b4t = BoxPtr(demo66o)
+    newboxes = _resume_remap(liveboxes, [b2s, b4s], b2t, b4t)
+
+    metainterp = MyMetaInterp()
+    reader = ResumeDataReader(storage, newboxes, metainterp)
+    assert reader.virtuals is None
+    trace = metainterp.trace
+    b2set = (rop.SETFIELD_GC, [b2t, b4t], None, LLtypeMixin.nextdescr)
+    expected = [b2set]
+
+    for x, y in zip(expected, trace):
+        assert x == y
+    assert demo55.next == demo66
+
+
 def test_invalidation_needed():
     class options:
         failargs_limit = 10

Modified: pypy/branch/virtual-forcing/pypy/lib/app_test/test_runpy.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/lib/app_test/test_runpy.py	(original)
+++ pypy/branch/virtual-forcing/pypy/lib/app_test/test_runpy.py	Tue Dec 29 10:12:39 2009
@@ -137,6 +137,12 @@
             d1 = run_module(mod_name) # Read from source
             __import__(mod_name)
             os.remove(mod_fname)
+
+            #--- the block below is to check that "imp.find_module"
+            #--- manages to import the .pyc file alone.  We don't
+            #--- support it in PyPy in the default configuration.
+            return
+
             if verbose: print "Running from compiled:", mod_name
             d2 = run_module(mod_name) # Read from bytecode
         finally:

Modified: pypy/branch/virtual-forcing/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/__builtin__/__init__.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/__builtin__/__init__.py	Tue Dec 29 10:12:39 2009
@@ -1,6 +1,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter import module
 from pypy.interpreter.mixedmodule import MixedModule
+import pypy.module.imp.importing
 
 # put builtins here that should be optimized somehow
 
@@ -35,9 +36,6 @@
         'vars'          : 'app_inspect.vars',
         'dir'           : 'app_inspect.dir',
 
-        '_find_module'  : 'app_misc.find_module',
-        'reload'        : 'app_misc.reload',
-
         '__filestub'    : 'app_file_stub.file',
     }
 
@@ -88,7 +86,8 @@
         'compile'       : 'compiling.compile',
         'eval'          : 'compiling.eval',
 
-        '__import__'    : 'importing.importhook',
+        '__import__'    : 'pypy.module.imp.importing.importhook',
+        'reload'        : 'pypy.module.imp.importing.reload',
 
         'range'         : 'functional.range_int',
         'xrange'        : 'functional.W_XRange',
@@ -152,16 +151,3 @@
         space.exception_is_valid_obj_as_class_w = ab.exception_is_valid_obj_as_class_w.__get__(space)
         space.exception_getclass = ab.exception_getclass.__get__(space)
         space.exception_issubclass_w = ab.exception_issubclass_w.__get__(space)
-
-    def startup(self, space):
-        # install zipimport hook if --withmod-zipimport is used
-        if space.config.objspace.usemodules.zipimport:
-            w_import = space.builtin.get('__import__')
-            w_zipimport = space.call(w_import, space.newlist(
-                [space.wrap('zipimport')]))
-            w_sys = space.getbuiltinmodule('sys')
-            w_path_hooks = space.getattr(w_sys, space.wrap('path_hooks'))
-            w_append = space.getattr(w_path_hooks, space.wrap('append'))
-            w_zipimporter = space.getattr(w_zipimport,
-                                          space.wrap('zipimporter'))
-            space.call(w_append, space.newlist([w_zipimporter]))

Modified: pypy/branch/virtual-forcing/pypy/module/__pypy__/__init__.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/__pypy__/__init__.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/__pypy__/__init__.py	Tue Dec 29 10:12:39 2009
@@ -1,7 +1,7 @@
 
 # Package initialisation
 from pypy.interpreter.mixedmodule import MixedModule
-from pypy.module.__builtin__.importing import get_pyc_magic
+from pypy.module.imp.importing import get_pyc_magic
 
 class Module(MixedModule):
     appleveldefs = {

Modified: pypy/branch/virtual-forcing/pypy/module/_demo/__init__.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/_demo/__init__.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/_demo/__init__.py	Tue Dec 29 10:12:39 2009
@@ -12,3 +12,13 @@
     appleveldefs = {
         'DemoError'        : 'app_demo.DemoError',
     }
+
+    # Used in tests
+    demo_events = []
+    def setup_after_space_initialization(self):
+        Module.demo_events.append('setup')
+    def startup(self, space):
+        Module.demo_events.append('startup')
+    def shutdown(self, space):
+        Module.demo_events.append('shutdown')
+

Modified: pypy/branch/virtual-forcing/pypy/module/oracle/__init__.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/oracle/__init__.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/oracle/__init__.py	Tue Dec 29 10:12:39 2009
@@ -39,6 +39,7 @@
     def startup(self, space):
         from pypy.module.oracle.interp_error import get
         state = get(space)
+        state.startup(space)
         (state.w_DecimalType,
          state.w_DateTimeType, state.w_DateType, state.w_TimedeltaType,
          ) = space.fixedview(space.appexec([], """():

Modified: pypy/branch/virtual-forcing/pypy/module/oracle/interp_error.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/oracle/interp_error.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/oracle/interp_error.py	Tue Dec 29 10:12:39 2009
@@ -4,32 +4,47 @@
 from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
 from pypy.interpreter.gateway import interp2app
 from pypy.interpreter.error import OperationError
+
 from pypy.module.oracle import roci, config
+from pypy.rlib.unroll import unrolling_iterable
+
+exported_names = unrolling_iterable("""
+    DatabaseError OperationalError InterfaceError ProgrammingError
+    NotSupportedError IntegrityError InternalError DataError
+    Variable Connection""".split())
 
 class State:
     # XXX move to another file
+
     def __init__(self, space):
-        w_module = space.getbuiltinmodule('cx_Oracle')
-        def get(name):
-            return space.getattr(w_module, space.wrap(name))
+        "NOT_RPYTHON"
+        self.variableTypeByPythonType = {}
+        self.w_DecimalType = None
+        self.w_DateTimeType = None
+        self.w_DateType = None
+        self.w_TimedeltaType = None
 
-        self.w_DatabaseError = get('DatabaseError')
-        self.w_OperationalError = get('OperationalError')
-        self.w_InterfaceError = get('InterfaceError')
-        self.w_ProgrammingError = get('ProgrammingError')
-        self.w_NotSupportedError = get('NotSupportedError')
-        self.w_IntegrityError = get('IntegrityError')
-        self.w_InternalError = get('InternalError')
-        self.w_DataError = get('DataError')
-        self.w_Variable = get('Variable')
-        self.w_Connection = get('Connection')
+        for name in exported_names:
+            setattr(self, 'w_' + name, None)
+
+    def startup(self, space):
+        w_module = space.getbuiltinmodule('cx_Oracle')
+        for name in exported_names:
+            setattr(self, 'w_' + name, space.getattr(w_module, space.wrap(name)))
 
         from pypy.module.oracle.interp_variable import all_variable_types
-        self.variableTypeByPythonType = {}
         for varType in all_variable_types:
             w_type = space.gettypeobject(varType.typedef)
             self.variableTypeByPythonType[w_type] = varType
 
+        (self.w_DecimalType,
+         self.w_DateTimeType, self.w_DateType, self.w_TimedeltaType,
+         ) = space.fixedview(space.appexec([], """():
+             import decimal, datetime
+             return (decimal.Decimal,
+                     datetime.datetime, datetime.date, datetime.timedelta)
+        """))
+
 def get(space): 
     return space.fromcache(State) 
 

Modified: pypy/branch/virtual-forcing/pypy/module/thread/__init__.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/thread/__init__.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/thread/__init__.py	Tue Dec 29 10:12:39 2009
@@ -18,11 +18,6 @@
         'allocate':               'os_lock.allocate_lock',  # obsolete synonym
         'LockType':               'os_lock.getlocktype(space)',
         '_local':                 'os_local.getlocaltype(space)',
-
-        # custom interface for the 'imp' module
-        '_importlock_held':       'importlock.held',
-        '_importlock_acquire':    'importlock.acquire',
-        '_importlock_release':    'importlock.release',
     }
 
     def __init__(self, space, *args):

Modified: pypy/branch/virtual-forcing/pypy/module/zipimport/__init__.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/zipimport/__init__.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/zipimport/__init__.py	Tue Dec 29 10:12:39 2009
@@ -14,4 +14,12 @@
     appleveldefs = {
         'ZipImportError'      : 'app_zipimport.ZipImportError',
     }
-    
+
+    def setup_after_space_initialization(self):
+        """NOT_RPYTHON"""
+        space = self.space
+        # install zipimport hook
+        w_path_hooks = space.sys.get('path_hooks')
+        from pypy.module.zipimport.interp_zipimport import W_ZipImporter
+        w_zipimporter = space.gettypefor(W_ZipImporter)
+        space.call_method(w_path_hooks, 'append', w_zipimporter)

Modified: pypy/branch/virtual-forcing/pypy/module/zipimport/interp_zipimport.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/zipimport/interp_zipimport.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/zipimport/interp_zipimport.py	Tue Dec 29 10:12:39 2009
@@ -5,7 +5,7 @@
 from pypy.interpreter.gateway import interp2app
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.interpreter.module import Module
-from pypy.module.__builtin__ import importing
+from pypy.module.imp import importing
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.rzipfile import RZipFile, BadZipfile
 import os
@@ -149,9 +149,9 @@
         real_name = self.name + os.path.sep + self.corr_zname(filename)
         space.setattr(w_mod, w('__loader__'), space.wrap(self))
         importing._prepare_module(space, w_mod, real_name, pkgpath)
-        result = importing.load_source_module(space, w(modname), w_mod,
-                                            filename, buf, write_pyc=False)
-        return result
+        code_w = importing.parse_source_module(space, filename, buf)
+        importing.exec_code_module(space, w_mod, code_w)
+        return w_mod
 
     def _parse_mtime(self, space, filename):
         w = space.wrap

Modified: pypy/branch/virtual-forcing/pypy/module/zipimport/test/test_zipimport.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/module/zipimport/test/test_zipimport.py	(original)
+++ pypy/branch/virtual-forcing/pypy/module/zipimport/test/test_zipimport.py	Tue Dec 29 10:12:39 2009
@@ -4,7 +4,7 @@
 import py
 import time
 import struct
-from pypy.module.__builtin__.importing import get_pyc_magic, _w_long
+from pypy.module.imp.importing import get_pyc_magic, _w_long
 from StringIO import StringIO
 
 from pypy.tool.udir import udir
@@ -255,6 +255,11 @@
         l = [i for i in zipimport._zip_directory_cache]
         assert len(l)
 
+    def test_path_hooks(self):
+        import sys
+        import zipimport
+        assert sys.path_hooks.count(zipimport.zipimporter) == 1
+
 class AppTestZipimportDeflated(AppTestZipimport):
     compression = ZIP_DEFLATED
 

Modified: pypy/branch/virtual-forcing/pypy/objspace/flow/flowcontext.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/objspace/flow/flowcontext.py	(original)
+++ pypy/branch/virtual-forcing/pypy/objspace/flow/flowcontext.py	Tue Dec 29 10:12:39 2009
@@ -385,6 +385,9 @@
             operr = OperationError(operr.w_type, operr.w_value)
         return operr
 
+    def exception_trace(self, frame, operationerr):
+        pass    # overridden for performance only
+
     # hack for unrolling iterables, don't use this
     def replace_in_stack(self, oldvalue, newvalue):
         w_new = Constant(newvalue)

Modified: pypy/branch/virtual-forcing/pypy/rlib/rgc.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rlib/rgc.py	(original)
+++ pypy/branch/virtual-forcing/pypy/rlib/rgc.py	Tue Dec 29 10:12:39 2009
@@ -357,3 +357,8 @@
     keepalive_until_here(source)
     keepalive_until_here(dest)
 ll_arraycopy._annspecialcase_ = 'specialize:ll'
+
+def no_collect(func):
+    func._dont_inline_ = True
+    func._gc_no_collect_ = True
+    return func

Modified: pypy/branch/virtual-forcing/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/virtual-forcing/pypy/rpython/memory/gctransform/framework.py	Tue Dec 29 10:12:39 2009
@@ -567,6 +567,12 @@
         f.close()
 
     def transform_graph(self, graph):
+        func = getattr(graph, 'func', None)
+        if func and getattr(func, '_gc_no_collect_', False):
+            if self.collect_analyzer.analyze_direct_call(graph):
+                raise Exception("no_collect function can trigger collection: %s"
+                                % func.__name__)
+            
         if self.write_barrier_ptr:
             self.clean_sets = (
                 find_clean_setarrayitems(self.collect_analyzer, graph).union(

Modified: pypy/branch/virtual-forcing/pypy/rpython/memory/gctransform/test/test_framework.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rpython/memory/gctransform/test/test_framework.py	(original)
+++ pypy/branch/virtual-forcing/pypy/rpython/memory/gctransform/test/test_framework.py	Tue Dec 29 10:12:39 2009
@@ -1,5 +1,6 @@
 from pypy.objspace.flow.model import Constant, SpaceOperation
 from pypy.annotation.model import SomeInteger
+from pypy.annotation.listdef import s_list_of_strings
 from pypy.rpython.memory.gc.marksweep import MarkSweepGC
 from pypy.rpython.memory.gctransform.test.test_transform import rtype, \
     rtype_and_transform
@@ -34,7 +35,6 @@
     from pypy.rpython.llinterp import LLInterpreter
     from pypy.translator.c.genc import CStandaloneBuilder
     from pypy.translator.c import gc
-    from pypy.annotation.listdef import s_list_of_strings
 
     t = rtype(entrypoint, [s_list_of_strings])
     cbuild = CStandaloneBuilder(t, entrypoint, t.config,
@@ -113,6 +113,50 @@
     gg = graphof(t, g)
     assert CollectAnalyzer(t).analyze_direct_call(gg)
 
+def test_no_collect():
+    from pypy.rlib import rgc
+    from pypy.translator.c.genc import CStandaloneBuilder
+    from pypy.translator.c import gc
+
+    @rgc.no_collect
+    def g():
+        return 1
+
+    assert g._dont_inline_
+    assert g._gc_no_collect_
+
+    def entrypoint(argv):
+        return g() + 2
+    
+    t = rtype(entrypoint, [s_list_of_strings])
+    cbuild = CStandaloneBuilder(t, entrypoint, t.config,
+                                gcpolicy=FrameworkGcPolicy2)
+    db = cbuild.generate_graphs_for_llinterp()
+
+def test_no_collect_detection():
+    from pypy.rlib import rgc
+    from pypy.translator.c.genc import CStandaloneBuilder
+    from pypy.translator.c import gc
+
+    class A(object):
+        def __init__(self, x):
+            self.x = x
+
+    @rgc.no_collect
+    def g():
+        return A(1).x
+
+    assert g._dont_inline_
+    assert g._gc_no_collect_
+
+    def entrypoint(argv):
+        return g() + 2
+    
+    t = rtype(entrypoint, [s_list_of_strings])
+    cbuild = CStandaloneBuilder(t, entrypoint, t.config,
+                                gcpolicy=FrameworkGcPolicy2)
+    f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp)
+    assert str(f.value) == 'no_collect function can trigger collection: g'
 
 class WriteBarrierTransformer(FrameworkGCTransformer):
     clean_sets = {}

Modified: pypy/branch/virtual-forcing/pypy/rpython/rptr.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rpython/rptr.py	(original)
+++ pypy/branch/virtual-forcing/pypy/rpython/rptr.py	Tue Dec 29 10:12:39 2009
@@ -39,6 +39,14 @@
         attr = hop.args_s[1].const
         if isinstance(hop.s_result, annmodel.SomeLLADTMeth):
             return hop.inputarg(hop.r_result, arg=0)
+        try:
+            self.lowleveltype._example()._lookup_adtmeth(attr)
+        except AttributeError:
+            pass
+        else:
+            assert hop.s_result.is_constant()
+            return hop.inputconst(hop.r_result, hop.s_result.const)
+        assert attr in self.lowleveltype.TO._flds # check that the field exists
         FIELD_TYPE = getattr(self.lowleveltype.TO, attr)
         if isinstance(FIELD_TYPE, lltype.ContainerType):
             if (attr, FIELD_TYPE) == self.lowleveltype.TO._first_struct():

Modified: pypy/branch/virtual-forcing/pypy/rpython/test/test_rptr.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rpython/test/test_rptr.py	(original)
+++ pypy/branch/virtual-forcing/pypy/rpython/test/test_rptr.py	Tue Dec 29 10:12:39 2009
@@ -337,3 +337,13 @@
         return f([1])
     s, t = ll_rtype(lltest, [])
     assert s.is_constant() == False
+
+def test_staticadtmeths():
+    ll_func = staticAdtMethod(lambda x: x + 42)
+    S = GcStruct('S', adtmeths={'ll_func': ll_func})
+    def f():
+        return malloc(S).ll_func(5)
+    s, t = ll_rtype(f, [])
+    graphf = t.graphs[0]
+    for op in graphf.startblock.operations:
+        assert op.opname != 'getfield'

Modified: pypy/branch/virtual-forcing/pypy/rpython/tool/rffi_platform.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rpython/tool/rffi_platform.py	(original)
+++ pypy/branch/virtual-forcing/pypy/rpython/tool/rffi_platform.py	Tue Dec 29 10:12:39 2009
@@ -644,7 +644,7 @@
         else:
             raise CompilationError("Library %s is not installed" % (name,))
 
-def check_boehm(platform=None):
+def configure_boehm(platform=None):
     if platform is None:
         from pypy.translator.platform import platform
     if sys.platform == 'win32':
@@ -658,13 +658,10 @@
         includes=includes,
         libraries=['gc'],
         )
-    try:
-        return configure_external_library(
-            'gc', eci,
-            [dict(prefix='gc-', include_dir='include', library_dir=library_dir)],
-            symbol='GC_init')
-    except CompilationError:
-        return None
+    return configure_external_library(
+        'gc', eci,
+        [dict(prefix='gc-', include_dir='include', library_dir=library_dir)],
+        symbol='GC_init')
 
 if __name__ == '__main__':
     doc = """Example:

Modified: pypy/branch/virtual-forcing/pypy/tool/gcc_cache.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/tool/gcc_cache.py	(original)
+++ pypy/branch/virtual-forcing/pypy/tool/gcc_cache.py	Tue Dec 29 10:12:39 2009
@@ -10,7 +10,7 @@
 def cache_file_path(c_files, eci, cachename):
     cache_dir = cache_dir_root.join(cachename).ensure(dir=1)
     filecontents = [c_file.read() for c_file in c_files]
-    key = repr((filecontents, eci))
+    key = repr((filecontents, eci, platform.key()))
     hash = md5(key).hexdigest()
     return cache_dir.join(hash)
 

Modified: pypy/branch/virtual-forcing/pypy/tool/udir.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/tool/udir.py	(original)
+++ pypy/branch/virtual-forcing/pypy/tool/udir.py	Tue Dec 29 10:12:39 2009
@@ -18,7 +18,7 @@
 #
 
 import autopath
-import os
+import os, sys
 import py
 
 from py.path import local 
@@ -39,6 +39,8 @@
         try:
             p = py.path.local(__file__).dirpath()
             basename = svn_info(py.path.svnwc(p).info().url)
+            if isinstance(basename, unicode):
+                basename = basename.encode(sys.getdefaultencoding())
         except:
             basename = ''
     if not basename.startswith('-'):

Modified: pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_writeanalyze.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_writeanalyze.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_writeanalyze.py	Tue Dec 29 10:12:39 2009
@@ -4,14 +4,15 @@
 from pypy.translator.translator import TranslationContext, graphof
 from pypy.translator.simplify import get_funcobj
 from pypy.translator.backendopt.writeanalyze import WriteAnalyzer, top_set
+from pypy.translator.backendopt.writeanalyze import ReadWriteAnalyzer
 from pypy.translator.backendopt.all import backend_optimizations
 from pypy.conftest import option
 
 
-class BaseTestCanRaise(object):
+class BaseTest(object):
 
     type_system = None
-
+    Analyzer = WriteAnalyzer
     
     def translate(self, func, sig):
         t = TranslationContext()
@@ -19,7 +20,10 @@
         t.buildrtyper(type_system=self.type_system).specialize()
         if option.view:
             t.view()
-        return t, WriteAnalyzer(t)
+        return t, self.Analyzer(t)
+
+
+class BaseTestWriteAnalyze(BaseTest):
 
     def test_writes_simple(self):
         def g(x):
@@ -146,7 +150,7 @@
         assert not result
 
 
-class TestLLtype(BaseTestCanRaise):
+class TestLLtype(BaseTestWriteAnalyze):
     type_system = 'lltype'
 
     def test_list(self):
@@ -205,7 +209,7 @@
         assert name.endswith("foobar")
 
 
-class TestOOtype(BaseTestCanRaise):
+class TestOOtype(BaseTestWriteAnalyze):
     type_system = 'ootype'
     
     def test_array(self):
@@ -240,3 +244,88 @@
 
         result = wa.analyze(ggraph.startblock.operations[0])
         assert result is top_set
+
+
+class TestLLtypeReadWriteAnalyze(BaseTest):
+    Analyzer = ReadWriteAnalyzer
+    type_system = 'lltype'
+
+    def test_read_simple(self):
+        def g(x):
+            return True
+
+        def f(x):
+            return g(x - 1)
+        t, wa = self.translate(f, [int])
+        fgraph = graphof(t, f)
+        result = wa.analyze(fgraph.startblock.operations[0])
+        assert not result
+
+    def test_read_really(self):
+        class A(object):
+            def __init__(self, y):
+                self.y = y
+            def f(self):
+                self.x = 1
+                return self.y
+        def h(flag):
+            obj = A(flag)
+            return obj.f()
+        
+        t, wa = self.translate(h, [int])
+        hgraph = graphof(t, h)
+        op_call_f = hgraph.startblock.operations[-1]
+
+        # check that we fished the expected ops
+        assert op_call_f.opname == "direct_call"
+        assert get_funcobj(op_call_f.args[0].value)._name == 'A.f'
+
+        result = wa.analyze(op_call_f)
+        assert len(result) == 2
+        result = list(result)
+        result.sort()
+        [(struct1, T1, name1), (struct2, T2, name2)] = result
+        assert struct1 == "readstruct"
+        assert name1.endswith("y")
+        assert struct2 == "struct"
+        assert name2.endswith("x")
+        assert T1 == T2
+
+    def test_contains(self):
+        def g(x, y, z):
+            l = [x]
+            return f(l, y, z)
+        def f(x, y, z):
+            return y in x
+
+        t, wa = self.translate(g, [int, int, int])
+        ggraph = graphof(t, g)
+        assert ggraph.startblock.operations[-1].opname == 'direct_call'
+
+        result = wa.analyze(ggraph.startblock.operations[-1])
+        ARRAYPTR = list(result)[0][1]
+        assert list(result) == [("readarray", ARRAYPTR)]
+        assert isinstance(ARRAYPTR.TO, lltype.GcArray)
+
+    def test_adt_method(self):
+        def ll_callme(n):
+            return n
+        ll_callme = lltype.staticAdtMethod(ll_callme)
+        S = lltype.GcStruct('S', ('x', lltype.Signed),
+                            adtmeths = {'yep': True,
+                                        'callme': ll_callme})
+        def g(x, y, z):
+            p = lltype.malloc(S)
+            p.x = x
+            if p.yep:
+                z *= p.callme(y)
+            return z
+        def f(x, y, z):
+            return g(x, y, z)
+
+        t, wa = self.translate(f, [int, int, int])
+        fgraph = graphof(t, f)
+        assert fgraph.startblock.operations[-1].opname == 'direct_call'
+
+        result = wa.analyze(fgraph.startblock.operations[-1])
+        assert list(result) == [("struct", lltype.Ptr(S), "x")]

Modified: pypy/branch/virtual-forcing/pypy/translator/backendopt/writeanalyze.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/backendopt/writeanalyze.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/backendopt/writeanalyze.py	Tue Dec 29 10:12:39 2009
@@ -45,3 +45,15 @@
             elif methname in ('ll_getitem_fast', 'll_length'):
                 return self.bottom_result()
         return graphanalyze.GraphAnalyzer.analyze_external_method(self, op, TYPE, meth)
+
+
+class ReadWriteAnalyzer(WriteAnalyzer):
+
+    def analyze_simple_operation(self, op):
+        if op.opname == "getfield":
+            return frozenset([
+                ("readstruct", op.args[0].concretetype, op.args[1].value)])
+        elif op.opname == "getarrayitem":
+            return frozenset([
+                ("readarray", op.args[0].concretetype)])
+        return WriteAnalyzer.analyze_simple_operation(self, op)

Modified: pypy/branch/virtual-forcing/pypy/translator/c/gc.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/c/gc.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/c/gc.py	Tue Dec 29 10:12:39 2009
@@ -215,8 +215,8 @@
     def compilation_info(self):
         eci = BasicGcPolicy.compilation_info(self)
 
-        from pypy.rpython.tool.rffi_platform import check_boehm
-        eci = eci.merge(check_boehm())
+        from pypy.rpython.tool.rffi_platform import configure_boehm
+        eci = eci.merge(configure_boehm())
 
         pre_include_bits = []
         if sys.platform == "linux2":

Modified: pypy/branch/virtual-forcing/pypy/translator/c/test/test_boehm.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/c/test/test_boehm.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/c/test/test_boehm.py	Tue Dec 29 10:12:39 2009
@@ -3,12 +3,15 @@
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.memory.test import snippet
-from pypy.rpython.tool.rffi_platform import check_boehm
 from pypy.translator.c.genc import CExtModuleBuilder
 from pypy import conftest
 
 def setup_module(mod):
-    if not check_boehm():
+    from pypy.rpython.tool.rffi_platform import configure_boehm
+    from pypy.translator.platform import CompilationError
+    try:
+        configure_boehm()
+    except CompilationError:
         py.test.skip("Boehm GC not present")
 
 class AbstractGCTestClass(object):

Modified: pypy/branch/virtual-forcing/pypy/translator/c/test/test_stackless.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/c/test/test_stackless.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/c/test/test_stackless.py	Tue Dec 29 10:12:39 2009
@@ -20,8 +20,11 @@
             import py
             py.test.skip("stackless + refcounting doesn't work any more for now")
         elif cls.gcpolicy == "boehm":
-            from pypy.rpython.tool.rffi_platform import check_boehm
-            if not check_boehm():
+            from pypy.rpython.tool.rffi_platform import configure_boehm
+            from pypy.translator.platform import CompilationError
+            try:
+                configure_boehm()
+            except CompilationError:
                 py.test.skip("Boehm GC not present")
 
     def wrap_stackless_function(self, fn):

Modified: pypy/branch/virtual-forcing/pypy/translator/driver.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/driver.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/driver.py	Tue Dec 29 10:12:39 2009
@@ -428,10 +428,13 @@
 
     def possibly_check_for_boehm(self):
         if self.config.translation.gc == "boehm":
-            from pypy.rpython.tool.rffi_platform import check_boehm
-            if not check_boehm(self.translator.platform):
+            from pypy.rpython.tool.rffi_platform import configure_boehm
+            from pypy.translator.platform import CompilationError
+            try:
+                configure_boehm(self.translator.platform)
+            except CompilationError, e:
                 i = 'Boehm GC not installed.  Try e.g. "translate.py --gc=hybrid"'
-                raise Exception(i)
+                raise Exception(str(e) + '\n' + i)
 
     def task_database_c(self):
         translator = self.translator

Modified: pypy/branch/virtual-forcing/pypy/translator/platform/__init__.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/platform/__init__.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/platform/__init__.py	Tue Dec 29 10:12:39 2009
@@ -52,6 +52,8 @@
     name = "abstract platform"
     c_environ = None
 
+    relevant_environ = []
+
     so_prefixes = ['']
 
     def __init__(self, cc):
@@ -98,6 +100,12 @@
         return (self.__class__ is other.__class__ and
                 self.__dict__ == other.__dict__)
 
+    def key(self):
+        bits = [self.__class__.__name__, 'cc=%s' % self.cc]
+        for varname in self.relevant_environ:
+            bits.append('%s=%s' % (varname, os.environ.get(varname)))
+        return ' '.join(bits)
+
     # some helpers which seem to be cross-platform enough
 
     def _execute_c_compiler(self, cc, args, outname):
@@ -171,8 +179,15 @@
     else:
         host_factory = Linux64
 elif sys.platform == 'darwin':
-    from pypy.translator.platform.darwin import Darwin
-    host_factory = Darwin
+    from pypy.translator.platform.darwin import Darwin_i386, Darwin_x86_64
+    import platform
+    if platform.machine() == 'i386':
+        if sys.maxint <= 2147483647:
+            host_factory = Darwin_i386
+        else:
+            host_factory = Darwin_x86_64
+    else:
+        host_factory = Darwin
 elif sys.platform == 'freebsd7':
     from pypy.translator.platform.freebsd7 import Freebsd7, Freebsd7_64
     import platform

Modified: pypy/branch/virtual-forcing/pypy/translator/platform/darwin.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/platform/darwin.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/platform/darwin.py	Tue Dec 29 10:12:39 2009
@@ -4,7 +4,7 @@
 
 class Darwin(posix.BasePosix):
     name = "darwin"
-    
+
     link_flags = ['-mmacosx-version-min=10.4']
     cflags = ['-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
     standalone_only = ['-mdynamic-no-pic']
@@ -44,3 +44,13 @@
         include_dirs = self._includedirs(eci.include_dirs)
         return (args + frameworks + include_dirs)
 
+class Darwin_i386(Darwin):
+    name = "darwin_i386"
+    link_flags = ['-arch', 'i386', '-mmacosx-version-min=10.4']
+    cflags = ['-arch', 'i386', '-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
+
+class Darwin_x86_64(Darwin):
+    name = "darwin_x86_64"
+    link_flags = ['-arch', 'x86_64', '-mmacosx-version-min=10.4']
+    cflags = ['-arch', 'x86_64', '-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
+

Modified: pypy/branch/virtual-forcing/pypy/translator/platform/posix.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/platform/posix.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/platform/posix.py	Tue Dec 29 10:12:39 2009
@@ -10,6 +10,8 @@
     exe_ext = ''
     make_cmd = 'make'
 
+    relevant_environ=['CPATH', 'LIBRARY_PATH', 'C_INCLUDE_PATH']
+
     def __init__(self, cc=None):
         if cc is None:
             cc = 'gcc'

Modified: pypy/branch/virtual-forcing/pypy/translator/platform/test/test_darwin.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/platform/test/test_darwin.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/platform/test/test_darwin.py	Tue Dec 29 10:12:39 2009
@@ -2,17 +2,25 @@
 """ File containing darwin platform tests
 """
 
-import py, sys
+import py, sys, platform
 if sys.platform != 'darwin':
     py.test.skip("Darwin only")
 
 from pypy.tool.udir import udir
-from pypy.translator.platform.darwin import Darwin
+from pypy.translator.platform.darwin import Darwin_i386, Darwin_x86_64
 from pypy.translator.platform.test.test_platform import TestPlatform as BasicTest
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
+if platform.machine() == 'i386':
+    if sys.maxint <= 2147483647:
+        host_factory = Darwin_i386
+    else:
+        host_factory = Darwin_x86_64
+else:
+    host_factory = Darwin
+
 class TestDarwin(BasicTest):
-    platform = Darwin()
+    platform = host_factory()
 
     def test_frameworks(self):
         objcfile = udir.join('test_simple.m')
@@ -39,3 +47,81 @@
         res = self.platform.execute(executable)
         self.check_res(res)
 
+    def test_64_32_results(self):
+        if platform.machine() != 'i386':
+            py.test.skip("i386 only")
+        plat32 = Darwin_i386()
+        plat64 = Darwin_x86_64()
+        cfile = udir.join('test_int_size.c')
+        cfile.write(r'''
+        #include <stdio.h>
+        #include <limits.h>
+
+        int main() {
+                printf("%d\n", INT_MAX < LONG_MAX);
+                return 0;
+        }
+        ''')
+        eci = ExternalCompilationInfo()
+        executable = plat32.compile([cfile], eci)
+        res = plat32.execute(executable)
+        self.check_res(res, '0\n')
+        if host_factory == Darwin_x86_64:
+            executable = plat64.compile([cfile], eci)
+            res = plat64.execute(executable)
+            self.check_res(res, '1\n')
+
+    def test_longsize(self):
+        if platform.machine() != 'i386':
+            py.test.skip("i386 only")
+        cfile = udir.join('test_int_size.c')
+        cfile.write(r'''
+        #include <stdio.h>
+        #include <limits.h>
+
+        int main() {
+                printf("%ld\n", LONG_MAX);
+                return 0;
+        }
+        ''')
+        eci = ExternalCompilationInfo()
+        executable = self.platform.compile([cfile], eci)
+        res = self.platform.execute(executable)
+        self.check_res(res, str(sys.maxint) + '\n')
+        
+    def test_32bit_makefile(self):
+        if platform.machine() != 'i386':
+            py.test.skip("i386 only")
+        plat32 = Darwin_i386()
+        plat64 = Darwin_x86_64()
+        eci = ExternalCompilationInfo()
+        cfile_content =r'''
+        #include <stdio.h>
+        #include <limits.h>
+
+        int main() {
+                printf("%d\n", INT_MAX < LONG_MAX);
+                return 0;
+        }
+        '''
+
+        tmpdir = udir.join('32_makefile' + self.__class__.__name__).ensure(dir=1)
+        cfile = tmpdir.join('test_int_size.c')
+        cfile.write(cfile_content)
+        mk = plat32.gen_makefile([cfile], ExternalCompilationInfo(),
+                               path=tmpdir)
+        mk.write()
+        plat32.execute_makefile(mk)
+        res = plat32.execute(tmpdir.join('test_int_size'))
+        self.check_res(res, '0\n')
+        if host_factory == Darwin_x86_64:
+            tmpdir = udir.join('64_makefile' + self.__class__.__name__).ensure(dir=1)
+            cfile = tmpdir.join('test_int_size.c')
+            cfile.write(cfile_content)
+            mk = plat64.gen_makefile([cfile], ExternalCompilationInfo(),
+                                   path=tmpdir)
+            mk.write()
+            plat64.execute_makefile(mk)
+            res = plat64.execute(tmpdir.join('test_int_size'))
+            self.check_res(res, '1\n')
+

Modified: pypy/branch/virtual-forcing/pypy/translator/platform/test/test_platform.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/platform/test/test_platform.py	(original)
+++ pypy/branch/virtual-forcing/pypy/translator/platform/test/test_platform.py	Tue Dec 29 10:12:39 2009
@@ -115,6 +115,16 @@
         finally:
             del os.environ['_SOME_VARIABLE_2']
 
+    def test_key(self):
+        class XPlatform(Platform):
+            relevant_environ = ['CPATH']
+            
+            def __init__(self):
+                self.cc = 'xcc'
+        x = XPlatform()
+        res = x.key()
+        assert res.startswith('XPlatform cc=xcc CPATH=')
+
 def test_equality():
     class X(Platform):
         def __init__(self):



More information about the Pypy-commit mailing list