[pypy-svn] r79225 - in pypy/branch/jit-unroll-loops: . lib-python/modified-2.5.2/distutils lib_pypy/ctypes_config_cache lib_pypy/ctypes_config_cache/test pypy pypy/annotation pypy/config pypy/doc pypy/doc/config pypy/interpreter pypy/interpreter/test pypy/jit/backend pypy/jit/backend/llgraph pypy/jit/backend/llsupport pypy/jit/backend/llsupport/test pypy/jit/backend/test pypy/jit/backend/x86 pypy/jit/backend/x86/test pypy/jit/backend/x86/tool 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/__builtin__ pypy/module/__pypy__ pypy/module/__pypy__/test 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/signal pypy/module/signal/test pypy/module/sys pypy/module/thread pypy/module/thread/test pypy/objspace/flow pypy/objspace/flow/test 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/translator/c pypy/translator/c/gcc pypy/translator/c/src pypy/translator/c/test pypy/translator/cli/src pypy/translator/goal pypy/translator/goal/test2

hakanardo at codespeak.net hakanardo at codespeak.net
Wed Nov 17 20:41:33 CET 2010


Author: hakanardo
Date: Wed Nov 17 20:41:25 2010
New Revision: 79225

Added:
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/dumpcache.py
      - copied unchanged from r79224, pypy/trunk/lib_pypy/ctypes_config_cache/dumpcache.py
   pypy/branch/jit-unroll-loops/pypy/doc/config/objspace.soabi.txt
      - copied unchanged from r79224, pypy/trunk/pypy/doc/config/objspace.soabi.txt
   pypy/branch/jit-unroll-loops/pypy/doc/config/objspace.translationmodules.txt
      - copied unchanged from r79224, pypy/trunk/pypy/doc/config/objspace.translationmodules.txt
   pypy/branch/jit-unroll-loops/pypy/doc/release-1.4.0.txt
      - copied unchanged from r79224, pypy/trunk/pypy/doc/release-1.4.0.txt
   pypy/branch/jit-unroll-loops/pypy/jit/tool/loopcounter.py
      - copied unchanged from r79224, pypy/trunk/pypy/jit/tool/loopcounter.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_oparser.py
      - copied unchanged from r79224, pypy/trunk/pypy/jit/tool/test/test_oparser.py
   pypy/branch/jit-unroll-loops/pypy/module/_stackless/test/conftest.py
      - copied unchanged from r79224, pypy/trunk/pypy/module/_stackless/test/conftest.py
   pypy/branch/jit-unroll-loops/pypy/tool/gcdump.py
      - copied unchanged from r79224, pypy/trunk/pypy/tool/gcdump.py
Removed:
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_oparser.py
Modified:
   pypy/branch/jit-unroll-loops/   (props changed)
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/   (props changed)
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/hashlib.ctc.py
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/locale.ctc.py
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/pyexpat.ctc.py
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/rebuild.py
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/resource.ctc.py
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/syslog.ctc.py
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/test/test_cache.py
   pypy/branch/jit-unroll-loops/pypy/   (props changed)
   pypy/branch/jit-unroll-loops/pypy/annotation/bookkeeper.py
   pypy/branch/jit-unroll-loops/pypy/annotation/builtin.py
   pypy/branch/jit-unroll-loops/pypy/config/pypyoption.py
   pypy/branch/jit-unroll-loops/pypy/conftest.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/argument.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/baseobjspace.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/executioncontext.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/pyopcode.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_argument.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_executioncontext.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/detect_cpu.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llgraph/llimpl.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/descr.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/gc.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_descr.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_gc.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/test/runner_test.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/assembler.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_runner.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zrpy_gc.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_ztranslation.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/tool/viewcode.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/assembler.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/call.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/codewriter.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/effectinfo.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/jtransform.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_jtransform.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/blackhole.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/compile.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/logger.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/optimizer.py   (contents, props changed)
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/string.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/resoperation.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/resume.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_basic.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_compile.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_del.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_logger.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_resoperation.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_resume.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_send_nounroll.py   (props changed)
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_virtualref.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_ztranslation.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/virtualizable.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/warmspot.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/oparser.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/pypytrace-mode.el
   pypy/branch/jit-unroll-loops/pypy/jit/tool/pypytrace.vim
   pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_traceviewer.py
   pypy/branch/jit-unroll-loops/pypy/module/__builtin__/descriptor.py
   pypy/branch/jit-unroll-loops/pypy/module/__pypy__/__init__.py
   pypy/branch/jit-unroll-loops/pypy/module/__pypy__/interp_magic.py
   pypy/branch/jit-unroll-loops/pypy/module/__pypy__/test/test_special.py
   pypy/branch/jit-unroll-loops/pypy/module/_rawffi/test/test__rawffi.py
   pypy/branch/jit-unroll-loops/pypy/module/_rawffi/test/test_nested.py
   pypy/branch/jit-unroll-loops/pypy/module/array/benchmark/Makefile   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/array/benchmark/intimg.c   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/array/benchmark/intimgtst.c   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/array/benchmark/intimgtst.py   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/array/benchmark/loop.c   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/array/benchmark/sum.c   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/array/benchmark/sumtst.c   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/array/benchmark/sumtst.py   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/array/interp_array.py
   pypy/branch/jit-unroll-loops/pypy/module/array/test/test_array_old.py   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/api.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/cdatetime.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/presetup.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/pyobject.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_borrow.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/typeobject.py
   pypy/branch/jit-unroll-loops/pypy/module/gc/__init__.py
   pypy/branch/jit-unroll-loops/pypy/module/gc/app_referents.py
   pypy/branch/jit-unroll-loops/pypy/module/gc/interp_gc.py
   pypy/branch/jit-unroll-loops/pypy/module/gc/referents.py
   pypy/branch/jit-unroll-loops/pypy/module/gc/test/test_gc.py
   pypy/branch/jit-unroll-loops/pypy/module/imp/importing.py
   pypy/branch/jit-unroll-loops/pypy/module/imp/interp_imp.py
   pypy/branch/jit-unroll-loops/pypy/module/imp/test/test_app.py
   pypy/branch/jit-unroll-loops/pypy/module/imp/test/test_import.py
   pypy/branch/jit-unroll-loops/pypy/module/posix/interp_posix.py
   pypy/branch/jit-unroll-loops/pypy/module/pypyjit/interp_jit.py
   pypy/branch/jit-unroll-loops/pypy/module/pypyjit/policy.py
   pypy/branch/jit-unroll-loops/pypy/module/pypyjit/test/test_policy.py
   pypy/branch/jit-unroll-loops/pypy/module/pypyjit/test/test_pypy_c.py
   pypy/branch/jit-unroll-loops/pypy/module/rctime/interp_time.py
   pypy/branch/jit-unroll-loops/pypy/module/signal/__init__.py
   pypy/branch/jit-unroll-loops/pypy/module/signal/interp_signal.py
   pypy/branch/jit-unroll-loops/pypy/module/signal/test/test_signal.py
   pypy/branch/jit-unroll-loops/pypy/module/sys/__init__.py
   pypy/branch/jit-unroll-loops/pypy/module/sys/version.py
   pypy/branch/jit-unroll-loops/pypy/module/sys/vm.py
   pypy/branch/jit-unroll-loops/pypy/module/thread/gil.py
   pypy/branch/jit-unroll-loops/pypy/module/thread/test/test_gil.py
   pypy/branch/jit-unroll-loops/pypy/objspace/flow/model.py
   pypy/branch/jit-unroll-loops/pypy/objspace/flow/objspace.py
   pypy/branch/jit-unroll-loops/pypy/objspace/flow/test/test_objspace.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/callmethod.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/mapdict.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/stringobject.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_dictmultiobject.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_mapdict.py
   pypy/branch/jit-unroll-loops/pypy/rlib/clibffi.py
   pypy/branch/jit-unroll-loops/pypy/rlib/jit.py
   pypy/branch/jit-unroll-loops/pypy/rlib/rarithmetic.py
   pypy/branch/jit-unroll-loops/pypy/rlib/rerased.py   (props changed)
   pypy/branch/jit-unroll-loops/pypy/rlib/rgc.py
   pypy/branch/jit-unroll-loops/pypy/rlib/streamio.py
   pypy/branch/jit-unroll-loops/pypy/rlib/test/test_rarithmetic.py
   pypy/branch/jit-unroll-loops/pypy/rlib/test/test_rerased.py   (props changed)
   pypy/branch/jit-unroll-loops/pypy/rpython/annlowlevel.py
   pypy/branch/jit-unroll-loops/pypy/rpython/llinterp.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/llarena.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/llmemory.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/lloperation.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/lltype.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rffi.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/base.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/generation.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/inspector.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/minimark.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/semispace.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/test/test_minimark.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/support.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/test/test_gc.py
   pypy/branch/jit-unroll-loops/pypy/rpython/rbuiltin.py
   pypy/branch/jit-unroll-loops/pypy/rpython/rmodel.py
   pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rpbc.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/gcc/trackgcroot.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/genc.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/node.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/src/asm_gcc_x86.h
   pypy/branch/jit-unroll-loops/pypy/translator/c/src/g_include.h
   pypy/branch/jit-unroll-loops/pypy/translator/c/src/signals.h
   pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_lltyped.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_newgc.py
   pypy/branch/jit-unroll-loops/pypy/translator/cli/src/pypylib.cs
   pypy/branch/jit-unroll-loops/pypy/translator/goal/app_main.py
   pypy/branch/jit-unroll-loops/pypy/translator/goal/targetpypystandalone.py
   pypy/branch/jit-unroll-loops/pypy/translator/goal/test2/test_app_main.py
Log:
svn merge -r78744:HEAD svn+ssh://hakanardo@codespeak.net/svn/pypy/trunk

Modified: pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py	(original)
+++ pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/lib_pypy/ctypes_config_cache/hashlib.ctc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/hashlib.ctc.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/hashlib.ctc.py	Wed Nov 17 20:41:25 2010
@@ -4,7 +4,8 @@
 """
 
 from ctypes import *
-from ctypes_configure import configure, dumpcache
+from ctypes_configure import configure
+import dumpcache
 
 
 class CConfig:
@@ -17,4 +18,4 @@
                                   [('digest', c_void_p)])
 
 config = configure.configure(CConfig)
-dumpcache.dumpcache(__file__, '_hashlib_cache.py', config)
+dumpcache.dumpcache2('hashlib', config)

Modified: pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/locale.ctc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/locale.ctc.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/locale.ctc.py	Wed Nov 17 20:41:25 2010
@@ -5,7 +5,7 @@
 
 from ctypes_configure.configure import (configure, ExternalCompilationInfo,
     ConstantInteger, DefinedConstantInteger, SimpleType, check_eci)
-from ctypes_configure.dumpcache import dumpcache
+import dumpcache
 
 # ____________________________________________________________
 
@@ -70,4 +70,4 @@
 
 config['ALL_CONSTANTS'] = tuple(_CONSTANTS)
 config['HAS_LANGINFO'] = HAS_LANGINFO
-dumpcache(__file__, '_locale_cache.py', config)
+dumpcache.dumpcache2('locale', config)

Modified: pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/pyexpat.ctc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/pyexpat.ctc.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/pyexpat.ctc.py	Wed Nov 17 20:41:25 2010
@@ -5,7 +5,8 @@
 
 import ctypes
 from ctypes import c_char_p, c_int, c_void_p, c_char
-from ctypes_configure import configure, dumpcache
+from ctypes_configure import configure
+import dumpcache
 
 
 class CConfigure:
@@ -41,4 +42,4 @@
 
 config = configure.configure(CConfigure)
 
-dumpcache.dumpcache(__file__, '_pyexpat_cache.py', config)
+dumpcache.dumpcache2('pyexpat', config)

Modified: pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/rebuild.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/rebuild.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/rebuild.py	Wed Nov 17 20:41:25 2010
@@ -31,10 +31,25 @@
         sys.path[:] = path
 
 def try_rebuild():
+    from pypy.jit.backend import detect_cpu
+    model = detect_cpu.autodetect_main_model_and_size()
+    # remove the files '_*_model_.py'
+    left = {}
+    for p in os.listdir(_dirpath):
+        if p.startswith('_') and (p.endswith('_%s_.py' % model) or
+                                  p.endswith('_%s_.pyc' % model)):
+            os.unlink(os.path.join(_dirpath, p))
+        elif p.startswith('_') and (p.endswith('_.py') or
+                                    p.endswith('_.pyc')):
+            for i in range(2, len(p)-4):
+                left[p[:i]] = True
+    # remove the files '_*_cache.py' if there is no '_*_*_.py' left around
     for p in os.listdir(_dirpath):
         if p.startswith('_') and (p.endswith('_cache.py') or
                                   p.endswith('_cache.pyc')):
-            os.unlink(os.path.join(_dirpath, p))
+            if p[:-9] not in left:
+                os.unlink(os.path.join(_dirpath, p))
+    #
     for p in os.listdir(_dirpath):
         if p.endswith('.ctc.py'):
             try:

Modified: pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/resource.ctc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/resource.ctc.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/resource.ctc.py	Wed Nov 17 20:41:25 2010
@@ -4,7 +4,7 @@
 """
 
 from ctypes import sizeof
-from ctypes_configure.dumpcache import dumpcache
+import dumpcache
 from ctypes_configure.configure import (configure,
     ExternalCompilationInfo, ConstantInteger, DefinedConstantInteger,
     SimpleType)
@@ -58,4 +58,4 @@
         del config[key]
 
 config['ALL_CONSTANTS'] = _CONSTANTS + tuple(optional_constants)
-dumpcache(__file__, '_resource_cache.py', config)
+dumpcache.dumpcache2('resource', config)

Modified: pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/syslog.ctc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/syslog.ctc.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/syslog.ctc.py	Wed Nov 17 20:41:25 2010
@@ -5,7 +5,7 @@
 
 from ctypes_configure.configure import (configure,
     ExternalCompilationInfo, ConstantInteger, DefinedConstantInteger)
-from ctypes_configure.dumpcache import dumpcache
+import dumpcache
 
 
 _CONSTANTS = (
@@ -72,4 +72,4 @@
 all_constants = config.keys()
 all_constants.sort()
 config['ALL_CONSTANTS'] = tuple(all_constants)
-dumpcache(__file__, '_syslog_cache.py', config)
+dumpcache.dumpcache2('syslog', config)

Modified: pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/test/test_cache.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/test/test_cache.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/ctypes_config_cache/test/test_cache.py	Wed Nov 17 20:41:25 2010
@@ -7,19 +7,26 @@
 
 def run(filename, outputname):
     filepath = dirpath.join(filename)
-    tmpdir = udir.ensure('testcache-' + filename, dir=True)
-    outputpath = tmpdir.join(outputname)
-    d = {'__file__': str(outputpath)}
+    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:
-        sys.path.insert(0, str(dirpath))
-        execfile(str(filepath), d)
+        sys.path.insert(0, str(tmpdir))
+        execfile(str(filepath), {})
     finally:
         sys.path[:] = path
+        sys.modules.pop('dumpcache', None)
     #
+    outputpath = tmpdir.join(outputname)
     assert outputpath.check(exists=1)
-    d = {}
-    execfile(str(outputpath), d)
+    modname = os.path.splitext(outputname)[0]
+    try:
+        sys.path.insert(0, str(tmpdir))
+        d = {}
+        execfile(str(outputpath), d)
+    finally:
+        sys.path[:] = path
     return d
 
 

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/bookkeeper.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/bookkeeper.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/annotation/builtin.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/builtin.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/builtin.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/config/pypyoption.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/config/pypyoption.py	Wed Nov 17 20:41:25 2010
@@ -34,6 +34,11 @@
      "_bisect"]
 ))
 
+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/jit-unroll-loops/pypy/conftest.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/conftest.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/conftest.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/interpreter/argument.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/argument.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/argument.py	Wed Nov 17 20:41:25 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

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/baseobjspace.py	Wed Nov 17 20:41:25 2010
@@ -258,10 +258,9 @@
 
         self.interned_strings = {}
         self.actionflag = ActionFlag()    # changed by the signal module
+        self.check_signal_action = None   # changed by the signal module
         self.user_del_action = UserDelAction(self)
         self.frame_trace_action = FrameTraceAction(self)
-        self.actionflag.register_action(self.user_del_action)
-        self.actionflag.register_action(self.frame_trace_action)
 
         from pypy.interpreter.pycode import cpython_magic, default_magic
         self.our_magic = default_magic
@@ -299,8 +298,6 @@
                 self.timer.start("startup " + modname)
                 mod.init(self)
                 self.timer.stop("startup " + modname)
-        # Force the tick counter to have a valid value
-        self.actionflag.force_tick_counter()
 
     def finish(self):
         self.wait_for_thread_shutdown()

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/executioncontext.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/executioncontext.py	Wed Nov 17 20:41:25 2010
@@ -5,6 +5,8 @@
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib import jit
 
+TICK_COUNTER_STEP = 100
+
 def app_profile_call(space, w_callable, frame, event, w_arg):
     space.call_function(w_callable,
                         space.wrap(frame),
@@ -166,24 +168,19 @@
         if self.w_tracefunc is not None:
             self._trace(frame, 'return', w_retval)
 
-    def bytecode_trace(self, frame):
+    def bytecode_trace(self, frame, decr_by=TICK_COUNTER_STEP):
         "Trace function called before each bytecode."
         # this is split into a fast path and a slower path that is
         # not invoked every time bytecode_trace() is.
         actionflag = self.space.actionflag
-        ticker = actionflag.get()
-        if actionflag.has_bytecode_counter:    # this "if" is constant-folded
-            ticker += 1
-            actionflag.set(ticker)
-        if ticker & actionflag.interesting_bits:  # fast check
+        if actionflag.decrement_ticker(decr_by) < 0:
             actionflag.action_dispatcher(self, frame)     # slow path
     bytecode_trace._always_inline_ = True
 
     def bytecode_trace_after_exception(self, frame):
         "Like bytecode_trace(), but without increasing the ticker."
         actionflag = self.space.actionflag
-        ticker = actionflag.get()
-        if ticker & actionflag.interesting_bits:  # fast check
+        if actionflag.get_ticker() < 0:
             actionflag.action_dispatcher(self, frame)     # slow path
     bytecode_trace_after_exception._always_inline_ = True
 
@@ -314,6 +311,13 @@
                 frame.last_exception = last_exception
                 self.is_tracing -= 1
 
+    def checksignals(self):
+        """Similar to PyErr_CheckSignals().  If called in the main thread,
+        and if signals are pending for the process, deliver them now
+        (i.e. call the signal handlers)."""
+        if self.space.check_signal_action is not None:
+            self.space.check_signal_action.perform(self, None)
+
     def _freeze_(self):
         raise Exception("ExecutionContext instances should not be seen during"
                         " translation.  Now is a good time to inspect the"
@@ -321,118 +325,95 @@
 
 
 class AbstractActionFlag(object):
-    """This holds the global 'action flag'.  It is a single bitfield
-    integer, with bits corresponding to AsyncAction objects that need to
-    be immediately triggered.  The correspondance from bits to
-    AsyncAction instances is built at translation time.  We can quickly
-    check if there is anything at all to do by checking if any of the
-    relevant bits is set.  If threads are enabled, they consume the 20
-    lower bits to hold a counter incremented at each bytecode, to know
-    when to release the GIL.
+    """This holds in an integer the 'ticker'.  If threads are enabled,
+    it is decremented at each bytecode; when it reaches zero, we release
+    the GIL.  And whether we have threads or not, it is forced to zero
+    whenever we fire any of the asynchronous actions.
     """
     def __init__(self):
         self._periodic_actions = []
         self._nonperiodic_actions = []
-        self.unused_bits = self.FREE_BITS[:]
         self.has_bytecode_counter = False
-        self.interesting_bits = 0
+        self.fired_actions = None
+        self.checkinterval_scaled = 100 * TICK_COUNTER_STEP
         self._rebuild_action_dispatcher()
 
     def fire(self, action):
-        """Request for the action to be run before the next opcode.
-        The action must have been registered at space initalization time."""
-        ticker = self.get()
-        self.set(ticker | action.bitmask)
-
-    def register_action(self, action):
-        "NOT_RPYTHON"
-        assert isinstance(action, AsyncAction)
-        if action.bitmask == 0:
-            while True:
-                action.bitmask = self.unused_bits.pop(0)
-                if not (action.bitmask & self.interesting_bits):
-                    break
-        self.interesting_bits |= action.bitmask
-        if action.bitmask & self.BYTECODE_COUNTER_OVERFLOW_BIT:
-            assert action.bitmask == self.BYTECODE_COUNTER_OVERFLOW_BIT
-            self._periodic_actions.append(action)
+        """Request for the action to be run before the next opcode."""
+        if not action._fired:
+            action._fired = True
+            if self.fired_actions is None:
+                self.fired_actions = []
+            self.fired_actions.append(action)
+            # set the ticker to -1 in order to force action_dispatcher()
+            # to run at the next possible bytecode
+            self.reset_ticker(-1)
+
+    def register_periodic_action(self, action, use_bytecode_counter):
+        """NOT_RPYTHON:
+        Register the PeriodicAsyncAction action to be called whenever the
+        tick counter becomes smaller than 0.  If 'use_bytecode_counter' is
+        True, make sure that we decrease the tick counter at every bytecode.
+        This is needed for threads.  Note that 'use_bytecode_counter' can be
+        False for signal handling, because whenever the process receives a
+        signal, the tick counter is set to -1 by C code in signals.h.
+        """
+        assert isinstance(action, PeriodicAsyncAction)
+        self._periodic_actions.append(action)
+        if use_bytecode_counter:
             self.has_bytecode_counter = True
-            self.force_tick_counter()
-        else:
-            self._nonperiodic_actions.append((action, action.bitmask))
         self._rebuild_action_dispatcher()
 
-    def setcheckinterval(self, space, interval):
-        if interval < self.CHECK_INTERVAL_MIN:
-            interval = self.CHECK_INTERVAL_MIN
-        elif interval > self.CHECK_INTERVAL_MAX:
-            interval = self.CHECK_INTERVAL_MAX
-        space.sys.checkinterval = interval
-        self.force_tick_counter()
-
-    def force_tick_counter(self):
-        # force the tick counter to a valid value -- this actually forces
-        # it to reach BYTECODE_COUNTER_OVERFLOW_BIT at the next opcode.
-        ticker = self.get()
-        ticker &= ~ self.BYTECODE_COUNTER_OVERFLOW_BIT
-        ticker |= self.BYTECODE_COUNTER_MASK
-        self.set(ticker)
+    def getcheckinterval(self):
+        return self.checkinterval_scaled // TICK_COUNTER_STEP
+
+    def setcheckinterval(self, interval):
+        MAX = sys.maxint // TICK_COUNTER_STEP
+        if interval < 1:
+            interval = 1
+        elif interval > MAX:
+            interval = MAX
+        self.checkinterval_scaled = interval * TICK_COUNTER_STEP
 
     def _rebuild_action_dispatcher(self):
         periodic_actions = unrolling_iterable(self._periodic_actions)
-        nonperiodic_actions = unrolling_iterable(self._nonperiodic_actions)
-        has_bytecode_counter = self.has_bytecode_counter
 
         @jit.dont_look_inside
         def action_dispatcher(ec, frame):
-            # periodic actions
-            if has_bytecode_counter:
-                ticker = self.get()
-                if ticker & self.BYTECODE_COUNTER_OVERFLOW_BIT:
-                    # We must run the periodic actions now, but first
-                    # reset the bytecode counter (the following line
-                    # works by assuming that we just overflowed the
-                    # counter, i.e. BYTECODE_COUNTER_OVERFLOW_BIT is
-                    # set but none of the BYTECODE_COUNTER_MASK bits
-                    # are).
-                    ticker -= ec.space.sys.checkinterval
-                    self.set(ticker)
-                    for action in periodic_actions:
-                        action.perform(ec, frame)
+            # periodic actions (first reset the bytecode counter)
+            self.reset_ticker(self.checkinterval_scaled)
+            for action in periodic_actions:
+                action.perform(ec, frame)
 
             # nonperiodic actions
-            for action, bitmask in nonperiodic_actions:
-                ticker = self.get()
-                if ticker & bitmask:
-                    self.set(ticker & ~ bitmask)
+            list = self.fired_actions
+            if list is not None:
+                self.fired_actions = None
+                for action in list:
+                    action._fired = False
                     action.perform(ec, frame)
 
         action_dispatcher._dont_inline_ = True
         self.action_dispatcher = action_dispatcher
 
-    # Bits reserved for the bytecode counter, if used
-    BYTECODE_COUNTER_MASK = (1 << 20) - 1
-    BYTECODE_COUNTER_OVERFLOW_BIT = (1 << 20)
-
-    # Free bits
-    FREE_BITS = [1 << _b for _b in range(21, LONG_BIT-1)]
-
-    # The acceptable range of values for sys.checkinterval, so that
-    # the bytecode_counter fits in 20 bits
-    CHECK_INTERVAL_MIN = 1
-    CHECK_INTERVAL_MAX = BYTECODE_COUNTER_OVERFLOW_BIT
-
 
 class ActionFlag(AbstractActionFlag):
     """The normal class for space.actionflag.  The signal module provides
     a different one."""
-    _flags = 0
+    _ticker = 0
+
+    def get_ticker(self):
+        return self._ticker
 
-    def get(self):
-        return self._flags
+    def reset_ticker(self, value):
+        self._ticker = value
 
-    def set(self, value):
-        self._flags = value
+    def decrement_ticker(self, by):
+        value = self._ticker
+        if self.has_bytecode_counter:    # this 'if' is constant-folded
+            value -= by
+            self._ticker = value
+        return value
 
 
 class AsyncAction(object):
@@ -440,7 +421,7 @@
     asynchronously with regular bytecode execution, but that still need
     to occur between two opcodes, not at a completely random time.
     """
-    bitmask = 0      # means 'please choose one bit automatically'
+    _fired = False
 
     def __init__(self, space):
         self.space = space
@@ -453,10 +434,11 @@
     def fire_after_thread_switch(self):
         """Bit of a hack: fire() the action but only the next time the GIL
         is released and re-acquired (i.e. after a potential thread switch).
-        Don't call this if threads are not enabled.
+        Don't call this if threads are not enabled.  Currently limited to
+        one action (i.e. reserved for CheckSignalAction from module/signal).
         """
         from pypy.module.thread.gil import spacestate
-        spacestate.set_actionflag_bit_after_thread_switch |= self.bitmask
+        spacestate.action_after_thread_switch = self
 
     def perform(self, executioncontext, frame):
         """To be overridden."""
@@ -466,7 +448,6 @@
     """Abstract base class for actions that occur automatically
     every sys.checkinterval bytecodes.
     """
-    bitmask = ActionFlag.BYTECODE_COUNTER_OVERFLOW_BIT
 
 
 class UserDelAction(AsyncAction):

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/pyopcode.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/pyopcode.py	Wed Nov 17 20:41:25 2010
@@ -1140,7 +1140,7 @@
     state_pack_variables = staticmethod(state_pack_variables)
 
 
-class FrameBlock:
+class FrameBlock(object):
 
     """Abstract base class for frame blocks from the blockstack,
     used by the SETUP_XXX and POP_BLOCK opcodes."""

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_argument.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_argument.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_argument.py	Wed Nov 17 20:41:25 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)

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_executioncontext.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_executioncontext.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_executioncontext.py	Wed Nov 17 20:41:25 2010
@@ -19,7 +19,6 @@
 
         space = self.space
         a1 = DemoAction(space)
-        space.actionflag.register_action(a1)
         for i in range(20):
             # assert does not raise:
             space.appexec([], """():
@@ -50,7 +49,7 @@
 
         space = self.space
         a2 = DemoAction(space)
-        space.actionflag.register_action(a2)
+        space.actionflag.register_periodic_action(a2, True)
         try:
             for i in range(500):
                 space.appexec([], """():
@@ -59,7 +58,8 @@
                 """)
         except Finished:
             pass
-        assert space.sys.checkinterval / 10 < i < space.sys.checkinterval * 3
+        checkinterval = space.actionflag.getcheckinterval()
+        assert checkinterval / 10 < i < checkinterval * 1.1
 
     def test_llprofile(self):
         l = []

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/detect_cpu.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/detect_cpu.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/detect_cpu.py	Wed Nov 17 20:41:25 2010
@@ -34,7 +34,17 @@
                 'x86_64': 'x86', 
                 }[mach]
     except KeyError:
-        raise ProcessorAutodetectError, "unsupported processor '%s'" % mach
+        return mach
+
+def autodetect_main_model_and_size():
+    model = autodetect_main_model()
+    if sys.maxint == 2**31-1:
+        model += '_32'
+    elif sys.maxint == 2**63-1:
+        model += '_64'
+    else:
+        raise AssertionError, "bad value for sys.maxint"
+    return model
 
 def autodetect():
     model = autodetect_main_model()

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/llgraph/llimpl.py	Wed Nov 17 20:41:25 2010
@@ -152,7 +152,7 @@
     'unicodegetitem'  : (('ref', 'int'), 'int'),
     'unicodesetitem'  : (('ref', 'int', 'int'), 'int'),
     'cast_ptr_to_int' : (('ref',), 'int'),
-    'debug_merge_point': (('ref',), None),
+    'debug_merge_point': (('ref', 'int'), None),
     'force_token'     : ((), 'int'),
     'call_may_force'  : (('int', 'varargs'), 'intorptr'),
     'guard_not_forced': ((), None),
@@ -568,7 +568,7 @@
         #
         return _op_default_implementation
 
-    def op_debug_merge_point(self, _, value):
+    def op_debug_merge_point(self, _, value, recdepth):
         from pypy.jit.metainterp.warmspot import get_stats
         loc = ConstPtr(value)._get_str()
         get_stats().add_merge_point_location(loc)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/descr.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/descr.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/descr.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/backend/llsupport/gc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/gc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/gc.py	Wed Nov 17 20:41:25 2010
@@ -19,6 +19,7 @@
 # ____________________________________________________________
 
 class GcLLDescription(GcCache):
+    minimal_size_in_nursery = 0
     def __init__(self, gcdescr, translator=None, rtyper=None):
         GcCache.__init__(self, translator is not None, rtyper)
         self.gcdescr = gcdescr
@@ -386,6 +387,7 @@
         (self.array_basesize, _, self.array_length_ofs) = \
              symbolic.get_array_token(lltype.GcArray(lltype.Signed), True)
         self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
+        self.minimal_size_in_nursery=self.GCClass.JIT_minimal_size_in_nursery()
 
         # make a malloc function, with three arguments
         def malloc_basic(size, tid):
@@ -468,6 +470,7 @@
         def malloc_fixedsize_slowpath(size):
             if self.DEBUG:
                 random_usage_of_xmm_registers()
+            assert size >= self.minimal_size_in_nursery
             try:
                 gcref = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
                                             0, size, True, False, False)
@@ -570,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
@@ -587,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/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_descr.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_descr.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_descr.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_gc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_gc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_gc.py	Wed Nov 17 20:41:25 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
@@ -270,7 +272,7 @@
 
     def test_get_rid_of_debug_merge_point(self):
         operations = [
-            ResOperation(rop.DEBUG_MERGE_POINT, ['dummy'], None),
+            ResOperation(rop.DEBUG_MERGE_POINT, ['dummy', 2], None),
             ]
         gc_ll_descr = self.gc_ll_descr
         gc_ll_descr.rewrite_assembler(None, operations)
@@ -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/jit-unroll-loops/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/test/runner_test.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/assembler.py	Wed Nov 17 20:41:25 2010
@@ -303,6 +303,7 @@
                _x86_frame_depth
                _x86_param_depth
                _x86_arglocs
+               _x86_debug_checksum
         """
         if not we_are_translated():
             # Arguments should be unique
@@ -312,7 +313,7 @@
         funcname = self._find_debug_merge_point(operations)
         if log:
             self._register_counter()
-            operations = self._inject_debugging_code(operations)
+            operations = self._inject_debugging_code(looptoken, operations)
         
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
         arglocs = regalloc.prepare_loop(inputargs, operations, looptoken)
@@ -336,8 +337,9 @@
         self._assemble_bootstrap_direct_call(arglocs, curadr,
                                              frame_depth+param_depth)
         #
-        debug_print("Loop #", looptoken.number, "has address",
-                    looptoken._x86_loop_code, "to", self.mc.tell())
+        debug_print("Loop #%d has address %x to %x" % (looptoken.number,
+                                                       looptoken._x86_loop_code,
+                                                       self.mc.tell()))
         self.mc.end_function()
         self.write_pending_failure_recoveries()
         
@@ -350,7 +352,7 @@
         funcname = self._find_debug_merge_point(operations)
         if log:
             self._register_counter()
-            operations = self._inject_debugging_code(operations)
+            operations = self._inject_debugging_code(faildescr, operations)
 
         arglocs = self.rebuild_faillocs_from_descr(
             faildescr._x86_failure_recovery_bytecode)
@@ -358,7 +360,6 @@
             assert ([loc.assembler() for loc in arglocs] ==
                     [loc.assembler() for loc in faildescr._x86_debug_faillocs])
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
-        operations = self._inject_debugging_code(operations)
         fail_depths = faildescr._x86_current_depths
         regalloc.prepare_bridge(fail_depths, inputargs, arglocs,
                                 operations)
@@ -378,9 +379,8 @@
             faildescr._x86_bridge_param_depth = param_depth
         # patch the jump from original guard
         self.patch_jump_for_descr(faildescr, adr_bridge)
-        debug_print("Bridge out of guard",
-                    descr_number,
-                    "has address", adr_bridge, "to", self.mc.tell())
+        debug_print("Bridge out of guard %d has address %x to %x" %
+                    (descr_number, adr_bridge, self.mc.tell()))
         self.mc.end_function()
         self.write_pending_failure_recoveries()
 
@@ -433,9 +433,14 @@
 
         mc.done()
 
-    def _inject_debugging_code(self, operations):
+    @specialize.argtype(1)
+    def _inject_debugging_code(self, looptoken, operations):
         if self._debug:
             # before doing anything, let's increase a counter
+            s = 0
+            for op in operations:
+                s += op.getopnum()
+            looptoken._x86_debug_checksum = s
             c_adr = ConstInt(rffi.cast(lltype.Signed,
                                      self.loop_run_counters[-1][1]))
             box = BoxInt()
@@ -1768,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)
@@ -1782,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
@@ -1848,6 +1861,7 @@
 
     def malloc_cond_fixedsize(self, nursery_free_adr, nursery_top_adr,
                               size, tid):
+        size = max(size, self.cpu.gc_ll_descr.minimal_size_in_nursery)
         self.mc.ensure_bytes_available(256)
         self.mc.MOV(eax, heap(nursery_free_adr))
         self.mc.LEA_rm(edx.value, (eax.value, size))

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_runner.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_runner.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_runner.py	Wed Nov 17 20:41:25 2010
@@ -346,7 +346,7 @@
                 return self.val
 
         operations = [
-            ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("hello")], None),
+            ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("hello"), 0], None),
             ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1),
             ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2),
             ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1),
@@ -365,7 +365,7 @@
         bridge = [
             ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3),
             ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2),
-            ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("bye")], None),
+            ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("bye"), 0], None),
             ResOperation(rop.JUMP, [i1b], None, descr=looptoken),
         ]
         bridge[1].setfailargs([i1b])
@@ -497,7 +497,7 @@
     def test_debugger_on(self):
         loop = """
         [i0]
-        debug_merge_point('xyz')
+        debug_merge_point('xyz', 0)
         i1 = int_add(i0, 1)
         i2 = int_ge(i1, 10)
         guard_false(i2) []
@@ -515,3 +515,20 @@
         self.cpu.finish_once()
         lines = py.path.local(self.logfile + ".count").readlines()
         assert lines[0] == '0:10\n'  # '10      xyz\n'
+
+    def test_debugger_checksum(self):
+        loop = """
+        [i0]
+        debug_merge_point('xyz', 0)
+        i1 = int_add(i0, 1)
+        i2 = int_ge(i1, 10)
+        guard_false(i2) []
+        jump(i1)
+        """
+        ops = parse(loop)
+        self.cpu.assembler.set_debug(True)
+        self.cpu.compile_loop(ops.inputargs, ops.operations, ops.token)
+        self.cpu.set_future_value_int(0, 0)
+        self.cpu.execute_token(ops.token)
+        assert ops.token._x86_debug_checksum == sum([op.getopnum()
+                                                     for op in ops.operations])

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zrpy_gc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zrpy_gc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zrpy_gc.py	Wed Nov 17 20:41:25 2010
@@ -550,3 +550,29 @@
 
     def test_compile_framework_float(self):
         self.run('compile_framework_float')
+
+    def define_compile_framework_minimal_size_in_nursery(self):
+        S = lltype.GcStruct('S')    # no fields!
+        T = lltype.GcStruct('T', ('i', lltype.Signed))
+        @unroll_safe
+        def f42(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s):
+            lst1 = []
+            lst2 = []
+            i = 0
+            while i < 42:
+                s1 = lltype.malloc(S)
+                t1 = lltype.malloc(T)
+                t1.i = 10000 + i + n
+                lst1.append(s1)
+                lst2.append(t1)
+                i += 1
+            i = 0
+            while i < 42:
+                check(lst2[i].i == 10000 + i + n)
+                i += 1
+            n -= 1
+            return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s
+        return None, f42, None
+
+    def test_compile_framework_minimal_size_in_nursery(self):
+        self.run('compile_framework_minimal_size_in_nursery')

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_ztranslation.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_ztranslation.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_ztranslation.py	Wed Nov 17 20:41:25 2010
@@ -2,6 +2,7 @@
 from pypy.tool.udir import udir
 from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL, unroll_parameters
 from pypy.rlib.jit import PARAMETERS, dont_look_inside
+from pypy.rlib.jit import hint
 from pypy.jit.metainterp.jitprof import Profiler
 from pypy.jit.backend.detect_cpu import getcpuclass
 from pypy.jit.backend.test.support import CCompiledMixin
@@ -9,6 +10,7 @@
 from pypy.translator.translator import TranslationContext
 from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64
 from pypy.config.translationoption import DEFL_GC
+from pypy.rlib import rgc
 
 class TestTranslationX86(CCompiledMixin):
     CPUClass = getcpuclass()
@@ -82,12 +84,12 @@
                 argchain.arg(x)
                 res = func.call(argchain, rffi.DOUBLE)
                 i -= 1
-            return res
+            return int(res)
         #
         def main(i, j):
             return f(i, j) + libffi_stuff(i, j)
-        expected = f(40, -49)
-        res = self.meta_interp(f, [40, -49])
+        expected = main(40, -49)
+        res = self.meta_interp(main, [40, -49])
         assert res == expected
 
     def test_direct_assembler_call_translates(self):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/tool/viewcode.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/tool/viewcode.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/tool/viewcode.py	Wed Nov 17 20:41:25 2010
@@ -37,7 +37,7 @@
         'x86_64': 'x86-64',
         'i386': 'i386',
     }
-    objdump = ('objdump -M intel,%(backend)s -b binary -m i386 '
+    objdump = ('objdump -M %(backend)s -b binary -m i386 '
                '--adjust-vma=%(origin)d -D %(file)s')
     #
     f = open(tmpfile, 'wb')

Modified: pypy/branch/jit-unroll-loops/pypy/jit/codewriter/assembler.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/assembler.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/assembler.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/codewriter/call.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/call.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/call.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/codewriter/codewriter.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/codewriter.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/codewriter.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/codewriter/effectinfo.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/effectinfo.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/effectinfo.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/jtransform.py	Wed Nov 17 20:41:25 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
@@ -873,6 +873,8 @@
         elif oopspec_name == 'jit.assert_green':
             kind = getkind(args[0].concretetype)
             return SpaceOperation('%s_assert_green' % kind, args, None)
+        elif oopspec_name == 'jit.current_trace_length':
+            return SpaceOperation('current_trace_length', [], op.result)
         else:
             raise AssertionError("missing support for %r" % oopspec_name)
 
@@ -1082,7 +1084,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)
@@ -1093,7 +1096,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,
@@ -1107,7 +1110,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/jit-unroll-loops/pypy/jit/codewriter/test/test_jtransform.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_jtransform.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_jtransform.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/metainterp/blackhole.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/blackhole.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/blackhole.py	Wed Nov 17 20:41:25 2010
@@ -774,6 +774,10 @@
     def bhimpl_float_assert_green(x):
         pass
 
+    @arguments(returns="i")
+    def bhimpl_current_trace_length():
+        return -1
+
     # ----------
     # the main hints and recursive calls
 

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/compile.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/compile.py	Wed Nov 17 20:41:25 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
@@ -13,6 +14,7 @@
 from pypy.jit.metainterp import history
 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():
@@ -52,7 +54,6 @@
     """
     history = metainterp.history
     loop = create_empty_loop(metainterp)
-    loop.greenkey = greenkey
     loop.inputargs = history.inputargs
     for box in loop.inputargs:
         assert isinstance(box, Box)
@@ -66,7 +67,6 @@
     loop.operations[-1].setdescr(loop_token)     # patch the target of the JUMP
 
     loop.preamble = create_empty_loop(metainterp, 'Preamble ')
-    loop.preamble.greenkey = greenkey
     loop.preamble.inputargs = loop.inputargs
     loop.preamble.token = make_loop_token(len(loop.inputargs), jitdriver_sd)
 
@@ -214,8 +214,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;
@@ -224,7 +223,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
@@ -234,8 +233,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):
@@ -339,14 +337,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):
@@ -413,7 +411,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
@@ -480,9 +477,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
@@ -491,10 +487,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/jit-unroll-loops/pypy/jit/metainterp/logger.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/logger.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/logger.py	Wed Nov 17 20:41:25 2010
@@ -81,7 +81,8 @@
             op = operations[i]
             if op.getopnum() == rop.DEBUG_MERGE_POINT:
                 loc = op.getarg(0)._get_str()
-                debug_print("debug_merge_point('%s')" % (loc,))
+                reclev = op.getarg(1).getint()
+                debug_print("debug_merge_point('%s', %s)" % (loc, reclev))
                 continue
             args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())])
             if op.result is not None:

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/optimizer.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/optimizer.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/optimizer.py	Wed Nov 17 20:41:25 2010
@@ -86,10 +86,10 @@
         assert isinstance(constbox, Const)
         self.box = constbox
         self.level = LEVEL_CONSTANT
-        try:
-            val = self.box.getint()
+        if isinstance(constbox, ConstInt):
+            val = constbox.getint()
             self.intbound = IntBound(val, val)
-        except NotImplementedError:
+        else:
             self.intbound = IntUnbounded()
 
     def get_constant_class(self, cpu):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/string.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/string.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/string.py	Wed Nov 17 20:41:25 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
@@ -642,7 +642,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/jit-unroll-loops/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/pyjitpl.py	Wed Nov 17 20:41:25 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
@@ -820,7 +820,8 @@
         jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
         self.verify_green_args(jitdriver_sd, greenboxes)
         # xxx we may disable the following line in some context later
-        self.debug_merge_point(jitdriver_sd, greenboxes)
+        self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion,
+                               greenboxes)
         if self.metainterp.seen_loop_header_for_jdindex < 0:
             if not jitdriver_sd.no_loop_header or not any_operation:
                 return
@@ -860,13 +861,13 @@
                                     assembler_call=True)
             raise ChangeFrame
 
-    def debug_merge_point(self, jitdriver_sd, greenkey):
+    def debug_merge_point(self, jitdriver_sd, in_recursion, greenkey):
         # debugging: produce a DEBUG_MERGE_POINT operation
         loc = jitdriver_sd.warmstate.get_location_str(greenkey)
         debug_print(loc)
         constloc = self.metainterp.cpu.ts.conststr(loc)
         self.metainterp.history.record(rop.DEBUG_MERGE_POINT,
-                                       [constloc], None)
+                                       [constloc, ConstInt(in_recursion)], None)
 
     @arguments("box", "label")
     def opimpl_goto_if_exception_mismatch(self, vtablebox, next_exc_target):
@@ -948,6 +949,11 @@
     opimpl_ref_assert_green   = _opimpl_assert_green
     opimpl_float_assert_green = _opimpl_assert_green
 
+    @arguments()
+    def opimpl_current_trace_length(self):
+        trace_length = len(self.metainterp.history.operations)
+        return ConstInt(trace_length)
+
     @arguments("box")
     def opimpl_virtual_ref(self, box):
         # Details on the content of metainterp.virtualref_boxes:
@@ -1042,14 +1048,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
@@ -1255,6 +1258,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
@@ -1618,7 +1622,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()
@@ -1629,9 +1633,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()
@@ -1653,11 +1656,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:
@@ -1721,7 +1720,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]
@@ -1730,10 +1729,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!

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/resoperation.py	Wed Nov 17 20:41:25 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,19 +466,18 @@
     '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/1',      # debugging only
+    'DEBUG_MERGE_POINT/2',      # debugging only
     'JIT_DEBUG/*',              # debugging only
     'VIRTUAL_REF_FINISH/2',   # removed before it's passed to the backend
     'COPYSTRCONTENT/5',       # src, dst, srcstart, dststart, length
     '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/jit-unroll-loops/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/resume.py	Wed Nov 17 20:41:25 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
         snapshot = storage.rd_snapshot
         assert snapshot is not None # is that true?
         numb, liveboxes_from_env, v = self.memo.number(values, snapshot)
@@ -724,34 +732,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):
@@ -775,14 +785,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)
@@ -801,14 +813,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)
@@ -904,8 +918,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
@@ -940,7 +954,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)
@@ -954,8 +968,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:
@@ -974,23 +989,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()
@@ -1002,7 +1018,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
@@ -1019,12 +1035,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
@@ -1048,7 +1064,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)
 
@@ -1057,7 +1074,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)
 
@@ -1073,7 +1091,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)
 
@@ -1082,7 +1101,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)
 
@@ -1173,8 +1193,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/jit-unroll-loops/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_basic.py	Wed Nov 17 20:41:25 2010
@@ -3,6 +3,7 @@
 from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside
 from pypy.rlib.jit import OPTIMIZER_FULL, OPTIMIZER_SIMPLE, loop_invariant
 from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed
+from pypy.rlib.jit import unroll_safe, current_trace_length
 from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
 from pypy.jit.backend.llgraph import runner
 from pypy.jit.metainterp import pyjitpl, history
@@ -1837,6 +1838,31 @@
                           'int_add': 1, 'int_mul': 1, 'int_sub': 2,
                           'int_gt': 2, 'jump': 2})
 
+    def test_current_trace_length(self):
+        myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
+        @dont_look_inside
+        def residual():
+            print "hi there"
+        @unroll_safe
+        def loop(g):
+            y = 0
+            while y < g:
+                residual()
+                y += 1
+        def f(x, g):
+            n = 0
+            while x > 0:
+                myjitdriver.can_enter_jit(x=x, g=g)
+                myjitdriver.jit_merge_point(x=x, g=g)
+                loop(g)
+                x -= 1
+                n = current_trace_length()
+            return n
+        res = self.meta_interp(f, [5, 8])
+        assert 14 < res < 42
+        res = self.meta_interp(f, [5, 2])
+        assert 4 < res < 14
+
 
 class TestOOtype(BasicTests, OOJitMixin):
 

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_compile.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_compile.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_compile.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/metainterp/test/test_del.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_del.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_del.py	Wed Nov 17 20:41:25 2010
@@ -85,6 +85,7 @@
     def test_signal_action(self):
         from pypy.module.signal.interp_signal import SignalActionFlag
         action = SignalActionFlag()
+        action.has_bytecode_counter = True
         #
         myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
         class X:
@@ -92,17 +93,17 @@
         #
         def f(n):
             x = X()
-            while n > 0:
+            action.reset_ticker(n)
+            while True:
                 myjitdriver.can_enter_jit(n=n, x=x)
                 myjitdriver.jit_merge_point(n=n, x=x)
                 x.foo = n
                 n -= 1
-                if action.get() != 0:
+                if action.decrement_ticker(1) < 0:
                     break
-                action.set(0)
             return 42
         self.meta_interp(f, [20])
-        self.check_loops(getfield_raw=1, call=0, call_pure=0)
+        self.check_loops(getfield_raw=1, setfield_raw=1, call=0, call_pure=0)
 
 class TestOOtype(DelTests, OOJitMixin):
     def setup_class(cls):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_logger.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_logger.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_logger.py	Wed Nov 17 20:41:25 2010
@@ -97,7 +97,7 @@
     def test_debug_merge_point(self):
         inp = '''
         []
-        debug_merge_point("info")
+        debug_merge_point("info", 0)
         '''
         loop, oloop = self.reparse(inp, check_equal=False)
         assert loop.operations[0].getarg(0)._get_str() == 'info'

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizeopt.py	Wed Nov 17 20:41:25 2010
@@ -26,6 +26,100 @@
         self.options = Fake()
         self.globaldata = Fake()
 
+def test_store_final_boxes_in_guard():
+    from pypy.jit.metainterp.compile import ResumeGuardDescr
+    from pypy.jit.metainterp.resume import tag, TAGBOX
+    b0 = BoxInt()
+    b1 = BoxInt()
+    opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu),
+                                None)
+    fdescr = ResumeGuardDescr(None)
+    op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr)
+    # setup rd data
+    fi0 = resume.FrameInfo(None, "code0", 11)
+    fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33)
+    snapshot0 = resume.Snapshot(None, [b0])
+    fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1])
+    #
+    opt.store_final_boxes_in_guard(op)
+    if op.getfailargs() == [b0, b1]:
+        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 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 == []
+
+def test_sharing_field_lists_of_virtual():
+    class FakeOptimizer(object):
+        class cpu(object):
+            pass
+    opt = FakeOptimizer()
+    virt1 = virtualize.AbstractVirtualStructValue(opt, None)
+    lst1 = virt1._get_field_descr_list()
+    assert lst1 == []
+    lst2 = virt1._get_field_descr_list()
+    assert lst1 is lst2
+    virt1.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None))
+    lst3 = virt1._get_field_descr_list()
+    assert lst3 == [LLtypeMixin.valuedescr]
+    lst4 = virt1._get_field_descr_list()
+    assert lst3 is lst4
+
+    virt2 = virtualize.AbstractVirtualStructValue(opt, None)
+    lst5 = virt2._get_field_descr_list()
+    assert lst5 is lst1
+    virt2.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None))
+    lst6 = virt1._get_field_descr_list()
+    assert lst6 is lst3
+
+def test_reuse_vinfo():
+    class FakeVInfo(object):
+        def set_content(self, fieldnums):
+            self.fieldnums = fieldnums
+        def equals(self, fieldnums):
+            return self.fieldnums == fieldnums
+    class FakeVirtualValue(virtualize.AbstractVirtualValue):
+        def _make_virtual(self, *args):
+            return FakeVInfo()
+    v1 = FakeVirtualValue(None, None, None)
+    vinfo1 = v1.make_virtual_info(None, [1, 2, 4])
+    vinfo2 = v1.make_virtual_info(None, [1, 2, 4])
+    assert vinfo1 is vinfo2
+    vinfo3 = v1.make_virtual_info(None, [1, 2, 6])
+    assert vinfo3 is not vinfo2
+    vinfo4 = v1.make_virtual_info(None, [1, 2, 6])
+    assert vinfo3 is vinfo4
+
+def test_descrlist_dict():
+    from pypy.jit.metainterp import optimizeutil
+    h1 = optimizeutil.descrlist_hash([])
+    h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr])
+    h3 = optimizeutil.descrlist_hash(
+            [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+    assert h1 != h2
+    assert h2 != h3
+    assert optimizeutil.descrlist_eq([], [])
+    assert not optimizeutil.descrlist_eq([], [LLtypeMixin.valuedescr])
+    assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr],
+                                     [LLtypeMixin.valuedescr])
+    assert not optimizeutil.descrlist_eq([LLtypeMixin.valuedescr],
+                                         [LLtypeMixin.nextdescr])
+    assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr, LLtypeMixin.nextdescr],
+                                     [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+    assert not optimizeutil.descrlist_eq([LLtypeMixin.nextdescr, LLtypeMixin.valuedescr],
+                                         [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+
+    # descrlist_eq should compare by identity of the descrs, not by the result
+    # of sort_key
+    class FakeDescr(object):
+        def sort_key(self):
+            return 1
+
+    assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()])
+
 # ____________________________________________________________
 class Storage(compile.ResumeGuardDescr):
     "for tests."
@@ -76,6 +170,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)
         #
 
@@ -1430,7 +1526,7 @@
         ops = """
         [p1]
         i1 = getfield_gc(p1, descr=valuedescr)
-        debug_merge_point(15)
+        debug_merge_point(15, 0)
         i2 = getfield_gc(p1, descr=valuedescr)
         escape(i1)
         escape(i2)
@@ -1439,7 +1535,7 @@
         expected = """
         [p1]
         i1 = getfield_gc(p1, descr=valuedescr)
-        debug_merge_point(15)
+        debug_merge_point(15, 0)
         escape(i1)
         escape(i1)
         jump(p1)
@@ -4288,22 +4384,20 @@
     # ----------
     def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None):
         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, optops, preamble)
-        finally:
-            string.callinfo_for_oopspec = saved
+        self.callinfocollection = FakeCallInfoCollection()
+        self.optimize_strunicode_loop(ops, optops, preamble)
 
     def test_str_equal_noop1(self):
         ops = """

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_resoperation.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_resoperation.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_resoperation.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_resume.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_resume.py	Wed Nov 17 20:41:25 2010
@@ -52,6 +52,7 @@
 
 class MyMetaInterp:
     _already_allocated_resume_virtuals = None
+    callinfocollection = None
 
     def __init__(self, cpu=None):
         if cpu is None:
@@ -142,6 +143,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)]
@@ -157,12 +165,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,
@@ -194,7 +202,7 @@
     storage.rd_numb = numb
     #
     cpu = MyCPU([])
-    reader = ResumeDataDirectReader(cpu, storage)
+    reader = ResumeDataDirectReader(MyMetaInterp(cpu), storage)
     _next_section(reader, 100)
 
 
@@ -212,7 +220,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]
 
 # ____________________________________________________________
@@ -391,15 +399,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()]
@@ -765,11 +773,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
@@ -777,9 +786,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)
@@ -800,9 +809,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]
@@ -813,9 +822,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)    
@@ -826,9 +835,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())
@@ -926,7 +935,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/jit-unroll-loops/pypy/jit/metainterp/test/test_virtualref.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_virtualref.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_virtualref.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/metainterp/test/test_ztranslation.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_ztranslation.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_ztranslation.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/metainterp/virtualizable.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/virtualizable.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/virtualizable.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/warmspot.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/tool/oparser.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tool/oparser.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tool/oparser.py	Wed Nov 17 20:41:25 2010
@@ -192,7 +192,7 @@
         descr = None
         if argspec.strip():
             if opname == 'debug_merge_point':
-                allargs = [argspec]
+                allargs = argspec.rsplit(', ', 1)
             else:
                 allargs = [arg for arg in argspec.split(",")
                            if arg != '']

Modified: pypy/branch/jit-unroll-loops/pypy/jit/tool/pypytrace-mode.el
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tool/pypytrace-mode.el	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tool/pypytrace-mode.el	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/jit/tool/pypytrace.vim
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tool/pypytrace.vim	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tool/pypytrace.vim	Wed Nov 17 20:41:25 2010
@@ -21,10 +21,10 @@
 
 hi def link pypyLoopStart   Structure
 "hi def link pypyLoopArgs    PreProc
-hi def link pypyFailArgs    String
+hi def link pypyFailArgs    Special
 "hi def link pypyOpName      Statement
-hi def link pypyDebugMergePoint  Comment
+hi def link pypyDebugMergePoint  String
 hi def link pypyConstPtr    Constant
 hi def link pypyNumber      Number
-hi def link pypyDescr       String
+hi def link pypyDescr       PreProc
 hi def link pypyDescrField  Label

Modified: pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_traceviewer.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_traceviewer.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_traceviewer.py	Wed Nov 17 20:41:25 2010
@@ -19,7 +19,7 @@
     def test_no_of_loops(self):
         data = [preparse("""
         # Loop 0 : loop with 39 ops
-        debug_merge_point('')
+        debug_merge_point('', 0)
         guard_class(p4, 141310752, descr=<Guard5>) [p0, p1]
         p60 = getfield_gc(p4, descr=<GcPtrFieldDescr 16>)
         guard_nonnull(p60, descr=<Guard6>) [p0, p1]
@@ -51,7 +51,7 @@
         assert loop.right.content == 'extra'
 
     def test_postparse(self):
-        real_loops = [FinalBlock("debug_merge_point('<code object _runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357> #40 POP_TOP')", None)]
+        real_loops = [FinalBlock("debug_merge_point('<code object _runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357> #40 POP_TOP', 0)", None)]
         postprocess(real_loops, real_loops[:], {})
         assert real_loops[0].header.startswith("_runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357")
 

Modified: pypy/branch/jit-unroll-loops/pypy/module/__builtin__/descriptor.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/__builtin__/descriptor.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/__builtin__/descriptor.py	Wed Nov 17 20:41:25 2010
@@ -96,6 +96,8 @@
 )
 
 class W_Property(Wrappable):
+    _immutable_fields_ = ["w_fget", "w_fset", "w_fdel"]
+
     def init(self, space, w_fget=None, w_fset=None, w_fdel=None, w_doc=None):
         self.w_fget = w_fget
         self.w_fset = w_fset
@@ -183,4 +185,3 @@
     fget = interp_attrproperty_w('w_fget', W_Property),
     fset = interp_attrproperty_w('w_fset', W_Property),
 )
-

Modified: pypy/branch/jit-unroll-loops/pypy/module/__pypy__/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/__pypy__/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/__pypy__/__init__.py	Wed Nov 17 20:41:25 2010
@@ -23,5 +23,12 @@
                                  '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)
+        #
+        from pypy.jit.backend import detect_cpu
+        model = detect_cpu.autodetect_main_model_and_size()
+        self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model)

Modified: pypy/branch/jit-unroll-loops/pypy/module/__pypy__/interp_magic.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/__pypy__/interp_magic.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/__pypy__/interp_magic.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/__pypy__/test/test_special.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/__pypy__/test/test_special.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/__pypy__/test/test_special.py	Wed Nov 17 20:41:25 2010
@@ -17,3 +17,7 @@
         from __pypy__ import isfake
         import select
         assert isfake(select)
+
+    def test_cpumodel(self):
+        import __pypy__
+        assert hasattr(__pypy__, 'cpumodel')

Modified: pypy/branch/jit-unroll-loops/pypy/module/_rawffi/test/test__rawffi.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/_rawffi/test/test__rawffi.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/_rawffi/test/test__rawffi.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/_rawffi/test/test_nested.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/_rawffi/test/test_nested.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/_rawffi/test/test_nested.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/array/interp_array.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/array/interp_array.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/array/interp_array.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/api.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/cpyext/cdatetime.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/cdatetime.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/cdatetime.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/cpyext/presetup.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/presetup.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/presetup.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/pyobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/pyobject.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/cpyext/test/test_borrow.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_borrow.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_borrow.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_cpyext.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_cpyext.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/typeobject.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/gc/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/gc/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/gc/__init__.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/gc/app_referents.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/gc/app_referents.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/gc/app_referents.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/gc/interp_gc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/gc/interp_gc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/gc/interp_gc.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/gc/referents.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/gc/referents.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/gc/referents.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/gc/test/test_gc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/gc/test/test_gc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/gc/test/test_gc.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/imp/importing.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/imp/importing.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/imp/importing.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/imp/interp_imp.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/imp/interp_imp.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/imp/interp_imp.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/imp/test/test_app.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/imp/test/test_app.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/imp/test/test_app.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/imp/test/test_import.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/imp/test/test_import.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/imp/test/test_import.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/posix/interp_posix.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/posix/interp_posix.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/posix/interp_posix.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/pypyjit/interp_jit.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/pypyjit/interp_jit.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/pypyjit/interp_jit.py	Wed Nov 17 20:41:25 2010
@@ -6,6 +6,7 @@
 from pypy.tool.pairtype import extendabletype
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
+from pypy.rlib.jit import current_trace_length
 import pypy.interpreter.pyopcode   # for side-effects
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import ObjSpace, Arguments, W_Root
@@ -80,9 +81,22 @@
 
     def jump_absolute(self, jumpto, _, ec=None):
         if we_are_jitted():
+            # Normally, the tick counter is decremented by 100 for every
+            # Python opcode.  Here, to better support JIT compilation of
+            # small loops, we decrement it by a possibly smaller constant.
+            # We get the maximum 100 when the (unoptimized) trace length
+            # is at least 3200 (a bit randomly).
+            trace_length = r_uint(current_trace_length())
+            decr_by = trace_length // 32
+            if decr_by < 1:
+                decr_by = 1
+            elif decr_by > 100:    # also if current_trace_length() returned -1
+                decr_by = 100
+            #
             self.last_instr = intmask(jumpto)
-            ec.bytecode_trace(self)
+            ec.bytecode_trace(self, intmask(decr_by))
             jumpto = r_uint(self.last_instr)
+        #
         pypyjitdriver.can_enter_jit(frame=self, ec=ec, next_instr=jumpto,
                                     pycode=self.getcode())
         return jumpto

Modified: pypy/branch/jit-unroll-loops/pypy/module/pypyjit/policy.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/pypyjit/policy.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/pypyjit/policy.py	Wed Nov 17 20:41:25 2010
@@ -6,7 +6,8 @@
         if (modname == '__builtin__.operation' or
                 modname == '__builtin__.abstractinst' or
                 modname == '__builtin__.interp_classobj' or
-                modname == '__builtin__.functional'):
+                modname == '__builtin__.functional' or
+                modname == '__builtin__.descriptor'):
             return True
         if '.' in modname:
             modname, _ = modname.split('.', 1)
@@ -19,7 +20,7 @@
         # this function should never actually return True directly
         # but instead call the base implementation
         mod = func.__module__ or '?'
-        
+
         if mod.startswith('pypy.objspace.'):
             # gc_id operation
             if func.__name__ == 'id__ANY':
@@ -36,5 +37,5 @@
             modname = mod[len('pypy.module.'):]
             if not self.look_inside_pypy_module(modname):
                 return False
-            
+
         return True

Modified: pypy/branch/jit-unroll-loops/pypy/module/pypyjit/test/test_policy.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/pypyjit/test/test_policy.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/pypyjit/test/test_policy.py	Wed Nov 17 20:41:25 2010
@@ -12,7 +12,7 @@
 
 def test_rlocale():
     from pypy.rlib.rlocale import setlocale
-    assert not pypypolicy.look_inside_function(setlocale)    
+    assert not pypypolicy.look_inside_function(setlocale)
 
 def test_geninterp():
     d = {'_geninterp_': True}
@@ -28,6 +28,10 @@
     from pypy.interpreter.pyparser import parser
     assert not pypypolicy.look_inside_function(parser.Grammar.__init__.im_func)
 
+def test_property():
+    from pypy.module.__builtin__.descriptor import W_Property
+    assert pypypolicy.look_inside_function(W_Property.get.im_func)
+
 def test_pypy_module():
     from pypy.module._random.interp_random import W_Random
     assert not pypypolicy.look_inside_function(W_Random.random)
@@ -35,6 +39,7 @@
     assert pypypolicy.look_inside_pypy_module('__builtin__.operation')
     assert pypypolicy.look_inside_pypy_module('__builtin__.abstractinst')
     assert pypypolicy.look_inside_pypy_module('__builtin__.functional')
+    assert pypypolicy.look_inside_pypy_module('__builtin__.descriptor')
     assert pypypolicy.look_inside_pypy_module('exceptions.interp_exceptions')
     for modname in 'pypyjit', 'signal', 'micronumpy', 'math', 'imp':
         assert pypypolicy.look_inside_pypy_module(modname)
@@ -42,4 +47,3 @@
 
 def test_see_jit_module():
     assert pypypolicy.look_inside_pypy_module('pypyjit.interp_jit')
-

Modified: pypy/branch/jit-unroll-loops/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/pypyjit/test/test_pypy_c.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/pypyjit/test/test_pypy_c.py	Wed Nov 17 20:41:25 2010
@@ -422,10 +422,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/jit-unroll-loops/pypy/module/rctime/interp_time.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/rctime/interp_time.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/rctime/interp_time.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/module/signal/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/signal/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/signal/__init__.py	Wed Nov 17 20:41:25 2010
@@ -34,9 +34,7 @@
         MixedModule.__init__(self, space, *args)
         # add the signal-checking callback as an action on the space
         space.check_signal_action = interp_signal.CheckSignalAction(space)
-        space.actionflag.register_action(space.check_signal_action)
-        # use the C-level pypysig_occurred variable as the action flag
-        # (the result is that the C-level signal handler will directly
-        # set the flag for the CheckSignalAction)
+        space.actionflag.register_periodic_action(space.check_signal_action,
+                                                  use_bytecode_counter=False)
         space.actionflag.__class__ = interp_signal.SignalActionFlag
         # xxx yes I know the previous line is a hack

Modified: pypy/branch/jit-unroll-loops/pypy/module/signal/interp_signal.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/signal/interp_signal.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/signal/interp_signal.py	Wed Nov 17 20:41:25 2010
@@ -1,6 +1,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.baseobjspace import W_Root, ObjSpace
 from pypy.interpreter.executioncontext import AsyncAction, AbstractActionFlag
+from pypy.interpreter.executioncontext import PeriodicAsyncAction
 import signal as cpy_signal
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -52,19 +53,29 @@
 
 
 class SignalActionFlag(AbstractActionFlag):
-    def get(self):
+    # This class uses the C-level pypysig_counter variable as the tick
+    # counter.  The C-level signal handler will reset it to -1 whenever
+    # a signal is received.
+
+    def get_ticker(self):
         p = pypysig_getaddr_occurred()
         return p.c_value
-    def set(self, value):
+
+    def reset_ticker(self, value):
         p = pypysig_getaddr_occurred()
         p.c_value = value
 
+    def decrement_ticker(self, by):
+        p = pypysig_getaddr_occurred()
+        value = p.c_value
+        if self.has_bytecode_counter:    # this 'if' is constant-folded
+            value -= by
+            p.c_value = value
+        return value
 
-class CheckSignalAction(AsyncAction):
-    """An action that is automatically invoked when a signal is received."""
 
-    # The C-level signal handler sets the bit 30 of pypysig_occurred:
-    bitmask = 1 << 30
+class CheckSignalAction(PeriodicAsyncAction):
+    """An action that is automatically invoked when a signal is received."""
 
     def __init__(self, space):
         AsyncAction.__init__(self, space)
@@ -73,7 +84,6 @@
             # need a helper action in case signals arrive in a non-main thread
             self.pending_signals = {}
             self.reissue_signal_action = ReissueSignalAction(space)
-            space.actionflag.register_action(self.reissue_signal_action)
         else:
             self.reissue_signal_action = None
 

Modified: pypy/branch/jit-unroll-loops/pypy/module/signal/test/test_signal.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/signal/test/test_signal.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/signal/test/test_signal.py	Wed Nov 17 20:41:25 2010
@@ -1,6 +1,38 @@
 import os, py
+import signal as cpy_signal
 from pypy.conftest import gettestobjspace
 
+
+class TestCheckSignals:
+
+    def setup_class(cls):
+        if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
+            py.test.skip("requires os.kill() and os.getpid()")
+        cls.space = gettestobjspace(usemodules=['signal'])
+
+    def test_checksignals(self):
+        space = self.space
+        w_received = space.appexec([], """():
+            import signal
+            received = []
+            def myhandler(signum, frame):
+                received.append(signum)
+            signal.signal(signal.SIGUSR1, myhandler)
+            return received""")
+        #
+        assert not space.is_true(w_received)
+        #
+        # send the signal now
+        os.kill(os.getpid(), cpy_signal.SIGUSR1)
+        #
+        # myhandler() should not be immediately called
+        assert not space.is_true(w_received)
+        #
+        # calling ec.checksignals() should call it
+        space.getexecutioncontext().checksignals()
+        assert space.is_true(w_received)
+
+
 class AppTestSignal:
 
     def setup_class(cls):
@@ -24,18 +56,12 @@
         signal.signal(signal.SIGUSR1, myhandler)
 
         posix.kill(posix.getpid(), signal.SIGUSR1)
-        for i in range(10000):
-             # wait a bit for the signal to be delivered to the handler
-            if received:
-                break
+        # the signal should be delivered to the handler immediately
         assert received == [signal.SIGUSR1]
         del received[:]
 
         posix.kill(posix.getpid(), signal.SIGUSR1)
-        for i in range(10000):
-             # wait a bit for the signal to be delivered to the handler
-            if received:
-                break
+        # the signal should be delivered to the handler immediately
         assert received == [signal.SIGUSR1]
         del received[:]
 

Modified: pypy/branch/jit-unroll-loops/pypy/module/sys/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/sys/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/sys/__init__.py	Wed Nov 17 20:41:25 2010
@@ -10,7 +10,6 @@
         if space.config.translating:
             del self.__class__.interpleveldefs['pypy_getudir']
         super(Module, self).__init__(space, w_name) 
-        self.checkinterval = 100
         self.recursionlimit = 100
         self.w_default_encoder = None
         self.defaultencoding = "ascii"

Modified: pypy/branch/jit-unroll-loops/pypy/module/sys/version.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/sys/version.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/sys/version.py	Wed Nov 17 20:41:25 2010
@@ -8,7 +8,7 @@
 CPYTHON_VERSION            = (2, 5, 2, "beta", 42)   #XXX # sync patchlevel.h
 CPYTHON_API_VERSION        = 1012   #XXX # sync with include/modsupport.h
 
-PYPY_VERSION               = (1, 3, 0, "beta", '?')  #XXX # sync patchlevel.h
+PYPY_VERSION               = (1, 4, 0, "beta", '?')  #XXX # sync patchlevel.h
 # the last item is replaced by the svn revision ^^^
 
 TRIM_URL_UP_TO = 'svn/pypy/'

Modified: pypy/branch/jit-unroll-loops/pypy/module/sys/vm.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/sys/vm.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/sys/vm.py	Wed Nov 17 20:41:25 2010
@@ -67,7 +67,7 @@
 def setcheckinterval(space, interval):
     """Tell the Python interpreter to check for asynchronous events every
     n instructions.  This also affects how often thread switches occur."""
-    space.actionflag.setcheckinterval(space, interval)
+    space.actionflag.setcheckinterval(interval)
 setcheckinterval.unwrap_spec = [ObjSpace, int]
 
 def getcheckinterval(space):
@@ -77,7 +77,7 @@
     # return 0.  The idea is that according to the CPython docs, <= 0
     # means "check every virtual instruction, maximizing responsiveness
     # as well as overhead".
-    result = space.sys.checkinterval
+    result = space.actionflag.getcheckinterval()
     if result <= 1:
         result = 0
     return space.wrap(result)

Modified: pypy/branch/jit-unroll-loops/pypy/module/thread/gil.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/thread/gil.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/thread/gil.py	Wed Nov 17 20:41:25 2010
@@ -20,7 +20,8 @@
 
     def initialize(self, space):
         # add the GIL-releasing callback as an action on the space
-        space.actionflag.register_action(GILReleaseAction(space))
+        space.actionflag.register_periodic_action(GILReleaseAction(space),
+                                                  use_bytecode_counter=True)
 
     def setup_threads(self, space):
         """Enable threads in the object space, if they haven't already been."""
@@ -44,7 +45,6 @@
         # test_compile_lock.  As a workaround, we repatch these global
         # fields systematically.
         spacestate.ll_GIL = self.ll_GIL
-        spacestate.actionflag = space.actionflag
         invoke_around_extcall(before_external_call, after_external_call)
         return result
 
@@ -68,18 +68,17 @@
 
     def _freeze_(self):
         self.ll_GIL = thread.null_ll_lock
-        self.actionflag = None
-        self.set_actionflag_bit_after_thread_switch = 0
+        self.action_after_thread_switch = None
+        # ^^^ set by AsyncAction.fire_after_thread_switch()
         return False
 
     def after_thread_switch(self):
         # this is support logic for the signal module, to help it deliver
         # signals to the main thread.
-        actionflag = self.actionflag
-        if actionflag is not None:
-            flag = actionflag.get()
-            flag |= self.set_actionflag_bit_after_thread_switch
-            actionflag.set(flag)
+        action = self.action_after_thread_switch
+        if action is not None:
+            self.action_after_thread_switch = None
+            action.fire()
 
 spacestate = SpaceState()
 spacestate._freeze_()

Modified: pypy/branch/jit-unroll-loops/pypy/module/thread/test/test_gil.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/thread/test/test_gil.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/thread/test/test_gil.py	Wed Nov 17 20:41:25 2010
@@ -8,7 +8,7 @@
     pass
 
 class FakeActionFlag(object):
-    def register_action(self, action):
+    def register_periodic_action(self, action, use_bytecode_counter):
         pass
     def get(self):
         return 0

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/flow/model.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/flow/model.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/flow/model.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/objspace/flow/objspace.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/flow/objspace.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/flow/objspace.py	Wed Nov 17 20:41:25 2010
@@ -210,6 +210,11 @@
             check_class = self.unwrap(w_check_class)
         except UnwrapException:
             raise Exception, "non-constant except guard"
+        if check_class in (NotImplementedError, AssertionError):
+            # if we are in geninterp, we cannot catch these exceptions
+            if not self.config.translation.builtins_can_raise_exceptions:
+                raise error.FlowingError("Catching %s is not valid in RPython" %
+                                         check_class.__name__)
         if not isinstance(check_class, tuple):
             # the simple case
             return ObjSpace.exception_match(self, w_exc_type, w_check_class)

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/flow/test/test_objspace.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/flow/test/test_objspace.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/flow/test/test_objspace.py	Wed Nov 17 20:41:25 2010
@@ -5,7 +5,7 @@
 from pypy.objspace.flow.model import flatten, mkentrymap, c_last_exception
 from pypy.interpreter.argument import Arguments
 from pypy.translator.simplify import simplify_graph
-from pypy.objspace.flow.objspace import FlowObjSpace 
+from pypy.objspace.flow.objspace import FlowObjSpace, error
 from pypy.objspace.flow import objspace, flowcontext
 from pypy import conftest
 from pypy.tool.stdlib_opcode import bytecode_spec
@@ -953,6 +953,22 @@
                 assert op.args[0] == Constant(g)
 
 
+    def test_cannot_catch_special_exceptions(self):
+        def f():
+            try:
+                f()
+            except NotImplementedError:
+                pass
+        py.test.raises(error.FlowingError, "self.codetest(f)")
+        #
+        def f():
+            try:
+                f()
+            except AssertionError:
+                pass
+        py.test.raises(error.FlowingError, "self.codetest(f)")
+
+
 class TestFlowObjSpaceDelay(Base):
     def setup_class(cls):
         cls.space = FlowObjSpace()
@@ -1013,6 +1029,15 @@
         expected.sort()
         assert excfound == expected
 
+    def test_can_catch_special_exceptions(self):
+        def f():
+            try:
+                f()
+            except NotImplementedError:
+                pass
+        graph = self.codetest(f)
+        # assert did not crash
+
 
 DATA = {'x': 5,
         'y': 6}

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/callmethod.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/callmethod.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/objspace/std/mapdict.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/mapdict.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/mapdict.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/objspace/std/stringobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/stringobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/stringobject.py	Wed Nov 17 20:41:25 2010
@@ -937,10 +937,17 @@
 
     string = w_string._value
     chars = []
-    for char in string:
-        w_char = W_StringObject.PREBUILT[ord(char)]
-        if not space.is_true(space.contains(w_deletechars, w_char)):
-             chars.append(table[ord(char)])
+    deletechars = space.str_w(w_deletechars)
+    if len(deletechars) == 0:
+        for char in string:
+            chars.append(table[ord(char)])
+    else:
+        deletion_table = [False] * 256
+        for c in deletechars:
+            deletion_table[ord(c)] = True
+        for char in string:
+            if not deletion_table[ord(char)]:
+                chars.append(table[ord(char)])
     return W_StringObject(''.join(chars))
 
 def str_decode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None):

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_dictmultiobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_dictmultiobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_dictmultiobject.py	Wed Nov 17 20:41:25 2010
@@ -616,6 +616,7 @@
             withdictmeasurement = False
             withsmalldicts = False
             withcelldict = False
+            withmethodcache = False
         class opcodes:
             CALL_LIKELY_BUILTIN = False
 

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_mapdict.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_mapdict.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_mapdict.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rlib/clibffi.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/clibffi.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/clibffi.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rlib/jit.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/jit.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/jit.py	Wed Nov 17 20:41:25 2010
@@ -4,6 +4,7 @@
 from pypy.rlib.objectmodel import CDefinedIntSymbolic
 from pypy.rlib.objectmodel import keepalive_until_here
 from pypy.rlib.unroll import unrolling_iterable
+from pypy.rlib.nonconst import NonConstant
 
 def purefunction(func):
     """ Decorate a function as pure. Pure means precisely that:
@@ -145,6 +146,14 @@
         return hop.inputconst(lltype.Signed, _we_are_jitted)
 
 
+def current_trace_length():
+    """During JIT tracing, returns the current trace length (as a constant).
+    If not tracing, returns -1."""
+    if NonConstant(False):
+        return 73
+    return -1
+current_trace_length.oopspec = 'jit.current_trace_length()'
+
 def jit_debug(string, arg1=-sys.maxint-1, arg2=-sys.maxint-1,
                       arg3=-sys.maxint-1, arg4=-sys.maxint-1):
     """When JITted, cause an extra operation DEBUG_MERGE_POINT to appear in

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/rarithmetic.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/rarithmetic.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/rarithmetic.py	Wed Nov 17 20:41:25 2010
@@ -501,6 +501,11 @@
     def __cmp__(self, other):
         raise TypeError("not supported on r_singlefloat instances")
 
+    def __eq__(self, other):
+        return self.__class__ is other.__class__ and self._bytes == other._bytes
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
 
 class For_r_singlefloat_values_Entry(extregistry.ExtRegistryEntry):
     _type_ = r_singlefloat

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/rgc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/rgc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/rgc.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rlib/streamio.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/streamio.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/streamio.py	Wed Nov 17 20:41:25 2010
@@ -12,7 +12,7 @@
   * some other methods also have no default parameters.
   * close() should be called exactly once and no further operations performed;
     there is no __del__() closing the stream for you.
-  * some methods may raise NotImplementedError.
+  * some methods may raise MyNotImplementedError.
   * peek() returns some (or no) characters that have already been read ahead.
   * flushable() returns True/False if flushing that stream is useful/pointless.
 
@@ -54,6 +54,12 @@
            ('a', True):  O_RDWR   | O_CREAT,
            }
 
+class MyNotImplementedError(Exception):
+    """
+    Catching NotImplementedError is not RPython, so we use this custom class
+    instead of it
+    """
+
 # ____________________________________________________________
 
 
@@ -209,16 +215,16 @@
     some methods."""
 
     def read(self, n):
-        raise NotImplementedError
+        raise MyNotImplementedError
 
     def write(self, data):
-        raise NotImplementedError
+        raise MyNotImplementedError
 
     def tell(self):
-        raise NotImplementedError
+        raise MyNotImplementedError
 
     def seek(self, offset, whence):
-        raise NotImplementedError
+        raise MyNotImplementedError
 
     def readall(self):
         bufsize = 8192
@@ -251,7 +257,7 @@
         return ''.join(result)
 
     def truncate(self, size):
-        raise NotImplementedError
+        raise MyNotImplementedError
 
     def flush_buffers(self):
         pass
@@ -487,7 +493,7 @@
         if self.lines or self.buf:
             try:
                 self.do_seek(self.tell(), 0)
-            except NotImplementedError:
+            except MyNotImplementedError:
                 pass
             else:
                 self.lines = []
@@ -535,14 +541,14 @@
             self.buf = ""
             try:
                 self.do_seek(offset, 1)
-            except NotImplementedError:
+            except MyNotImplementedError:
                 intoffset = offset2int(offset)
                 self.read(intoffset)
             return
         if whence == 2:
             try:
                 self.do_seek(offset, 2)
-            except NotImplementedError:
+            except MyNotImplementedError:
                 pass
             else:
                 self.lines = []
@@ -1019,7 +1025,7 @@
         if self.buf:
             try:
                 self.base.seek(-len(self.buf), 1)
-            except NotImplementedError:
+            except MyNotImplementedError:
                 pass
             else:
                 self.buf = ""

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/test/test_rarithmetic.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/test/test_rarithmetic.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/test/test_rarithmetic.py	Wed Nov 17 20:41:25 2010
@@ -325,6 +325,15 @@
     assert float(x) != 2.1
     assert abs(float(x) - 2.1) < 1E-6
 
+def test_r_singlefloat_eq():
+    x = r_singlefloat(2.5)       # exact number
+    y = r_singlefloat(2.5)
+    assert x == y
+    assert not x != y
+    assert not x == 2.5
+    assert x != 2.5
+    py.test.raises(TypeError, "x>y")
+
 class BaseTestRarithmetic(BaseRtypingTest):
     def test_formatd(self):
         from pypy.rlib.rarithmetic import formatd
@@ -358,7 +367,17 @@
         assert res == 1.0
 
         res = self.interpret(f, [1])
-        assert res == 1e-100                 
+        assert res == 1e-100
+
+    def test_compare_singlefloat_crashes(self):
+        from pypy.rlib.rarithmetic import r_singlefloat
+        from pypy.rpython.error import MissingRTypeOperation
+        def f(x):
+            a = r_singlefloat(x)
+            b = r_singlefloat(x+1)
+            return a == b
+        py.test.raises(MissingRTypeOperation, "self.interpret(f, [42.0])")
+
 
 class TestLLtype(BaseTestRarithmetic, LLRtypeMixin):
     pass

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/annlowlevel.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/annlowlevel.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/annlowlevel.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/llinterp.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/llinterp.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/lltypesystem/llarena.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/llarena.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/llarena.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/llmemory.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/llmemory.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/lloperation.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/lltype.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rffi.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/base.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/generation.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/generation.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/memory/gc/inspector.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/inspector.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/inspector.py	Wed Nov 17 20:41:25 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):
@@ -172,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)
@@ -188,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)
@@ -198,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/jit-unroll-loops/pypy/rpython/memory/gc/minimark.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/minimark.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/minimark.py	Wed Nov 17 20:41:25 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
@@ -77,7 +110,7 @@
 
     # During a minor collection, the objects in the nursery that are
     # moved outside are changed in-place: their header is replaced with
-    # the value -1, and the following word is set to the address of
+    # the value -42, and the following word is set to the address of
     # where the object was moved.  This means that all objects in the
     # nursery need to be at least 2 words long, but objects outside the
     # nursery don't need to.
@@ -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
@@ -178,6 +215,7 @@
         self.nursery      = NULL
         self.nursery_free = NULL
         self.nursery_top  = NULL
+        self.debug_always_do_minor_collect = False
         #
         # The ArenaCollection() handles the nonmovable objects allocation.
         if ArenaCollectionClass is None:
@@ -245,6 +283,10 @@
             # From there on, the GC is fully initialized and the code
             # below can use it
             newsize = base.read_from_env('PYPY_GC_NURSERY')
+            # PYPY_GC_NURSERY=1 forces a minor collect for every malloc.
+            # Useful to debug external factors, like trackgcroot or the
+            # handling of the write barrier.
+            self.debug_always_do_minor_collect = newsize == 1
             if newsize <= 0:
                 newsize = generation.estimate_best_nursery_size()
                 if newsize <= 0:
@@ -252,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)
@@ -290,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
         #
@@ -444,6 +498,10 @@
         result = self.nursery_free
         self.nursery_free = result + totalsize
         ll_assert(self.nursery_free <= self.nursery_top, "nursery overflow")
+        #
+        if self.debug_always_do_minor_collect:
+            self.nursery_free = self.nursery_top
+        #
         return result
     collect_and_reserve._dont_inline_ = True
 
@@ -647,10 +705,13 @@
     def is_forwarded(self, obj):
         """Returns True if the nursery obj is marked as forwarded.
         Implemented a bit obscurely by checking an unrelated flag
-        that can never be set on a young object -- except if tid == -1.
+        that can never be set on a young object -- except if tid == -42.
         """
         assert self.is_in_nursery(obj)
-        return self.header(obj).tid & GCFLAG_FINALIZATION_ORDERING
+        result = (self.header(obj).tid & GCFLAG_FINALIZATION_ORDERING != 0)
+        if result:
+            ll_assert(self.header(obj).tid == -42, "bogus header for young obj")
+        return result
 
     def get_forwarding_address(self, obj):
         return llmemory.cast_adr_to_ptr(obj, FORWARDSTUBPTR).forw
@@ -734,6 +795,10 @@
     def JIT_max_size_of_young_obj(cls):
         return cls.TRANSLATION_PARAMS['large_object']
 
+    @classmethod
+    def JIT_minimal_size_in_nursery(cls):
+        return cls.minimal_size_in_nursery
+
     def write_barrier(self, newvalue, addr_struct):
         if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS:
             self.remember_young_pointer(addr_struct, newvalue)
@@ -906,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.
@@ -1000,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
@@ -1063,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.
@@ -1071,7 +1136,7 @@
         llarena.arena_reset(obj - size_gc_header, totalsize, 0)
         llarena.arena_reserve(obj - size_gc_header,
                               size_gc_header + llmemory.sizeof(FORWARDSTUB))
-        self.header(obj).tid = -1
+        self.header(obj).tid = -42
         newobj = newhdr + size_gc_header
         llmemory.cast_adr_to_ptr(obj, FORWARDSTUBPTR).forw = newobj
         #
@@ -1140,6 +1205,10 @@
         self.collect_roots()
         self.visit_all_objects()
         #
+        # Weakref support: clear the weak pointers to dying objects
+        if self.old_objects_with_weakrefs.non_empty():
+            self.invalidate_old_weakrefs()
+        #
         # Finalizer support: adds the flag GCFLAG_VISITED to all objects
         # with a finalizer and all objects reachable from there (and also
         # moves some objects from 'objects_with_finalizers' to
@@ -1149,10 +1218,6 @@
         #
         self.objects_to_trace.delete()
         #
-        # Weakref support: clear the weak pointers to dying objects
-        if self.old_objects_with_weakrefs.non_empty():
-            self.invalidate_old_weakrefs()
-        #
         # Walk all rawmalloced objects and free the ones that don't
         # have the GCFLAG_VISITED flag.
         self.free_unvisited_rawmalloc_objects()
@@ -1182,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.
@@ -1272,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)
@@ -1323,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/jit-unroll-loops/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/semispace.py	Wed Nov 17 20:41:25 2010
@@ -230,6 +230,10 @@
         while self.max_space_size > size:
             self.max_space_size >>= 1
 
+    @classmethod
+    def JIT_minimal_size_in_nursery(cls):
+        return cls.object_minimal_size
+
     def collect(self, gen=0):
         self.debug_check_consistency()
         self.semispace_collect()
@@ -262,10 +266,10 @@
         if self.run_finalizers.non_empty():
             self.update_run_finalizers()
         scan = self.scan_copied(scan)
-        if self.objects_with_finalizers.non_empty():
-            scan = self.deal_with_objects_with_finalizers(scan)
         if self.objects_with_weakrefs.non_empty():
             self.invalidate_weakrefs()
+        if self.objects_with_finalizers.non_empty():
+            scan = self.deal_with_objects_with_finalizers(scan)
         self.update_objects_with_id()
         self.finished_full_collect()
         self.debug_check_consistency()
@@ -689,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
@@ -710,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/jit-unroll-loops/pypy/rpython/memory/gc/test/test_minimark.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/test/test_minimark.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/test/test_minimark.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/framework.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/memory/support.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/support.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/support.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/test/test_gc.py	Wed Nov 17 20:41:25 2010
@@ -278,6 +278,80 @@
         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 should have been cleared
+                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 should have been cleared
+                if self.ref() is None:
+                    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_id(self):
         class A(object):
             pass
@@ -657,6 +731,9 @@
     def test_finalizer_order(self):
         py.test.skip("Not implemented yet")
 
+    def test_weakref_to_object_with_finalizer_ordering(self):
+        py.test.skip("Not implemented yet")
+
 class TestHybridGC(TestGenerationalGC):
     from pypy.rpython.memory.gc.hybrid import HybridGC as GCClass
     GC_CAN_MALLOC_NONMOVABLE = True

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/rbuiltin.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/rbuiltin.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/rpython/rmodel.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/rmodel.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/rmodel.py	Wed Nov 17 20:41:25 2010
@@ -11,14 +11,14 @@
 
 # initialization states for Repr instances 
 
-class setupstate: 
+class setupstate(object): 
     NOTINITIALIZED = 0 
     INPROGRESS = 1
     BROKEN = 2 
     FINISHED = 3
     DELAYED = 4
 
-class Repr:
+class Repr(object):
     """ An instance of Repr is associated with each instance of SomeXxx.
     It defines the chosen representation for the SomeXxx.  The Repr subclasses
     generally follows the SomeXxx subclass hierarchy, but there are numerous

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rpbc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rpbc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rpbc.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/translator/c/gcc/trackgcroot.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/gcc/trackgcroot.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/gcc/trackgcroot.py	Wed Nov 17 20:41:25 2010
@@ -1905,7 +1905,7 @@
 
 
 if __name__ == '__main__':
-    verbose = 1
+    verbose = 0
     shuffle = False
     output_raw_table = False
     if sys.platform == 'darwin':

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/genc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/genc.py	Wed Nov 17 20:41:25 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)'),
@@ -623,9 +623,15 @@
                 mk.definition('OBJECTS', '$(ASMLBLFILES) gcmaptable.s')
                 mk.rule('%.s', '%.c', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -frandom-seed=$< -o $@ -S $< $(INCLUDEDIRS)')
                 mk.rule('%.lbl.s %.gcmap', '%.s',
-                        python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -m$(PYPY_MAIN_FUNCTION) -t $< > $*.gcmap')
+                        [python +
+                             '$(PYPYDIR)/translator/c/gcc/trackgcroot.py '
+                             '-m$(PYPY_MAIN_FUNCTION) -t $< > $*.gctmp',
+                         'mv $*.gctmp $*.gcmap'])
                 mk.rule('gcmaptable.s', '$(GCMAPFILES)',
-                        python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py $(GCMAPFILES) > $@')
+                        [python +
+                             '$(PYPYDIR)/translator/c/gcc/trackgcroot.py '
+                             '$(GCMAPFILES) > $@.tmp',
+                         'mv $@.tmp $@'])
                 mk.rule('.PRECIOUS', '%.s', "# don't remove .s files if Ctrl-C'ed")
 
         else:

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/node.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/node.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/node.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/translator/c/src/asm_gcc_x86.h
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/src/asm_gcc_x86.h	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/src/asm_gcc_x86.h	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/translator/c/src/g_include.h
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/src/g_include.h	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/src/g_include.h	Wed Nov 17 20:41:25 2010
@@ -39,10 +39,9 @@
 #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(__ppc__)
 #  include "src/asm_ppc.h"

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/src/signals.h
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/src/signals.h	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/src/signals.h	Wed Nov 17 20:41:25 2010
@@ -47,16 +47,12 @@
 /* utility to poll for signals that arrived */
 int pypysig_poll(void);   /* => signum or -1 */
 
-/* When a signal is received, the bit 30 of pypysig_occurred is set.
-   After all signals are processed by pypysig_poll(), the bit 30 is
-   cleared again.  The variable is exposed and RPython code is free to
-   use the other bits in any way. */
-#define PENDING_SIGNAL_BIT   (1 << 30)
+/* When a signal is received, pypysig_counter is set to -1. */
 /* This is a struct for the JIT. See interp_signal.py. */
 struct pypysig_long_struct {
     long value;
 };
-extern struct pypysig_long_struct pypysig_occurred;
+extern struct pypysig_long_struct pypysig_counter;
 
 /* some C tricks to get/set the variable as efficiently as possible:
    use macros when compiling as a stand-alone program, but still
@@ -64,18 +60,20 @@
 #undef pypysig_getaddr_occurred
 void *pypysig_getaddr_occurred(void);
 #ifndef PYPY_NOT_MAIN_FILE
-void *pypysig_getaddr_occurred(void) { return (void *)(&pypysig_occurred); }
+void *pypysig_getaddr_occurred(void) { return (void *)(&pypysig_counter); }
 #endif
-#define pypysig_getaddr_occurred()   ((void *)(&pypysig_occurred))
+#define pypysig_getaddr_occurred()   ((void *)(&pypysig_counter))
 
 /************************************************************/
 /* Implementation                                           */
 
 #ifndef PYPY_NOT_MAIN_FILE
 
-struct pypysig_long_struct pypysig_occurred;
-static volatile long *pypysig_occurred_v = (volatile long *)&pypysig_occurred.value;
-static volatile int pypysig_flags[NSIG];
+struct pypysig_long_struct pypysig_counter = {0};
+static char volatile pypysig_flags[NSIG] = {0};
+static int volatile pypysig_occurred = 0;
+/* pypysig_occurred is only an optimization: it tells if any
+   pypysig_flags could be set. */
 
 void pypysig_ignore(int signum)
 {
@@ -108,10 +106,11 @@
 static void signal_setflag_handler(int signum)
 {
     if (0 <= signum && signum < NSIG)
+      {
         pypysig_flags[signum] = 1;
-    /* the point of "*pypysig_occurred_v" instead of just "pypysig_occurred"
-       is the volatile declaration */
-    *pypysig_occurred_v |= PENDING_SIGNAL_BIT;
+        pypysig_occurred = 1;
+        pypysig_counter.value = -1;
+      }
 }
 
 void pypysig_setflag(int signum)
@@ -130,27 +129,21 @@
 
 int pypysig_poll(void)
 {
-  /* the two commented out lines below are useful for performance in
-     normal usage of pypysig_poll(); however, pypy/module/signal/ is
-     not normal usage.  It only calls pypysig_poll() if the
-     PENDING_SIGNAL_BIT is set, and it clears that bit first. */
-
-/* if (pypysig_occurred & PENDING_SIGNAL_BIT) */
+  if (pypysig_occurred)
     {
-        int i;
-/*     pypysig_occurred &= ~PENDING_SIGNAL_BIT; */
-        for (i=0; i<NSIG; i++)
-            if (pypysig_flags[i])
-            {
-                pypysig_flags[i] = 0;
-                /* maybe another signal is pending: */
-                pypysig_occurred.value |= PENDING_SIGNAL_BIT;
-                return i;
-            }
+      int i;
+      pypysig_occurred = 0;
+      for (i=0; i<NSIG; i++)
+        if (pypysig_flags[i])
+          {
+            pypysig_flags[i] = 0;
+            pypysig_occurred = 1;   /* maybe another signal is pending */
+            return i;
+          }
     }
-    return -1;  /* no pending signal */
+  return -1;  /* no pending signal */
 }
 
-#endif
+#endif  /* !PYPY_NOT_MAIN_FILE */
 
 #endif

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_lltyped.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_lltyped.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_lltyped.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_newgc.py	Wed Nov 17 20:41:25 2010
@@ -1066,7 +1066,9 @@
 
     filename_dump = str(udir.join('test_dump_rpy_heap'))
     def define_dump_rpy_heap(self):
-        U = lltype.GcStruct('U', ('x', lltype.Signed))
+        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
@@ -1074,11 +1076,16 @@
         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)
             #
             fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666)
             rgc.dump_rpy_heap(fd)
+            keepalive_until_here(s2)
+            keepalive_until_here(s)
+            keepalive_until_here(a)
             os.close(fd)
             return 0
 
@@ -1087,8 +1094,43 @@
     def test_dump_rpy_heap(self):
         self.run("dump_rpy_heap")
         assert os.path.exists(self.filename_dump)
-        assert os.path.getsize(self.filename_dump) > 0       # minimal test
+        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"
@@ -1173,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/jit-unroll-loops/pypy/translator/cli/src/pypylib.cs
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/cli/src/pypylib.cs	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/cli/src/pypylib.cs	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/translator/goal/app_main.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/goal/app_main.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/goal/app_main.py	Wed Nov 17 20:41:25 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/jit-unroll-loops/pypy/translator/goal/targetpypystandalone.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/goal/targetpypystandalone.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/goal/targetpypystandalone.py	Wed Nov 17 20:41:25 2010
@@ -150,6 +150,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/jit-unroll-loops/pypy/translator/goal/test2/test_app_main.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/goal/test2/test_app_main.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/goal/test2/test_app_main.py	Wed Nov 17 20:41:25 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:



More information about the Pypy-commit mailing list