[pypy-svn] r79389 - in pypy/branch/jitypes2: . lib-python/modified-2.5.2/distutils lib_pypy/_ctypes lib_pypy/ctypes_config_cache/test pypy pypy/annotation pypy/config pypy/doc pypy/doc/config pypy/interpreter pypy/interpreter/test pypy/jit/backend/llsupport pypy/jit/backend/llsupport/test pypy/jit/backend/test pypy/jit/backend/x86 pypy/jit/codewriter pypy/jit/codewriter/test pypy/jit/metainterp pypy/jit/metainterp/optimizeopt pypy/jit/metainterp/test pypy/jit/tool pypy/jit/tool/test pypy/module/__pypy__ pypy/module/_rawffi/test pypy/module/_stackless/test pypy/module/array pypy/module/array/benchmark pypy/module/array/test pypy/module/cpyext pypy/module/cpyext/test pypy/module/gc pypy/module/gc/test pypy/module/imp pypy/module/imp/test pypy/module/posix pypy/module/pypyjit pypy/module/pypyjit/test pypy/module/rctime pypy/module/sys pypy/module/sys/test pypy/objspace/flow pypy/objspace/std pypy/objspace/std/test pypy/rlib pypy/rlib/test pypy/rpython pypy/rpython/lltypesystem pypy/rpython/memory pypy/rpython/memory/gc pypy/rpython/memory/gc/test pypy/rpython/memory/gctransform pypy/rpython/memory/test pypy/rpython/test pypy/tool pypy/tool/release pypy/tool/release/test pypy/translator/c pypy/translator/c/gcc pypy/translator/c/gcc/test pypy/translator/c/src pypy/translator/c/test pypy/translator/cli/src pypy/translator/goal pypy/translator/goal/test2 pypy/translator/platform

antocuni at codespeak.net antocuni at codespeak.net
Tue Nov 23 13:26:41 CET 2010


Author: antocuni
Date: Tue Nov 23 13:26:19 2010
New Revision: 79389

Added:
   pypy/branch/jitypes2/pypy/doc/config/objspace.soabi.txt
      - copied unchanged from r79388, pypy/trunk/pypy/doc/config/objspace.soabi.txt
   pypy/branch/jitypes2/pypy/doc/config/objspace.translationmodules.txt
      - copied unchanged from r79388, pypy/trunk/pypy/doc/config/objspace.translationmodules.txt
   pypy/branch/jitypes2/pypy/doc/release-1.4.0beta.txt
      - copied unchanged from r79388, pypy/trunk/pypy/doc/release-1.4.0beta.txt
   pypy/branch/jitypes2/pypy/jit/tool/log-template.gnumeric
      - copied unchanged from r79388, pypy/trunk/pypy/jit/tool/log-template.gnumeric
   pypy/branch/jitypes2/pypy/jit/tool/log2gnumeric.py
      - copied unchanged from r79388, pypy/trunk/pypy/jit/tool/log2gnumeric.py
   pypy/branch/jitypes2/pypy/jit/tool/loopcounter.py
      - copied unchanged from r79388, pypy/trunk/pypy/jit/tool/loopcounter.py
   pypy/branch/jitypes2/pypy/jit/tool/test/test_loopcounter.py
      - copied unchanged from r79388, pypy/trunk/pypy/jit/tool/test/test_loopcounter.py
   pypy/branch/jitypes2/pypy/jit/tool/test/test_oparser.py
      - copied unchanged from r79388, pypy/trunk/pypy/jit/tool/test/test_oparser.py
   pypy/branch/jitypes2/pypy/module/_stackless/test/conftest.py
      - copied unchanged from r79388, pypy/trunk/pypy/module/_stackless/test/conftest.py
   pypy/branch/jitypes2/pypy/tool/gcdump.py
      - copied unchanged from r79388, pypy/trunk/pypy/tool/gcdump.py
   pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86_64.h
      - copied unchanged from r79388, pypy/trunk/pypy/translator/c/src/asm_gcc_x86_64.h
Removed:
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_oparser.py
Modified:
   pypy/branch/jitypes2/   (props changed)
   pypy/branch/jitypes2/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py
   pypy/branch/jitypes2/lib_pypy/_ctypes/function.py
   pypy/branch/jitypes2/lib_pypy/ctypes_config_cache/test/test_cache.py
   pypy/branch/jitypes2/pypy/   (props changed)
   pypy/branch/jitypes2/pypy/annotation/bookkeeper.py
   pypy/branch/jitypes2/pypy/annotation/builtin.py
   pypy/branch/jitypes2/pypy/config/pypyoption.py
   pypy/branch/jitypes2/pypy/config/translationoption.py
   pypy/branch/jitypes2/pypy/conftest.py
   pypy/branch/jitypes2/pypy/doc/release-1.4.0.txt
   pypy/branch/jitypes2/pypy/interpreter/argument.py
   pypy/branch/jitypes2/pypy/interpreter/test/test_argument.py
   pypy/branch/jitypes2/pypy/jit/backend/llsupport/descr.py
   pypy/branch/jitypes2/pypy/jit/backend/llsupport/gc.py
   pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_descr.py
   pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_gc.py
   pypy/branch/jitypes2/pypy/jit/backend/test/runner_test.py
   pypy/branch/jitypes2/pypy/jit/backend/x86/assembler.py
   pypy/branch/jitypes2/pypy/jit/codewriter/assembler.py
   pypy/branch/jitypes2/pypy/jit/codewriter/call.py
   pypy/branch/jitypes2/pypy/jit/codewriter/codewriter.py
   pypy/branch/jitypes2/pypy/jit/codewriter/effectinfo.py
   pypy/branch/jitypes2/pypy/jit/codewriter/jtransform.py
   pypy/branch/jitypes2/pypy/jit/codewriter/test/test_jtransform.py
   pypy/branch/jitypes2/pypy/jit/metainterp/compile.py
   pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/optimizer.py   (contents, props changed)
   pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/string.py
   pypy/branch/jitypes2/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/jitypes2/pypy/jit/metainterp/resoperation.py
   pypy/branch/jitypes2/pypy/jit/metainterp/resume.py
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_compile.py
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_exception.py
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_recursive.py
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resoperation.py
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resume.py
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_virtualref.py
   pypy/branch/jitypes2/pypy/jit/metainterp/test/test_ztranslation.py
   pypy/branch/jitypes2/pypy/jit/metainterp/virtualizable.py
   pypy/branch/jitypes2/pypy/jit/metainterp/warmspot.py
   pypy/branch/jitypes2/pypy/jit/tool/pypytrace-mode.el
   pypy/branch/jitypes2/pypy/module/__pypy__/__init__.py
   pypy/branch/jitypes2/pypy/module/__pypy__/interp_magic.py
   pypy/branch/jitypes2/pypy/module/_rawffi/test/test__rawffi.py
   pypy/branch/jitypes2/pypy/module/_rawffi/test/test_nested.py
   pypy/branch/jitypes2/pypy/module/array/benchmark/Makefile   (props changed)
   pypy/branch/jitypes2/pypy/module/array/benchmark/intimg.c   (props changed)
   pypy/branch/jitypes2/pypy/module/array/benchmark/intimgtst.c   (props changed)
   pypy/branch/jitypes2/pypy/module/array/benchmark/intimgtst.py   (props changed)
   pypy/branch/jitypes2/pypy/module/array/benchmark/loop.c   (props changed)
   pypy/branch/jitypes2/pypy/module/array/benchmark/sum.c   (props changed)
   pypy/branch/jitypes2/pypy/module/array/benchmark/sumtst.c   (props changed)
   pypy/branch/jitypes2/pypy/module/array/benchmark/sumtst.py   (props changed)
   pypy/branch/jitypes2/pypy/module/array/interp_array.py
   pypy/branch/jitypes2/pypy/module/array/test/test_array_old.py   (props changed)
   pypy/branch/jitypes2/pypy/module/cpyext/api.py
   pypy/branch/jitypes2/pypy/module/cpyext/cdatetime.py
   pypy/branch/jitypes2/pypy/module/cpyext/presetup.py
   pypy/branch/jitypes2/pypy/module/cpyext/pyobject.py
   pypy/branch/jitypes2/pypy/module/cpyext/test/test_borrow.py
   pypy/branch/jitypes2/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/jitypes2/pypy/module/cpyext/typeobject.py
   pypy/branch/jitypes2/pypy/module/gc/__init__.py
   pypy/branch/jitypes2/pypy/module/gc/app_referents.py
   pypy/branch/jitypes2/pypy/module/gc/interp_gc.py
   pypy/branch/jitypes2/pypy/module/gc/referents.py
   pypy/branch/jitypes2/pypy/module/gc/test/test_gc.py
   pypy/branch/jitypes2/pypy/module/imp/importing.py
   pypy/branch/jitypes2/pypy/module/imp/interp_imp.py
   pypy/branch/jitypes2/pypy/module/imp/test/test_app.py
   pypy/branch/jitypes2/pypy/module/imp/test/test_import.py
   pypy/branch/jitypes2/pypy/module/posix/interp_posix.py
   pypy/branch/jitypes2/pypy/module/pypyjit/__init__.py
   pypy/branch/jitypes2/pypy/module/pypyjit/test/test_pypy_c.py
   pypy/branch/jitypes2/pypy/module/rctime/interp_time.py
   pypy/branch/jitypes2/pypy/module/sys/state.py
   pypy/branch/jitypes2/pypy/module/sys/test/test_initialpath.py
   pypy/branch/jitypes2/pypy/objspace/flow/model.py
   pypy/branch/jitypes2/pypy/objspace/std/callmethod.py
   pypy/branch/jitypes2/pypy/objspace/std/mapdict.py
   pypy/branch/jitypes2/pypy/objspace/std/test/test_dictmultiobject.py
   pypy/branch/jitypes2/pypy/objspace/std/test/test_mapdict.py
   pypy/branch/jitypes2/pypy/rlib/clibffi.py
   pypy/branch/jitypes2/pypy/rlib/rerased.py   (props changed)
   pypy/branch/jitypes2/pypy/rlib/rgc.py
   pypy/branch/jitypes2/pypy/rlib/test/test_rerased.py   (props changed)
   pypy/branch/jitypes2/pypy/rpython/annlowlevel.py
   pypy/branch/jitypes2/pypy/rpython/llinterp.py
   pypy/branch/jitypes2/pypy/rpython/lltypesystem/llarena.py
   pypy/branch/jitypes2/pypy/rpython/lltypesystem/llmemory.py
   pypy/branch/jitypes2/pypy/rpython/lltypesystem/lloperation.py
   pypy/branch/jitypes2/pypy/rpython/lltypesystem/lltype.py
   pypy/branch/jitypes2/pypy/rpython/lltypesystem/rffi.py
   pypy/branch/jitypes2/pypy/rpython/memory/gc/base.py
   pypy/branch/jitypes2/pypy/rpython/memory/gc/generation.py
   pypy/branch/jitypes2/pypy/rpython/memory/gc/inspector.py
   pypy/branch/jitypes2/pypy/rpython/memory/gc/minimark.py
   pypy/branch/jitypes2/pypy/rpython/memory/gc/semispace.py
   pypy/branch/jitypes2/pypy/rpython/memory/gc/test/test_minimark.py
   pypy/branch/jitypes2/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/jitypes2/pypy/rpython/memory/support.py
   pypy/branch/jitypes2/pypy/rpython/memory/test/test_gc.py
   pypy/branch/jitypes2/pypy/rpython/rbuiltin.py
   pypy/branch/jitypes2/pypy/rpython/test/test_rpbc.py
   pypy/branch/jitypes2/pypy/tool/release/force-builds.py
   pypy/branch/jitypes2/pypy/tool/release/make_release.py
   pypy/branch/jitypes2/pypy/tool/release/package.py
   pypy/branch/jitypes2/pypy/tool/release/test/test_package.py
   pypy/branch/jitypes2/pypy/tool/terminal.py
   pypy/branch/jitypes2/pypy/translator/c/gcc/test/test_trackgcroot.py
   pypy/branch/jitypes2/pypy/translator/c/gcc/trackgcroot.py
   pypy/branch/jitypes2/pypy/translator/c/genc.py
   pypy/branch/jitypes2/pypy/translator/c/node.py
   pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86.h
   pypy/branch/jitypes2/pypy/translator/c/src/debug_print.h
   pypy/branch/jitypes2/pypy/translator/c/src/g_include.h
   pypy/branch/jitypes2/pypy/translator/c/test/test_lltyped.py
   pypy/branch/jitypes2/pypy/translator/c/test/test_newgc.py
   pypy/branch/jitypes2/pypy/translator/c/test/test_standalone.py
   pypy/branch/jitypes2/pypy/translator/cli/src/pypylib.cs
   pypy/branch/jitypes2/pypy/translator/goal/app_main.py
   pypy/branch/jitypes2/pypy/translator/goal/targetpypystandalone.py
   pypy/branch/jitypes2/pypy/translator/goal/test2/test_app_main.py
   pypy/branch/jitypes2/pypy/translator/platform/linux.py
   pypy/branch/jitypes2/pypy/translator/platform/posix.py
Log:
merge from trunk: svn merge svn+ssh://codespeak.net/svn/pypy/trunk -r78974:HEAD

Modified: pypy/branch/jitypes2/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py
==============================================================================
--- pypy/branch/jitypes2/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py	(original)
+++ pypy/branch/jitypes2/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py	Tue Nov 23 13:26:19 2010
@@ -3,6 +3,7 @@
 
 import sys
 import os
+import imp
 
 from distutils.errors import DistutilsPlatformError
 
@@ -47,11 +48,17 @@
 
 _config_vars = None
 
+def _get_so_extension():
+    for ext, mod, typ in imp.get_suffixes():
+        if typ == imp.C_EXTENSION:
+            return ext
+
 def _init_posix():
     """Initialize the module as appropriate for POSIX systems."""
     g = {}
     g['EXE'] = ""
-    g['SO'] = ".so"
+    g['SO'] = _get_so_extension() or ".so"
+    g['SOABI'] = g['SO'].rsplit('.')[0]
 
     global _config_vars
     _config_vars = g
@@ -61,7 +68,8 @@
     """Initialize the module as appropriate for NT"""
     g = {}
     g['EXE'] = ".exe"
-    g['SO'] = ".pyd"
+    g['SO'] = _get_so_extension() or ".pyd"
+    g['SOABI'] = g['SO'].rsplit('.')[0]
 
     global _config_vars
     _config_vars = g

Modified: pypy/branch/jitypes2/lib_pypy/_ctypes/function.py
==============================================================================
--- pypy/branch/jitypes2/lib_pypy/_ctypes/function.py	(original)
+++ pypy/branch/jitypes2/lib_pypy/_ctypes/function.py	Tue Nov 23 13:26:19 2010
@@ -30,6 +30,7 @@
 
     from_address = cdata_from_address
 
+
 class CFuncPtr(_CData):
     __metaclass__ = CFuncPtrType
 
@@ -174,8 +175,8 @@
         
         restype = self._restype_
         funcptr = self._getfuncptr(argtypes, restype, thisarg)
-        return funcptr(*args)
-        #return funcptr(args[0])
+        #return funcptr(*args)
+        return funcptr(args[0])
         #resbuffer = funcptr(*[arg._buffer for _, arg in argsandobjs])
         #return self._build_result(restype, resbuffer, argtypes, argsandobjs)
 
@@ -217,6 +218,8 @@
             ffi_argtypes = [self._shape_to_ffi_type(shape) for shape in argshapes]
             ffi_restype = self._shape_to_ffi_type(resshape)
             self._ptr = cdll.getfunc(self.name, ffi_argtypes, ffi_restype)
+            if len(ffi_argtypes) == 1:
+                self.__class__ = _FuncPtr_1_arg # black magic
             return self._ptr
         except AttributeError:
             if self._flags_ & _rawffi.FUNCFLAG_CDECL:
@@ -393,3 +396,26 @@
                 self._ptr.free()
                 self._ptr = None
             self._needs_free = False
+
+
+# hack hack
+
+#import ctypes
+class _FuncPtr_1_arg(CFuncPtr):
+
+    def _rollback(self, *args):
+        self.__class__ = CFuncPtr
+        return self(*args)
+
+    def __call__(self, arg0):
+        if self.callable is not None or self._com_index:
+            return self._rollback(arg0)
+
+        #argtypes, argsandobjs = self._wrap_args(argtypes, args)
+
+        argtypes = self._argtypes_
+        restype = self._restype_
+        thisarg = None
+        funcptr = self._getfuncptr(argtypes, restype, thisarg)
+        return funcptr(arg0)
+

Modified: pypy/branch/jitypes2/lib_pypy/ctypes_config_cache/test/test_cache.py
==============================================================================
--- pypy/branch/jitypes2/lib_pypy/ctypes_config_cache/test/test_cache.py	(original)
+++ pypy/branch/jitypes2/lib_pypy/ctypes_config_cache/test/test_cache.py	Tue Nov 23 13:26:19 2010
@@ -7,9 +7,8 @@
 
 def run(filename, outputname):
     filepath = dirpath.join(filename)
-    tmpdir2 = udir.ensure('testcache-' + filename, dir=True)
-    tmpdir = tmpdir2.ensure('ctypes_config_cache', dir=True)
-    tmpdir.join('__init__.py').write('\n')
+    tmpdir = udir.ensure('testcache-' + os.path.splitext(filename)[0],
+                         dir=True)
     tmpdir.join('dumpcache.py').write(dirpath.join('dumpcache.py').read())
     path = sys.path[:]
     try:
@@ -23,14 +22,12 @@
     assert outputpath.check(exists=1)
     modname = os.path.splitext(outputname)[0]
     try:
-        sys.path.insert(0, str(tmpdir2))
+        sys.path.insert(0, str(tmpdir))
         d = {}
-        exec "from ctypes_config_cache import %s" % modname in d
-        mod = d[modname]
+        execfile(str(outputpath), d)
     finally:
         sys.path[:] = path
-        sys.modules.pop('ctypes_config_cache', None)
-    return mod.__dict__
+    return d
 
 
 def test_syslog():

Modified: pypy/branch/jitypes2/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/branch/jitypes2/pypy/annotation/bookkeeper.py	(original)
+++ pypy/branch/jitypes2/pypy/annotation/bookkeeper.py	Tue Nov 23 13:26:19 2010
@@ -87,13 +87,6 @@
         else:
             return obj.knowntype.__name__
 
-    def consider_tuple_iter(self, tup):
-        ctxt = "[%s]" % sys._getframe(4).f_code.co_name
-        if tup.is_constant():
-            return ctxt, tup.const
-        else:
-            return ctxt, tuple([self.typerepr(x) for x in tup.items])
-
     def consider_tuple_random_getitem(self, tup):
         return tuple([self.typerepr(x) for x in tup.items])
 

Modified: pypy/branch/jitypes2/pypy/annotation/builtin.py
==============================================================================
--- pypy/branch/jitypes2/pypy/annotation/builtin.py	(original)
+++ pypy/branch/jitypes2/pypy/annotation/builtin.py	Tue Nov 23 13:26:19 2010
@@ -453,6 +453,9 @@
     #p = lltype.malloc(T, flavor=s_flavor.const)
     #lltype.free(p, flavor=s_flavor.const)
 
+def render_immortal(s_p, s_track_allocation=None):
+    assert s_track_allocation is None or s_track_allocation.is_constant()
+
 def typeOf(s_val):
     lltype = annotation_to_lltype(s_val, info="in typeOf(): ")
     return immutablevalue(lltype)
@@ -520,6 +523,7 @@
 
 BUILTIN_ANALYZERS[lltype.malloc] = malloc
 BUILTIN_ANALYZERS[lltype.free] = free
+BUILTIN_ANALYZERS[lltype.render_immortal] = render_immortal
 BUILTIN_ANALYZERS[lltype.typeOf] = typeOf
 BUILTIN_ANALYZERS[lltype.cast_primitive] = cast_primitive
 BUILTIN_ANALYZERS[lltype.nullptr] = nullptr

Modified: pypy/branch/jitypes2/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/jitypes2/pypy/config/pypyoption.py	(original)
+++ pypy/branch/jitypes2/pypy/config/pypyoption.py	Tue Nov 23 13:26:19 2010
@@ -34,6 +34,11 @@
      "_bisect", "_ffi"]
 ))
 
+translation_modules = default_modules.copy()
+translation_modules.update(dict.fromkeys(
+    ["fcntl", "rctime", "select", "signal", "_rawffi", "zlib",
+     "struct", "md5", "cStringIO", "array"]))
+
 working_oo_modules = default_modules.copy()
 working_oo_modules.update(dict.fromkeys(
     ["md5", "sha", "cStringIO", "itertools"]
@@ -149,6 +154,12 @@
                cmdline="--allworkingmodules",
                negation=True),
 
+    BoolOption("translationmodules",
+          "use only those modules that are needed to run translate.py on pypy",
+               default=False,
+               cmdline="--translationmodules",
+               suggests=[("objspace.allworkingmodules", False)]),
+
     BoolOption("geninterp", "specify whether geninterp should be used",
                cmdline=None,
                default=True),
@@ -164,6 +175,11 @@
                default=False,
                requires=[("objspace.usepycfiles", True)]),
 
+    StrOption("soabi",
+              "Tag to differentiate extension modules built for different Python interpreters",
+              cmdline="--soabi",
+              default=None),
+
     BoolOption("honor__builtins__",
                "Honor the __builtins__ key of a module dictionary",
                default=False),
@@ -369,6 +385,11 @@
     modules = [name for name in modules if name not in essential_modules]
     config.objspace.usemodules.suggest(**dict.fromkeys(modules, True))
 
+def enable_translationmodules(config):
+    modules = translation_modules
+    modules = [name for name in modules if name not in essential_modules]
+    config.objspace.usemodules.suggest(**dict.fromkeys(modules, True))
+
 
 if __name__ == '__main__':
     config = get_pypy_config()

Modified: pypy/branch/jitypes2/pypy/config/translationoption.py
==============================================================================
--- pypy/branch/jitypes2/pypy/config/translationoption.py	(original)
+++ pypy/branch/jitypes2/pypy/config/translationoption.py	Tue Nov 23 13:26:19 2010
@@ -115,7 +115,7 @@
                  default="auto", cmdline="--jit-backend"),
     ChoiceOption("jit_debug", "the amount of debugging dumps made by the JIT",
                  ["off", "profile", "steps", "detailed"],
-                 default="profile",      # XXX for now
+                 default="off",
                  cmdline="--jit-debug"),
     ChoiceOption("jit_profiler", "integrate profiler support into the JIT",
                  ["off", "oprofile"],

Modified: pypy/branch/jitypes2/pypy/conftest.py
==============================================================================
--- pypy/branch/jitypes2/pypy/conftest.py	(original)
+++ pypy/branch/jitypes2/pypy/conftest.py	Tue Nov 23 13:26:19 2010
@@ -327,6 +327,31 @@
 class PyPyTestFunction(py.test.collect.Function):
     # All PyPy test items catch and display OperationErrors specially.
     #
+    def runtest(self):
+        self.runtest_open()
+        try:
+            self.runtest_perform()
+        finally:
+            self.runtest_close()
+        self.runtest_finish()
+
+    def runtest_open(self):
+        leakfinder.start_tracking_allocations()
+
+    def runtest_perform(self):
+        super(PyPyTestFunction, self).runtest()
+
+    def runtest_close(self):
+        if leakfinder.TRACK_ALLOCATIONS:
+            self._pypytest_leaks = leakfinder.stop_tracking_allocations(False)
+        else:            # stop_tracking_allocations() already called
+            self._pypytest_leaks = None
+
+    def runtest_finish(self):
+        # check for leaks, but only if the test passed so far
+        if self._pypytest_leaks:
+            raise leakfinder.MallocMismatch(self._pypytest_leaks)
+
     def execute_appex(self, space, target, *args):
         try:
             target(*args)
@@ -353,16 +378,9 @@
     def _keywords(self):
         return super(IntTestFunction, self)._keywords() + ['interplevel']
 
-    def runtest(self):
+    def runtest_perform(self):
         try:
-            leakfinder.start_tracking_allocations()
-            try:
-                super(IntTestFunction, self).runtest()
-            finally:
-                if leakfinder.TRACK_ALLOCATIONS:
-                    leaks = leakfinder.stop_tracking_allocations(False)
-                else:
-                    leaks = None   # stop_tracking_allocations() already called
+            super(IntTestFunction, self).runtest_perform()
         except OperationError, e:
             check_keyboard_interrupt(e)
             raise
@@ -375,14 +393,15 @@
                         py.test.skip('%s: %s' % (e.__class__.__name__, e))
                 cls = cls.__bases__[0]
             raise
+
+    def runtest_finish(self):
         if 'pygame' in sys.modules:
             global _pygame_imported
             if not _pygame_imported:
                 _pygame_imported = True
                 assert option.view, ("should not invoke Pygame "
                                      "if conftest.option.view is False")
-        if leaks:        # check for leaks, but only if the test passed so far
-            raise leakfinder.MallocMismatch(leaks)
+        super(IntTestFunction, self).runtest_finish()
 
 class AppTestFunction(PyPyTestFunction):
     def _prunetraceback(self, traceback):
@@ -395,7 +414,7 @@
     def _keywords(self):
         return ['applevel'] + super(AppTestFunction, self)._keywords()
 
-    def runtest(self):
+    def runtest_perform(self):
         target = self.obj
         if option.runappdirect:
             return target()
@@ -427,7 +446,7 @@
                     space.setattr(w_instance, space.wrap(name[2:]), 
                                   getattr(instance, name)) 
 
-    def runtest(self):
+    def runtest_perform(self):
         target = self.obj
         if option.runappdirect:
             return target()

Modified: pypy/branch/jitypes2/pypy/doc/release-1.4.0.txt
==============================================================================
--- pypy/branch/jitypes2/pypy/doc/release-1.4.0.txt	(original)
+++ pypy/branch/jitypes2/pypy/doc/release-1.4.0.txt	Tue Nov 23 13:26:19 2010
@@ -4,21 +4,25 @@
 
 Hello.
 
-We're pleased to announce release of PyPy 1.4. This is a major breaktrhough
-in our long journey, since PyPy 1.4 is the first PyPy release that can translate
-itself faster than CPython. Since today, we plan to start using
-PyPy for our own development.
+We're pleased to announce the 1.4 release of PyPy. This is a major breakthrough
+in our long journey, as PyPy 1.4 is the first PyPy release that can translate
+itself faster than CPython. Starting today, we plan to start using PyPy for our
+own development.
 
 Among other features, this release includes numerous performance improvements
-(which made fast self-hosting possible), 64jit backend as well as serious
-stabilization. As of now, we can consider 32bit version of PyPy stable enough
-to run in production.
+(which made fast self-hosting possible), a 64-bit JIT backend, as well
+as serious stabilization. As of now, we can consider the 32-bit and 64-bit
+linux versions of PyPy stable enoughto run in production.
 
 More highlights
 ===============
 
-Virtualenv support: now PyPy is fully compatible with virtualenv_: note that
-to use it, you need a recent version of virtualenv (>= 1.5).
+* Virtualenv support: now PyPy is fully compatible with virtualenv_: note that
+  to use it, you need a recent version of virtualenv (>= 1.5).
 
-XXX write me: better regular expressions
+* Faster (and JITted) regular expressions - huge boost in speeding up
+  sre module.
 
+* Faster (and JITted) calls to functions like map().
+
+.. _virtualenv: http://pypi.python.org/pypi/virtualenv

Modified: pypy/branch/jitypes2/pypy/interpreter/argument.py
==============================================================================
--- pypy/branch/jitypes2/pypy/interpreter/argument.py	(original)
+++ pypy/branch/jitypes2/pypy/interpreter/argument.py	Tue Nov 23 13:26:19 2010
@@ -64,7 +64,7 @@
         return not self == other
 
 
-    # make it look tuply for the annotator
+    # make it look tuply for its use in the annotator
 
     def __len__(self):
         return 3
@@ -103,10 +103,11 @@
             make_sure_not_resized(self.keywords_w)
 
         make_sure_not_resized(self.arguments_w)
-        if ((w_stararg is not None and w_stararg) or
-            (w_starstararg is not None and w_starstararg)):
-            self._combine_wrapped(w_stararg, w_starstararg)
-            # if we have a call where * or ** args are used at the callsite
+        if w_stararg is not None and space.is_true(w_stararg):
+            self._combine_starargs_wrapped(w_stararg)
+        if w_starstararg is not None and space.is_true(w_starstararg):
+            self._combine_starstarargs_wrapped(w_starstararg)
+            # if we have a call where **args are used at the callsite
             # we shouldn't let the JIT see the argument matching
             self._dont_jit = True
         else:
@@ -142,42 +143,48 @@
 
     def _combine_wrapped(self, w_stararg, w_starstararg):
         "unpack the *arg and **kwd into arguments_w and keywords_w"
-        # unpack the * arguments 
         if w_stararg is not None:
-            self.arguments_w = (self.arguments_w +
-                                self.space.fixedview(w_stararg))
-        # unpack the ** arguments
+            self._combine_starargs_wrapped(w_stararg)
         if w_starstararg is not None:
-            space = self.space
-            if not space.is_true(space.isinstance(w_starstararg, space.w_dict)):
+            self._combine_starstarargs_wrapped(w_starstararg)
+
+    def _combine_starargs_wrapped(self, w_stararg):
+        # unpack the * arguments 
+        self.arguments_w = (self.arguments_w +
+                            self.space.fixedview(w_stararg))
+
+    def _combine_starstarargs_wrapped(self, w_starstararg):
+        # unpack the ** arguments
+        space = self.space
+        if not space.is_true(space.isinstance(w_starstararg, space.w_dict)):
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("argument after ** must be "
+                                            "a dictionary"))
+        keywords_w = [None] * space.int_w(space.len(w_starstararg))
+        keywords = [None] * space.int_w(space.len(w_starstararg))
+        i = 0
+        for w_key in space.unpackiterable(w_starstararg):
+            try:
+                key = space.str_w(w_key)
+            except OperationError, e:
+                if not e.match(space, space.w_TypeError):
+                    raise
                 raise OperationError(space.w_TypeError,
-                                     space.wrap("argument after ** must be "
-                                                "a dictionary"))
-            keywords_w = [None] * space.int_w(space.len(w_starstararg))
-            keywords = [None] * space.int_w(space.len(w_starstararg))
-            i = 0
-            for w_key in space.unpackiterable(w_starstararg):
-                try:
-                    key = space.str_w(w_key)
-                except OperationError, e:
-                    if not e.match(space, space.w_TypeError):
-                        raise
-                    raise OperationError(space.w_TypeError,
-                                         space.wrap("keywords must be strings"))
-                if self.keywords and key in self.keywords:
-                    raise operationerrfmt(self.space.w_TypeError,
-                                          "got multiple values "
-                                          "for keyword argument "
-                                          "'%s'", key)
-                keywords[i] = key
-                keywords_w[i] = space.getitem(w_starstararg, w_key)
-                i += 1
-            if self.keywords is None:
-                self.keywords = keywords
-                self.keywords_w = keywords_w
-            else:
-                self.keywords = self.keywords + keywords
-                self.keywords_w = self.keywords_w + keywords_w
+                                     space.wrap("keywords must be strings"))
+            if self.keywords and key in self.keywords:
+                raise operationerrfmt(self.space.w_TypeError,
+                                      "got multiple values "
+                                      "for keyword argument "
+                                      "'%s'", key)
+            keywords[i] = key
+            keywords_w[i] = space.getitem(w_starstararg, w_key)
+            i += 1
+        if self.keywords is None:
+            self.keywords = keywords
+            self.keywords_w = keywords_w
+        else:
+            self.keywords = self.keywords + keywords
+            self.keywords_w = self.keywords_w + keywords_w
 
     def fixedunpack(self, argcount):
         """The simplest argument parsing: get the 'argcount' arguments,
@@ -226,6 +233,10 @@
         #   argnames = list of formal parameter names
         #   scope_w = resulting list of wrapped values
         #
+
+        # some comments about the JIT: it assumes that signature is a constant,
+        # so all values coming from there can be assumed constant. It assumes
+        # that the length of the defaults_w does not vary too much.
         co_argcount = signature.num_argnames() # expected formal arguments, without */**
         has_vararg = signature.has_vararg()
         has_kwarg = signature.has_kwarg()
@@ -245,12 +256,6 @@
         args_w = self.arguments_w
         num_args = len(args_w)
 
-        keywords = self.keywords
-        keywords_w = self.keywords_w
-        num_kwds = 0
-        if keywords is not None:
-            num_kwds = len(keywords)
-
         avail = num_args + upfront
 
         if input_argcount < co_argcount:
@@ -260,15 +265,24 @@
             else:
                 take = num_args
 
+            # letting the JIT unroll this loop is safe, because take is always
+            # smaller than co_argcount
             for i in range(take):
                 scope_w[i + input_argcount] = args_w[i]
             input_argcount += take
 
+        keywords = self.keywords
+        keywords_w = self.keywords_w
+        num_kwds = 0
+        if keywords is not None:
+            num_kwds = len(keywords)
         # the code assumes that keywords can potentially be large, but that
         # argnames is typically not too large
         num_remainingkwds = num_kwds
         used_keywords = None
         if keywords:
+            # letting JIT unroll the loop is *only* safe if the callsite didn't
+            # use **args because num_kwds can be arbitrarily large otherwise.
             used_keywords = [False] * num_kwds
             for i in range(num_kwds):
                 name = keywords[i]
@@ -276,7 +290,7 @@
                 if j < 0:
                     continue
                 elif j < input_argcount:
-                    # check that no keyword argument conflicts with these note
+                    # check that no keyword argument conflicts with these. note
                     # that for this purpose we ignore the first blindargs,
                     # which were put into place by prepend().  This way,
                     # keywords do not conflict with the hidden extra argument
@@ -388,9 +402,10 @@
         space = self.space
         w_args = space.newtuple(self.arguments_w)
         w_kwds = space.newdict()
-        for i in range(len(self.keywords)):
-            space.setitem(w_kwds, space.wrap(self.keywords[i]),
-                                  self.keywords_w[i])
+        if self.keywords is not None:
+            for i in range(len(self.keywords)):
+                space.setitem(w_kwds, space.wrap(self.keywords[i]),
+                                      self.keywords_w[i])
         return w_args, w_kwds
 
 class ArgumentsForTranslation(Arguments):

Modified: pypy/branch/jitypes2/pypy/interpreter/test/test_argument.py
==============================================================================
--- pypy/branch/jitypes2/pypy/interpreter/test/test_argument.py	(original)
+++ pypy/branch/jitypes2/pypy/interpreter/test/test_argument.py	Tue Nov 23 13:26:19 2010
@@ -52,12 +52,17 @@
         assert y == "d"
         assert z == "e"
 
+class dummy_wrapped_dict(dict):
+    def __nonzero__(self):
+        raise NotImplementedError
 
 class DummySpace(object):
     def newtuple(self, items):
         return tuple(items)
 
     def is_true(self, obj):
+        if isinstance(obj, dummy_wrapped_dict):
+            return bool(dict(obj))
         return bool(obj)
 
     def fixedview(self, it):
@@ -229,7 +234,7 @@
             kwds_w = dict(kwds[:i])
             keywords = kwds_w.keys()
             keywords_w = kwds_w.values()
-            w_kwds = dict(kwds[i:])
+            w_kwds = dummy_wrapped_dict(kwds[i:])
             if i == 2:
                 w_kwds = None
             assert len(keywords) == len(keywords_w)
@@ -265,7 +270,7 @@
             kwds_w = dict(kwds[:i])
             keywords = kwds_w.keys()
             keywords_w = kwds_w.values()
-            w_kwds = dict(kwds[i:])
+            w_kwds = dummy_wrapped_dict(kwds[i:])
             if i == 3:
                 w_kwds = None
             args = Arguments(space, [1, 2], keywords, keywords_w, w_starstararg=w_kwds)
@@ -448,7 +453,11 @@
         assert set(args.keywords) == set(['a', 'b'])
         assert args.keywords_w[args.keywords.index('a')] == 2
         assert args.keywords_w[args.keywords.index('b')] == 3        
-                                 
+
+        args = Arguments(space, [1])
+        w_args, w_kwds = args.topacked()
+        assert w_args == (1, )
+        assert not w_kwds
 
 class TestErrorHandling(object):
     def test_missing_args(self):

Modified: pypy/branch/jitypes2/pypy/jit/backend/llsupport/descr.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/llsupport/descr.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/backend/llsupport/descr.py	Tue Nov 23 13:26:19 2010
@@ -130,6 +130,7 @@
 # ArrayDescrs
 
 _A = lltype.GcArray(lltype.Signed)     # a random gcarray
+_AF = lltype.GcArray(lltype.Float)     # an array of C doubles
 
 
 class BaseArrayDescr(AbstractDescr):
@@ -171,16 +172,21 @@
     _clsname = 'GcPtrArrayDescr'
     _is_array_of_pointers = True
 
-_CA = rffi.CArray(lltype.Signed)
+class FloatArrayDescr(BaseArrayDescr):
+    _clsname = 'FloatArrayDescr'
+    _is_array_of_floats = True
+    def get_base_size(self, translate_support_code):
+        basesize, _, _ = symbolic.get_array_token(_AF, translate_support_code)
+        return basesize
+    def get_item_size(self, translate_support_code):
+        return symbolic.get_size(lltype.Float, translate_support_code)
 
 class BaseArrayNoLengthDescr(BaseArrayDescr):
     def get_base_size(self, translate_support_code):
-        basesize, _, _ = symbolic.get_array_token(_CA, translate_support_code)
-        return basesize
+        return 0
 
     def get_ofs_length(self, translate_support_code):
-        _, _, ofslength = symbolic.get_array_token(_CA, translate_support_code)
-        return ofslength
+        return -1
 
 class NonGcPtrArrayNoLengthDescr(BaseArrayNoLengthDescr):
     _clsname = 'NonGcPtrArrayNoLengthDescr'
@@ -192,6 +198,8 @@
     _is_array_of_pointers = True
 
 def getArrayDescrClass(ARRAY):
+    if ARRAY.OF is lltype.Float:
+        return FloatArrayDescr
     return getDescrClass(ARRAY.OF, BaseArrayDescr, GcPtrArrayDescr,
                          NonGcPtrArrayDescr, 'Array', 'get_item_size',
                          '_is_array_of_floats', '_is_item_signed')
@@ -219,7 +227,8 @@
         basesize, itemsize, ofslength = symbolic.get_array_token(ARRAY, False)
         assert basesize == arraydescr.get_base_size(False)
         assert itemsize == arraydescr.get_item_size(False)
-        assert ofslength == arraydescr.get_ofs_length(False)
+        if not ARRAY._hints.get('nolength', False):
+            assert ofslength == arraydescr.get_ofs_length(False)
         if isinstance(ARRAY, lltype.GcArray):
             gccache.init_array_descr(ARRAY, arraydescr)
         cache[ARRAY] = arraydescr

Modified: pypy/branch/jitypes2/pypy/jit/backend/llsupport/gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/llsupport/gc.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/backend/llsupport/gc.py	Tue Nov 23 13:26:19 2010
@@ -573,6 +573,9 @@
         #   GETFIELD_RAW from the array 'gcrefs.list'.
         #
         newops = []
+        # we can only remember one malloc since the next malloc can possibly
+        # collect
+        last_malloc = None
         for op in operations:
             if op.getopnum() == rop.DEBUG_MERGE_POINT:
                 continue
@@ -590,22 +593,32 @@
                                                    [ConstInt(addr)], box,
                                                    self.single_gcref_descr))
                         op.setarg(i, box)
+            if op.is_malloc():
+                last_malloc = op.result
+            elif op.can_malloc():
+                last_malloc = None
             # ---------- write barrier for SETFIELD_GC ----------
             if op.getopnum() == rop.SETFIELD_GC:
-                v = op.getarg(1)
-                if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
-                                             bool(v.value)): # store a non-NULL
-                    self._gen_write_barrier(newops, op.getarg(0), v)
-                    op = op.copy_and_change(rop.SETFIELD_RAW)
+                val = op.getarg(0)
+                # no need for a write barrier in the case of previous malloc
+                if val is not last_malloc:
+                    v = op.getarg(1)
+                    if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+                                            bool(v.value)): # store a non-NULL
+                        self._gen_write_barrier(newops, op.getarg(0), v)
+                        op = op.copy_and_change(rop.SETFIELD_RAW)
             # ---------- write barrier for SETARRAYITEM_GC ----------
             if op.getopnum() == rop.SETARRAYITEM_GC:
-                v = op.getarg(2)
-                if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
-                                             bool(v.value)): # store a non-NULL
-                    # XXX detect when we should produce a
-                    # write_barrier_from_array
-                    self._gen_write_barrier(newops, op.getarg(0), v)
-                    op = op.copy_and_change(rop.SETARRAYITEM_RAW)
+                val = op.getarg(0)
+                # no need for a write barrier in the case of previous malloc
+                if val is not last_malloc:
+                    v = op.getarg(2)
+                    if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+                                            bool(v.value)): # store a non-NULL
+                        # XXX detect when we should produce a
+                        # write_barrier_from_array
+                        self._gen_write_barrier(newops, op.getarg(0), v)
+                        op = op.copy_and_change(rop.SETARRAYITEM_RAW)
             # ----------
             newops.append(op)
         del operations[:]

Modified: pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_descr.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_descr.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_descr.py	Tue Nov 23 13:26:19 2010
@@ -5,6 +5,7 @@
 from pypy.rpython.annlowlevel import llhelper
 from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
 from pypy.jit.metainterp import history
+import struct
 
 def test_get_size_descr():
     c0 = GcCache(False)
@@ -130,11 +131,13 @@
     assert not descr3.is_array_of_floats()
     assert     descr4.is_array_of_floats()
     #
-    WORD = rffi.sizeof(lltype.Signed)
-    assert descr1.get_base_size(False) == WORD
-    assert descr2.get_base_size(False) == WORD
-    assert descr3.get_base_size(False) == WORD
-    assert descr4.get_base_size(False) == WORD
+    def get_alignment(code):
+        # Retrieve default alignment for the compiler/platform
+        return struct.calcsize('l' + code) - struct.calcsize(code)
+    assert descr1.get_base_size(False) == get_alignment('c')
+    assert descr2.get_base_size(False) == get_alignment('p')
+    assert descr3.get_base_size(False) == get_alignment('p')
+    assert descr4.get_base_size(False) == get_alignment('d')
     assert descr1.get_ofs_length(False) == 0
     assert descr2.get_ofs_length(False) == 0
     assert descr3.get_ofs_length(False) == 0

Modified: pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_gc.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_gc.py	Tue Nov 23 13:26:19 2010
@@ -6,7 +6,9 @@
 from pypy.jit.backend.llsupport.gc import *
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.metainterp.gc import get_description
-
+from pypy.jit.tool.oparser import parse
+from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
+from pypy.jit.metainterp.test.test_optimizeopt import equaloplists
 
 def test_boehm():
     gc_ll_descr = GcLLDescr_boehm(None, None, None)
@@ -114,7 +116,7 @@
         assert gcrootmap._gcmap[i*2+1] == expected_shapeaddr[i]
 
 
-class FakeLLOp:
+class FakeLLOp(object):
     def __init__(self):
         self.record = []
 
@@ -148,19 +150,19 @@
         return llhelper(FPTRTYPE, self._write_barrier_failing_case)
 
 
-class TestFramework:
+class TestFramework(object):
     gc = 'hybrid'
 
     def setup_method(self, meth):
-        class config_:
-            class translation:
+        class config_(object):
+            class translation(object):
                 gc = self.gc
                 gcrootfinder = 'asmgcc'
                 gctransformer = 'framework'
                 gcremovetypeptr = False
-        class FakeTranslator:
+        class FakeTranslator(object):
             config = config_
-        class FakeCPU:
+        class FakeCPU(object):
             def cast_adr_to_int(self, adr):
                 ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR)
                 assert ptr._obj._callable == llop1._write_barrier_failing_case
@@ -278,11 +280,11 @@
 
     def test_rewrite_assembler_1(self):
         # check rewriting of ConstPtrs
-        class MyFakeCPU:
+        class MyFakeCPU(object):
             def cast_adr_to_int(self, adr):
                 assert adr == "some fake address"
                 return 43
-        class MyFakeGCRefList:
+        class MyFakeGCRefList(object):
             def get_address_of_gcref(self, s_gcref1):
                 assert s_gcref1 == s_gcref
                 return "some fake address"
@@ -311,10 +313,10 @@
 
     def test_rewrite_assembler_1_cannot_move(self):
         # check rewriting of ConstPtrs
-        class MyFakeCPU:
+        class MyFakeCPU(object):
             def cast_adr_to_int(self, adr):
                 xxx    # should not be called
-        class MyFakeGCRefList:
+        class MyFakeGCRefList(object):
             def get_address_of_gcref(self, s_gcref1):
                 seen.append(s_gcref1)
                 assert s_gcref1 == s_gcref
@@ -394,6 +396,68 @@
         assert operations[1].getarg(2) == v_value
         assert operations[1].getdescr() == array_descr
 
+    def test_rewrite_assembler_initialization_store(self):
+        S = lltype.GcStruct('S', ('parent', OBJECT),
+                            ('x', lltype.Signed))
+        s_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+        xdescr = get_field_descr(self.gc_ll_descr, S, 'x')
+        ops = parse("""
+        [p1]
+        p0 = new_with_vtable(ConstClass(s_vtable))
+        setfield_gc(p0, p1, descr=xdescr)
+        jump()
+        """, namespace=locals())
+        expected = parse("""
+        [p1]
+        p0 = new_with_vtable(ConstClass(s_vtable))
+        # no write barrier
+        setfield_gc(p0, p1, descr=xdescr)
+        jump()
+        """, namespace=locals())
+        self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+        equaloplists(ops.operations, expected.operations)
+
+    def test_rewrite_assembler_initialization_store_2(self):
+        S = lltype.GcStruct('S', ('parent', OBJECT),
+                            ('x', lltype.Signed))
+        s_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+        wbdescr = self.gc_ll_descr.write_barrier_descr
+        xdescr = get_field_descr(self.gc_ll_descr, S, 'x')
+        ops = parse("""
+        [p1]
+        p0 = new_with_vtable(ConstClass(s_vtable))
+        p3 = new_with_vtable(ConstClass(s_vtable))
+        setfield_gc(p0, p1, descr=xdescr)
+        jump()
+        """, namespace=locals())
+        expected = parse("""
+        [p1]
+        p0 = new_with_vtable(ConstClass(s_vtable))
+        p3 = new_with_vtable(ConstClass(s_vtable))
+        cond_call_gc_wb(p0, p1, descr=wbdescr)
+        setfield_raw(p0, p1, descr=xdescr)
+        jump()
+        """, namespace=locals())
+        self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+        equaloplists(ops.operations, expected.operations)
+
+    def test_rewrite_assembler_initialization_store_3(self):
+        A = lltype.GcArray(lltype.Ptr(lltype.GcStruct('S')))
+        arraydescr = get_array_descr(self.gc_ll_descr, A)
+        ops = parse("""
+        [p1]
+        p0 = new_array(3, descr=arraydescr)
+        setarrayitem_gc(p0, 0, p1, descr=arraydescr)
+        jump()
+        """, namespace=locals())
+        expected = parse("""
+        [p1]
+        p0 = new_array(3, descr=arraydescr)
+        setarrayitem_gc(p0, 0, p1, descr=arraydescr)
+        jump()
+        """, namespace=locals())
+        self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+        equaloplists(ops.operations, expected.operations)
 
 class TestFrameworkMiniMark(TestFramework):
     gc = 'minimark'

Modified: pypy/branch/jitypes2/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/backend/test/runner_test.py	Tue Nov 23 13:26:19 2010
@@ -2168,12 +2168,14 @@
             # Tested with a function that intentionally does not cast the
             # result to RESTYPE, but makes sure that we return the whole
             # value in eax or rax.
-            eci = ExternalCompilationInfo(separate_module_sources=["""
+            eci = ExternalCompilationInfo(
+                separate_module_sources=["""
                 long fn_test_result_of_call(long x)
                 {
                     return x + 1;
                 }
-            """])
+                """],
+                export_symbols=['fn_test_result_of_call'])
             f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
                                 RESTYPE, compilation_info=eci, _nowrapper=True)
             value = intmask(0xFFEEDDCCBBAA9988)
@@ -2199,12 +2201,14 @@
             # Tested with a function that intentionally does not cast the
             # result to RESTYPE, but makes sure that we return the whole
             # value in eax or rax.
-            eci = ExternalCompilationInfo(separate_module_sources=["""
+            eci = ExternalCompilationInfo(
+                separate_module_sources=["""
                 long fn_test_result_of_call(long x)
                 {
                     return x + 1;
                 }
-            """])
+                """],
+                export_symbols=['fn_test_result_of_call'])
             f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
                                 RESTYPE, compilation_info=eci, _nowrapper=True)
             value = intmask(0xFFEEDDCCBBAA9988)

Modified: pypy/branch/jitypes2/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/backend/x86/assembler.py	Tue Nov 23 13:26:19 2010
@@ -1773,13 +1773,18 @@
         self.implement_guard(guard_token, 'L')
 
     def genop_discard_cond_call_gc_wb(self, op, arglocs):
-        # use 'mc._mc' directly instead of 'mc', to avoid
-        # bad surprizes if the code buffer is mostly full
+        # Write code equivalent to write_barrier() in the GC: it checks
+        # a flag in the object at arglocs[0], and if set, it calls the
+        # function remember_young_pointer() from the GC.  The two arguments
+        # to the call are in arglocs[:2].  The rest, arglocs[2:], contains
+        # registers that need to be saved and restored across the call.
         descr = op.getdescr()
         if we_are_translated():
             cls = self.cpu.gc_ll_descr.has_write_barrier_class()
             assert cls is not None and isinstance(descr, cls)
         loc_base = arglocs[0]
+        # ensure that enough bytes are available to write the whole
+        # following piece of code atomically (for the JZ)
         self.mc.ensure_bytes_available(256)
         self.mc.TEST8_mi((loc_base.value, descr.jit_wb_if_flag_byteofs),
                 descr.jit_wb_if_flag_singlebyte)
@@ -1787,36 +1792,39 @@
         jz_location = self.mc.get_relative_pos()
         # the following is supposed to be the slow path, so whenever possible
         # we choose the most compact encoding over the most efficient one.
-        # XXX improve a bit, particularly for IS_X86_64.
-        for i in range(len(arglocs)-1, -1, -1):
+        if IS_X86_32:
+            limit = -1      # push all arglocs on the stack
+        elif IS_X86_64:
+            limit = 1       # push only arglocs[2:] on the stack
+        for i in range(len(arglocs)-1, limit, -1):
             loc = arglocs[i]
             if isinstance(loc, RegLoc):
                 self.mc.PUSH_r(loc.value)
             else:
-                if IS_X86_64:
-                    self.mc.MOV_ri(X86_64_SCRATCH_REG.value, loc.getint())
-                    self.mc.PUSH_r(X86_64_SCRATCH_REG.value)
-                else:
-                    self.mc.PUSH_i32(loc.getint())
-        
+                assert not IS_X86_64 # there should only be regs in arglocs[2:]
+                self.mc.PUSH_i32(loc.getint())
         if IS_X86_64:
             # We clobber these registers to pass the arguments, but that's
             # okay, because consider_cond_call_gc_wb makes sure that any
-            # caller-save registers with values in them are present in arglocs,
-            # so they are saved on the stack above and restored below 
-            self.mc.MOV_rs(edi.value, 0)
-            self.mc.MOV_rs(esi.value, 8)
+            # caller-save registers with values in them are present in
+            # arglocs[2:] too, so they are saved on the stack above and
+            # restored below.
+            remap_frame_layout(self, arglocs[:2], [edi, esi],
+                               X86_64_SCRATCH_REG)
 
         # misaligned stack in the call, but it's ok because the write barrier
         # is not going to call anything more.  Also, this assumes that the
-        # write barrier does not touch the xmm registers.
+        # write barrier does not touch the xmm registers.  (Slightly delicate
+        # assumption, given that the write barrier can end up calling the
+        # platform's malloc() from AddressStack.append().  XXX may need to
+        # be done properly)
         self.mc.CALL(imm(descr.get_write_barrier_fn(self.cpu)))
-        for i in range(len(arglocs)):
+        if IS_X86_32:
+            self.mc.ADD_ri(esp.value, 2*WORD)
+        for i in range(2, len(arglocs)):
             loc = arglocs[i]
-            if isinstance(loc, RegLoc):
-                self.mc.POP_r(loc.value)
-            else:
-                self.mc.ADD_ri(esp.value, WORD)   # ignore the pushed constant
+            assert isinstance(loc, RegLoc)
+            self.mc.POP_r(loc.value)
         # patch the JZ above
         offset = self.mc.get_relative_pos() - jz_location
         assert 0 < offset <= 127

Modified: pypy/branch/jitypes2/pypy/jit/codewriter/assembler.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/assembler.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/assembler.py	Tue Nov 23 13:26:19 2010
@@ -233,10 +233,9 @@
             addr = llmemory.cast_ptr_to_adr(value)
             self.list_of_addr2name.append((addr, name))
 
-    def finished(self):
+    def finished(self, callinfocollection):
         # Helper called at the end of assembling.  Registers the extra
         # functions shown in _callinfo_for_oopspec.
-        from pypy.jit.codewriter.effectinfo import _callinfo_for_oopspec
-        for _, func in _callinfo_for_oopspec.values():
+        for func in callinfocollection.all_function_addresses_as_int():
             func = heaptracker.int2adr(func)
             self.see_raw_object(func.ptr)

Modified: pypy/branch/jitypes2/pypy/jit/codewriter/call.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/call.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/call.py	Tue Nov 23 13:26:19 2010
@@ -7,7 +7,7 @@
 from pypy.jit.codewriter.jitcode import JitCode
 from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer
 from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze
-from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection
 from pypy.translator.simplify import get_funcobj, get_functype
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.translator.backendopt.canraise import RaiseAnalyzer
@@ -23,6 +23,7 @@
         self.jitdrivers_sd = jitdrivers_sd
         self.jitcodes = {}             # map {graph: jitcode}
         self.unfinished_graphs = []    # list of graphs with pending jitcodes
+        self.callinfocollection = CallInfoCollection()
         if hasattr(cpu, 'rtyper'):     # for tests
             self.rtyper = cpu.rtyper
             translator = self.rtyper.annotator.translator

Modified: pypy/branch/jitypes2/pypy/jit/codewriter/codewriter.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/codewriter.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/codewriter.py	Tue Nov 23 13:26:19 2010
@@ -73,7 +73,7 @@
             count += 1
             if not count % 500:
                 log.info("Produced %d jitcodes" % count)
-        self.assembler.finished()
+        self.assembler.finished(self.callcontrol.callinfocollection)
         heaptracker.finish_registering(self.cpu)
         log.info("there are %d JitCode instances." % count)
 

Modified: pypy/branch/jitypes2/pypy/jit/codewriter/effectinfo.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/effectinfo.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/effectinfo.py	Tue Nov 23 13:26:19 2010
@@ -144,30 +144,44 @@
 
 # ____________________________________________________________
 
-_callinfo_for_oopspec = {} # {oopspecindex: (calldescr, func_as_int)}
-
-def callinfo_for_oopspec(oopspecindex):
-    """A function that returns the calldescr and the function
-    address (as an int) of one of the OS_XYZ functions defined above.
-    Don't use this if there might be several implementations of the same
-    OS_XYZ specialized by type, e.g. OS_ARRAYCOPY."""
-    try:
-        return _callinfo_for_oopspec[oopspecindex]
-    except KeyError:
-        return (None, 0)
-
-
-def _funcptr_for_oopspec_memo(oopspecindex):
-    from pypy.jit.codewriter import heaptracker
-    _, func_as_int = callinfo_for_oopspec(oopspecindex)
-    funcadr = heaptracker.int2adr(func_as_int)
-    return funcadr.ptr
-_funcptr_for_oopspec_memo._annspecialcase_ = 'specialize:memo'
-
-def funcptr_for_oopspec(oopspecindex):
-    """A memo function that returns a pointer to the function described
-    by OS_XYZ (as a real low-level function pointer)."""
-    funcptr = _funcptr_for_oopspec_memo(oopspecindex)
-    assert funcptr
-    return funcptr
-funcptr_for_oopspec._annspecialcase_ = 'specialize:arg(0)'
+class CallInfoCollection(object):
+    def __init__(self):
+        # {oopspecindex: (calldescr, func_as_int)}
+        self._callinfo_for_oopspec = {}
+
+    def _freeze_(self):
+        return True
+
+    def add(self, oopspecindex, calldescr, func_as_int):
+        self._callinfo_for_oopspec[oopspecindex] = calldescr, func_as_int
+
+    def has_oopspec(self, oopspecindex):
+        return oopspecindex in self._callinfo_for_oopspec
+
+    def all_function_addresses_as_int(self):
+        return [func for (_, func) in self._callinfo_for_oopspec.values()]
+
+    def callinfo_for_oopspec(self, oopspecindex):
+        """A function that returns the calldescr and the function
+        address (as an int) of one of the OS_XYZ functions defined above.
+        Don't use this if there might be several implementations of the same
+        OS_XYZ specialized by type, e.g. OS_ARRAYCOPY."""
+        try:
+            return self._callinfo_for_oopspec[oopspecindex]
+        except KeyError:
+            return (None, 0)
+
+    def _funcptr_for_oopspec_memo(self, oopspecindex):
+        from pypy.jit.codewriter import heaptracker
+        _, func_as_int = self.callinfo_for_oopspec(oopspecindex)
+        funcadr = heaptracker.int2adr(func_as_int)
+        return funcadr.ptr
+    _funcptr_for_oopspec_memo._annspecialcase_ = 'specialize:memo'
+
+    def funcptr_for_oopspec(self, oopspecindex):
+        """A memo function that returns a pointer to the function described
+        by OS_XYZ (as a real low-level function pointer)."""
+        funcptr = self._funcptr_for_oopspec_memo(oopspecindex)
+        assert funcptr
+        return funcptr
+    funcptr_for_oopspec._annspecialcase_ = 'specialize:arg(1)'

Modified: pypy/branch/jitypes2/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/jtransform.py	Tue Nov 23 13:26:19 2010
@@ -6,7 +6,7 @@
 from pypy.objspace.flow.model import Block, Link, c_last_exception
 from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
 from pypy.jit.codewriter import support, heaptracker
-from pypy.jit.codewriter.effectinfo import EffectInfo, _callinfo_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.codewriter.policy import log
 from pypy.jit.metainterp.typesystem import deref, arrayItem
 from pypy.rlib import objectmodel
@@ -843,9 +843,16 @@
             "general mix-up of jitdrivers?")
         ops = self.promote_greens(op.args[2:], jitdriver)
         num_green_args = len(jitdriver.greens)
+        redlists = self.make_three_lists(op.args[2+num_green_args:])
+        for redlist in redlists:
+            for v in redlist:
+                assert isinstance(v, Variable), (
+                    "Constant specified red in jit_merge_point()")
+            assert len(dict.fromkeys(redlist)) == len(list(redlist)), (
+                "duplicate red variable on jit_merge_point()")
         args = ([Constant(self.portal_jd.index, lltype.Signed)] +
                 self.make_three_lists(op.args[2:2+num_green_args]) +
-                self.make_three_lists(op.args[2+num_green_args:]))
+                redlists)
         op1 = SpaceOperation('jit_merge_point', args, None)
         op2 = SpaceOperation('-live-', [], None)
         # ^^^ we need a -live- for the case of do_recursive_call()
@@ -1084,7 +1091,8 @@
         else:
             func = heaptracker.adr2int(
                 llmemory.cast_ptr_to_adr(op.args[0].value))
-            _callinfo_for_oopspec[oopspecindex] = calldescr, func
+            self.callcontrol.callinfocollection.add(oopspecindex,
+                                                    calldescr, func)
         op1 = self.rewrite_call(op, 'residual_call',
                                 [op.args[0], calldescr],
                                 args=args)
@@ -1095,7 +1103,7 @@
     def _register_extra_helper(self, oopspecindex, oopspec_name,
                                argtypes, resulttype):
         # a bit hackish
-        if oopspecindex in _callinfo_for_oopspec:
+        if self.callcontrol.callinfocollection.has_oopspec(oopspecindex):
             return
         c_func, TP = support.builtin_func_for_spec(self.cpu.rtyper,
                                                    oopspec_name, argtypes,
@@ -1109,7 +1117,7 @@
         else:
             func = heaptracker.adr2int(
                 llmemory.cast_ptr_to_adr(c_func.value))
-        _callinfo_for_oopspec[oopspecindex] = calldescr, func
+        self.callcontrol.callinfocollection.add(oopspecindex, calldescr, func)
 
     def _handle_stroruni_call(self, op, oopspec_name, args):
         SoU = args[0].concretetype     # Ptr(STR) or Ptr(UNICODE)

Modified: pypy/branch/jitypes2/pypy/jit/codewriter/test/test_jtransform.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/test/test_jtransform.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/test/test_jtransform.py	Tue Nov 23 13:26:19 2010
@@ -74,7 +74,20 @@
     def calldescr_canraise(self, calldescr):
         return False
 
+class FakeCallInfoCollection:
+    def __init__(self):
+        self.seen = []
+    def add(self, oopspecindex, calldescr, func):
+        self.seen.append((oopspecindex, calldescr, func))
+    def has_oopspec(self, oopspecindex):
+        for i, c, f in self.seen:
+            if i == oopspecindex:
+                return True
+        return False
+
 class FakeBuiltinCallControl:
+    def __init__(self):
+        self.callinfocollection = FakeCallInfoCollection()
     def guess_call_kind(self, op):
         return 'builtin'
     def getcalldescr(self, op, oopspecindex=None):
@@ -810,7 +823,8 @@
     v2 = varoftype(PSTR)
     v3 = varoftype(PSTR)
     op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
-    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+    cc = FakeBuiltinCallControl()
+    tr = Transformer(FakeCPU(), cc)
     op1 = tr.rewrite_operation(op)
     assert op1.opname == 'residual_call_r_r'
     assert op1.args[0].value == func
@@ -819,9 +833,10 @@
     assert op1.result == v3
     #
     # check the callinfo_for_oopspec
-    got = effectinfo.callinfo_for_oopspec(effectinfo.EffectInfo.OS_UNI_CONCAT)
-    assert got[0] == op1.args[1]    # the calldescr
-    assert heaptracker.int2adr(got[1]) == llmemory.cast_ptr_to_adr(func)
+    got = cc.callinfocollection.seen[0]
+    assert got[0] == effectinfo.EffectInfo.OS_UNI_CONCAT
+    assert got[1] == op1.args[1]    # the calldescr
+    assert heaptracker.int2adr(got[2]) == llmemory.cast_ptr_to_adr(func)
 
 def test_str_slice():
     # test that the oopspec is present and correctly transformed
@@ -893,7 +908,8 @@
     v2 = varoftype(PUNICODE)
     v3 = varoftype(lltype.Bool)
     op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
-    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+    cc = FakeBuiltinCallControl()
+    tr = Transformer(FakeCPU(), cc)
     op1 = tr.rewrite_operation(op)
     assert op1.opname == 'residual_call_r_i'
     assert op1.args[0].value == func
@@ -901,9 +917,9 @@
     assert op1.args[2] == ListOfKind('ref', [v1, v2])
     assert op1.result == v3
     # test that the OS_UNIEQ_* functions are registered
-    cifo = effectinfo._callinfo_for_oopspec
-    assert effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL in cifo
-    assert effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR in cifo
+    cic = cc.callinfocollection
+    assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL)
+    assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR)
 
 def test_list_ll_arraycopy():
     from pypy.rlib.rgc import ll_arraycopy

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/compile.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/compile.py	Tue Nov 23 13:26:19 2010
@@ -1,4 +1,5 @@
 
+from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.ootypesystem import ootype
 from pypy.objspace.flow.model import Constant, Variable
 from pypy.rlib.objectmodel import we_are_translated
@@ -14,6 +15,7 @@
 from pypy.jit.metainterp.specnode import NotSpecNode, more_general_specnodes
 from pypy.jit.metainterp.typesystem import llhelper, oohelper
 from pypy.jit.metainterp.optimizeutil import InvalidLoop
+from pypy.jit.metainterp.resume import NUMBERING
 from pypy.jit.codewriter import heaptracker
 
 def giveup():
@@ -48,13 +50,12 @@
 
 # ____________________________________________________________
 
-def compile_new_loop(metainterp, old_loop_tokens, greenkey, start):
+def compile_new_loop(metainterp, old_loop_tokens, start):
     """Try to compile a new loop by closing the current history back
     to the first operation.
     """
     history = metainterp.history
     loop = create_empty_loop(metainterp)
-    loop.greenkey = greenkey
     loop.inputargs = history.inputargs
     for box in loop.inputargs:
         assert isinstance(box, Box)
@@ -207,8 +208,7 @@
             }
 
 class ResumeDescr(AbstractFailDescr):
-    def __init__(self, original_greenkey):
-        self.original_greenkey = original_greenkey
+    pass
 
 class ResumeGuardDescr(ResumeDescr):
     _counter = 0        # if < 0, there is one counter per value;
@@ -217,7 +217,7 @@
     # this class also gets the following attributes stored by resume.py code
     rd_snapshot = None
     rd_frame_info_list = None
-    rd_numb = None
+    rd_numb = lltype.nullptr(NUMBERING)
     rd_consts = None
     rd_virtuals = None
     rd_pendingfields = None
@@ -227,8 +227,7 @@
     CNT_FLOAT = -0x60000000
     CNT_MASK  =  0x1FFFFFFF
 
-    def __init__(self, metainterp_sd, original_greenkey):
-        ResumeDescr.__init__(self, original_greenkey)
+    def __init__(self, metainterp_sd):
         self.metainterp_sd = metainterp_sd
 
     def store_final_boxes(self, guard_op, boxes):
@@ -332,14 +331,14 @@
         res.rd_pendingfields = self.rd_pendingfields
 
     def _clone_if_mutable(self):
-        res = ResumeGuardDescr(self.metainterp_sd, self.original_greenkey)
+        res = ResumeGuardDescr(self.metainterp_sd)
         self.copy_all_attrbutes_into(res)
         return res
 
 class ResumeGuardForcedDescr(ResumeGuardDescr):
 
-    def __init__(self, metainterp_sd, original_greenkey, jitdriver_sd):
-        ResumeGuardDescr.__init__(self, metainterp_sd, original_greenkey)
+    def __init__(self, metainterp_sd, jitdriver_sd):
+        ResumeGuardDescr.__init__(self, metainterp_sd)
         self.jitdriver_sd = jitdriver_sd
 
     def handle_fail(self, metainterp_sd, jitdriver_sd):
@@ -406,7 +405,6 @@
 
     def _clone_if_mutable(self):
         res = ResumeGuardForcedDescr(self.metainterp_sd,
-                                     self.original_greenkey,
                                      self.jitdriver_sd)
         self.copy_all_attrbutes_into(res)
         return res
@@ -473,9 +471,8 @@
 
 
 class ResumeFromInterpDescr(ResumeDescr):
-    def __init__(self, original_greenkey, redkey):
-        ResumeDescr.__init__(self, original_greenkey)
-        self.redkey = redkey
+    def __init__(self, original_greenkey):
+        self.original_greenkey = original_greenkey
 
     def compile_and_attach(self, metainterp, new_loop):
         # We managed to create a bridge going from the interpreter
@@ -484,10 +481,8 @@
         # with completely unoptimized arguments, as in the interpreter.
         metainterp_sd = metainterp.staticdata
         jitdriver_sd = metainterp.jitdriver_sd
-        metainterp.history.inputargs = self.redkey
-        new_loop_token = make_loop_token(len(self.redkey), jitdriver_sd)
-        new_loop.greenkey = self.original_greenkey
-        new_loop.inputargs = self.redkey
+        redargs = new_loop.inputargs
+        new_loop_token = make_loop_token(len(redargs), jitdriver_sd)
         new_loop.token = new_loop_token
         send_loop_to_backend(metainterp_sd, new_loop, "entry bridge")
         # send the new_loop to warmspot.py, to be called directly the next time

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/optimizer.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/optimizer.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/optimizer.py	Tue Nov 23 13:26:19 2010
@@ -299,7 +299,9 @@
             return CVAL_ZERO
 
     def propagate_all_forward(self):
-        self.exception_might_have_happened = False
+        self.exception_might_have_happened = True
+        # ^^^ at least at the start of bridges.  For loops, we could set
+        # it to False, but we probably don't care
         self.newoperations = []
         self.i = 0
         while self.i < len(self.loop.operations):

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/string.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/string.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/string.py	Tue Nov 23 13:26:19 2010
@@ -9,7 +9,7 @@
 from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
 from pypy.jit.metainterp.optimizeopt.optimizer import llhelper
 from pypy.jit.metainterp.optimizeutil import _findall
-from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.codewriter import heaptracker
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.objectmodel import specialize, we_are_translated
@@ -593,7 +593,8 @@
 
     def generate_modified_call(self, oopspecindex, args, result, mode):
         oopspecindex += mode.OS_offset
-        calldescr, func = callinfo_for_oopspec(oopspecindex)
+        cic = self.optimizer.metainterp_sd.callinfocollection
+        calldescr, func = cic.callinfo_for_oopspec(oopspecindex)
         op = ResOperation(rop.CALL, [ConstInt(func)] + args, result,
                           descr=calldescr)
         self.optimizer.newoperations.append(op)

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/pyjitpl.py	Tue Nov 23 13:26:19 2010
@@ -14,7 +14,7 @@
 from pypy.jit.metainterp.logger import Logger
 from pypy.jit.metainterp.jitprof import EmptyProfiler
 from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE
-from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE
+from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG
 from pypy.jit.metainterp.jitexc import JitException, get_llexception
 from pypy.rlib.rarithmetic import intmask
 from pypy.rlib.objectmodel import specialize
@@ -94,6 +94,18 @@
             else: raise AssertionError(argcode)
             outvalue[startindex+i] = reg
 
+    def _put_back_list_of_boxes(self, outvalue, startindex, position):
+        code = self.bytecode
+        length = ord(code[position])
+        position += 1
+        for i in range(length):
+            index = ord(code[position+i])
+            box = outvalue[startindex+i]
+            if   box.type == history.INT:   self.registers_i[index] = box
+            elif box.type == history.REF:   self.registers_r[index] = box
+            elif box.type == history.FLOAT: self.registers_f[index] = box
+            else: raise AssertionError(box.type)
+
     def get_current_position_info(self):
         return self.jitcode.get_live_vars_info(self.pc)
 
@@ -814,8 +826,9 @@
         for i in range(num_green_args):
             assert isinstance(varargs[i], Const)
 
-    @arguments("orgpc", "int", "boxes3", "boxes3")
-    def opimpl_jit_merge_point(self, orgpc, jdindex, greenboxes, redboxes):
+    @arguments("orgpc", "int", "boxes3", "jitcode_position", "boxes3")
+    def opimpl_jit_merge_point(self, orgpc, jdindex, greenboxes,
+                               jcposition, redboxes):
         any_operation = len(self.metainterp.history.operations) > 0
         jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
         self.verify_green_args(jitdriver_sd, greenboxes)
@@ -843,6 +856,10 @@
             self.pc = orgpc
             self.metainterp.reached_loop_header(greenboxes, redboxes)
             self.pc = saved_pc
+            # no exception, which means that the jit_merge_point did not
+            # close the loop.  We have to put the possibly-modified list
+            # 'redboxes' back into the registers where it comes from.
+            put_back_list_of_boxes3(self, jcposition, redboxes)
         else:
             # warning! careful here.  We have to return from the current
             # frame containing the jit_merge_point, and then use
@@ -1048,14 +1065,11 @@
         else:
             moreargs = list(extraargs)
         metainterp_sd = metainterp.staticdata
-        original_greenkey = metainterp.resumekey.original_greenkey
         if opnum == rop.GUARD_NOT_FORCED:
             resumedescr = compile.ResumeGuardForcedDescr(metainterp_sd,
-                                                   original_greenkey,
                                                    metainterp.jitdriver_sd)
         else:
-            resumedescr = compile.ResumeGuardDescr(metainterp_sd,
-                                                   original_greenkey)
+            resumedescr = compile.ResumeGuardDescr(metainterp_sd)
         guard_op = metainterp.history.record(opnum, moreargs, None,
                                              descr=resumedescr)
         virtualizable_boxes = None
@@ -1261,6 +1275,7 @@
         #
         self.jitdrivers_sd = codewriter.callcontrol.jitdrivers_sd
         self.virtualref_info = codewriter.callcontrol.virtualref_info
+        self.callinfocollection = codewriter.callcontrol.callinfocollection
         self.setup_jitdrivers_sd(optimizer)
         #
         # store this information for fastpath of call_assembler
@@ -1624,7 +1639,7 @@
         assert jitdriver_sd is self.jitdriver_sd
         self.create_empty_history()
         try:
-            original_boxes = self.initialize_original_boxes(jitdriver_sd,*args)
+            original_boxes = self.initialize_original_boxes(jitdriver_sd, *args)
             return self._compile_and_run_once(original_boxes)
         finally:
             self.staticdata.profiler.end_tracing()
@@ -1635,9 +1650,8 @@
         self.current_merge_points = [(original_boxes, 0)]
         num_green_args = self.jitdriver_sd.num_green_args
         original_greenkey = original_boxes[:num_green_args]
-        redkey = original_boxes[num_green_args:]
-        self.resumekey = compile.ResumeFromInterpDescr(original_greenkey,
-                                                       redkey)
+        self.resumekey = compile.ResumeFromInterpDescr(original_greenkey)
+        self.history.inputargs = original_boxes[num_green_args:]
         self.seen_loop_header_for_jdindex = -1
         try:
             self.interpret()
@@ -1659,11 +1673,7 @@
             debug_stop('jit-tracing')
 
     def _handle_guard_failure(self, key):
-        original_greenkey = key.original_greenkey
-        # notice that here we just put the greenkey
-        # use -1 to mark that we will have to give up
-        # because we cannot reconstruct the beginning of the proper loop
-        self.current_merge_points = [(original_greenkey, -1)]
+        self.current_merge_points = []
         self.resumekey = key
         self.seen_loop_header_for_jdindex = -1
         try:
@@ -1727,7 +1737,7 @@
         num_green_args = self.jitdriver_sd.num_green_args
         for j in range(len(self.current_merge_points)-1, -1, -1):
             original_boxes, start = self.current_merge_points[j]
-            assert len(original_boxes) == len(live_arg_boxes) or start < 0
+            assert len(original_boxes) == len(live_arg_boxes)
             for i in range(num_green_args):
                 box1 = original_boxes[i]
                 box2 = live_arg_boxes[i]
@@ -1736,10 +1746,6 @@
                     break
             else:
                 # Found!  Compile it as a loop.
-                if start < 0:
-                    # we cannot reconstruct the beginning of the proper loop
-                    raise SwitchToBlackhole(ABORT_BRIDGE)
-
                 # raises in case it works -- which is the common case
                 self.compile(original_boxes, live_arg_boxes, start)
                 # creation of the loop was cancelled!
@@ -1804,8 +1810,7 @@
         greenkey = original_boxes[:num_green_args]
         old_loop_tokens = self.get_compiled_merge_points(greenkey)
         self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
-        loop_token = compile.compile_new_loop(self, old_loop_tokens,
-                                              greenkey, start)
+        loop_token = compile.compile_new_loop(self, old_loop_tokens, start)
         if loop_token is not None: # raise if it *worked* correctly
             raise GenerateMergePoint(live_arg_boxes, loop_token)
         self.history.operations.pop()     # remove the JUMP
@@ -2305,6 +2310,8 @@
                 else:
                     raise AssertionError("bad argcode")
                 position += 1
+            elif argtype == "jitcode_position":
+                value = position
             else:
                 raise AssertionError("bad argtype: %r" % (argtype,))
             args += (value,)
@@ -2349,3 +2356,15 @@
     argtypes = unrolling_iterable(unboundmethod.argtypes)
     handler.func_name = 'handler_' + name
     return handler
+
+def put_back_list_of_boxes3(frame, position, newvalue):
+    code = frame.bytecode
+    length1 = ord(code[position])
+    position2 = position + 1 + length1
+    length2 = ord(code[position2])
+    position3 = position2 + 1 + length2
+    length3 = ord(code[position3])
+    assert len(newvalue) == length1 + length2 + length3
+    frame._put_back_list_of_boxes(newvalue, 0, position)
+    frame._put_back_list_of_boxes(newvalue, length1, position2)
+    frame._put_back_list_of_boxes(newvalue, length1 + length2, position3)

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/resoperation.py	Tue Nov 23 13:26:19 2010
@@ -143,6 +143,16 @@
     def can_raise(self):
         return rop._CANRAISE_FIRST <= self.getopnum() <= rop._CANRAISE_LAST
 
+    def is_malloc(self):
+        # a slightly different meaning from can_malloc
+        return rop._MALLOC_FIRST <= self.getopnum() <= rop._MALLOC_LAST
+
+    def can_malloc(self):
+        return self.is_call() or self.is_malloc()
+
+    def is_call(self):
+        return rop._CALL_FIRST <= self.getopnum() <= rop._CALL_LAST
+
     def is_ovf(self):
         return rop._OVF_FIRST <= self.getopnum() <= rop._OVF_LAST
 
@@ -441,9 +451,13 @@
     'GETARRAYITEM_RAW/2d',
     'GETFIELD_GC/1d',
     'GETFIELD_RAW/1d',
+    '_MALLOC_FIRST',
     'NEW/0d',
     'NEW_WITH_VTABLE/1',
     'NEW_ARRAY/1d',
+    'NEWSTR/1',
+    'NEWUNICODE/1',
+    '_MALLOC_LAST',
     'FORCE_TOKEN/0',
     'VIRTUAL_REF/2',         # removed before it's passed to the backend
     '_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
@@ -452,10 +466,8 @@
     'SETARRAYITEM_RAW/3d',
     'SETFIELD_GC/2d',
     'SETFIELD_RAW/2d',
-    'NEWSTR/1',
     'STRSETITEM/3',
     'UNICODESETITEM/3',
-    'NEWUNICODE/1',
     #'RUNTIMENEW/1',     # ootype operation    
     'COND_CALL_GC_WB/2d', # [objptr, newvalue]   (for the write barrier)
     'DEBUG_MERGE_POINT/2',      # debugging only
@@ -465,6 +477,7 @@
     'COPYUNICODECONTENT/5',
 
     '_CANRAISE_FIRST', # ----- start of can_raise operations -----
+    '_CALL_FIRST',
     'CALL/*d',
     'CALL_ASSEMBLER/*d',  # call already compiled assembler
     'CALL_MAY_FORCE/*d',
@@ -473,6 +486,7 @@
     #'OOSEND_PURE',                # ootype operation
     'CALL_PURE/*d',             # removed before it's passed to the backend
                              # CALL_PURE(result, func, arg_1,..,arg_n)
+    '_CALL_LAST',
     '_CANRAISE_LAST', # ----- end of can_raise operations -----
 
     '_OVF_FIRST', # ----- start of is_ovf operations -----

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/resume.py	Tue Nov 23 13:26:19 2010
@@ -4,8 +4,7 @@
 from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp import jitprof
-from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
-from pypy.jit.codewriter.effectinfo import funcptr_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
 from pypy.rlib import rarithmetic
 from pypy.rlib.objectmodel import we_are_translated, specialize
@@ -66,12 +65,21 @@
     snapshot = Snapshot(snapshot, boxes)
     storage.rd_snapshot = snapshot
 
-class Numbering(object):
-    __slots__ = ('prev', 'nums')
-
-    def __init__(self, prev, nums):
-        self.prev = prev
-        self.nums = nums
+#
+# The following is equivalent to the RPython-level declaration:
+#
+#     class Numbering: __slots__ = ['prev', 'nums']
+#
+# except that it is more compact in translated programs, because the
+# array 'nums' is inlined in the single NUMBERING object.  This is
+# important because this is often the biggest single consumer of memory
+# in a pypy-c-jit.
+#
+NUMBERINGP = lltype.Ptr(lltype.GcForwardReference())
+NUMBERING = lltype.GcStruct('Numbering',
+                            ('prev', NUMBERINGP),
+                            ('nums', lltype.Array(rffi.SHORT)))
+NUMBERINGP.TO.become(NUMBERING)
 
 TAGMASK = 3
 
@@ -163,7 +171,7 @@
 
     def number(self, values, snapshot):
         if snapshot is None:
-            return None, {}, 0
+            return lltype.nullptr(NUMBERING), {}, 0
         if snapshot in self.numberings:
              numb, liveboxes, v = self.numberings[snapshot]
              return numb, liveboxes.copy(), v
@@ -172,7 +180,7 @@
         n = len(liveboxes)-v
         boxes = snapshot.boxes
         length = len(boxes)
-        nums = [UNASSIGNED] * length
+        numb = lltype.malloc(NUMBERING, length)
         for i in range(length):
             box = boxes[i]
             value = values.get(box, None)
@@ -191,9 +199,9 @@
                     tagged = tag(n, TAGBOX)
                     n += 1
                 liveboxes[box] = tagged
-            nums[i] = tagged
+            numb.nums[i] = tagged
         #
-        numb = Numbering(numb1, nums)
+        numb.prev = numb1
         self.numberings[snapshot] = numb, liveboxes, v
         return numb, liveboxes.copy(), v
 
@@ -298,7 +306,7 @@
         # compute the numbering
         storage = self.storage
         # make sure that nobody attached resume data to this guard yet
-        assert storage.rd_numb is None
+        assert not storage.rd_numb
         numb, liveboxes_from_env, v = self.memo.number(values,
                                                        storage.rd_snapshot)
         self.liveboxes_from_env = liveboxes_from_env
@@ -723,34 +731,36 @@
         self.boxes_f = boxes_f
         self._prepare_next_section(info)
 
-    def consume_virtualizable_boxes(self, vinfo, nums):
+    def consume_virtualizable_boxes(self, vinfo, numb):
         # we have to ignore the initial part of 'nums' (containing vrefs),
         # find the virtualizable from nums[-1], and use it to know how many
         # boxes of which type we have to return.  This does not write
         # anything into the virtualizable.
-        virtualizablebox = self.decode_ref(nums[-1])
+        index = len(numb.nums) - 1
+        virtualizablebox = self.decode_ref(numb.nums[index])
         virtualizable = vinfo.unwrap_virtualizable_box(virtualizablebox)
-        return vinfo.load_list_of_boxes(virtualizable, self, nums)
+        return vinfo.load_list_of_boxes(virtualizable, self, numb)
 
-    def consume_virtualref_boxes(self, nums, end):
+    def consume_virtualref_boxes(self, numb, end):
         # Returns a list of boxes, assumed to be all BoxPtrs.
         # We leave up to the caller to call vrefinfo.continue_tracing().
         assert (end & 1) == 0
-        return [self.decode_ref(nums[i]) for i in range(end)]
+        return [self.decode_ref(numb.nums[i]) for i in range(end)]
 
     def consume_vref_and_vable_boxes(self, vinfo, ginfo):
-        nums = self.cur_numb.nums
-        self.cur_numb = self.cur_numb.prev
+        numb = self.cur_numb
+        self.cur_numb = numb.prev
         if vinfo is not None:
-            virtualizable_boxes = self.consume_virtualizable_boxes(vinfo, nums)
-            end = len(nums) - len(virtualizable_boxes)
+            virtualizable_boxes = self.consume_virtualizable_boxes(vinfo, numb)
+            end = len(numb.nums) - len(virtualizable_boxes)
         elif ginfo is not None:
-            virtualizable_boxes = [self.decode_ref(nums[-1])]
-            end = len(nums) - 1
+            index = len(numb.nums) - 1
+            virtualizable_boxes = [self.decode_ref(numb.nums[index])]
+            end = len(numb.nums) - 1
         else:
             virtualizable_boxes = None
-            end = len(nums)
-        virtualref_boxes = self.consume_virtualref_boxes(nums, end)
+            end = len(numb.nums)
+        virtualref_boxes = self.consume_virtualref_boxes(numb, end)
         return virtualizable_boxes, virtualref_boxes
 
     def allocate_with_vtable(self, known_class):
@@ -774,14 +784,16 @@
                                            strbox, ConstInt(index), charbox)
 
     def concat_strings(self, str1num, str2num):
-        calldescr, func = callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
+        cic = self.metainterp.staticdata.callinfocollection
+        calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
         str1box = self.decode_box(str1num, REF)
         str2box = self.decode_box(str2num, REF)
         return self.metainterp.execute_and_record_varargs(
             rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
 
     def slice_string(self, strnum, startnum, lengthnum):
-        calldescr, func = callinfo_for_oopspec(EffectInfo.OS_STR_SLICE)
+        cic = self.metainterp.staticdata.callinfocollection
+        calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_STR_SLICE)
         strbox = self.decode_box(strnum, REF)
         startbox = self.decode_box(startnum, INT)
         lengthbox = self.decode_box(lengthnum, INT)
@@ -800,14 +812,16 @@
                                            strbox, ConstInt(index), charbox)
 
     def concat_unicodes(self, str1num, str2num):
-        calldescr, func = callinfo_for_oopspec(EffectInfo.OS_UNI_CONCAT)
+        cic = self.metainterp.staticdata.callinfocollection
+        calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_UNI_CONCAT)
         str1box = self.decode_box(str1num, REF)
         str2box = self.decode_box(str2num, REF)
         return self.metainterp.execute_and_record_varargs(
             rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
 
     def slice_unicode(self, strnum, startnum, lengthnum):
-        calldescr, func = callinfo_for_oopspec(EffectInfo.OS_UNI_SLICE)
+        cic = self.metainterp.staticdata.callinfocollection
+        calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_UNI_SLICE)
         strbox = self.decode_box(strnum, REF)
         startbox = self.decode_box(startnum, INT)
         lengthbox = self.decode_box(lengthnum, INT)
@@ -903,8 +917,8 @@
 
 def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage,
                               all_virtuals=None):
-    resumereader = ResumeDataDirectReader(blackholeinterpbuilder.cpu, storage,
-                                          all_virtuals)
+    resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
+                                          storage, all_virtuals)
     vinfo = jitdriver_sd.virtualizable_info
     ginfo = jitdriver_sd.greenfield_info
     vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
@@ -939,7 +953,7 @@
     return firstbh
 
 def force_from_resumedata(metainterp_sd, storage, vinfo, ginfo):
-    resumereader = ResumeDataDirectReader(metainterp_sd.cpu, storage)
+    resumereader = ResumeDataDirectReader(metainterp_sd, storage)
     resumereader.handling_async_forcing()
     vrefinfo = metainterp_sd.virtualref_info
     resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
@@ -953,8 +967,9 @@
     #             1: in handle_async_forcing
     #             2: resuming from the GUARD_NOT_FORCED
 
-    def __init__(self, cpu, storage, all_virtuals=None):
-        self._init(cpu, storage)
+    def __init__(self, metainterp_sd, storage, all_virtuals=None):
+        self._init(metainterp_sd.cpu, storage)
+        self.callinfocollection = metainterp_sd.callinfocollection
         if all_virtuals is None:        # common case
             self._prepare(storage)
         else:
@@ -973,23 +988,24 @@
         info = blackholeinterp.get_current_position_info()
         self._prepare_next_section(info)
 
-    def consume_virtualref_info(self, vrefinfo, nums, end):
+    def consume_virtualref_info(self, vrefinfo, numb, end):
         # we have to decode a list of references containing pairs
         # [..., virtual, vref, ...]  stopping at 'end'
         assert (end & 1) == 0
         for i in range(0, end, 2):
-            virtual = self.decode_ref(nums[i])
-            vref = self.decode_ref(nums[i+1])
+            virtual = self.decode_ref(numb.nums[i])
+            vref = self.decode_ref(numb.nums[i+1])
             # For each pair, we store the virtual inside the vref.
             vrefinfo.continue_tracing(vref, virtual)
 
-    def consume_vable_info(self, vinfo, nums):
+    def consume_vable_info(self, vinfo, numb):
         # we have to ignore the initial part of 'nums' (containing vrefs),
         # find the virtualizable from nums[-1], load all other values
         # from the CPU stack, and copy them into the virtualizable
         if vinfo is None:
-            return len(nums)
-        virtualizable = self.decode_ref(nums[-1])
+            return len(numb.nums)
+        index = len(numb.nums) - 1
+        virtualizable = self.decode_ref(numb.nums[index])
         virtualizable = vinfo.cast_gcref_to_vtype(virtualizable)
         if self.resume_after_guard_not_forced == 1:
             # in the middle of handle_async_forcing()
@@ -1001,7 +1017,7 @@
             # is and stays 0.  Note the call to reset_vable_token() in
             # warmstate.py.
             assert not virtualizable.vable_token
-        return vinfo.write_from_resume_data_partial(virtualizable, self, nums)
+        return vinfo.write_from_resume_data_partial(virtualizable, self, numb)
 
     def load_value_of_type(self, TYPE, tagged):
         from pypy.jit.metainterp.warmstate import specialize_value
@@ -1018,12 +1034,12 @@
     load_value_of_type._annspecialcase_ = 'specialize:arg(1)'
 
     def consume_vref_and_vable(self, vrefinfo, vinfo, ginfo):
-        nums = self.cur_numb.nums
-        self.cur_numb = self.cur_numb.prev
+        numb = self.cur_numb
+        self.cur_numb = numb.prev
         if self.resume_after_guard_not_forced != 2:
-            end_vref = self.consume_vable_info(vinfo, nums)
+            end_vref = self.consume_vable_info(vinfo, numb)
             if ginfo is not None: end_vref -= 1
-            self.consume_virtualref_info(vrefinfo, nums, end_vref)
+            self.consume_virtualref_info(vrefinfo, numb, end_vref)
 
     def allocate_with_vtable(self, known_class):
         from pypy.jit.metainterp.executor import exec_new_with_vtable
@@ -1047,7 +1063,8 @@
         str2 = self.decode_ref(str2num)
         str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str1)
         str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str2)
-        funcptr = funcptr_for_oopspec(EffectInfo.OS_STR_CONCAT)
+        cic = self.callinfocollection
+        funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_STR_CONCAT)
         result = funcptr(str1, str2)
         return lltype.cast_opaque_ptr(llmemory.GCREF, result)
 
@@ -1056,7 +1073,8 @@
         start = self.decode_int(startnum)
         length = self.decode_int(lengthnum)
         str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str)
-        funcptr = funcptr_for_oopspec(EffectInfo.OS_STR_SLICE)
+        cic = self.callinfocollection
+        funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_STR_SLICE)
         result = funcptr(str, start, start + length)
         return lltype.cast_opaque_ptr(llmemory.GCREF, result)
 
@@ -1072,7 +1090,8 @@
         str2 = self.decode_ref(str2num)
         str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str1)
         str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str2)
-        funcptr = funcptr_for_oopspec(EffectInfo.OS_UNI_CONCAT)
+        cic = self.callinfocollection
+        funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_UNI_CONCAT)
         result = funcptr(str1, str2)
         return lltype.cast_opaque_ptr(llmemory.GCREF, result)
 
@@ -1081,7 +1100,8 @@
         start = self.decode_int(startnum)
         length = self.decode_int(lengthnum)
         str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str)
-        funcptr = funcptr_for_oopspec(EffectInfo.OS_UNI_SLICE)
+        cic = self.callinfocollection
+        funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_UNI_SLICE)
         result = funcptr(str, start, start + length)
         return lltype.cast_opaque_ptr(llmemory.GCREF, result)
 
@@ -1172,8 +1192,9 @@
                         'at', compute_unique_id(frameinfo))
             frameinfo = frameinfo.prev
         numb = storage.rd_numb
-        while numb is not None:
-            debug_print('\tnumb', str([untag(i) for i in numb.nums]),
+        while numb:
+            debug_print('\tnumb', str([untag(numb.nums[i])
+                                       for i in range(len(numb.nums))]),
                         'at', compute_unique_id(numb))
             numb = numb.prev
         for const in storage.rd_consts:

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_compile.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_compile.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_compile.py	Tue Nov 23 13:26:19 2010
@@ -85,7 +85,7 @@
     metainterp.history.inputargs = loop.inputargs[:]
     #
     loop_tokens = []
-    loop_token = compile_new_loop(metainterp, loop_tokens, [], 0)
+    loop_token = compile_new_loop(metainterp, loop_tokens, 0)
     assert loop_tokens == [loop_token]
     assert loop_token.number == 1
     assert staticdata.globaldata.loopnumbering == 2
@@ -101,7 +101,7 @@
     metainterp.history.operations = loop.operations[:]
     metainterp.history.inputargs = loop.inputargs[:]
     #
-    loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0)
+    loop_token_2 = compile_new_loop(metainterp, loop_tokens, 0)
     assert loop_token_2 is loop_token
     assert loop_tokens == [loop_token]
     assert len(cpu.seen) == 0

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_exception.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_exception.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_exception.py	Tue Nov 23 13:26:19 2010
@@ -1,6 +1,6 @@
 import py, sys
 from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
-from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE
+from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE, dont_look_inside
 from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask
 from pypy.jit.codewriter.policy import StopAtXPolicy
 
@@ -588,6 +588,33 @@
         res = self.interp_operations(f, [99])
         assert res == 21
 
+    def test_bug_exc1_noexc_exc2(self):
+        myjitdriver = JitDriver(greens=[], reds=['i'])
+        @dont_look_inside
+        def rescall(i):
+            if i < 10:
+                raise KeyError
+            if i < 20:
+                return None
+            raise ValueError
+        def f(i):
+            while i < 30:
+                myjitdriver.can_enter_jit(i=i)
+                myjitdriver.jit_merge_point(i=i)
+                try:
+                    rescall(i)
+                except KeyError:
+                    assert i < 10
+                except ValueError:
+                    assert i >= 20
+                else:
+                    assert 10 <= i < 20
+                i += 1
+            return i
+        res = self.meta_interp(f, [0], inline=True)
+        assert res == 30
+
+
 class MyError(Exception):
     def __init__(self, n):
         self.n = n

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_optimizeopt.py	Tue Nov 23 13:26:19 2010
@@ -41,7 +41,7 @@
     b1 = BoxInt()
     opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu),
                                 None)
-    fdescr = ResumeGuardDescr(None, None)
+    fdescr = ResumeGuardDescr(None)
     op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr)
     # setup rd data
     fi0 = resume.FrameInfo(None, "code0", 11)
@@ -51,12 +51,12 @@
     #
     opt.store_final_boxes_in_guard(op)
     if op.getfailargs() == [b0, b1]:
-        assert fdescr.rd_numb.nums      == [tag(1, TAGBOX)]
-        assert fdescr.rd_numb.prev.nums == [tag(0, TAGBOX)]
+        assert list(fdescr.rd_numb.nums)      == [tag(1, TAGBOX)]
+        assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)]
     else:
         assert op.getfailargs() == [b1, b0]
-        assert fdescr.rd_numb.nums      == [tag(0, TAGBOX)]
-        assert fdescr.rd_numb.prev.nums == [tag(1, TAGBOX)]
+        assert list(fdescr.rd_numb.nums)      == [tag(0, TAGBOX)]
+        assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)]
     assert fdescr.rd_virtuals is None
     assert fdescr.rd_consts == []
 
@@ -264,6 +264,8 @@
         metainterp_sd = FakeMetaInterpStaticData(self.cpu)
         if hasattr(self, 'vrefinfo'):
             metainterp_sd.virtualref_info = self.vrefinfo
+        if hasattr(self, 'callinfocollection'):
+            metainterp_sd.callinfocollection = self.callinfocollection
         optimize_loop_1(metainterp_sd, loop)
         #
         expected = self.parse(optops)
@@ -787,8 +789,12 @@
         i3 = call(i2, descr=nonwritedescr)
         jump(i1)       # the exception is considered lost when we loop back
         """
+        # note that 'guard_no_exception' at the very start must be kept
+        # around: bridges may start with one.  (In case of loops we could
+        # remove it, but we probably don't care.)
         expected = """
         [i]
+        guard_no_exception() []
         i1 = int_add(i, 3)
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
@@ -4180,22 +4186,20 @@
     # ----------
     def optimize_strunicode_loop_extradescrs(self, ops, spectext, optops):
         from pypy.jit.metainterp.optimizeopt import string
-        def my_callinfo_for_oopspec(oopspecindex):
-            calldescrtype = type(LLtypeMixin.strequaldescr)
-            for value in LLtypeMixin.__dict__.values():
-                if isinstance(value, calldescrtype):
-                    if (value.get_extra_info() and
-                        value.get_extra_info().oopspecindex == oopspecindex):
-                        # returns 0 for 'func' in this test
-                        return value, 0
-            raise AssertionError("not found: oopspecindex=%d" % oopspecindex)
+        class FakeCallInfoCollection:
+            def callinfo_for_oopspec(self, oopspecindex):
+                calldescrtype = type(LLtypeMixin.strequaldescr)
+                for value in LLtypeMixin.__dict__.values():
+                    if isinstance(value, calldescrtype):
+                        extra = value.get_extra_info()
+                        if extra and extra.oopspecindex == oopspecindex:
+                            # returns 0 for 'func' in this test
+                            return value, 0
+                raise AssertionError("not found: oopspecindex=%d" %
+                                     oopspecindex)
         #
-        saved = string.callinfo_for_oopspec
-        try:
-            string.callinfo_for_oopspec = my_callinfo_for_oopspec
-            self.optimize_strunicode_loop(ops, spectext, optops)
-        finally:
-            string.callinfo_for_oopspec = saved
+        self.callinfocollection = FakeCallInfoCollection()
+        self.optimize_strunicode_loop(ops, spectext, optops)
 
     def test_str_equal_noop1(self):
         ops = """

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_recursive.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_recursive.py	Tue Nov 23 13:26:19 2010
@@ -1142,6 +1142,19 @@
             res = self.meta_interp(main, [], inline=True, trace_limit=tlimit)
             assert ''.join(res.chars) == 'ABCDEFGHIabcdefghijJ' * 5
 
+    def test_no_duplicates_bug(self):
+        driver = JitDriver(greens = ['codeno'], reds = ['i'],
+                           get_printable_location = lambda codeno: str(codeno))
+        def portal(codeno, i):
+            while i > 0:
+                driver.can_enter_jit(codeno=codeno, i=i)
+                driver.jit_merge_point(codeno=codeno, i=i)
+                if codeno > 0:
+                    break
+                portal(i, i)
+                i -= 1
+        self.meta_interp(portal, [0, 10], inline=True)
+
 
 class TestLLtype(RecursiveTests, LLJitMixin):
     pass

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resoperation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resoperation.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resoperation.py	Tue Nov 23 13:26:19 2010
@@ -61,3 +61,10 @@
     assert op.getarglist() == ['a', 'b']
     assert op.result == 'c'
     assert op.getdescr() is mydescr
+
+def test_can_malloc():
+    mydescr = AbstractDescr()
+    assert rop.ResOperation(rop.rop.NEW, [], 'b').can_malloc()
+    call = rop.ResOperation(rop.rop.CALL, ['a', 'b'], 'c', descr=mydescr)
+    assert call.can_malloc()
+    assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c').can_malloc()

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resume.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resume.py	Tue Nov 23 13:26:19 2010
@@ -51,6 +51,7 @@
 
 class MyMetaInterp:
     _already_allocated_resume_virtuals = None
+    callinfocollection = None
 
     def __init__(self, cpu=None):
         if cpu is None:
@@ -141,6 +142,13 @@
     assert bh.written_f == expected_f
 
 
+def Numbering(prev, nums):
+    numb = lltype.malloc(NUMBERING, len(nums))
+    numb.prev = prev or lltype.nullptr(NUMBERING)
+    for i in range(len(nums)):
+        numb.nums[i] = nums[i]
+    return numb
+
 def test_simple_read():
     #b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()]
     c1, c2, c3 = [ConstInt(111), ConstInt(222), ConstInt(333)]
@@ -156,12 +164,12 @@
     storage.rd_numb = numb
     #
     cpu = MyCPU([42, gcref1, -66])
-    reader = ResumeDataDirectReader(cpu, storage)
+    metainterp = MyMetaInterp(cpu)
+    reader = ResumeDataDirectReader(metainterp, storage)
     _next_section(reader, 42, 111, gcrefnull, 42, gcref1)
     _next_section(reader, 222, 333)
     _next_section(reader, 42, gcref1, -66)
     #
-    metainterp = MyMetaInterp(cpu)
     reader = ResumeDataBoxReader(storage, metainterp)
     bi, br, bf = [None]*3, [None]*2, [None]*0
     info = MyBlackholeInterp([lltype.Signed, lltype.Signed,
@@ -193,7 +201,7 @@
     storage.rd_numb = numb
     #
     cpu = MyCPU([])
-    reader = ResumeDataDirectReader(cpu, storage)
+    reader = ResumeDataDirectReader(MyMetaInterp(cpu), storage)
     _next_section(reader, 100)
 
 
@@ -211,7 +219,7 @@
     class FakeMetainterp(object):
         _already_allocated_resume_virtuals = None
         cpu = None
-    reader = ResumeDataDirectReader(None, FakeStorage())
+    reader = ResumeDataDirectReader(MyMetaInterp(None), FakeStorage())
     assert reader.force_all_virtuals() == ["allocated", reader.virtual_default]
 
 # ____________________________________________________________
@@ -390,15 +398,15 @@
     assert fi1.pc == 3
 
 def test_Numbering_create():
-    l = [1, 2]
+    l = [rffi.r_short(1), rffi.r_short(2)]
     numb = Numbering(None, l)
-    assert numb.prev is None
-    assert numb.nums is l
+    assert not numb.prev
+    assert list(numb.nums) == l
 
-    l1 = ['b3']
+    l1 = [rffi.r_short(3)]
     numb1 = Numbering(numb, l1)
-    assert numb1.prev is numb
-    assert numb1.nums is l1
+    assert numb1.prev == numb
+    assert list(numb1.nums) == l1
 
 def test_capture_resumedata():
     b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()]
@@ -764,11 +772,12 @@
 
     assert liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
                          b3: tag(2, TAGBOX)}
-    assert numb.nums == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
-                         tag(1, TAGINT)]
-    assert numb.prev.nums == [tag(0, TAGBOX), tag(1, TAGINT), tag(1, TAGBOX),
-                              tag(0, TAGBOX), tag(2, TAGINT)]
-    assert numb.prev.prev is None
+    assert list(numb.nums) == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
+                               tag(1, TAGINT)]
+    assert list(numb.prev.nums) == [tag(0, TAGBOX), tag(1, TAGINT),
+                                    tag(1, TAGBOX),
+                                    tag(0, TAGBOX), tag(2, TAGINT)]
+    assert not numb.prev.prev
 
     numb2, liveboxes2, v = memo.number({}, snap2)
     assert v == 0
@@ -776,9 +785,9 @@
     assert liveboxes2 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
                          b3: tag(2, TAGBOX)}
     assert liveboxes2 is not liveboxes
-    assert numb2.nums == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
-                         tag(3, TAGINT)]
-    assert numb2.prev is numb.prev
+    assert list(numb2.nums) == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
+                                tag(3, TAGINT)]
+    assert numb2.prev == numb.prev
 
     env3 = [c3, b3, b1, c3]
     snap3 = Snapshot(snap, env3)
@@ -799,9 +808,9 @@
     assert v == 0
     
     assert liveboxes3 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX)}
-    assert numb3.nums == [tag(3, TAGINT), tag(4, TAGINT), tag(0, TAGBOX),
-                          tag(3, TAGINT)]
-    assert numb3.prev is numb.prev
+    assert list(numb3.nums) == [tag(3, TAGINT), tag(4, TAGINT), tag(0, TAGBOX),
+                                tag(3, TAGINT)]
+    assert numb3.prev == numb.prev
 
     # virtual
     env4 = [c3, b4, b1, c3]
@@ -812,9 +821,9 @@
     
     assert liveboxes4 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
                           b4: tag(0, TAGVIRTUAL)}
-    assert numb4.nums == [tag(3, TAGINT), tag(0, TAGVIRTUAL), tag(0, TAGBOX),
-                          tag(3, TAGINT)]
-    assert numb4.prev is numb.prev
+    assert list(numb4.nums) == [tag(3, TAGINT), tag(0, TAGVIRTUAL),
+                                tag(0, TAGBOX), tag(3, TAGINT)]
+    assert numb4.prev == numb.prev
 
     env5 = [b1, b4, b5]
     snap5 = Snapshot(snap4, env5)    
@@ -825,9 +834,9 @@
     
     assert liveboxes5 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
                           b4: tag(0, TAGVIRTUAL), b5: tag(1, TAGVIRTUAL)}
-    assert numb5.nums == [tag(0, TAGBOX), tag(0, TAGVIRTUAL),
-                                          tag(1, TAGVIRTUAL)]
-    assert numb5.prev is numb4
+    assert list(numb5.nums) == [tag(0, TAGBOX), tag(0, TAGVIRTUAL),
+                                                tag(1, TAGVIRTUAL)]
+    assert numb5.prev == numb4
 
 def test_ResumeDataLoopMemo_number_boxes():
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
@@ -925,7 +934,7 @@
     liveboxes = modifier.finish({})
     assert storage.rd_snapshot is None
     cpu = MyCPU([])
-    reader = ResumeDataDirectReader(cpu, storage)
+    reader = ResumeDataDirectReader(MyMetaInterp(cpu), storage)
     _next_section(reader, sys.maxint, 2**16, -65)
     _next_section(reader, 2, 3)
     _next_section(reader, sys.maxint, 1, sys.maxint, 2**16)

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_virtualref.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_virtualref.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_virtualref.py	Tue Nov 23 13:26:19 2010
@@ -88,7 +88,11 @@
         cpu.get_latest_value_int = lambda i:guard_op.getfailargs()[i].getint()
         cpu.get_latest_value_ref = lambda i:guard_op.getfailargs()[i].getref_base()
         cpu.clear_latest_values = lambda count: None
-        resumereader = ResumeDataDirectReader(cpu, guard_op.getdescr())
+        class FakeMetaInterpSd:
+            callinfocollection = None
+        FakeMetaInterpSd.cpu = cpu
+        resumereader = ResumeDataDirectReader(FakeMetaInterpSd(),
+                                              guard_op.getdescr())
         vrefinfo = self.metainterp.staticdata.virtualref_info
         lst = []
         vrefinfo.continue_tracing = lambda vref, virtual: \

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_ztranslation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_ztranslation.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_ztranslation.py	Tue Nov 23 13:26:19 2010
@@ -79,7 +79,7 @@
         res = ll_meta_interp(main, [40, 5], CPUClass=self.CPUClass,
                              type_system=self.type_system)
         assert res == main(40, 5)
-        res = rpython_ll_meta_interp(main, [40, 5], loops=2,
+        res = rpython_ll_meta_interp(main, [40, 5],
                                      CPUClass=self.CPUClass,
                                      type_system=self.type_system,
                                      optimizer=OPTIMIZER_FULL,
@@ -120,7 +120,7 @@
         res = ll_meta_interp(main, [40], CPUClass=self.CPUClass,
                              type_system=self.type_system)
         assert res == main(40)
-        res = rpython_ll_meta_interp(main, [40], loops=2, CPUClass=self.CPUClass,
+        res = rpython_ll_meta_interp(main, [40], CPUClass=self.CPUClass,
                                      type_system=self.type_system,
                                      optimizer=OPTIMIZER_FULL,
                                      ProfilerClass=Profiler)

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/virtualizable.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/virtualizable.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/virtualizable.py	Tue Nov 23 13:26:19 2010
@@ -100,48 +100,48 @@
                     i = i + 1
             assert len(boxes) == i + 1
         #
-        def write_from_resume_data_partial(virtualizable, reader, nums):
+        def write_from_resume_data_partial(virtualizable, reader, numb):
             # Load values from the reader (see resume.py) described by
             # the list of numbers 'nums', and write them in their proper
             # place in the 'virtualizable'.  This works from the end of
             # the list and returns the index in 'nums' of the start of
             # the virtualizable data found, allowing the caller to do
             # further processing with the start of the list.
-            i = len(nums) - 1
+            i = len(numb.nums) - 1
             assert i >= 0
             for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev:
                 lst = getattr(virtualizable, fieldname)
                 for j in range(getlength(lst)-1, -1, -1):
                     i -= 1
                     assert i >= 0
-                    x = reader.load_value_of_type(ARRAYITEMTYPE, nums[i])
+                    x = reader.load_value_of_type(ARRAYITEMTYPE, numb.nums[i])
                     setarrayitem(lst, j, x)
             for FIELDTYPE, fieldname in unroll_static_fields_rev:
                 i -= 1
                 assert i >= 0
-                x = reader.load_value_of_type(FIELDTYPE, nums[i])
+                x = reader.load_value_of_type(FIELDTYPE, numb.nums[i])
                 setattr(virtualizable, fieldname, x)
             return i
         #
-        def load_list_of_boxes(virtualizable, reader, nums):
+        def load_list_of_boxes(virtualizable, reader, numb):
             # Uses 'virtualizable' only to know the length of the arrays;
             # does not write anything into it.  The returned list is in
             # the format expected of virtualizable_boxes, so it ends in
             # the virtualizable itself.
-            i = len(nums) - 1
+            i = len(numb.nums) - 1
             assert i >= 0
-            boxes = [reader.decode_box_of_type(self.VTYPEPTR, nums[i])]
+            boxes = [reader.decode_box_of_type(self.VTYPEPTR, numb.nums[i])]
             for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev:
                 lst = getattr(virtualizable, fieldname)
                 for j in range(getlength(lst)-1, -1, -1):
                     i -= 1
                     assert i >= 0
-                    box = reader.decode_box_of_type(ARRAYITEMTYPE, nums[i])
+                    box = reader.decode_box_of_type(ARRAYITEMTYPE,numb.nums[i])
                     boxes.append(box)
             for FIELDTYPE, fieldname in unroll_static_fields_rev:
                 i -= 1
                 assert i >= 0
-                box = reader.decode_box_of_type(FIELDTYPE, nums[i])
+                box = reader.decode_box_of_type(FIELDTYPE, numb.nums[i])
                 boxes.append(box)
             boxes.reverse()
             return boxes

Modified: pypy/branch/jitypes2/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/warmspot.py	Tue Nov 23 13:26:19 2010
@@ -98,8 +98,7 @@
         repeat -= 1
     return res
 
-def rpython_ll_meta_interp(function, args, backendopt=True,
-                           loops='not used right now', **kwds):
+def rpython_ll_meta_interp(function, args, backendopt=True, **kwds):
     return ll_meta_interp(function, args, backendopt=backendopt,
                           translate_support_code=True, **kwds)
 

Modified: pypy/branch/jitypes2/pypy/jit/tool/pypytrace-mode.el
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/tool/pypytrace-mode.el	(original)
+++ pypy/branch/jitypes2/pypy/jit/tool/pypytrace-mode.el	Tue Nov 23 13:26:19 2010
@@ -26,7 +26,7 @@
     ("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face))
     ;; comment out debug_merge_point, but then highlight specific part of it
     ("^debug_merge_point.*" . font-lock-comment-face)
-    ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)')"
+    ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)"
      (1 'compilation-warning t)
      (2 'escape-glyph t)
      (3 'font-lock-string-face t)

Modified: pypy/branch/jitypes2/pypy/module/__pypy__/__init__.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/__pypy__/__init__.py	(original)
+++ pypy/branch/jitypes2/pypy/module/__pypy__/__init__.py	Tue Nov 23 13:26:19 2010
@@ -23,6 +23,9 @@
                                  'interp_magic.method_cache_counter')
             self.extra_interpdef('reset_method_cache_counter',
                                  'interp_magic.reset_method_cache_counter')
+            if self.space.config.objspace.std.withmapdict:
+                self.extra_interpdef('mapdict_cache_counter',
+                                     'interp_magic.mapdict_cache_counter')
         PYC_MAGIC = get_pyc_magic(self.space)
         self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC)
         #

Modified: pypy/branch/jitypes2/pypy/module/__pypy__/interp_magic.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/__pypy__/interp_magic.py	(original)
+++ pypy/branch/jitypes2/pypy/module/__pypy__/interp_magic.py	Tue Nov 23 13:26:19 2010
@@ -2,6 +2,7 @@
 from pypy.interpreter.gateway import ObjSpace
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.objspace.std.typeobject import MethodCache
+from pypy.objspace.std.mapdict import IndexCache
 
 def internal_repr(space, w_object):
     return space.wrap('%r' % (w_object,))
@@ -36,4 +37,17 @@
     cache = space.fromcache(MethodCache)
     cache.misses = {}
     cache.hits = {}
-
+    if space.config.objspace.std.withmapdict:
+        cache = space.fromcache(IndexCache)
+        cache.misses = {}
+        cache.hits = {}
+
+def mapdict_cache_counter(space, name):
+    """Return a tuple (index_cache_hits, index_cache_misses) for lookups
+    in the mapdict cache with the given attribute name."""
+    assert space.config.objspace.std.withmethodcachecounter
+    assert space.config.objspace.std.withmapdict
+    cache = space.fromcache(IndexCache)
+    return space.newtuple([space.newint(cache.hits.get(name, 0)),
+                           space.newint(cache.misses.get(name, 0))])
+mapdict_cache_counter.unwrap_spec = [ObjSpace, str]

Modified: pypy/branch/jitypes2/pypy/module/_rawffi/test/test__rawffi.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/_rawffi/test/test__rawffi.py	(original)
+++ pypy/branch/jitypes2/pypy/module/_rawffi/test/test__rawffi.py	Tue Nov 23 13:26:19 2010
@@ -296,6 +296,7 @@
         assert _rawffi.charp2string(res[0]) is None
         arg1.free()
         arg2.free()
+        a.free()
 
     def test_raw_callable(self):
         import _rawffi

Modified: pypy/branch/jitypes2/pypy/module/_rawffi/test/test_nested.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/_rawffi/test/test_nested.py	(original)
+++ pypy/branch/jitypes2/pypy/module/_rawffi/test/test_nested.py	Tue Nov 23 13:26:19 2010
@@ -107,7 +107,6 @@
         assert S.fieldoffset('x') == 0
         assert S.fieldoffset('ar') == A5alignment
         s = S()
-        s = S()
         s.x = 'G'
         raises(TypeError, 's.ar')
         assert s.fieldaddress('ar') == s.buffer + S.fieldoffset('ar')

Modified: pypy/branch/jitypes2/pypy/module/array/interp_array.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/array/interp_array.py	(original)
+++ pypy/branch/jitypes2/pypy/module/array/interp_array.py	Tue Nov 23 13:26:19 2010
@@ -27,7 +27,7 @@
     typecode = typecode[0]
 
     if space.is_w(w_cls, space.gettypeobject(W_ArrayBase.typedef)):
-        if len(w_args.keywords_w) > 0:
+        if w_args.keywords: # XXX this might be forbidden fishing
             msg = 'array.array() does not take keyword arguments'
             raise OperationError(space.w_TypeError, space.wrap(msg))
         

Modified: pypy/branch/jitypes2/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/api.py	Tue Nov 23 13:26:19 2010
@@ -226,7 +226,7 @@
             def unwrapper(space, *args):
                 from pypy.module.cpyext.pyobject import Py_DecRef
                 from pypy.module.cpyext.pyobject import make_ref, from_ref
-                from pypy.module.cpyext.pyobject import BorrowPair
+                from pypy.module.cpyext.pyobject import Reference
                 newargs = ()
                 to_decref = []
                 assert len(args) == len(api_function.argtypes)
@@ -270,8 +270,8 @@
                             return api_function.error_value
                     if res is None:
                         return None
-                    elif isinstance(res, BorrowPair):
-                        return res.w_borrowed
+                    elif isinstance(res, Reference):
+                        return res.get_wrapped(space)
                     else:
                         return res
                 finally:
@@ -473,7 +473,7 @@
     @specialize.ll()
     def wrapper(*args):
         from pypy.module.cpyext.pyobject import make_ref, from_ref
-        from pypy.module.cpyext.pyobject import BorrowPair
+        from pypy.module.cpyext.pyobject import Reference
         # we hope that malloc removal removes the newtuple() that is
         # inserted exactly here by the varargs specializer
         llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
@@ -525,7 +525,7 @@
             elif is_PyObject(callable.api_func.restype):
                 if result is None:
                     retval = make_ref(space, None)
-                elif isinstance(result, BorrowPair):
+                elif isinstance(result, Reference):
                     retval = result.get_ref(space)
                 elif not rffi._isllptr(result):
                     retval = rffi.cast(callable.api_func.restype,
@@ -908,8 +908,10 @@
         from pypy.rlib import rdynload
         try:
             ll_libname = rffi.str2charp(path)
-            dll = rdynload.dlopen(ll_libname)
-            lltype.free(ll_libname, flavor='raw')
+            try:
+                dll = rdynload.dlopen(ll_libname)
+            finally:
+                lltype.free(ll_libname, flavor='raw')
         except rdynload.DLOpenError, e:
             raise operationerrfmt(
                 space.w_ImportError,

Modified: pypy/branch/jitypes2/pypy/module/cpyext/cdatetime.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/cdatetime.py	(original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/cdatetime.py	Tue Nov 23 13:26:19 2010
@@ -4,7 +4,7 @@
 from pypy.module.cpyext.api import (
     cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields)
 from pypy.module.cpyext.import_ import PyImport_Import
-from pypy.module.cpyext.typeobject import PyTypeObjectPtr
+from pypy.module.cpyext.typeobject import PyTypeObjectPtr, render_immortal
 from pypy.module.cpyext.state import State
 from pypy.interpreter.error import OperationError
 from pypy.tool.sourcetools import func_renamer
@@ -22,25 +22,34 @@
 @cpython_api([], lltype.Ptr(PyDateTime_CAPI),
              error=lltype.nullptr(PyDateTime_CAPI))
 def _PyDateTime_Import(space):
-    datetimeAPI = lltype.malloc(PyDateTime_CAPI, flavor='raw')
+    datetimeAPI = lltype.malloc(PyDateTime_CAPI, flavor='raw',
+                                track_allocation=False)
 
     if not we_are_translated():
         datetimeAPI_dealloc(space)
         space.fromcache(State).datetimeAPI = datetimeAPI
 
     w_datetime = PyImport_Import(space, space.wrap("datetime"))
+
     w_type = space.getattr(w_datetime, space.wrap("date"))
     datetimeAPI.c_DateType = rffi.cast(
         PyTypeObjectPtr, make_ref(space, w_type))
+    render_immortal(datetimeAPI.c_DateType, w_type)
+
     w_type = space.getattr(w_datetime, space.wrap("datetime"))
     datetimeAPI.c_DateTimeType = rffi.cast(
         PyTypeObjectPtr, make_ref(space, w_type))
+    render_immortal(datetimeAPI.c_DateTimeType, w_type)
+
     w_type = space.getattr(w_datetime, space.wrap("time"))
     datetimeAPI.c_TimeType = rffi.cast(
         PyTypeObjectPtr, make_ref(space, w_type))
+    render_immortal(datetimeAPI.c_TimeType, w_type)
+
     w_type = space.getattr(w_datetime, space.wrap("timedelta"))
     datetimeAPI.c_DeltaType = rffi.cast(
         PyTypeObjectPtr, make_ref(space, w_type))
+    render_immortal(datetimeAPI.c_DeltaType, w_type)
 
     return datetimeAPI
 

Modified: pypy/branch/jitypes2/pypy/module/cpyext/presetup.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/presetup.py	(original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/presetup.py	Tue Nov 23 13:26:19 2010
@@ -21,6 +21,8 @@
 
 from pypy.conftest import gettestobjspace
 from pypy.module.cpyext.api import build_bridge
+from pypy.module.imp.importing import get_so_extension
+
 usemodules = ['cpyext', 'thread']
 if sys.platform == 'win32':
     usemodules.append('_winreg') # necessary in distutils
@@ -35,6 +37,7 @@
 
 def patch_distutils():
     sysconfig.get_python_inc = get_python_inc
+    sysconfig.get_config_vars()['SO'] = get_so_extension(space)
 
 patch_distutils()
 

Modified: pypy/branch/jitypes2/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/pyobject.py	(original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/pyobject.py	Tue Nov 23 13:26:19 2010
@@ -424,7 +424,18 @@
     state = space.fromcache(RefcountState)
     return state.make_borrowed(w_container, w_borrowed)
 
-class BorrowPair:
+class Reference:
+    def __init__(self, pyobj):
+        assert not isinstance(pyobj, W_Root)
+        self.pyobj = pyobj
+
+    def get_ref(self, space):
+        return self.pyobj
+
+    def get_wrapped(self, space):
+        return from_ref(space, self.pyobj)
+
+class BorrowPair(Reference):
     """
     Delays the creation of a borrowed reference.
     """
@@ -435,6 +446,9 @@
     def get_ref(self, space):
         return make_borrowed_ref(space, self.w_container, self.w_borrowed)
 
+    def get_wrapped(self, space):
+        return self.w_borrowed
+
 def borrow_from(container, borrowed):
     return BorrowPair(container, borrowed)
 

Modified: pypy/branch/jitypes2/pypy/module/cpyext/test/test_borrow.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/test/test_borrow.py	(original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/test/test_borrow.py	Tue Nov 23 13:26:19 2010
@@ -31,6 +31,7 @@
                 g = PyTuple_GetItem(t, 0); // borrows reference again
                 printf("Refcnt4: %i\\n", f->ob_refcnt);
                 printf("COMPARE: %i\\n", f == g);
+                fflush(stdout);
                 Py_DECREF(t);
                 Py_RETURN_TRUE;
              """),

Modified: pypy/branch/jitypes2/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/test/test_cpyext.py	(original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/test/test_cpyext.py	Tue Nov 23 13:26:19 2010
@@ -42,7 +42,7 @@
         raises(ImportError, cpyext.load_module, "missing.file", "foo")
         raises(ImportError, cpyext.load_module, self.libc, "invalid.function")
 
-def compile_module(modname, **kwds):
+def compile_module(space, modname, **kwds):
     """
     Build an extension module and return the filename of the resulting native
     code file.
@@ -65,10 +65,8 @@
         [], eci,
         outputfilename=str(dirname/modname),
         standalone=False)
-    if sys.platform == 'win32':
-        pydname = soname.new(purebasename=modname, ext='.pyd')
-    else:
-        pydname = soname.new(purebasename=modname, ext='.so')
+    from pypy.module.imp.importing import get_so_extension
+    pydname = soname.new(purebasename=modname, ext=get_so_extension(space))
     soname.rename(pydname)
     return str(pydname)
 
@@ -153,7 +151,7 @@
             kwds["link_files"] = [str(api_library + '.so')]
             if sys.platform == 'linux2':
                 kwds["compile_extra"]=["-Werror=implicit-function-declaration"]
-        return compile_module(name, **kwds)
+        return compile_module(self.space, name, **kwds)
 
 
     def import_module(self, name, init=None, body='', load_it=True, filename=None):

Modified: pypy/branch/jitypes2/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/typeobject.py	Tue Nov 23 13:26:19 2010
@@ -182,10 +182,10 @@
 
     subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
     try:
-        obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
+        w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
     finally:
         Py_DecRef(space, w_subtype)
-    return obj
+    return w_obj
 
 @specialize.memo()
 def get_new_method_def(space):
@@ -193,10 +193,14 @@
     if state.new_method_def:
         return state.new_method_def
     from pypy.module.cpyext.modsupport import PyMethodDef
-    ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True)
+    ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
+                        immortal=True)
     ptr.c_ml_name = rffi.str2charp("__new__")
+    lltype.render_immortal(ptr.c_ml_name)
     rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
-    ptr.c_ml_doc = rffi.str2charp("T.__new__(S, ...) -> a new object with type S, a subtype of T")
+    ptr.c_ml_doc = rffi.str2charp(
+        "T.__new__(S, ...) -> a new object with type S, a subtype of T")
+    lltype.render_immortal(ptr.c_ml_doc)
     state.new_method_def = ptr
     return ptr
 
@@ -429,6 +433,12 @@
     finish_type_1(space, pto)
     finish_type_2(space, pto, w_type)
 
+    if space.type(w_type).is_cpytype():
+        # XXX Types with a C metatype are never freed, try to see why...
+        render_immortal(pto, w_type)
+        lltype.render_immortal(pto)
+        lltype.render_immortal(pto.c_tp_name)
+
     pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
     if pto.c_tp_base:
         if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
@@ -534,12 +544,25 @@
     w_obj.ready()
 
     finish_type_2(space, py_type, w_obj)
+    render_immortal(py_type, w_obj)
 
     state = space.fromcache(RefcountState)
     state.non_heaptypes_w.append(w_obj)
 
     return w_obj
 
+def render_immortal(py_type, w_obj):
+    lltype.render_immortal(py_type.c_tp_bases)
+    lltype.render_immortal(py_type.c_tp_mro)
+
+    assert isinstance(w_obj, W_TypeObject)
+    if w_obj.is_cpytype():
+        lltype.render_immortal(py_type.c_tp_dict)
+    else:
+        lltype.render_immortal(py_type.c_tp_name)
+    if not w_obj.is_cpytype() and w_obj.is_heaptype():
+        lltype.render_immortal(py_type)
+
 def finish_type_1(space, pto):
     """
     Sets up tp_bases, necessary before creating the interpreter type.

Modified: pypy/branch/jitypes2/pypy/module/gc/__init__.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/__init__.py	(original)
+++ pypy/branch/jitypes2/pypy/module/gc/__init__.py	Tue Nov 23 13:26:19 2010
@@ -29,6 +29,7 @@
                 'get_referents': 'referents.get_referents',
                 'get_referrers': 'referents.get_referrers',
                 '_dump_rpy_heap': 'referents._dump_rpy_heap',
+                'get_typeids_z': 'referents.get_typeids_z',
                 'GcRef': 'referents.W_GcRef',
                 })
         MixedModule.__init__(self, space, w_name)

Modified: pypy/branch/jitypes2/pypy/module/gc/app_referents.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/app_referents.py	(original)
+++ pypy/branch/jitypes2/pypy/module/gc/app_referents.py	Tue Nov 23 13:26:19 2010
@@ -14,11 +14,25 @@
     and [addr1]..[addrn] are addresses of other objects that this object
     points to.  The full dump is a list of such objects, with a marker
     [0][0][0][-1] inserted after all GC roots, before all non-roots.
+
+    If the argument is a filename and the 'zlib' module is available,
+    we also write a 'typeids.txt' in the same directory, if none exists.
     """
     if isinstance(file, str):
         f = open(file, 'wb')
         gc._dump_rpy_heap(f.fileno())
         f.close()
+        try:
+            import zlib, os
+        except ImportError:
+            pass
+        else:
+            filename2 = os.path.join(os.path.dirname(file), 'typeids.txt')
+            if not os.path.exists(filename2):
+                data = zlib.decompress(gc.get_typeids_z())
+                f = open(filename2, 'wb')
+                f.write(data)
+                f.close()
     else:
         if isinstance(file, int):
             fd = file

Modified: pypy/branch/jitypes2/pypy/module/gc/interp_gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/interp_gc.py	(original)
+++ pypy/branch/jitypes2/pypy/module/gc/interp_gc.py	Tue Nov 23 13:26:19 2010
@@ -10,6 +10,10 @@
         from pypy.objspace.std.typeobject import MethodCache
         cache = space.fromcache(MethodCache)
         cache.clear()
+        if space.config.objspace.std.withmapdict:
+            from pypy.objspace.std.mapdict import IndexCache
+            cache = space.fromcache(IndexCache)
+            cache.clear()
     rgc.collect()
     return space.wrap(0)
     

Modified: pypy/branch/jitypes2/pypy/module/gc/referents.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/referents.py	(original)
+++ pypy/branch/jitypes2/pypy/module/gc/referents.py	Tue Nov 23 13:26:19 2010
@@ -177,3 +177,9 @@
     if not ok:
         raise missing_operation(space)
 _dump_rpy_heap.unwrap_spec = [ObjSpace, int]
+
+def get_typeids_z(space):
+    a = rgc.get_typeids_z()
+    s = ''.join([a[i] for i in range(len(a))])
+    return space.wrap(s)
+get_typeids_z.unwrap_spec = [ObjSpace]

Modified: pypy/branch/jitypes2/pypy/module/gc/test/test_gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/test/test_gc.py	(original)
+++ pypy/branch/jitypes2/pypy/module/gc/test/test_gc.py	Tue Nov 23 13:26:19 2010
@@ -117,6 +117,33 @@
                     pass
             C().f()    # Fill the method cache
             rlist.append(weakref.ref(C))
+        for i in range(10):
+            f()
+        gc.collect()    # the classes C should all go away here
+        # the last class won't go in mapdict, as long as the code object of f
+        # is around
+        rlist.pop()
+        for r in rlist:
+            assert r() is None
+
+class AppTestGcMapDictIndexCache(AppTestGcMethodCache):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withmethodcache": True,
+                                       "objspace.std.withmapdict": True})
+
+
+    def test_clear_index_cache(self):
+        import gc, weakref
+        rlist = []
+        def f():
+            class C(object):
+                def f(self):
+                    pass
+            c = C()
+            c.x = 1
+            getattr(c, "x") # fill the index cache without using the local cache
+            getattr(c, "x")
+            rlist.append(weakref.ref(C))
         for i in range(5):
             f()
         gc.collect()    # the classes C should all go away here

Modified: pypy/branch/jitypes2/pypy/module/imp/importing.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/imp/importing.py	(original)
+++ pypy/branch/jitypes2/pypy/module/imp/importing.py	Tue Nov 23 13:26:19 2010
@@ -12,7 +12,7 @@
 from pypy.rlib import streamio, jit
 from pypy.rlib.streamio import StreamErrors
 from pypy.rlib.rarithmetic import intmask
-from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.objectmodel import we_are_translated, specialize
 
 SEARCH_ERROR = 0
 PY_SOURCE = 1
@@ -25,10 +25,26 @@
 # PY_CODERESOURCE = 8
 IMP_HOOK = 9
 
-if sys.platform.startswith('win'):
-    so_extension = ".pyd"
+if sys.platform == 'win32':
+    SO = ".pyd"
 else:
-    so_extension = ".so"
+    SO = ".so"
+DEFAULT_SOABI = 'pypy-14'
+
+ at specialize.memo()
+def get_so_extension(space):
+    if space.config.objspace.soabi is not None:
+        soabi = space.config.objspace.soabi
+    else:
+        soabi = DEFAULT_SOABI
+
+    if not soabi:
+        return SO
+
+    if not space.config.translating:
+        soabi += 'i'
+
+    return '.' + soabi + SO
 
 def find_modtype(space, filepart):
     """Check which kind of module to import for the given filepart,
@@ -53,6 +69,7 @@
             return PY_COMPILED, ".pyc", "rb"
 
     if space.config.objspace.usemodules.cpyext:
+        so_extension = get_so_extension(space)
         pydfile = filepart + so_extension
         if os.path.exists(pydfile) and case_ok(pydfile):
             return C_EXTENSION, so_extension, "rb"

Modified: pypy/branch/jitypes2/pypy/module/imp/interp_imp.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/imp/interp_imp.py	(original)
+++ pypy/branch/jitypes2/pypy/module/imp/interp_imp.py	Tue Nov 23 13:26:19 2010
@@ -8,10 +8,16 @@
 
 def get_suffixes(space):
     w = space.wrap
-    return space.newlist([
+    suffixes_w = []
+    if space.config.objspace.usemodules.cpyext:
+        suffixes_w.append(
+            space.newtuple([w(importing.get_so_extension(space)),
+                            w('rb'), w(importing.C_EXTENSION)]))
+    suffixes_w.extend([
         space.newtuple([w('.py'), w('U'), w(importing.PY_SOURCE)]),
         space.newtuple([w('.pyc'), w('rb'), w(importing.PY_COMPILED)]),
         ])
+    return space.newlist(suffixes_w)
 
 def get_magic(space):
     x = importing.get_pyc_magic(space)

Modified: pypy/branch/jitypes2/pypy/module/imp/test/test_app.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/imp/test/test_app.py	(original)
+++ pypy/branch/jitypes2/pypy/module/imp/test/test_app.py	Tue Nov 23 13:26:19 2010
@@ -47,6 +47,9 @@
             elif mode == self.imp.PY_COMPILED:
                 assert suffix in ('.pyc', '.pyo')
                 assert type == 'rb'
+            elif mode == self.imp.C_EXTENSION:
+                assert suffix.endswith(('.pyd', '.so'))
+                assert type == 'rb'
 
 
     def test_obscure_functions(self):

Modified: pypy/branch/jitypes2/pypy/module/imp/test/test_import.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/imp/test/test_import.py	(original)
+++ pypy/branch/jitypes2/pypy/module/imp/test/test_import.py	Tue Nov 23 13:26:19 2010
@@ -473,6 +473,17 @@
         except ImportError:
             pass
 
+class TestAbi:
+    def test_abi_tag(self):
+        space1 = gettestobjspace(soabi='TEST')
+        space2 = gettestobjspace(soabi='')
+        if sys.platform == 'win32':
+            assert importing.get_so_extension(space1) == '.TESTi.pyd'
+            assert importing.get_so_extension(space2) == '.pyd'
+        else:
+            assert importing.get_so_extension(space1) == '.TESTi.so'
+            assert importing.get_so_extension(space2) == '.so'
+
 def _getlong(data):
     x = marshal.dumps(data)
     return x[-4:]

Modified: pypy/branch/jitypes2/pypy/module/posix/interp_posix.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/posix/interp_posix.py	(original)
+++ pypy/branch/jitypes2/pypy/module/posix/interp_posix.py	Tue Nov 23 13:26:19 2010
@@ -454,7 +454,8 @@
         self.w_environ = space.newdict()
         if _WIN:
             self.cryptProviderPtr = lltype.malloc(
-                rffi.CArray(HCRYPTPROV), 1, zero=True, flavor='raw')
+                rffi.CArray(HCRYPTPROV), 1, zero=True,
+                flavor='raw', immortal=True)
     def startup(self, space):
         _convertenviron(space, self.w_environ)
     def _freeze_(self):

Modified: pypy/branch/jitypes2/pypy/module/pypyjit/__init__.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/pypyjit/__init__.py	(original)
+++ pypy/branch/jitypes2/pypy/module/pypyjit/__init__.py	Tue Nov 23 13:26:19 2010
@@ -15,6 +15,5 @@
         # add the 'defaults' attribute
         from pypy.rlib.jit import PARAMETERS
         space = self.space
-        # XXX this is not really the default compiled into a pypy-c-jit XXX
         w_obj = space.wrap(PARAMETERS)
         space.setattr(space.wrap(self), space.wrap('defaults'), w_obj)

Modified: pypy/branch/jitypes2/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/pypyjit/test/test_pypy_c.py	(original)
+++ pypy/branch/jitypes2/pypy/module/pypyjit/test/test_pypy_c.py	Tue Nov 23 13:26:19 2010
@@ -377,10 +377,75 @@
                     ([1000], 49500),
                     ([10000], 495000),
                     ([100000], 4950000))
-        assert len(self.loops) == 2
+        assert len(self.loops) == 3
         op, = self.get_by_bytecode("CALL_FUNCTION_KW")
         # XXX a bit too many guards, but better than before
-        assert len(op.get_opnames("guard")) <= 10
+        assert len(op.get_opnames("guard")) <= 12
+
+    def test_stararg_virtual(self):
+        self.run_source('''
+            d = {}
+
+            def g(*args):
+                return len(args)
+            def h(a, b, c):
+                return c
+
+            def main(x):
+                s = 0
+                for i in range(x):
+                    l = [i, x, 2]
+                    s += g(*l)
+                    s += h(*l)
+                    s += g(i, x, 2)
+                for i in range(x):
+                    l = [x, 2]
+                    s += g(i, *l)
+                    s += h(i, *l)
+                return s
+        ''', 100000, ([100], 1300),
+                    ([1000], 13000),
+                    ([10000], 130000),
+                    ([100000], 1300000))
+        assert len(self.loops) == 2
+        ops = self.get_by_bytecode("CALL_FUNCTION_VAR")
+        assert len(ops) == 4
+        for op in ops:
+            assert len(op.get_opnames("new")) == 0
+            assert len(op.get_opnames("call_may_force")) == 0
+
+        ops = self.get_by_bytecode("CALL_FUNCTION")
+        for op in ops:
+            assert len(op.get_opnames("new")) == 0
+            assert len(op.get_opnames("call_may_force")) == 0
+
+    def test_stararg(self):
+        self.run_source('''
+            d = {}
+
+            def g(*args):
+                return args[-1]
+            def h(*args):
+                return len(args)
+
+            def main(x):
+                s = 0
+                l = []
+                i = 0
+                while i < x:
+                    l.append(1)
+                    s += g(*l)
+                    i = h(*l)
+                return s
+        ''', 100000, ([100], 100),
+                     ([1000], 1000),
+                     ([2000], 2000),
+                     ([4000], 4000))
+        assert len(self.loops) == 1
+        ops = self.get_by_bytecode("CALL_FUNCTION_VAR")
+        for op in ops:
+            assert len(op.get_opnames("new_with_vtable")) == 0
+            assert len(op.get_opnames("call_may_force")) == 0
 
     def test_virtual_instance(self):
         self.run_source('''

Modified: pypy/branch/jitypes2/pypy/module/rctime/interp_time.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/rctime/interp_time.py	(original)
+++ pypy/branch/jitypes2/pypy/module/rctime/interp_time.py	Tue Nov 23 13:26:19 2010
@@ -69,7 +69,7 @@
 CLOCKS_PER_SEC = cConfig.CLOCKS_PER_SEC
 clock_t = cConfig.clock_t
 tm = cConfig.tm
-glob_buf = lltype.malloc(tm, flavor='raw', zero=True)
+glob_buf = lltype.malloc(tm, flavor='raw', zero=True, immortal=True)
 
 if cConfig.has_gettimeofday:
     c_gettimeofday = external('gettimeofday', [rffi.VOIDP, rffi.VOIDP], rffi.INT)

Modified: pypy/branch/jitypes2/pypy/module/sys/state.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/sys/state.py	(original)
+++ pypy/branch/jitypes2/pypy/module/sys/state.py	Tue Nov 23 13:26:19 2010
@@ -33,6 +33,8 @@
         raise OSError(errno.ENOTDIR, path)
 
 
+platform = sys.platform
+
 def getinitialpath(prefix):
     from pypy.module.sys.version import CPYTHON_VERSION
     dirname = '%d.%d.%d' % (CPYTHON_VERSION[0],
@@ -51,6 +53,15 @@
     importlist.append(lib_pypy)
     importlist.append(python_std_lib_modified)
     importlist.append(python_std_lib)
+    #
+    # List here the extra platform-specific paths.
+    if platform != 'win32':
+        importlist.append(os.path.join(python_std_lib, 'plat-'+platform))
+    if platform == 'darwin':
+        platmac = os.path.join(python_std_lib, 'plat-mac')
+        importlist.append(platmac)
+        importlist.append(os.path.join(platmac, 'lib-scriptpackages'))
+    #
     return importlist
 
 def pypy_initial_path(space, srcdir):

Modified: pypy/branch/jitypes2/pypy/module/sys/test/test_initialpath.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/sys/test/test_initialpath.py	(original)
+++ pypy/branch/jitypes2/pypy/module/sys/test/test_initialpath.py	Tue Nov 23 13:26:19 2010
@@ -15,4 +15,5 @@
 def test_stdlib_in_prefix(tmpdir):
     dirs = build_hierarchy(tmpdir)
     path = getinitialpath(str(tmpdir))
-    assert path == map(str, dirs)
+    # we get at least 'dirs', and maybe more (e.g. plat-linux2)
+    assert path[:len(dirs)] == map(str, dirs)

Modified: pypy/branch/jitypes2/pypy/objspace/flow/model.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/flow/model.py	(original)
+++ pypy/branch/jitypes2/pypy/objspace/flow/model.py	Tue Nov 23 13:26:19 2010
@@ -355,7 +355,7 @@
         return "%r = %s(%s)" % (self.result, self.opname,
                                 ", ".join(map(repr, self.args)))
 
-class Atom:
+class Atom(object):
     def __init__(self, name):
         self.__name__ = name # make save_global happy
     def __repr__(self):

Modified: pypy/branch/jitypes2/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/std/callmethod.py	(original)
+++ pypy/branch/jitypes2/pypy/objspace/std/callmethod.py	Tue Nov 23 13:26:19 2010
@@ -13,6 +13,9 @@
 from pypy.interpreter import function
 from pypy.objspace.descroperation import object_getattribute
 from pypy.rlib import jit, rstack # for resume points
+from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict, \
+    LOOKUP_METHOD_mapdict_fill_cache_method
+
 
 # This module exports two extra methods for StdObjSpaceFrame implementing
 # the LOOKUP_METHOD and CALL_METHOD opcodes in an efficient way, as well
@@ -30,6 +33,13 @@
     #
     space = f.space
     w_obj = f.popvalue()
+
+    if space.config.objspace.std.withmapdict and not jit.we_are_jitted():
+        # mapdict has an extra-fast version of this function
+        from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict
+        if LOOKUP_METHOD_mapdict(f, nameindex, w_obj):
+            return
+
     w_name = f.getname_w(nameindex)
     w_value = None
 
@@ -50,6 +60,11 @@
                     # nothing in the instance
                     f.pushvalue(w_descr)
                     f.pushvalue(w_obj)
+                    if (space.config.objspace.std.withmapdict and
+                            not jit.we_are_jitted()):
+                        # let mapdict cache stuff
+                        LOOKUP_METHOD_mapdict_fill_cache_method(
+                            f.getcode(), nameindex, w_obj, w_type, w_descr)
                     return
     if w_value is None:
         w_value = space.getattr(w_obj, w_name)

Modified: pypy/branch/jitypes2/pypy/objspace/std/mapdict.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/std/mapdict.py	(original)
+++ pypy/branch/jitypes2/pypy/objspace/std/mapdict.py	Tue Nov 23 13:26:19 2010
@@ -1,4 +1,5 @@
 from pypy.rlib import jit, objectmodel, debug
+from pypy.rlib.rarithmetic import intmask, r_uint
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.objspace.std.dictmultiobject import W_DictMultiObject
@@ -15,24 +16,70 @@
 # we want to propagate knowledge that the result cannot be negative
 
 class AbstractAttribute(object):
-    _immutable_fields_ = ['w_cls']
+    _immutable_fields_ = ['terminator']
     cache_attrs = None
     _size_estimate = 0
 
-    def __init__(self, space, w_cls):
+    def __init__(self, space, terminator):
         self.space = space
-        self.w_cls = w_cls
+        assert isinstance(terminator, Terminator)
+        self.terminator = terminator
 
     def read(self, obj, selector):
-        raise NotImplementedError("abstract base class")
+        index = self.index(selector)
+        if index < 0:
+            return self.terminator._read_terminator(obj, selector)
+        return obj._mapdict_read_storage(index)
 
     def write(self, obj, selector, w_value):
-        raise NotImplementedError("abstract base class")
+        index = self.index(selector)
+        if index < 0:
+            return self.terminator._write_terminator(obj, selector, w_value)
+        obj._mapdict_write_storage(index, w_value)
+        return True
 
     def delete(self, obj, selector):
         return None
 
     def index(self, selector):
+        if (self.space.config.objspace.std.withmethodcache and 
+                not jit.we_are_jitted()):
+            return self._index_cache(selector)
+        else:
+            return self._index(selector)
+
+    @jit.dont_look_inside
+    def _index_cache(self, selector):
+        space = self.space
+        cache = space.fromcache(IndexCache)
+        SHIFT2 = r_uint.BITS - space.config.objspace.std.methodcachesizeexp
+        SHIFT1 = SHIFT2 - 5
+        attrs_as_int = objectmodel.current_object_addr_as_int(self)
+        # ^^^Note: see comment in typeobject.py for
+        # _pure_lookup_where_with_method_cache()
+        hash_selector = objectmodel.compute_hash(selector)
+        product = intmask(attrs_as_int * hash_selector)
+        index_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2
+        # ^^^Note2: same comment too
+        cached_attr = cache.attrs[index_hash]
+        if cached_attr is self:
+            cached_selector = cache.selectors[index_hash]
+            if cached_selector == selector:
+                index = cache.indices[index_hash]
+                if space.config.objspace.std.withmethodcachecounter:
+                    name = selector[0]
+                    cache.hits[name] = cache.hits.get(name, 0) + 1
+                return index
+        index = self._index(selector)
+        cache.attrs[index_hash] = self
+        cache.selectors[index_hash] = selector
+        cache.indices[index_hash] = index
+        if space.config.objspace.std.withmethodcachecounter:
+            name = selector[0]
+            cache.misses[name] = cache.misses.get(name, 0) + 1
+        return index
+
+    def _index(self, selector):
         return -1
 
     def copy(self, obj):
@@ -42,7 +89,7 @@
         raise NotImplementedError("abstract base class")
 
     def get_terminator(self):
-        raise NotImplementedError("abstract base class")
+        return self.terminator
 
     def set_terminator(self, obj, terminator):
         raise NotImplementedError("abstract base class")
@@ -95,15 +142,20 @@
         raise NotImplementedError("abstract base class")
 
     def __repr__(self):
-        return "<%s w_cls=%s>" % (self.__class__.__name__, self.w_cls)
+        return "<%s>" % (self.__class__.__name__,)
 
 
 class Terminator(AbstractAttribute):
+    _immutable_fields_ = ['w_cls']
 
-    def read(self, obj, selector):
+    def __init__(self, space, w_cls):
+        AbstractAttribute.__init__(self, space, self)
+        self.w_cls = w_cls
+
+    def _read_terminator(self, obj, selector):
         return None
 
-    def write(self, obj, selector, w_value):
+    def _write_terminator(self, obj, selector, w_value):
         obj._get_mapdict_map().add_attr(obj, selector, w_value)
         return True
 
@@ -116,9 +168,6 @@
     def length(self):
         return 0
 
-    def get_terminator(self):
-        return self
-
     def set_terminator(self, obj, terminator):
         result = Object()
         result.space = self.space
@@ -128,6 +177,9 @@
     def remove_dict_entries(self, obj):
         return self.copy(obj)
 
+    def __repr__(self):
+        return "<%s w_cls=%s>" % (self.__class__.__name__, self.w_cls)
+
 class DictTerminator(Terminator):
     _immutable_fields_ = ['devolved_dict_terminator']
     def __init__(self, space, w_cls):
@@ -142,27 +194,27 @@
 
 
 class NoDictTerminator(Terminator):
-    def write(self, obj, selector, w_value):
+    def _write_terminator(self, obj, selector, w_value):
         if selector[1] == DICT:
             return False
-        return Terminator.write(self, obj, selector, w_value)
+        return Terminator._write_terminator(self, obj, selector, w_value)
 
 
 class DevolvedDictTerminator(Terminator):
-    def read(self, obj, selector):
+    def _read_terminator(self, obj, selector):
         if selector[1] == DICT:
             w_dict = obj.getdict()
             space = self.space
             return space.finditem_str(w_dict, selector[0])
-        return Terminator.read(self, obj, selector)
+        return Terminator._read_terminator(self, obj, selector)
 
-    def write(self, obj, selector, w_value):
+    def _write_terminator(self, obj, selector, w_value):
         if selector[1] == DICT:
             w_dict = obj.getdict()
             space = self.space
             space.setitem_str(w_dict, selector[0], w_value)
             return True
-        return Terminator.write(self, obj, selector, w_value)
+        return Terminator._write_terminator(self, obj, selector, w_value)
 
     def delete(self, obj, selector):
         from pypy.interpreter.error import OperationError
@@ -189,7 +241,7 @@
 class PlainAttribute(AbstractAttribute):
     _immutable_fields_ = ['selector', 'position', 'back']
     def __init__(self, selector, back):
-        AbstractAttribute.__init__(self, back.space, back.w_cls)
+        AbstractAttribute.__init__(self, back.space, back.terminator)
         self.selector = selector
         self.position = back.length()
         self.back = back
@@ -199,17 +251,6 @@
         w_value = self.read(obj, self.selector)
         new_obj._get_mapdict_map().add_attr(new_obj, self.selector, w_value)
 
-    def read(self, obj, selector):
-        if selector == self.selector:
-            return obj._mapdict_read_storage(self.position)
-        return self.back.read(obj, selector)
-
-    def write(self, obj, selector, w_value):
-        if selector == self.selector:
-            obj._mapdict_write_storage(self.position, w_value)
-            return True
-        return self.back.write(obj, selector, w_value)
-
     def delete(self, obj, selector):
         if selector == self.selector:
             # ok, attribute is deleted
@@ -219,10 +260,10 @@
             self._copy_attr(obj, new_obj)
         return new_obj
 
-    def index(self, selector):
+    def _index(self, selector):
         if selector == self.selector:
             return self.position
-        return self.back.index(selector)
+        return self.back._index(selector)
 
     def copy(self, obj):
         new_obj = self.back.copy(obj)
@@ -232,9 +273,6 @@
     def length(self):
         return self.position + 1
 
-    def get_terminator(self):
-        return self.back.get_terminator()
-
     def set_terminator(self, obj, terminator):
         new_obj = self.back.set_terminator(obj, terminator)
         self._copy_attr(obj, new_obj)
@@ -268,6 +306,24 @@
     # RPython reasons
     w_obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
 
+class IndexCache(object):
+    def __init__(self, space):
+        assert space.config.objspace.std.withmethodcache
+        SIZE = 1 << space.config.objspace.std.methodcachesizeexp
+        self.attrs = [None] * SIZE
+        self._empty_selector = (None, INVALID)
+        self.selectors = [self._empty_selector] * SIZE
+        self.indices = [0] * SIZE
+        if space.config.objspace.std.withmethodcachecounter:
+            self.hits = {}
+            self.misses = {}
+
+    def clear(self):
+        for i in range(len(self.attrs)):
+            self.attrs[i] = None
+        for i in range(len(self.selectors)):
+            self.selectors[i] = self._empty_selector
+
 # ____________________________________________________________
 # object implementation
 
@@ -328,7 +384,7 @@
         assert flag
 
     def getclass(self, space):
-        return self._get_mapdict_map().w_cls
+        return self._get_mapdict_map().terminator.w_cls
 
     def setclass(self, space, w_cls):
         new_obj = self._get_mapdict_map().set_terminator(self, w_cls.terminator)
@@ -373,6 +429,7 @@
         self.storage = make_sure_not_resized([None] * map.size_estimate())
 
     def _mapdict_read_storage(self, index):
+        assert index >= 0
         return self.storage[index]
     def _mapdict_write_storage(self, index, value):
         self.storage[index] = value
@@ -440,6 +497,7 @@
             return rerased.unerase_fixedsizelist(erased, W_Root)
 
         def _mapdict_read_storage(self, index):
+            assert index >= 0
             for i in rangenmin1:
                 if index == i:
                     erased = getattr(self, "_value%s" % i)
@@ -604,30 +662,54 @@
     map = None
     version_tag = None
     index = 0
+    w_method = None # for callmethod
     success_counter = 0
     failure_counter = 0
 
+    def is_valid_for_obj(self, w_obj):
+        map = w_obj._get_mapdict_map()
+        return self.is_valid_for_map(map)
+
+    def is_valid_for_map(self, map):
+        if map is self.map:
+            version_tag = map.terminator.w_cls.version_tag()
+            if version_tag is self.version_tag:
+                # everything matches, it's incredibly fast
+                if map.space.config.objspace.std.withmethodcachecounter:
+                    self.success_counter += 1
+                return True
+        return False
+
 INVALID_CACHE_ENTRY = CacheEntry()
 INVALID_CACHE_ENTRY.map = objectmodel.instantiate(AbstractAttribute)
                              # different from any real map ^^^
-INVALID_CACHE_ENTRY.map.w_cls = None
+INVALID_CACHE_ENTRY.map.terminator = None
+
 
 def init_mapdict_cache(pycode):
     num_entries = len(pycode.co_names_w)
     pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries
 
+def _fill_cache(pycode, nameindex, map, version_tag, index, w_method=None):
+    entry = pycode._mapdict_caches[nameindex]
+    if entry is INVALID_CACHE_ENTRY:
+        entry = CacheEntry()
+        pycode._mapdict_caches[nameindex] = entry
+    entry.map = map
+    entry.version_tag = version_tag
+    entry.index = index
+    entry.w_method = w_method
+    if pycode.space.config.objspace.std.withmethodcachecounter:
+        entry.failure_counter += 1
+
 def LOAD_ATTR_caching(pycode, w_obj, nameindex):
     # this whole mess is to make the interpreter quite a bit faster; it's not
     # used if we_are_jitted().
     entry = pycode._mapdict_caches[nameindex]
     map = w_obj._get_mapdict_map()
-    if map is entry.map:
-        version_tag = map.w_cls.version_tag()
-        if version_tag is entry.version_tag:
-            # everything matches, it's incredibly fast
-            if pycode.space.config.objspace.std.withmethodcachecounter:
-                entry.success_counter += 1
-            return w_obj._mapdict_read_storage(entry.index)
+    if entry.is_valid_for_map(map) and entry.w_method is None:
+        # everything matches, it's incredibly fast
+        return w_obj._mapdict_read_storage(entry.index)
     return LOAD_ATTR_slowpath(pycode, w_obj, nameindex, map)
 LOAD_ATTR_caching._always_inline_ = True
 
@@ -635,7 +717,7 @@
     space = pycode.space
     w_name = pycode.co_names_w[nameindex]
     if map is not None:
-        w_type = map.w_cls
+        w_type = map.terminator.w_cls
         w_descr = w_type.getattribute_if_not_from_object()
         if w_descr is not None:
             return space._handle_getattribute(w_descr, w_obj, w_name)
@@ -655,17 +737,30 @@
             if selector[1] != INVALID:
                 index = map.index(selector)
                 if index >= 0:
-                    entry = pycode._mapdict_caches[nameindex]
-                    if entry is INVALID_CACHE_ENTRY:
-                        entry = CacheEntry()
-                        pycode._mapdict_caches[nameindex] = entry
-                    entry.map = map
-                    entry.version_tag = version_tag
-                    entry.index = index
-                    if space.config.objspace.std.withmethodcachecounter:
-                        entry.failure_counter += 1
+                    _fill_cache(pycode, nameindex, map, version_tag, index)
                     return w_obj._mapdict_read_storage(index)
     if space.config.objspace.std.withmethodcachecounter:
         INVALID_CACHE_ENTRY.failure_counter += 1
     return space.getattr(w_obj, w_name)
 LOAD_ATTR_slowpath._dont_inline_ = True
+
+def LOOKUP_METHOD_mapdict(f, nameindex, w_obj):
+    space = f.space
+    pycode = f.getcode()
+    entry = pycode._mapdict_caches[nameindex]
+    if entry.is_valid_for_obj(w_obj):
+        w_method = entry.w_method
+        if w_method is not None:
+            f.pushvalue(w_method)
+            f.pushvalue(w_obj)
+            return True
+    return False
+
+def LOOKUP_METHOD_mapdict_fill_cache_method(pycode, nameindex, w_obj, w_type, w_method):
+    version_tag = w_type.version_tag()
+    if version_tag is None:
+        return
+    map = w_obj._get_mapdict_map()
+    if map is None:
+        return
+    _fill_cache(pycode, nameindex, map, version_tag, -1, w_method)

Modified: pypy/branch/jitypes2/pypy/objspace/std/test/test_dictmultiobject.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/std/test/test_dictmultiobject.py	(original)
+++ pypy/branch/jitypes2/pypy/objspace/std/test/test_dictmultiobject.py	Tue Nov 23 13:26:19 2010
@@ -616,6 +616,7 @@
             withdictmeasurement = False
             withsmalldicts = False
             withcelldict = False
+            withmethodcache = False
         class opcodes:
             CALL_LIKELY_BUILTIN = False
 

Modified: pypy/branch/jitypes2/pypy/objspace/std/test/test_mapdict.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/std/test/test_mapdict.py	(original)
+++ pypy/branch/jitypes2/pypy/objspace/std/test/test_mapdict.py	Tue Nov 23 13:26:19 2010
@@ -24,13 +24,13 @@
         hasdict = False
 
 def test_plain_attribute():
-    space = " "
     w_cls = "class"
     aa = PlainAttribute(("b", DICT),
                         PlainAttribute(("a", DICT),
                                        Terminator(space, w_cls)))
     assert aa.space is space
-    assert aa.w_cls is w_cls
+    assert aa.terminator.w_cls is w_cls
+    assert aa.get_terminator() is aa.terminator
 
     obj = Object()
     obj.map, obj.storage = aa, [10, 20]
@@ -604,7 +604,8 @@
         from pypy.interpreter import gateway
         cls.space = gettestobjspace(
             **{"objspace.std.withmapdict": True,
-               "objspace.std.withmethodcachecounter": True})
+               "objspace.std.withmethodcachecounter": True,
+               "objspace.opcodes.CALL_METHOD": True})
         #
         def check(space, w_func, name):
             w_code = space.getattr(w_func, space.wrap('func_code'))
@@ -785,6 +786,135 @@
         res = self.check(f, 'x')
         assert res == (0, 0, 1)
 
+    def test_call_method_uses_cache(self):
+        # bit sucky
+        global C
+
+        class C(object):
+            def m(*args):
+                return args
+        C.sm = staticmethod(C.m.im_func)
+        C.cm = classmethod(C.m.im_func)
+
+        exec """if 1:
+
+            def f():
+                c = C()
+                res = c.m(1)
+                assert res == (c, 1)
+                return 42
+
+            def g():
+                c = C()
+                res = c.sm(1)
+                assert res == (1, )
+                return 42
+
+            def h():
+                c = C()
+                res = c.cm(1)
+                assert res == (C, 1)
+                return 42
+        """
+        res = self.check(f, 'm')
+        assert res == (1, 0, 0)
+        res = self.check(f, 'm')
+        assert res == (0, 1, 0)
+        res = self.check(f, 'm')
+        assert res == (0, 1, 0)
+        res = self.check(f, 'm')
+        assert res == (0, 1, 0)
+
+        # static methods are not cached
+        res = self.check(g, 'sm')
+        assert res == (0, 0, 0)
+        res = self.check(g, 'sm')
+        assert res == (0, 0, 0)
+
+        # neither are class methods
+        res = self.check(h, 'cm')
+        assert res == (0, 0, 0)
+        res = self.check(h, 'cm')
+        assert res == (0, 0, 0)
+
+    def test_mix_cache_bug(self):
+        # bit sucky
+        global C
+
+        class C(object):
+            def m(*args):
+                return args
+
+        exec """if 1:
+
+            def f():
+                c = C()
+                res = c.m(1)
+                assert res == (c, 1)
+                bm = c.m
+                res = bm(1)
+                assert res == (c, 1)
+                return 42
+
+        """
+        res = self.check(f, 'm')
+        assert res == (1, 1, 1)
+        res = self.check(f, 'm')
+        assert res == (0, 2, 1)
+        res = self.check(f, 'm')
+        assert res == (0, 2, 1)
+        res = self.check(f, 'm')
+        assert res == (0, 2, 1)
+
+class AppTestGlobalCaching(AppTestWithMapDict):
+    def setup_class(cls):
+        cls.space = gettestobjspace(
+            **{"objspace.std.withmethodcachecounter": True,
+               "objspace.std.withmapdict": True,
+               "objspace.opcodes.CALL_METHOD": True})
+
+    def test_mix_classes(self):
+        import __pypy__
+        class A(object):
+            def f(self):
+                return 42
+        class B(object):
+            def f(self):
+                return 43
+        class C(object):
+            def f(self):
+                return 44
+        l = [A(), B(), C()] * 10
+        __pypy__.reset_method_cache_counter()
+        # 'exec' to make sure that a.f() is compiled with CALL_METHOD
+        exec """for i, a in enumerate(l):
+                    assert a.f() == 42 + i % 3
+"""
+        cache_counter = __pypy__.mapdict_cache_counter("f")
+        assert cache_counter[0] >= 15
+        assert cache_counter[1] >= 3 # should be (27, 3)
+        assert sum(cache_counter) == 30
+
+    def test_mix_classes_attribute(self):
+        import __pypy__
+        class A(object):
+            def __init__(self):
+                self.x = 42
+        class B(object):
+            def __init__(self):
+                self.x = 43
+        class C(object):
+            def __init__(self):
+                self.x = 44
+        l = [A(), B(), C()] * 10
+        __pypy__.reset_method_cache_counter()
+        for i, a in enumerate(l):
+            assert a.x == 42 + i % 3
+        cache_counter = __pypy__.mapdict_cache_counter("x")
+        assert cache_counter[0] >= 15
+        assert cache_counter[1] >= 3 # should be (27, 3)
+        assert sum(cache_counter) == 30
+
 class TestDictSubclassShortcutBug(object):
     def setup_class(cls):
         cls.space = gettestobjspace(

Modified: pypy/branch/jitypes2/pypy/rlib/clibffi.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rlib/clibffi.py	(original)
+++ pypy/branch/jitypes2/pypy/rlib/clibffi.py	Tue Nov 23 13:26:19 2010
@@ -432,7 +432,8 @@
                  flags=FUNCFLAG_CDECL):
         AbstractFuncPtr.__init__(self, "callback", argtypes, restype, flags)
         self.ll_closure = closureHeap.alloc()
-        self.ll_userdata = lltype.malloc(USERDATA_P.TO, flavor='raw')
+        self.ll_userdata = lltype.malloc(USERDATA_P.TO, flavor='raw',
+                                         track_allocation=False)
         self.ll_userdata.callback = rffi.llhelper(CALLBACK_TP, func)
         self.ll_userdata.addarg = additional_arg
         res = c_ffi_prep_closure(self.ll_closure, self.ll_cif,
@@ -447,7 +448,7 @@
             closureHeap.free(self.ll_closure)
             self.ll_closure = lltype.nullptr(FFI_CLOSUREP.TO)
         if self.ll_userdata:
-            lltype.free(self.ll_userdata, flavor='raw')
+            lltype.free(self.ll_userdata, flavor='raw', track_allocation=False)
             self.ll_userdata = lltype.nullptr(USERDATA_P.TO)
 
 class RawFuncPtr(AbstractFuncPtr):

Modified: pypy/branch/jitypes2/pypy/rlib/rgc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rlib/rgc.py	(original)
+++ pypy/branch/jitypes2/pypy/rlib/rgc.py	Tue Nov 23 13:26:19 2010
@@ -379,6 +379,11 @@
     "NOT_RPYTHON"
     raise NotImplementedError
 
+def get_typeids_z():
+    "NOT_RPYTHON"
+    raise NotImplementedError
+
+ARRAY_OF_CHAR = lltype.Array(lltype.Char)
 NULL_GCREF = lltype.nullptr(llmemory.GCREF.TO)
 
 class _GcRef(object):
@@ -530,3 +535,12 @@
         vlist = hop.inputargs(lltype.Signed)
         hop.exception_is_here()
         return hop.genop('gc_dump_rpy_heap', vlist, resulttype = hop.r_result)
+
+class Entry(ExtRegistryEntry):
+    _about_ = get_typeids_z
+    def compute_result_annotation(self):
+        from pypy.annotation.model import SomePtr
+        return SomePtr(lltype.Ptr(ARRAY_OF_CHAR))
+    def specialize_call(self, hop):
+        hop.exception_is_here()
+        return hop.genop('gc_typeids_z', [], resulttype = hop.r_result)

Modified: pypy/branch/jitypes2/pypy/rpython/annlowlevel.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/annlowlevel.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/annlowlevel.py	Tue Nov 23 13:26:19 2010
@@ -136,7 +136,7 @@
         return funcdesc.cachedgraph(TYPE, alt_name=valid_identifier(alt_name))
 
 
-class MixLevelHelperAnnotator:
+class MixLevelHelperAnnotator(object):
 
     def __init__(self, rtyper):
         self.rtyper = rtyper

Modified: pypy/branch/jitypes2/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/llinterp.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/llinterp.py	Tue Nov 23 13:26:19 2010
@@ -912,6 +912,9 @@
     def op_gc_dump_rpy_heap(self):
         raise NotImplementedError("gc_dump_rpy_heap")
 
+    def op_gc_typeids_z(self):
+        raise NotImplementedError("gc_typeids_z")
+
     def op_do_malloc_fixedsize_clear(self):
         raise NotImplementedError("do_malloc_fixedsize_clear")
 

Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/llarena.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/llarena.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/llarena.py	Tue Nov 23 13:26:19 2010
@@ -440,7 +440,8 @@
                                    [rffi.INT],
                                    rffi.INT,
                                    sandboxsafe=True, _nowrapper=True)
-    _dev_zero = rffi.str2charp_immortal('/dev/zero')   # prebuilt
+    _dev_zero = rffi.str2charp('/dev/zero')   # prebuilt
+    lltype.render_immortal(_dev_zero)
 
     def clear_large_memory_chunk(baseaddr, size):
         # on some Unixy platforms, reading from /dev/zero is the fastest way

Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/llmemory.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/llmemory.py	Tue Nov 23 13:26:19 2010
@@ -766,8 +766,10 @@
         return '<%s>' % (self,)
     def __str__(self):
         return 'gctransformed_wref(%s)' % (self._ptr,)
-    def _normalizedcontainer(self):
-        return self._ptr._obj
+    def _normalizedcontainer(self, check=True):
+        return self._ptr._getobj(check=check)._normalizedcontainer(check=check)
+    def _was_freed(self):
+        return self._ptr._was_freed()
 
 # ____________________________________________________________
 

Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/lloperation.py	Tue Nov 23 13:26:19 2010
@@ -476,6 +476,7 @@
     'gc_get_rpy_type_index': LLOp(),
     'gc_is_rpy_instance'  : LLOp(),
     'gc_dump_rpy_heap'    : LLOp(),
+    'gc_typeids_z'        : LLOp(),
 
     # ------- JIT & GC interaction, only for some GCs ----------
     

Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/lltype.py	Tue Nov 23 13:26:19 2010
@@ -1868,6 +1868,13 @@
         leakfinder.remember_free(p._obj0)
     p._obj0._free()
 
+def render_immortal(p, track_allocation=True):
+    T = typeOf(p)
+    if not isinstance(T, Ptr) or p._togckind() != 'raw':
+        raise TypeError, "free(): only for pointers to non-gc containers"
+    if track_allocation:
+        leakfinder.remember_free(p._obj0)
+
 def _make_scoped_allocator(T):
     class ScopedAlloc:
         def __init__(self, n=None, zero=False):

Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/rffi.py	Tue Nov 23 13:26:19 2010
@@ -607,15 +607,6 @@
         return array
     str2charp._annenforceargs_ = [strtype]
 
-    def str2charp_immortal(s):
-        "NOT_RPYTHON"
-        array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw',
-                              immortal=True)
-        for i in range(len(s)):
-            array[i] = s[i]
-        array[len(s)] = lastchar
-        return array
-
     def free_charp(cp):
         lltype.free(cp, flavor='raw')
 
@@ -734,19 +725,19 @@
         l = [cp[i] for i in range(size)]
         return emptystr.join(l)
 
-    return (str2charp, str2charp_immortal, free_charp, charp2str,
+    return (str2charp, free_charp, charp2str,
             get_nonmovingbuffer, free_nonmovingbuffer,
             alloc_buffer, str_from_buffer, keep_buffer_alive_until_here,
             charp2strn, charpsize2str,
             )
 
-(str2charp, str2charp_immortal, free_charp, charp2str,
+(str2charp, free_charp, charp2str,
  get_nonmovingbuffer, free_nonmovingbuffer,
  alloc_buffer, str_from_buffer, keep_buffer_alive_until_here,
  charp2strn, charpsize2str,
  ) = make_string_mappings(str)
 
-(unicode2wcharp, unicode2wcharp_immortal, free_wcharp, wcharp2unicode,
+(unicode2wcharp, free_wcharp, wcharp2unicode,
  get_nonmoving_unicodebuffer, free_nonmoving_unicodebuffer,
  alloc_unicodebuffer, unicode_from_buffer, keep_unicodebuffer_alive_until_here,
  wcharp2unicoden, wcharpsize2unicode,

Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/base.py	Tue Nov 23 13:26:19 2010
@@ -247,6 +247,21 @@
                 (not self.config.taggedpointers or
                  llmemory.cast_adr_to_int(addr) & 1 == 0))
 
+    def enumerate_all_roots(self, callback, arg):
+        """For each root object, invoke callback(obj, arg).
+        'callback' should not be a bound method.
+        Note that this method is not suitable for actually doing the
+        collection in a moving GC, because you cannot write back a
+        modified address.  It is there only for inspection.
+        """
+        # overridden in some subclasses, for GCs which have an additional
+        # list of last generation roots
+        callback2, attrname = _convert_callback_formats(callback)    # :-/
+        setattr(self, attrname, arg)
+        self.root_walker.walk_roots(callback2, callback2, callback2)
+        self.run_finalizers.foreach(callback, arg)
+    enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
+
     def debug_check_consistency(self):
         """To use after a collection.  If self.DEBUG is set, this
         enumerates all roots and traces all objects to check if we didn't
@@ -260,8 +275,7 @@
             self._debug_pending = self.AddressStack()
             if not we_are_translated():
                 self.root_walker._walk_prebuilt_gc(self._debug_record)
-            callback = GCBase._debug_callback
-            self.root_walker.walk_roots(callback, callback, callback)
+            self.enumerate_all_roots(GCBase._debug_callback, self)
             pending = self._debug_pending
             while pending.non_empty():
                 obj = pending.pop()
@@ -275,9 +289,8 @@
             seen.add(obj)
             self.debug_check_object(obj)
             self._debug_pending.append(obj)
-    def _debug_callback(self, root):
-        obj = root.address[0]
-        ll_assert(bool(obj), "NULL address from walk_roots()")
+    @staticmethod
+    def _debug_callback(obj, self):
         self._debug_record(obj)
     def _debug_callback2(self, pointer, ignored):
         obj = pointer.address[0]
@@ -432,3 +445,17 @@
     if factor != 1:
         return 0.0
     return value
+
+def _convert_callback_formats(callback):
+    callback = getattr(callback, 'im_func', callback)
+    if callback not in _converted_callback_formats:
+        def callback2(gc, root):
+            obj = root.address[0]
+            ll_assert(bool(obj), "NULL address from walk_roots()")
+            callback(obj, getattr(gc, attrname))
+        attrname = '_callback2_arg%d' % len(_converted_callback_formats)
+        _converted_callback_formats[callback] = callback2, attrname
+    return _converted_callback_formats[callback]
+
+_convert_callback_formats._annspecialcase_ = 'specialize:memo'
+_converted_callback_formats = {}

Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/generation.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/generation.py	Tue Nov 23 13:26:19 2010
@@ -572,16 +572,10 @@
     def _compute_current_nursery_hash(self, obj):
         return intmask(llmemory.cast_adr_to_int(obj) + self.nursery_hash_base)
 
-    def heap_stats_walk_roots(self):
-        self.last_generation_root_objects.foreach(
-            self._track_heap_ext, None)
-        self.root_walker.walk_roots(
-            SemiSpaceGC._track_heap_root,
-            SemiSpaceGC._track_heap_root,
-            SemiSpaceGC._track_heap_root)
-
-    def _track_heap_ext(self, adr, ignored):
-        self.trace(adr, self.track_heap_parent, adr)
+    def enumerate_all_roots(self, callback, arg):
+        self.last_generation_root_objects.foreach(callback, arg)
+        SemiSpaceGC.enumerate_all_roots(self, callback, arg)
+    enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
 
     def debug_check_object(self, obj):
         """Check the invariants about 'obj' that should be true

Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/inspector.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/inspector.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/inspector.py	Tue Nov 23 13:26:19 2010
@@ -4,25 +4,22 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rlib.objectmodel import free_non_gc_object
 from pypy.rpython.module.ll_os import underscore_on_windows
-from pypy.rlib import rposix
+from pypy.rlib import rposix, rgc
 
 from pypy.rpython.memory.support import AddressDict, get_address_stack
 
 
 # ---------- implementation of pypy.rlib.rgc.get_rpy_roots() ----------
 
-def _counting_rpy_root(gc, root):
+def _counting_rpy_root(obj, gc):
     gc._count_rpy += 1
 
 def _do_count_rpy_roots(gc):
     gc._count_rpy = 0
-    gc.root_walker.walk_roots(
-        _counting_rpy_root,
-        _counting_rpy_root,
-        _counting_rpy_root)
+    gc.enumerate_all_roots(_counting_rpy_root, gc)
     return gc._count_rpy
 
-def _append_rpy_root(gc, root):
+def _append_rpy_root(obj, gc):
     # Can use the gc list, but should not allocate!
     # It is essential that the list is not resizable!
     lst = gc._list_rpy
@@ -30,15 +27,12 @@
     if index >= len(lst):
         raise ValueError
     gc._count_rpy = index + 1
-    lst[index] = llmemory.cast_adr_to_ptr(root.address[0], llmemory.GCREF)
+    lst[index] = llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
 
 def _do_append_rpy_roots(gc, lst):
     gc._count_rpy = 0
     gc._list_rpy = lst
-    gc.root_walker.walk_roots(
-        _append_rpy_root,
-        _append_rpy_root,
-        _append_rpy_root)
+    gc.enumerate_all_roots(_append_rpy_root, gc)
     gc._list_rpy = None
 
 def get_rpy_roots(gc):
@@ -101,8 +95,7 @@
 # ----------
 
 raw_os_write = rffi.llexternal(underscore_on_windows+'write',
-                               [rffi.INT, rffi.CArrayPtr(lltype.Signed),
-                                rffi.SIZE_T],
+                               [rffi.INT, llmemory.Address, rffi.SIZE_T],
                                rffi.SIZE_T,
                                sandboxsafe=True, _nowrapper=True)
 
@@ -131,7 +124,7 @@
         if self.buf_count > 0:
             bytes = self.buf_count * rffi.sizeof(rffi.LONG)
             count = raw_os_write(self.fd,
-                                 self.writebuffer,
+                                 rffi.cast(llmemory.Address, self.writebuffer),
                                  rffi.cast(rffi.SIZE_T, bytes))
             if rffi.cast(lltype.Signed, count) != bytes:
                 raise OSError(rposix.get_errno(), "raw_os_write failed")
@@ -140,7 +133,7 @@
 
     def write(self, value):
         x = self.buf_count
-        self.writebuffer[x] = llmemory.raw_malloc_usage(value)
+        self.writebuffer[x] = value
         x += 1
         self.buf_count = x
         if x == self.BUFSIZE:
@@ -173,12 +166,7 @@
             self.pending.append(obj)
 
     def add_roots(self):
-        self.gc._heap_dumper = self
-        self.gc.root_walker.walk_roots(
-            _hd_add_root,
-            _hd_add_root,
-            _hd_add_root)
-        self.gc._heap_dumper = None
+        self.gc.enumerate_all_roots(_hd_add_root, self)
         pendingroots = self.pending
         self.pending = AddressStack()
         self.walk(pendingroots)
@@ -189,8 +177,8 @@
         while pending.non_empty():
             self.writeobj(pending.pop())
 
-def _hd_add_root(gc, root):
-    gc._heap_dumper.add(root.address[0])
+def _hd_add_root(obj, heap_dumper):
+    heap_dumper.add(obj)
 
 def dump_rpy_heap(gc, fd):
     heapdumper = HeapDumper(gc, fd)
@@ -199,3 +187,7 @@
     heapdumper.flush()
     heapdumper.delete()
     return True
+
+def get_typeids_z(gc):
+    srcaddress = gc.root_walker.gcdata.typeids_z
+    return llmemory.cast_adr_to_ptr(srcaddress, lltype.Ptr(rgc.ARRAY_OF_CHAR))

Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/minimark.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/minimark.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/minimark.py	Tue Nov 23 13:26:19 2010
@@ -1,3 +1,36 @@
+""" MiniMark GC.
+
+Environment variables can be used to fine-tune the following parameters:
+    
+ PYPY_GC_NURSERY        The nursery size.  Defaults to half the size of
+                        the L2 cache.  Try values like '1.2MB'.
+
+ PYPY_GC_MAJOR_COLLECT  Major collection memory factor.  Default is '1.82',
+                        which means trigger a major collection when the
+                        memory consumed equals 1.82 times the memory
+                        really used at the end of the previous major
+                        collection.
+
+ PYPY_GC_GROWTH         Major collection threshold's max growth rate.
+                        Default is '1.3'.  Useful to collect more often
+                        than normally on sudden memory growth, e.g. when
+                        there is a temporary peak in memory usage.
+
+ PYPY_GC_MAX            The max heap size.  If coming near this limit, it
+                        will first collect more often, then raise an
+                        RPython MemoryError, and if that is not enough,
+                        crash the program with a fatal error.  Try values
+                        like '1.6GB'.
+
+ PYPY_GC_MIN            Don't collect while the memory size is below this
+                        limit.  Useful to avoid spending all the time in
+                        the GC in very small programs.  Defaults to 8
+                        times the nursery.
+"""
+# XXX Should find a way to bound the major collection threshold by the
+# XXX total addressable size.  Maybe by keeping some minimarkpage arenas
+# XXX pre-reserved, enough for a few nursery collections?  What about
+# XXX raw-malloced memory?
 import sys
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup
 from pypy.rpython.lltypesystem.lloperation import llop
@@ -87,13 +120,8 @@
 
     TRANSLATION_PARAMS = {
         # Automatically adjust the size of the nursery and the
-        # 'major_collection_threshold' from the environment.  For
-        # 'nursery_size' it will look it up in the env var
-        # PYPY_GC_NURSERY and fall back to half the size of
-        # the L2 cache.  For 'major_collection_threshold' it will look
-        # it up in the env var PYPY_GC_MAJOR_COLLECT.  It also sets
-        # 'max_heap_size' to PYPY_GC_MAX.  Finally, PYPY_GC_MIN sets
-        # the minimal value of 'next_major_collection_threshold'.
+        # 'major_collection_threshold' from the environment.
+        # See docstring at the start of the file.
         "read_from_env": True,
 
         # The size of the nursery.  Note that this is only used as a
@@ -121,6 +149,13 @@
         # we trigger the next major collection.
         "major_collection_threshold": 1.82,
 
+        # Threshold to avoid that the total heap size grows by a factor of
+        # major_collection_threshold at every collection: it can only
+        # grow at most by the following factor from one collection to the
+        # next.  Used e.g. when there is a sudden, temporary peak in memory
+        # usage; this avoids that the upper bound grows too fast.
+        "growth_rate_max": 1.3,
+
         # The number of array indices that are mapped to a single bit in
         # write_barrier_from_array().  Must be a power of two.  The default
         # value of 128 means that card pages are 512 bytes (1024 on 64-bits)
@@ -146,6 +181,7 @@
                  arena_size=64*WORD,
                  small_request_threshold=5*WORD,
                  major_collection_threshold=2.5,
+                 growth_rate_max=2.5,   # for tests
                  card_page_indices=0,
                  large_object=8*WORD,
                  large_object_gcptrs=10*WORD,
@@ -157,6 +193,7 @@
         self.nursery_size = nursery_size
         self.small_request_threshold = small_request_threshold
         self.major_collection_threshold = major_collection_threshold
+        self.growth_rate_max = growth_rate_max
         self.num_major_collects = 0
         self.min_heap_size = 0.0
         self.max_heap_size = 0.0
@@ -257,9 +294,13 @@
             newsize = max(newsize, minsize)
             #
             major_coll = base.read_float_from_env('PYPY_GC_MAJOR_COLLECT')
-            if major_coll >= 1.0:
+            if major_coll > 1.0:
                 self.major_collection_threshold = major_coll
             #
+            growth = base.read_float_from_env('PYPY_GC_GROWTH')
+            if growth > 1.0:
+                self.growth_rate_max = growth
+            #
             min_heap_size = base.read_uint_from_env('PYPY_GC_MIN')
             if min_heap_size > 0:
                 self.min_heap_size = float(min_heap_size)
@@ -295,11 +336,19 @@
         # initialize the threshold
         self.min_heap_size = max(self.min_heap_size, self.nursery_size *
                                               self.major_collection_threshold)
+        self.next_major_collection_threshold = self.min_heap_size
         self.set_major_threshold_from(0.0)
         debug_stop("gc-set-nursery-size")
 
-    def set_major_threshold_from(self, threshold):
+
+    def set_major_threshold_from(self, threshold, reserving_size=0):
         # Set the next_major_collection_threshold.
+        threshold_max = (self.next_major_collection_threshold *
+                         self.growth_rate_max)
+        if threshold > threshold_max:
+            threshold = threshold_max
+        #
+        threshold += reserving_size
         if threshold < self.min_heap_size:
             threshold = self.min_heap_size
         #
@@ -922,7 +971,7 @@
         #
         # Now all live nursery objects should be out.  Update the
         # young weakrefs' targets.
-        if self.young_objects_with_weakrefs.length() > 0:
+        if self.young_objects_with_weakrefs.non_empty():
             self.invalidate_young_weakrefs()
         #
         # Clear this mapping.
@@ -1016,7 +1065,7 @@
             obj = oldlist.pop()
             #
             # Add the flag GCFLAG_NO_YOUNG_PTRS.  All live objects should have
-            # this flag after a nursery collection.
+            # this flag set after a nursery collection.
             self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS
             #
             # Trace the 'obj' to replace pointers to nursery with pointers
@@ -1079,7 +1128,7 @@
         # nursery are kept unchanged in this step.
         llmemory.raw_memcopy(obj - size_gc_header, newhdr, totalsize)
         #
-        # Set the old object's tid to -1 (containing all flags) and
+        # Set the old object's tid to -42 (containing all flags) and
         # replace the old object's content with the target address.
         # A bit of no-ops to convince llarena that we are changing
         # the layout, in non-translated versions.
@@ -1198,8 +1247,8 @@
         # have allocated 'major_collection_threshold' times more than
         # we currently have.
         bounded = self.set_major_threshold_from(
-            (self.get_total_memory_used() * self.major_collection_threshold)
-            + reserving_size)
+            self.get_total_memory_used() * self.major_collection_threshold,
+            reserving_size)
         #
         # Max heap size: gives an upper bound on the threshold.  If we
         # already have at least this much allocated, raise MemoryError.
@@ -1288,6 +1337,11 @@
         self.run_finalizers.foreach(self._collect_obj,
                                     self.objects_to_trace)
 
+    def enumerate_all_roots(self, callback, arg):
+        self.prebuilt_root_objects.foreach(callback, arg)
+        MovingGCBase.enumerate_all_roots(self, callback, arg)
+    enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
+
     @staticmethod
     def _collect_obj(obj, objects_to_trace):
         objects_to_trace.append(obj)
@@ -1339,7 +1393,7 @@
         if self.is_valid_gc_object(obj):
             if self.is_in_nursery(obj):
                 #
-                # The object not a tagged pointer, and is it still in the
+                # The object is not a tagged pointer, and it is still in the
                 # nursery.  Find or allocate a "shadow" object, which is
                 # where the object will be moved by the next minor
                 # collection

Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/semispace.py	Tue Nov 23 13:26:19 2010
@@ -693,15 +693,10 @@
         self._ll_typeid_map[idx].size += llmemory.raw_malloc_usage(totsize)
         self.trace(adr, self.track_heap_parent, adr)
 
-    def _track_heap_root(self, root):
-        self.track_heap(root.address[0])
+    @staticmethod
+    def _track_heap_root(obj, self):
+        self.track_heap(obj)
 
-    def heap_stats_walk_roots(self):
-        self.root_walker.walk_roots(
-            SemiSpaceGC._track_heap_root,
-            SemiSpaceGC._track_heap_root,
-            SemiSpaceGC._track_heap_root)
-        
     def heap_stats(self):
         self._tracked_dict = self.AddressDict()
         max_tid = self.root_walker.gcdata.max_type_id
@@ -714,7 +709,7 @@
         while i < max_tid:
             self._tracked_dict.add(llmemory.cast_ptr_to_adr(ll_typeid_map[i]))
             i += 1
-        self.heap_stats_walk_roots()
+        self.enumerate_all_roots(SemiSpaceGC._track_heap_root, self)
         self._ll_typeid_map = lltype.nullptr(ARRAY_TYPEID_MAP)
         self._tracked_dict.delete()
         return ll_typeid_map

Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/test/test_minimark.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/test/test_minimark.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/test/test_minimark.py	Tue Nov 23 13:26:19 2010
@@ -28,3 +28,42 @@
     assert gc.card_marking_bytes_for_length(P+P+1) == 3
     assert gc.card_marking_bytes_for_length(P+P+P+P+P+P+P+P) == 8
     assert gc.card_marking_bytes_for_length(P+P+P+P+P+P+P+P+1) == 9
+
+def test_set_major_threshold():
+    gc = MiniMarkGC(None, major_collection_threshold=2.0,
+                    growth_rate_max=1.5)
+    gc.min_heap_size = 100.0
+    gc.max_heap_size = 300.0
+    gc.next_major_collection_threshold = 0.0
+    # first, we don't grow past min_heap_size
+    for i in range(5):
+        gc.set_major_threshold_from(100.0)
+        assert gc.next_major_collection_threshold == 100.0
+    # then we grow a lot
+    b = gc.set_major_threshold_from(100 * 2.0)
+    assert b is False
+    assert gc.next_major_collection_threshold == 150.0
+    b = gc.set_major_threshold_from(150 * 2.0)
+    assert b is False
+    assert gc.next_major_collection_threshold == 225.0
+    b = gc.set_major_threshold_from(225 * 2.0)
+    assert b is True
+    assert gc.next_major_collection_threshold == 300.0   # max reached
+    b = gc.set_major_threshold_from(300 * 2.0)
+    assert b is True
+    assert gc.next_major_collection_threshold == 300.0
+    # then we shrink instantly
+    b = gc.set_major_threshold_from(100.0)
+    assert b is False
+    assert gc.next_major_collection_threshold == 100.0
+    # then we grow a bit
+    b = gc.set_major_threshold_from(100 * 1.25)
+    assert b is False
+    assert gc.next_major_collection_threshold == 125.0
+    b = gc.set_major_threshold_from(125 * 1.25)
+    assert b is False
+    assert gc.next_major_collection_threshold == 156.25
+    # check that we cannot shrink below min_heap_size
+    b = gc.set_major_threshold_from(42.7)
+    assert b is False
+    assert gc.next_major_collection_threshold == 100.0

Modified: pypy/branch/jitypes2/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gctransform/framework.py	Tue Nov 23 13:26:19 2010
@@ -172,6 +172,7 @@
         gcdata.static_root_nongcend = a_random_address   # patched in finish()
         gcdata.static_root_end = a_random_address        # patched in finish()
         gcdata.max_type_id = 13                          # patched in finish()
+        gcdata.typeids_z = a_random_address              # patched in finish()
         self.gcdata = gcdata
         self.malloc_fnptr_cache = {}
 
@@ -212,6 +213,9 @@
         data_classdef.generalize_attr(
             'max_type_id',
             annmodel.SomeInteger())
+        data_classdef.generalize_attr(
+            'typeids_z',
+            annmodel.SomeAddress())
 
         annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper)
 
@@ -415,6 +419,11 @@
                                        [s_gc, annmodel.SomeInteger()],
                                        annmodel.s_Bool,
                                        minimal_transform=False)
+        self.get_typeids_z_ptr = getfn(inspector.get_typeids_z,
+                                       [s_gc],
+                                       annmodel.SomePtr(
+                                           lltype.Ptr(rgc.ARRAY_OF_CHAR)),
+                                       minimal_transform=False)
 
         self.set_max_heap_size_ptr = getfn(GCClass.set_max_heap_size.im_func,
                                            [s_gc,
@@ -572,7 +581,14 @@
         newgcdependencies = []
         newgcdependencies.append(ll_static_roots_inside)
         ll_instance.inst_max_type_id = len(group.members)
-        self.write_typeid_list()
+        typeids_z = self.write_typeid_list()
+        ll_typeids_z = lltype.malloc(rgc.ARRAY_OF_CHAR,
+                                     len(typeids_z),
+                                     immortal=True)
+        for i in range(len(typeids_z)):
+            ll_typeids_z[i] = typeids_z[i]
+        ll_instance.inst_typeids_z = llmemory.cast_ptr_to_adr(ll_typeids_z)
+        newgcdependencies.append(ll_typeids_z)
         return newgcdependencies
 
     def get_finish_tables(self):
@@ -599,6 +615,11 @@
         for index in range(len(self.layoutbuilder.type_info_group.members)):
             f.write("member%-4d %s\n" % (index, all_ids.get(index, '?')))
         f.close()
+        try:
+            import zlib
+            return zlib.compress(udir.join("typeids.txt").read(), 9)
+        except ImportError:
+            return ''
 
     def transform_graph(self, graph):
         func = getattr(graph, 'func', None)
@@ -988,6 +1009,13 @@
                   resultvar=hop.spaceop.result)
         self.pop_roots(hop, livevars)
 
+    def gct_gc_typeids_z(self, hop):
+        livevars = self.push_roots(hop)
+        hop.genop("direct_call",
+                  [self.get_typeids_z_ptr, self.c_const_gc],
+                  resultvar=hop.spaceop.result)
+        self.pop_roots(hop, livevars)
+
     def gct_malloc_nonmovable_varsize(self, hop):
         TYPE = hop.spaceop.result.concretetype
         if self.gcdata.gc.can_malloc_nonmovable():
@@ -1210,7 +1238,7 @@
 sizeofaddr = llmemory.sizeof(llmemory.Address)
 
 
-class BaseRootWalker:
+class BaseRootWalker(object):
     need_root_stack = False
 
     def __init__(self, gctransformer):

Modified: pypy/branch/jitypes2/pypy/rpython/memory/support.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/support.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/support.py	Tue Nov 23 13:26:19 2010
@@ -112,7 +112,7 @@
                 cur = next
             free_non_gc_object(self)
 
-        def length(self):
+        def _length_estimate(self):
             chunk = self.chunk
             count = self.used_in_last_chunk
             while chunk:
@@ -135,7 +135,7 @@
         foreach._annspecialcase_ = 'specialize:arg(1)'
 
         def stack2dict(self):
-            result = AddressDict(self.length())
+            result = AddressDict(self._length_estimate())
             self.foreach(_add_in_dict, result)
             return result
 

Modified: pypy/branch/jitypes2/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/test/test_gc.py	Tue Nov 23 13:26:19 2010
@@ -278,6 +278,105 @@
         res = self.interpret(f, [])
         assert res
 
+    def test_bug_1(self):
+        import weakref
+        class B(object):
+            pass
+        def g():
+            b = B()
+            llop.gc__collect(lltype.Void)    # force 'b' to be old
+            ref = weakref.ref(B())
+            b.ref = ref
+            return ref
+        def f():
+            ref = g()
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            result = (ref() is None)
+            return result
+        res = self.interpret(f, [])
+        assert res
+
+    def test_cycle_with_weakref_and_del(self):
+        import weakref, gc
+        class A(object):
+            count = 0
+        a = A()
+        class B(object):
+            def __del__(self):
+                # when __del__ is called, the weakref to c should be dead
+                if self.ref() is None:
+                    a.count += 10  # ok
+                else:
+                    a.count = 666  # not ok
+        class C(object):
+            pass
+        def g():
+            c = C()
+            c.b = B()
+            ref = weakref.ref(c)
+            c.b.ref = ref
+            return ref
+        def f():
+            ref = g()
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            result = a.count + (ref() is None)
+            return result
+        res = self.interpret(f, [])
+        assert res == 11
+
+    def test_weakref_to_object_with_finalizer_ordering(self):
+        import weakref, gc
+        class A(object):
+            count = 0
+        a = A()
+        class B(object):
+            def __del__(self):
+                # when __del__ is called, the weakref to myself is still valid
+                # in RPython (at least with most GCs; this test might be
+                # skipped for specific GCs)
+                if self.ref() is self:
+                    a.count += 10  # ok
+                else:
+                    a.count = 666  # not ok
+        def g():
+            b = B()
+            ref = weakref.ref(b)
+            b.ref = ref
+            return ref
+        def f():
+            ref = g()
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            result = a.count + (ref() is None)
+            return result
+        res = self.interpret(f, [])
+        assert res == 11
+
+    def test_weakref_bug_1(self):
+        import weakref
+        class A(object):
+            pass
+        class B(object):
+            def __del__(self):
+                self.wref().x += 1
+        def g(a):
+            b = B()
+            b.wref = weakref.ref(a)
+            # the only way to reach this weakref is via B, which is an
+            # object with finalizer (but the weakref itself points to
+            # a, which does not go away but will move during the next
+            # gc.collect)
+        def f():
+            a = A()
+            a.x = 10
+            g(a)
+            llop.gc__collect(lltype.Void)
+            return a.x
+        res = self.interpret(f, [])
+        assert res == 11
+
     def test_id(self):
         class A(object):
             pass
@@ -635,6 +734,9 @@
 class TestMarkSweepGC(GCTest):
     from pypy.rpython.memory.gc.marksweep import MarkSweepGC as GCClass
 
+    def test_weakref_to_object_with_finalizer_ordering(self):
+        py.test.skip("Does not work")
+
 class TestSemiSpaceGC(GCTest, snippet.SemiSpaceGCTests):
     from pypy.rpython.memory.gc.semispace import SemiSpaceGC as GCClass
     GC_CAN_MOVE = True

Modified: pypy/branch/jitypes2/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/rbuiltin.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/rbuiltin.py	Tue Nov 23 13:26:19 2010
@@ -386,6 +386,14 @@
     hop.exception_cannot_occur()
     hop.genop('free', vlist)
 
+def rtype_render_immortal(hop, i_track_allocation=None):
+    vlist = [hop.inputarg(hop.args_r[0], arg=0)]
+    v_track_allocation = parse_kwds(hop,
+        (i_track_allocation, None))
+    hop.exception_cannot_occur()
+    if i_track_allocation is None or v_track_allocation.value:
+        hop.genop('track_alloc_stop', vlist)
+
 def rtype_const_result(hop):
     hop.exception_cannot_occur()
     return hop.inputconst(hop.r_result.lowleveltype, hop.s_result.const)
@@ -523,6 +531,7 @@
 
 BUILTIN_TYPER[lltype.malloc] = rtype_malloc
 BUILTIN_TYPER[lltype.free] = rtype_free
+BUILTIN_TYPER[lltype.render_immortal] = rtype_render_immortal
 BUILTIN_TYPER[lltype.cast_primitive] = rtype_cast_primitive
 BUILTIN_TYPER[lltype.cast_pointer] = rtype_cast_pointer
 BUILTIN_TYPER[lltype.cast_opaque_ptr] = rtype_cast_opaque_ptr

Modified: pypy/branch/jitypes2/pypy/rpython/test/test_rpbc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/test/test_rpbc.py	(original)
+++ pypy/branch/jitypes2/pypy/rpython/test/test_rpbc.py	Tue Nov 23 13:26:19 2010
@@ -1547,7 +1547,7 @@
     def test_always_raising_methods(self):
         class Base:
             def m(self):
-                raise NotImplementedError
+                raise KeyError
         class A(Base):
             def m(self):
                 return 42
@@ -1560,11 +1560,11 @@
                 o = B()
             try:
                 o.m()
-            except NotImplementedError:
-                pass
+            except KeyError:
+                assert 0
             return B().m()
 
-        self.interpret_raises(NotImplementedError, f, [7])
+        self.interpret_raises(KeyError, f, [7])
 
     def test_possible_missing_attribute_access(self):
         py.test.skip("Should explode or give some warning")

Modified: pypy/branch/jitypes2/pypy/tool/release/force-builds.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/release/force-builds.py	(original)
+++ pypy/branch/jitypes2/pypy/tool/release/force-builds.py	Tue Nov 23 13:26:19 2010
@@ -20,11 +20,12 @@
     'own-linux-x86-32',
     'own-linux-x86-64',
 #    'own-macosx-x86-32',
-    'pypy-c-app-level-linux-x86-32',
-    'pypy-c-app-level-linux-x86-64',
+#    'pypy-c-app-level-linux-x86-32',
+#    'pypy-c-app-level-linux-x86-64',
     'pypy-c-stackless-app-level-linux-x86-32',
     'pypy-c-app-level-win-x86-32',
     'pypy-c-jit-linux-x86-32',
+    'pypy-c-jit-linux-x86-64',
 #    'pypy-c-jit-macosx-x86-32',
     'pypy-c-jit-win-x86-32',
 ]

Modified: pypy/branch/jitypes2/pypy/tool/release/make_release.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/release/make_release.py	(original)
+++ pypy/branch/jitypes2/pypy/tool/release/make_release.py	Tue Nov 23 13:26:19 2010
@@ -4,7 +4,7 @@
 into release packages. Note: you must run apropriate buildbots first and
 make sure there are no failures. Use force-builds.py from the same directory.
 
-Usage: make_release.py release/<release name>
+Usage: make_release.py release/<release name> release_version
 """
 
 import autopath
@@ -30,7 +30,8 @@
     else:
         xml = override_xml
     dom = minidom.parseString(xml)
-    refs = [node.getAttribute('href') for node in dom.getElementsByTagName('a')]
+    refs = [node.getAttribute('href') for node in dom.getElementsByTagName('a')
+            if 'pypy' in node.getAttribute('href')]
     # all refs are of form: pypy-{type}-{revision}-{platform}.tar.bz2
     r = re.compile('pypy-c-([\w\d]+)-(\d+)-([\w\d]+).tar.bz2$')
     d = {}
@@ -76,7 +77,7 @@
                 t.add('pypy-%s' % release)
                 alltars.append(name)
                 t.close()
-                shutil.rmtree(str(tmpdir.join('pypy-1.3')))
+                shutil.rmtree(str(tmpdir.join('pypy-' + release)))
         for name in alltars:
             print "Uploading %s" % name
             os.system('scp %s codespeak.net:/www/pypy.org/htdocs/download' % name)
@@ -84,8 +85,8 @@
         os.chdir(olddir)
 
 if __name__ == '__main__':
-    if len(sys.argv) != 2:
+    if len(sys.argv) != 3:
         print __doc__
         sys.exit(1)
-    main(sys.argv[1], release='1.3')
+    main(sys.argv[1], release=sys.argv[2])
     

Modified: pypy/branch/jitypes2/pypy/tool/release/package.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/release/package.py	(original)
+++ pypy/branch/jitypes2/pypy/tool/release/package.py	Tue Nov 23 13:26:19 2010
@@ -1,8 +1,12 @@
 #!/usr/bin/env python
 """ A sample script that packages PyPy, provided that it's already built.
-Usage:
+It uses 'pypy/translator/goal/pypy-c' and parts of the rest of the working
+copy.  Usage:
 
-package.py pypydir [name-of-archive] [name-of-pypy-c]
+    package.py root-pypy-dir [name-of-archive] [name-of-pypy-c]
+
+Usually you would do:   package.py ../../.. pypy-VER-PLATFORM.
+The output is found in the directory /tmp/usession-YOURNAME/build/.
 """
 
 import autopath
@@ -32,7 +36,7 @@
 class PyPyCNotFound(Exception):
     pass
 
-def package(basedir, name='pypy-nightly', rename_pypy_c='pypy-c',
+def package(basedir, name='pypy-nightly', rename_pypy_c='pypy',
             copy_to_dir = None, override_pypy_c = None):
     basedir = py.path.local(basedir)
     if sys.platform == 'win32':
@@ -64,6 +68,10 @@
     headers = includedir.listdir('*.h') + includedir.listdir('*.inl')
     for n in headers:
         shutil.copy(str(n), str(pypydir.join('include')))
+    #
+    spdir = pypydir.ensure('site-packages', dir=True)
+    shutil.copy(str(basedir.join('site-packages', 'README')), str(spdir))
+    #
     pypydir.ensure('bin', dir=True)
     archive_pypy_c = pypydir.join('bin', rename_pypy_c)
     shutil.copy(str(pypy_c), str(archive_pypy_c))

Modified: pypy/branch/jitypes2/pypy/tool/release/test/test_package.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/release/test/test_package.py	(original)
+++ pypy/branch/jitypes2/pypy/tool/release/test/test_package.py	Tue Nov 23 13:26:19 2010
@@ -18,7 +18,7 @@
         prefix = builddir.join(test)
         cpyver = '%d.%d.%d' % CPYTHON_VERSION[:3]
         assert prefix.join('lib-python', cpyver, 'test').check()
-        assert prefix.join('bin', 'pypy-c').check()
+        assert prefix.join('bin', 'pypy').check()
         assert prefix.join('lib_pypy', 'syslog.py').check()
         assert not prefix.join('lib_pypy', 'py').check()
         assert not prefix.join('lib_pypy', 'ctypes_configure').check()

Modified: pypy/branch/jitypes2/pypy/tool/terminal.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/terminal.py	(original)
+++ pypy/branch/jitypes2/pypy/tool/terminal.py	Tue Nov 23 13:26:19 2010
@@ -62,9 +62,10 @@
     for control in CONTROLS:
         # Set the control escape sequence
         setattr(MODULE, control, curses.tigetstr(CONTROLS[control]) or '')
-    for value in VALUES:
-        # Set terminal related values
-        setattr(MODULE, value, curses.tigetnum(VALUES[value]))
+    if hasattr(curses, 'tigetnum'):
+        for value in VALUES:
+            # Set terminal related values
+            setattr(MODULE, value, curses.tigetnum(VALUES[value]))
 
 def render(text):
     """Helper function to apply controls easily
@@ -74,7 +75,16 @@
     return text % MODULE.__dict__
 
 try:
-    import curses
+    if '__pypy__' in sys.builtin_module_names:
+        # this is not really the whole curses, but our _minimal_curses it's
+        # better than nothing
+        import _minimal_curses as curses
+        # a bit of a hack: we have tigetstr but not tigetnum, so we call
+        # default() to have default values, then setup() will overwrite the
+        # ones it can
+        default()
+    else:
+        import curses
     setup()
 except Exception, e:
     # There is a failure; set all attributes to default

Modified: pypy/branch/jitypes2/pypy/translator/c/gcc/test/test_trackgcroot.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/gcc/test/test_trackgcroot.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/gcc/test/test_trackgcroot.py	Tue Nov 23 13:26:19 2010
@@ -98,14 +98,13 @@
 """
     lines = source.splitlines(True)
     parts = list(DarwinAssemblerParser().find_functions(iter(lines)))
-    assert len(parts) == 7
+    assert len(parts) == 6
     assert parts[0] == (False, lines[:3])
     assert parts[1] == (True,  lines[3:7])
     assert parts[2] == (True,  lines[7:11])
-    assert parts[3] == (True,  lines[11:13])
-    assert parts[4] == (False, lines[13:18])
-    assert parts[5] == (True,  lines[18:20])
-    assert parts[6] == (False, lines[20:])
+    assert parts[3] == (True,  lines[11:18])
+    assert parts[4] == (True,  lines[18:20])
+    assert parts[5] == (False, lines[20:])
  
 def test_computegcmaptable():
     tests = []

Modified: pypy/branch/jitypes2/pypy/translator/c/gcc/trackgcroot.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/gcc/trackgcroot.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/gcc/trackgcroot.py	Tue Nov 23 13:26:19 2010
@@ -1405,6 +1405,7 @@
                      'const_data'
                      ]
     r_sectionstart = re.compile(r"\t\.("+'|'.join(OTHERSECTIONS)+").*$")
+    sections_doesnt_end_function = {'cstring': True, 'const': True}
 
     def find_functions(self, iterlines):
         functionlines = []
@@ -1412,20 +1413,20 @@
         in_function = False
         for n, line in enumerate(iterlines):
             if self.r_textstart.match(line):
-                assert not in_text, "unexpected repeated .text start: %d" % n
                 in_text = True
             elif self.r_sectionstart.match(line):
-                if in_function:
+                sectionname = self.r_sectionstart.match(line).group(1)
+                if (in_function and
+                    sectionname not in self.sections_doesnt_end_function):
                     yield in_function, functionlines
                     functionlines = []
+                    in_function = False
                 in_text = False
-                in_function = False
             elif in_text and self.FunctionGcRootTracker.r_functionstart.match(line):
                 yield in_function, functionlines
                 functionlines = []
                 in_function = True
             functionlines.append(line)
-
         if functionlines:
             yield in_function, functionlines
 
@@ -1442,23 +1443,6 @@
     format = "mingw32"
     FunctionGcRootTracker = Mingw32FunctionGcRootTracker
 
-    def find_functions(self, iterlines):
-        functionlines = []
-        in_text = False
-        in_function = False
-        for n, line in enumerate(iterlines):
-            if self.r_textstart.match(line):
-                in_text = True
-            elif self.r_sectionstart.match(line):
-                in_text = False
-            elif in_text and self.FunctionGcRootTracker.r_functionstart.match(line):
-                yield in_function, functionlines
-                functionlines = []
-                in_function = True
-            functionlines.append(line)
-        if functionlines:
-            yield in_function, functionlines
-
 class MsvcAssemblerParser(AssemblerParser):
     format = "msvc"
     FunctionGcRootTracker = MsvcFunctionGcRootTracker

Modified: pypy/branch/jitypes2/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/genc.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/genc.py	Tue Nov 23 13:26:19 2010
@@ -553,7 +553,7 @@
             ('debug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT" $(TARGET)'),
             ('debug_exc', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DDO_LOG_EXC" $(TARGET)'),
             ('debug_mem', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DTRIVIAL_MALLOC_DEBUG" $(TARGET)'),
-            ('no_obmalloc', '', '$(MAKE) CFLAGS="-g -O1 -DRPY_ASSERT -DNO_OBMALLOC" $(TARGET)'),
+            ('no_obmalloc', '', '$(MAKE) CFLAGS="-g -O2 -DRPY_ASSERT -DNO_OBMALLOC" $(TARGET)'),
             ('linuxmemchk', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DLINUXMEMCHK" $(TARGET)'),
             ('llsafer', '', '$(MAKE) CFLAGS="-O2 -DRPY_LL_ASSERT" $(TARGET)'),
             ('lldebug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DRPY_LL_ASSERT" $(TARGET)'),

Modified: pypy/branch/jitypes2/pypy/translator/c/node.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/node.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/node.py	Tue Nov 23 13:26:19 2010
@@ -714,7 +714,11 @@
                 s = ''.join([self.obj.getitem(i) for i in range(len(self.obj.items))])
             else:
                 s = ''.join(self.obj.items)
-            yield '\t%s%s' % (length, c_char_array_constant(s))
+            array_constant = c_char_array_constant(s)
+            if array_constant.startswith('{') and barebonearray(T):
+                assert array_constant.endswith('}')
+                array_constant = array_constant[1:-1].strip()
+            yield '\t%s%s' % (length, array_constant)
             yield '}'
         else:
             barebone = barebonearray(T)

Modified: pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86.h
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86.h	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86.h	Tue Nov 23 13:26:19 2010
@@ -2,6 +2,8 @@
  * It replaces some complex macros with native assembler instructions.
  */
 
+#if 0     /* --- disabled: does not give any speed-up --- */
+
 #undef OP_INT_ADD_OVF
 #define OP_INT_ADD_OVF(x,y,r)                   \
     asm volatile(                               \
@@ -50,6 +52,13 @@
         : "0"(x), "g"(y)     /* inputs  */      \
         : "cc", "memory")    /* clobber */
 
+extern void op_int_overflowed(void)
+     asm ("_op_int_overflowed")
+     __attribute__((used));
+
+#endif  /* 0 */
+
+
 /* Pentium only! */
 #define READ_TIMESTAMP(val) \
      asm volatile("rdtsc" : "=A" (val))
@@ -62,19 +71,15 @@
 // I don't know how important it is, comment talks about time warps
 
 
-/* prototypes */
-
-extern void op_int_overflowed(void)
-     asm ("_op_int_overflowed")
-     __attribute__((used));
-
 /* implementations */
 
 #ifndef PYPY_NOT_MAIN_FILE
 
+#  if 0   /* disabled */
 void op_int_overflowed(void)
 {
   FAIL_OVF("integer operation");
 }
+#  endif
 
 #endif

Modified: pypy/branch/jitypes2/pypy/translator/c/src/debug_print.h
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/src/debug_print.h	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/src/debug_print.h	Tue Nov 23 13:26:19 2010
@@ -10,6 +10,7 @@
                      but not any nested debug_print
    :fname         full logging
    prefix:fname   conditional logging
+   prefix1,prefix2:fname   conditional logging with multiple selections
 
    Conditional logging means that it only includes the debug_start/debug_stop
    sections whose name match 'prefix'.  Other sections are ignored, including
@@ -70,6 +71,8 @@
 static void pypy_debug_open(void)
 {
   char *filename = getenv("PYPYLOG");
+  if (filename)
+    unsetenv("PYPYLOG");   /* don't pass it to subprocesses */
   if (filename && filename[0])
     {
       char *colon = strchr(filename, ':');
@@ -139,12 +142,22 @@
 #endif
 
 
-static bool_t startswith(const char *str, const char *substr)
+static bool_t startswithoneof(const char *str, const char *substr)
 {
-  while (*substr)
-    if (*str++ != *substr++)
-      return 0;
-  return 1;
+  const char *p = str;
+  for (; *substr; substr++)
+    {
+      if (*substr != ',')
+        {
+          if (p && *p++ != *substr)
+            p = NULL;   /* mismatch */
+        }
+      else if (p != NULL)
+        return 1;   /* match */
+      else
+        p = str;    /* mismatched, retry with the next */
+    }
+  return p != NULL;
 }
 
 #if defined(_MSC_VER) || defined(__MINGW32__)
@@ -175,7 +188,7 @@
   if (!debug_profile)
     {
       /* non-profiling version */
-      if (!debug_prefix || !startswith(category, debug_prefix))
+      if (!debug_prefix || !startswithoneof(category, debug_prefix))
         {
           /* wrong section name, or no PYPYLOG at all, skip it */
           return;

Modified: pypy/branch/jitypes2/pypy/translator/c/src/g_include.h
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/src/g_include.h	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/src/g_include.h	Tue Nov 23 13:26:19 2010
@@ -39,10 +39,13 @@
 #include "src/instrument.h"
 
 /* optional assembler bits */
-// disabled: does not give any speed-up
-//#if defined(__GNUC__) && defined(__i386__)
-//#  include "src/asm_gcc_x86.h"
-//#endif
+#if defined(__GNUC__) && defined(__i386__)
+#  include "src/asm_gcc_x86.h"
+#endif
+
+#if defined(__GNUC__) && defined(__amd64__)
+#  include "src/asm_gcc_x86_64.h"
+#endif
 
 #if defined(__GNUC__) && defined(__ppc__)
 #  include "src/asm_ppc.h"

Modified: pypy/branch/jitypes2/pypy/translator/c/test/test_lltyped.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/test/test_lltyped.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/test/test_lltyped.py	Tue Nov 23 13:26:19 2010
@@ -1,6 +1,7 @@
 import py
 from pypy.rpython.lltypesystem.lltype import *
 from pypy.translator.c.test import test_typed
+from pypy.tool.sourcetools import func_with_new_name
 
 
 class TestLowLevelType(test_typed.CompilationTestCase):
@@ -655,6 +656,45 @@
             fn = self.getcompiled(llf)
             fn()
 
+    def test_prebuilt_raw_arrays(self):
+        from pypy.rpython.lltypesystem import rffi, ll2ctypes
+        #
+        def make_test_function(cast, haslength, length):
+            a = malloc(A, length, flavor='raw', immortal=True)
+            # two cases: a zero-terminated array if length == 6 or 1030,
+            # a non-zero-terminated array if length == 557 or 1031
+            for i in range(length):
+                a[i] = cast(256 - 5 + i)
+            def llf():
+                for i in range(length):
+                    if a[i] != cast(256 - 5 + i):
+                        return False
+                if haslength and len(a) != length:
+                    return False
+                return True
+            return func_with_new_name(llf, repr((A, haslength, length)))
+        #
+        testfns = []
+        records = []
+        for OF, cast in [(Void, lambda n: None),
+                         (Char, lambda n: chr(n & 0xFF)),
+                         (Signed, lambda n: n)]:
+            for A, haslength in [(rffi.CArray(OF), False),
+                                 (Array(OF), True)]:
+                for length in [0, 6, 557, 1030, 1031]:
+                    testfns.append(make_test_function(cast, haslength, length))
+                    records.append((A, haslength, length))
+        def llf():
+            i = 0
+            for fn in testfns:
+                if not fn():
+                    return i    # returns the index of the failing function
+                i += 1
+            return -42
+        fn = self.getcompiled(llf)
+        res = fn()
+        assert res == -42, "failing function: %r" % (records[res],)
+
     def test_prebuilt_ll2ctypes_array(self):
         from pypy.rpython.lltypesystem import rffi, ll2ctypes
         A = rffi.CArray(Char)
@@ -841,3 +881,17 @@
         assert res == -98765432
         res = fn(1)
         assert res == -9999999
+
+    def test_render_immortal(self):
+        A = FixedSizeArray(Signed, 1)
+        a1 = malloc(A, flavor='raw')
+        render_immortal(a1)
+        a1[0] = 42
+        def llf():
+            a2 = malloc(A, flavor='raw')
+            render_immortal(a2)
+            a2[0] = 3
+            return a1[0] + a2[0]
+        fn = self.getcompiled(llf)
+        assert fn() == 45
+

Modified: pypy/branch/jitypes2/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/test/test_newgc.py	Tue Nov 23 13:26:19 2010
@@ -1096,6 +1096,42 @@
         assert os.path.exists(self.filename_dump)
         assert os.path.getsize(self.filename_dump) > 64
 
+    filename_dump_typeids_z = str(udir.join('test_typeids_z'))
+    def define_write_typeids_z(self):
+        U = lltype.GcForwardReference()
+        U.become(lltype.GcStruct('U', ('next', lltype.Ptr(U)),
+                                 ('x', lltype.Signed)))
+        S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
+        A = lltype.GcArray(lltype.Ptr(S))
+        filename = self.filename_dump_typeids_z
+
+        def fn():
+            s = lltype.malloc(S)
+            s.u = lltype.malloc(U)
+            s.u.next = lltype.malloc(U)
+            s.u.next.next = lltype.malloc(U)
+            a = lltype.malloc(A, 1000)
+            s2 = lltype.malloc(S)
+            #
+            p = rgc.get_typeids_z()
+            s = ''.join([p[i] for i in range(len(p))])
+            fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666)
+            os.write(fd, s)
+            os.close(fd)
+            return 0
+
+        return fn
+
+    def test_write_typeids_z(self):
+        self.run("write_typeids_z")
+        f = open(self.filename_dump_typeids_z)
+        data_z = f.read()
+        f.close()
+        import zlib
+        data = zlib.decompress(data_z)
+        assert data.startswith('member0')
+        assert 'GcArray of * GcStruct S {' in data
+
 class TestSemiSpaceGC(TestUsingFramework, snippet.SemiSpaceGCTestDefines):
     gcpolicy = "semispace"
     should_be_moving = True
@@ -1179,21 +1215,22 @@
             b = 0
             c = 0
             for i in range(len(tb)):
-                if tb[i].count == 10:
+                if tb[i].count == 10:      # the type of S
                     a += 1
                     nr = i
             for i in range(len(tb)):
-                if tb[i].count == 3:
+                if tb[i].count == 3:       # the type GcArray(Ptr(S))
                     b += 1
                     c += tb[i].links[nr]
-            # we don't count b here since there can be more singletons,
+            # b can be 1 or 2 here since _heap_stats() is free to return or
+            # ignore the three GcStructs that point to the GcArray(Ptr(S)).
             # important one is c, a is for check
             return c * 100 + b * 10 + a
         return f
 
     def test_gc_heap_stats(self):
         res = self.run("gc_heap_stats")
-        assert res == 3011
+        assert res == 3011 or res == 3021
 
     def definestr_string_builder(cls):
         def fn(_):

Modified: pypy/branch/jitypes2/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/test/test_standalone.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/c/test/test_standalone.py	Tue Nov 23 13:26:19 2010
@@ -368,12 +368,27 @@
         assert not err
         assert path.check(file=1)
         data = path.read()
-        assert 'toplevel' in path.read()
-        assert 'mycat' not in path.read()
-        assert 'foo 2 bar 3' not in path.read()
+        assert 'toplevel' in data
+        assert 'mycat' not in data
+        assert 'foo 2 bar 3' not in data
         assert 'cat2' in data
         assert 'baz' in data
         assert 'bok' not in data
+        # check with PYPYLOG=myc,cat2:somefilename   (includes mycat and cat2)
+        path = udir.join('test_debug_xxx_myc_cat2.log')
+        out, err = cbuilder.cmdexec("", err=True,
+                                    env={'PYPYLOG': 'myc,cat2:%s' % path})
+        assert out.strip() == 'got:bcda.'
+        assert not err
+        assert path.check(file=1)
+        data = path.read()
+        assert 'toplevel' in data
+        assert '{mycat' in data
+        assert 'mycat}' in data
+        assert 'foo 2 bar 3' in data
+        assert 'cat2' in data
+        assert 'baz' in data
+        assert 'bok' in data
         #
         # finally, check compiling with logging disabled
         from pypy.config.pypyoption import get_pypy_config

Modified: pypy/branch/jitypes2/pypy/translator/cli/src/pypylib.cs
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/cli/src/pypylib.cs	(original)
+++ pypy/branch/jitypes2/pypy/translator/cli/src/pypylib.cs	Tue Nov 23 13:26:19 2010
@@ -83,8 +83,12 @@
                 return Double.NegativeInfinity;
             else if (s == "nan")
                 return Double.NaN;
-            else
-                return System.Convert.ToDouble(s);
+            else {
+                System.Globalization.NumberFormatInfo formatter;
+                formatter = new System.Globalization.NumberFormatInfo();
+                formatter.NumberDecimalSeparator = ".";
+                return System.Convert.ToDouble(s, formatter);
+            }
         }
     }
 

Modified: pypy/branch/jitypes2/pypy/translator/goal/app_main.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/goal/app_main.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/goal/app_main.py	Tue Nov 23 13:26:19 2010
@@ -326,10 +326,6 @@
         except:
             print >> sys.stderr, "'import site' failed"
 
-    # update sys.path *after* loading site.py, in case there is a
-    # "site.py" file in the script's directory.
-    sys.path.insert(0, '')
-
     if warnoptions:
         sys.warnoptions.append(warnoptions)
         from warnings import _processoptions
@@ -366,6 +362,9 @@
     try:
         if run_command:
             # handle the "-c" command
+            # Put '' on sys.path
+            sys.path.insert(0, '')
+
             def run_it():
                 exec cmd in mainmodule.__dict__
             success = run_toplevel(run_it)
@@ -378,6 +377,13 @@
         elif run_stdin:
             # handle the case where no command/filename/module is specified
             # on the command-line.
+
+            # update sys.path *after* loading site.py, in case there is a
+            # "site.py" file in the script's directory. Only run this if we're
+            # executing the interactive prompt, if we're running a script we
+            # put it's directory on sys.path
+            sys.path.insert(0, '')
+
             if go_interactive or sys.stdin.isatty():
                 # If stdin is a tty or if "-i" is specified, we print
                 # a banner and run $PYTHONSTARTUP.

Modified: pypy/branch/jitypes2/pypy/translator/goal/targetpypystandalone.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/goal/targetpypystandalone.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/goal/targetpypystandalone.py	Tue Nov 23 13:26:19 2010
@@ -28,9 +28,14 @@
     w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish))
     w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup))
     w_os = setup_nanos(space)
+    withjit = space.config.objspace.usemodules.pypyjit
 
     def entry_point(argv):
         space.timer.start("Entrypoint")
+        if withjit:
+            from pypy.jit.backend.hlinfo import highleveljitinfo
+            highleveljitinfo.sys_executable = argv[0]
+
         #debug("entry point starting") 
         #for arg in argv: 
         #    debug(" argv -> " + arg)
@@ -150,6 +155,9 @@
         if config.objspace.allworkingmodules:
             from pypy.config.pypyoption import enable_allworkingmodules
             enable_allworkingmodules(config)
+        if config.objspace.translationmodules:
+            from pypy.config.pypyoption import enable_translationmodules
+            enable_translationmodules(config)
 
         if config.translation.type_system == 'ootype':
             config.objspace.usemodules.suggest(rbench=True)

Modified: pypy/branch/jitypes2/pypy/translator/goal/test2/test_app_main.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/goal/test2/test_app_main.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/goal/test2/test_app_main.py	Tue Nov 23 13:26:19 2010
@@ -95,6 +95,11 @@
         child.expect('>>> ')
         child.sendline('__name__')
         child.expect("'__main__'")
+        child.expect('>>> ')
+        child.sendline('import sys')
+        child.expect('>>> ')
+        child.sendline("'' in sys.path")
+        child.expect("True")
 
     def test_run_script(self):
         child = self.spawn([demo_script])
@@ -463,8 +468,10 @@
                 yield
             finally:
                 old_cwd.chdir()
-                os.putenv('PYTHONPATH', old_pythonpath)
-        
+                # Can't call putenv with a None argument.
+                if old_pythonpath is not None:
+                    os.putenv('PYTHONPATH', old_pythonpath)
+
         tmpdir.join('site.py').write('print "SHOULD NOT RUN"')
         runme_py = tmpdir.join('runme.py')
         runme_py.write('print "some text"')
@@ -485,9 +492,12 @@
 
         with chdir_and_unset_pythonpath(tmpdir):
             data = self.run(cmdline2, python_flags='-S')
-
         assert data.startswith("some new text\n")
         assert repr(str(tmpdir.join('otherpath'))) in data
+        assert "''" not in data
+
+        data = self.run('-c "import sys; print sys.path"')
+        assert data.startswith("[''")
 
 
 class AppTestAppMain:
@@ -524,7 +534,8 @@
             newpath = app_main.get_library_path('/tmp/pypy-c') # stdlib not found
             assert newpath == sys.path
             newpath = app_main.get_library_path(self.fake_exe)
-            assert newpath == self.expected_path
+            # we get at least 'expected_path', and maybe more (e.g.plat-linux2)
+            assert newpath[:len(self.expected_path)] == self.expected_path
         finally:
             sys.path.pop()
 
@@ -537,7 +548,9 @@
             app_main.os = os
             pypy_c = os.path.join(self.trunkdir, 'pypy', 'translator', 'goal', 'pypy-c')
             newpath = app_main.get_library_path(pypy_c)
-            assert len(newpath) == 3
+            # we get at least lib_pypy, lib-python/modified-X.Y.Z,
+            # lib-python/X.Y.Z, and maybe more (e.g. plat-linux2)
+            assert len(newpath) >= 3
             for p in newpath:
                 assert p.startswith(self.trunkdir)
         finally:

Modified: pypy/branch/jitypes2/pypy/translator/platform/linux.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/platform/linux.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/platform/linux.py	Tue Nov 23 13:26:19 2010
@@ -27,6 +27,8 @@
 
 
 class Linux(BaseLinux):
+    shared_only = ()    # it seems that on 32-bit linux, compiling with -fPIC
+                        # gives assembler that asmgcc is not happy about.
     def library_dirs_for_libffi_a(self):
         # places where we need to look for libffi.a
         return self.library_dirs_for_libffi() + ['/usr/lib']

Modified: pypy/branch/jitypes2/pypy/translator/platform/posix.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/platform/posix.py	(original)
+++ pypy/branch/jitypes2/pypy/translator/platform/posix.py	Tue Nov 23 13:26:19 2010
@@ -104,12 +104,10 @@
         else:
             target_name = exe_name.basename
 
-        cflags = self.cflags
-        if sys.maxint > 2147483647:   # XXX XXX XXX sort this out
-            if shared:
-                cflags = self.cflags + self.shared_only
-            else:
-                cflags = self.cflags + self.standalone_only
+        if shared:
+            cflags = self.cflags + self.shared_only
+        else:
+            cflags = self.cflags + self.standalone_only
 
         m = GnuMakefile(path)
         m.exe_name = exe_name



More information about the Pypy-commit mailing list