[pypy-svn] r79977 - in pypy/branch/jit-unroll-loops: . ctypes_configure lib-python lib-python/modified-2.5.2/distutils lib-python/modified-2.5.2/distutils/tests lib-python/modified-2.5.2/encodings lib-python/modified-2.5.2/test lib-python/modified-2.5.2/test/output lib_pypy lib_pypy/_ctypes lib_pypy/pypy_test pypy pypy/annotation pypy/annotation/test pypy/config pypy/config/test pypy/doc pypy/doc/config pypy/doc/statistic pypy/interpreter pypy/interpreter/pyparser pypy/interpreter/pyparser/test pypy/interpreter/test pypy/jit 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/codewriter pypy/jit/codewriter/test pypy/jit/metainterp pypy/jit/metainterp/optimizeopt pypy/jit/metainterp/test pypy/jit/tl pypy/jit/tl/spli pypy/jit/tool pypy/jit/tool/test pypy/module/__pypy__ pypy/module/__pypy__/test pypy/module/_lsprof pypy/module/_lsprof/test pypy/module/_minimal_curses pypy/module/_pickle_support pypy/module/_stackless pypy/module/array/benchmark pypy/module/array/test pypy/module/binascii pypy/module/binascii/test pypy/module/cpyext pypy/module/cpyext/include pypy/module/cpyext/src pypy/module/cpyext/test pypy/module/exceptions pypy/module/fcntl/test pypy/module/imp pypy/module/itertools pypy/module/posix pypy/module/posix/test pypy/module/pyexpat pypy/module/pyexpat/test pypy/module/pypyjit pypy/module/pypyjit/test pypy/module/select pypy/module/sys pypy/module/sys/test pypy/module/test_lib_pypy/ctypes_tests pypy/objspace/std pypy/objspace/std/test pypy/rlib pypy/rlib/rsre pypy/rlib/rsre/test pypy/rlib/test pypy/rpython pypy/rpython/lltypesystem pypy/rpython/lltypesystem/test pypy/rpython/memory/gc pypy/rpython/memory/gc/test pypy/rpython/memory/gctransform pypy/rpython/memory/test pypy/rpython/module pypy/rpython/ootypesystem pypy/rpython/test pypy/tool pypy/tool/release pypy/tool/release/test pypy/translator pypy/translator/c pypy/translator/c/gcc pypy/translator/c/gcc/test pypy/translator/c/src pypy/translator/c/test pypy/translator/goal pypy/translator/goal/test2 pypy/translator/platform pypy/translator/sandbox/test pypy/translator/tool site-packages

hakanardo at codespeak.net hakanardo at codespeak.net
Sat Dec 11 15:10:31 CET 2010


Author: hakanardo
Date: Sat Dec 11 15:10:15 2010
New Revision: 79977

Added:
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/seq_tests.py
      - copied unchanged from r79975, pypy/trunk/lib-python/modified-2.5.2/test/seq_tests.py
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/test_eof.py
      - copied unchanged from r79975, pypy/trunk/lib-python/modified-2.5.2/test/test_eof.py
   pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/hack___pypy__.py
      - copied unchanged from r79975, pypy/trunk/lib_pypy/pypy_test/hack___pypy__.py
   pypy/branch/jit-unroll-loops/pypy/config/support.py
      - copied unchanged from r79975, pypy/trunk/pypy/config/support.py
   pypy/branch/jit-unroll-loops/pypy/config/test/test_support.py
      - copied unchanged from r79975, pypy/trunk/pypy/config/test/test_support.py
   pypy/branch/jit-unroll-loops/pypy/doc/config/objspace.usemodules.binascii.txt
      - copied unchanged from r79975, pypy/trunk/pypy/doc/config/objspace.usemodules.binascii.txt
   pypy/branch/jit-unroll-loops/pypy/doc/config/translation.jit_ffi.txt
      - copied unchanged from r79975, pypy/trunk/pypy/doc/config/translation.jit_ffi.txt
   pypy/branch/jit-unroll-loops/pypy/doc/release-1.4.0beta.txt
      - copied unchanged from r79975, pypy/trunk/pypy/doc/release-1.4.0beta.txt
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/asmmemmgr.py
      - copied unchanged from r79975, pypy/trunk/pypy/jit/backend/llsupport/asmmemmgr.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
      - copied unchanged from r79975, pypy/trunk/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/codebuf.py
      - copied unchanged from r79975, pypy/trunk/pypy/jit/backend/x86/codebuf.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/memmgr.py
      - copied unchanged from r79975, pypy/trunk/pypy/jit/metainterp/memmgr.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_memmgr.py
      - copied unchanged from r79975, pypy/trunk/pypy/jit/metainterp/test/test_memmgr.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/cpython.vmrss
      - copied unchanged from r79975, pypy/trunk/pypy/jit/tool/cpython.vmrss
   pypy/branch/jit-unroll-loops/pypy/jit/tool/log-template.gnumeric
      - copied unchanged from r79975, pypy/trunk/pypy/jit/tool/log-template.gnumeric
   pypy/branch/jit-unroll-loops/pypy/jit/tool/log2gnumeric.py
      - copied unchanged from r79975, pypy/trunk/pypy/jit/tool/log2gnumeric.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_log2gnumeric.py
      - copied unchanged from r79975, pypy/trunk/pypy/jit/tool/test/test_log2gnumeric.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_loopcounter.py
      - copied unchanged from r79975, pypy/trunk/pypy/jit/tool/test/test_loopcounter.py
   pypy/branch/jit-unroll-loops/pypy/module/__pypy__/interp_debug.py
      - copied unchanged from r79975, pypy/trunk/pypy/module/__pypy__/interp_debug.py
   pypy/branch/jit-unroll-loops/pypy/module/__pypy__/test/test_debug.py
      - copied unchanged from r79975, pypy/trunk/pypy/module/__pypy__/test/test_debug.py
   pypy/branch/jit-unroll-loops/pypy/module/binascii/   (props changed)
      - copied from r79975, pypy/trunk/pypy/module/binascii/
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/include/fileobject.h
      - copied unchanged from r79975, pypy/trunk/pypy/module/cpyext/include/fileobject.h
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/include/structseq.h
      - copied unchanged from r79975, pypy/trunk/pypy/module/cpyext/include/structseq.h
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/pypyintf.py
      - copied unchanged from r79975, pypy/trunk/pypy/module/cpyext/pypyintf.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/src/structseq.c
      - copied unchanged from r79975, pypy/trunk/pypy/module/cpyext/src/structseq.c
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_structseq.py
      - copied unchanged from r79975, pypy/trunk/pypy/module/cpyext/test/test_structseq.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/env.py
      - copied unchanged from r79975, pypy/trunk/pypy/rpython/memory/gc/env.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/test/test_env.py
      - copied unchanged from r79975, pypy/trunk/pypy/rpython/memory/gc/test/test_env.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/test/test_inspector.py
      - copied unchanged from r79975, pypy/trunk/pypy/rpython/memory/gc/test/test_inspector.py
   pypy/branch/jit-unroll-loops/pypy/tool/debug_print.py
      - copied unchanged from r79975, pypy/trunk/pypy/tool/debug_print.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/src/asm_gcc_x86_64.h
      - copied unchanged from r79975, pypy/trunk/pypy/translator/c/src/asm_gcc_x86_64.h
   pypy/branch/jit-unroll-loops/pypy/translator/platform/freebsd.py
      - copied unchanged from r79975, pypy/trunk/pypy/translator/platform/freebsd.py
Removed:
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/encodings/
   pypy/branch/jit-unroll-loops/pypy/doc/config/translation.jit_debug.txt
   pypy/branch/jit-unroll-loops/pypy/translator/platform/freebsd7.py
Modified:
   pypy/branch/jit-unroll-loops/   (props changed)
   pypy/branch/jit-unroll-loops/ctypes_configure/configure.py
   pypy/branch/jit-unroll-loops/lib-python/conftest.py
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/msvccompiler.py
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/tests/test_msvccompiler.py
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/unixccompiler.py
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/output/test_cProfile
   pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/test_genexps.py
   pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/array.py
   pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/basics.py
   pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/builtin.py
   pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/function.py
   pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/pointer.py
   pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/primitive.py
   pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/structure.py
   pypy/branch/jit-unroll-loops/lib_pypy/_hashlib.py
   pypy/branch/jit-unroll-loops/lib_pypy/_locale.py
   pypy/branch/jit-unroll-loops/lib_pypy/_marshal.py
   pypy/branch/jit-unroll-loops/lib_pypy/_minimal_curses.py
   pypy/branch/jit-unroll-loops/lib_pypy/_pypy_interact.py
   pypy/branch/jit-unroll-loops/lib_pypy/binascii.py
   pypy/branch/jit-unroll-loops/lib_pypy/cPickle.py
   pypy/branch/jit-unroll-loops/lib_pypy/cmath.py
   pypy/branch/jit-unroll-loops/lib_pypy/ctypes_support.py
   pypy/branch/jit-unroll-loops/lib_pypy/grp.py
   pypy/branch/jit-unroll-loops/lib_pypy/hashlib.py
   pypy/branch/jit-unroll-loops/lib_pypy/itertools.py
   pypy/branch/jit-unroll-loops/lib_pypy/msvcrt.py
   pypy/branch/jit-unroll-loops/lib_pypy/pwd.py
   pypy/branch/jit-unroll-loops/lib_pypy/pyexpat.py
   pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/test_hashlib.py
   pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/test_structseq.py
   pypy/branch/jit-unroll-loops/lib_pypy/readline.py
   pypy/branch/jit-unroll-loops/lib_pypy/resource.py
   pypy/branch/jit-unroll-loops/lib_pypy/syslog.py
   pypy/branch/jit-unroll-loops/pypy/   (props changed)
   pypy/branch/jit-unroll-loops/pypy/annotation/annrpython.py
   pypy/branch/jit-unroll-loops/pypy/annotation/binaryop.py
   pypy/branch/jit-unroll-loops/pypy/annotation/bookkeeper.py
   pypy/branch/jit-unroll-loops/pypy/annotation/description.py
   pypy/branch/jit-unroll-loops/pypy/annotation/listdef.py
   pypy/branch/jit-unroll-loops/pypy/annotation/model.py
   pypy/branch/jit-unroll-loops/pypy/annotation/specialize.py
   pypy/branch/jit-unroll-loops/pypy/annotation/test/test_annrpython.py
   pypy/branch/jit-unroll-loops/pypy/annotation/unaryop.py
   pypy/branch/jit-unroll-loops/pypy/config/pypyoption.py
   pypy/branch/jit-unroll-loops/pypy/config/translationoption.py
   pypy/branch/jit-unroll-loops/pypy/conftest.py
   pypy/branch/jit-unroll-loops/pypy/doc/cpython_differences.txt
   pypy/branch/jit-unroll-loops/pypy/doc/faq.txt
   pypy/branch/jit-unroll-loops/pypy/doc/index.txt
   pypy/branch/jit-unroll-loops/pypy/doc/release-1.4.0.txt
   pypy/branch/jit-unroll-loops/pypy/doc/sprint-reports.txt
   pypy/branch/jit-unroll-loops/pypy/doc/statistic/release_dates.dat
   pypy/branch/jit-unroll-loops/pypy/doc/statistic/sprint_dates.dat
   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/function.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/gateway.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/generator.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/mixedmodule.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/pycode.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/error.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/pytokenizer.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/test/test_pyparse.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_argument.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_compiler.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_executioncontext.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_function.py
   pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_gateway.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/llgraph/runner.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/gc.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/llmodel.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/test/test_gc.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/model.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/test/runner_test.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/test/test_random.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/assembler.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/regalloc.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/regloc.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/runner.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/rx86.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/support.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_assembler.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_gc_integration.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regalloc.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regalloc2.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regloc.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_rx86.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zll_random.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zmath.py
   pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/valgrind.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/call.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/jtransform.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/regalloc.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/support.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_codewriter.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_list.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_regalloc.py
   pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_void_list.py
   pypy/branch/jit-unroll-loops/pypy/jit/conftest.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/compile.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/history.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/jitprof.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/__init__.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/optimizer.py   (contents, props changed)
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/pyjitpl.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_exception.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_fficall.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_list.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_logger.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizefficall.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_pyjitpl.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_recursive.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_virtualizable.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_warmspot.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_warmstate.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/warmspot.py
   pypy/branch/jit-unroll-loops/pypy/jit/metainterp/warmstate.py
   pypy/branch/jit-unroll-loops/pypy/jit/tl/spli/interpreter.py
   pypy/branch/jit-unroll-loops/pypy/jit/tl/tl.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/jitoutput.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/loopcounter.py
   pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_jitoutput.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/_lsprof/interp_lsprof.py
   pypy/branch/jit-unroll-loops/pypy/module/_lsprof/test/test_cprofile.py
   pypy/branch/jit-unroll-loops/pypy/module/_minimal_curses/__init__.py
   pypy/branch/jit-unroll-loops/pypy/module/_pickle_support/maker.py
   pypy/branch/jit-unroll-loops/pypy/module/_stackless/interp_coroutine.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/test/test_array.py
   pypy/branch/jit-unroll-loops/pypy/module/array/test/test_array_old.py   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/binascii/test/   (props changed)
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/__init__.py
   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/include/Python.h
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/intobject.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/object.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/pyerrors.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/pythonrun.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/sequence.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/slotdefs.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/src/getargs.c
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/state.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/stubs.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_arraymodule.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_datetime.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_intobject.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_object.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_pyerrors.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_sequence.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_typeobject.py
   pypy/branch/jit-unroll-loops/pypy/module/cpyext/typeobject.py
   pypy/branch/jit-unroll-loops/pypy/module/exceptions/interp_exceptions.py
   pypy/branch/jit-unroll-loops/pypy/module/fcntl/test/test_fcntl.py
   pypy/branch/jit-unroll-loops/pypy/module/imp/importing.py
   pypy/branch/jit-unroll-loops/pypy/module/itertools/interp_itertools.py
   pypy/branch/jit-unroll-loops/pypy/module/posix/__init__.py
   pypy/branch/jit-unroll-loops/pypy/module/posix/interp_posix.py
   pypy/branch/jit-unroll-loops/pypy/module/posix/test/test_posix2.py
   pypy/branch/jit-unroll-loops/pypy/module/pyexpat/interp_pyexpat.py
   pypy/branch/jit-unroll-loops/pypy/module/pyexpat/test/test_parser.py
   pypy/branch/jit-unroll-loops/pypy/module/pypyjit/__init__.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/select/interp_select.py
   pypy/branch/jit-unroll-loops/pypy/module/sys/__init__.py
   pypy/branch/jit-unroll-loops/pypy/module/sys/state.py
   pypy/branch/jit-unroll-loops/pypy/module/sys/test/test_initialpath.py
   pypy/branch/jit-unroll-loops/pypy/module/sys/vm.py
   pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py
   pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py
   pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_keepalive.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/complexobject.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/complextype.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/floattype.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/longobject.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/mapdict.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/objspace.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/strutil.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_complexobject.py
   pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_strutil.py
   pypy/branch/jit-unroll-loops/pypy/rlib/debug.py
   pypy/branch/jit-unroll-loops/pypy/rlib/jit.py
   pypy/branch/jit-unroll-loops/pypy/rlib/libffi.py
   pypy/branch/jit-unroll-loops/pypy/rlib/rarithmetic.py
   pypy/branch/jit-unroll-loops/pypy/rlib/rdynload.py
   pypy/branch/jit-unroll-loops/pypy/rlib/rerased.py   (contents, props changed)
   pypy/branch/jit-unroll-loops/pypy/rlib/rmmap.py
   pypy/branch/jit-unroll-loops/pypy/rlib/rsre/rsre_core.py
   pypy/branch/jit-unroll-loops/pypy/rlib/rsre/test/test_zjit.py
   pypy/branch/jit-unroll-loops/pypy/rlib/test/test_debug.py
   pypy/branch/jit-unroll-loops/pypy/rlib/test/test_libffi.py
   pypy/branch/jit-unroll-loops/pypy/rlib/test/test_rerased.py   (props changed)
   pypy/branch/jit-unroll-loops/pypy/rpython/extfunc.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/ll2ctypes.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/lltype.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rbuiltin.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rclass.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rdict.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rpbc.py
   pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/test/test_llarena.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/markcompact.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_direct.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/asmgcroot.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/boehm.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/refcounting.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/support.py
   pypy/branch/jit-unroll-loops/pypy/rpython/memory/test/test_gc.py
   pypy/branch/jit-unroll-loops/pypy/rpython/module/ll_os.py
   pypy/branch/jit-unroll-loops/pypy/rpython/module/ll_time.py
   pypy/branch/jit-unroll-loops/pypy/rpython/ootypesystem/rpbc.py
   pypy/branch/jit-unroll-loops/pypy/rpython/rlist.py
   pypy/branch/jit-unroll-loops/pypy/rpython/rpbc.py
   pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rclass.py
   pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rint.py
   pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rlist.py
   pypy/branch/jit-unroll-loops/pypy/tool/ansi_print.py
   pypy/branch/jit-unroll-loops/pypy/tool/error.py
   pypy/branch/jit-unroll-loops/pypy/tool/logparser.py
   pypy/branch/jit-unroll-loops/pypy/tool/release/force-builds.py
   pypy/branch/jit-unroll-loops/pypy/tool/release/make_release.py
   pypy/branch/jit-unroll-loops/pypy/tool/release/package.py
   pypy/branch/jit-unroll-loops/pypy/tool/release/test/test_package.py
   pypy/branch/jit-unroll-loops/pypy/tool/terminal.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/funcgen.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/gcc/test/test_trackgcroot.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/gcc/trackgcroot.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/src/debug_alloc.h
   pypy/branch/jit-unroll-loops/pypy/translator/c/src/debug_print.h
   pypy/branch/jit-unroll-loops/pypy/translator/c/src/g_include.h
   pypy/branch/jit-unroll-loops/pypy/translator/c/src/mem.h
   pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_extfunc.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_newgc.py
   pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_standalone.py
   pypy/branch/jit-unroll-loops/pypy/translator/driver.py
   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
   pypy/branch/jit-unroll-loops/pypy/translator/platform/__init__.py
   pypy/branch/jit-unroll-loops/pypy/translator/platform/darwin.py
   pypy/branch/jit-unroll-loops/pypy/translator/platform/linux.py
   pypy/branch/jit-unroll-loops/pypy/translator/platform/posix.py
   pypy/branch/jit-unroll-loops/pypy/translator/sandbox/test/test_sandbox.py
   pypy/branch/jit-unroll-loops/pypy/translator/tool/cbuild.py
   pypy/branch/jit-unroll-loops/pypy/translator/tool/reftracker.py
   pypy/branch/jit-unroll-loops/site-packages/   (props changed)
Log:
svn merge -r79225:HEAD svn+ssh://hakanardo@codespeak.net/svn/pypy/trunk

Modified: pypy/branch/jit-unroll-loops/ctypes_configure/configure.py
==============================================================================
--- pypy/branch/jit-unroll-loops/ctypes_configure/configure.py	(original)
+++ pypy/branch/jit-unroll-loops/ctypes_configure/configure.py	Sat Dec 11 15:10:15 2010
@@ -559,6 +559,7 @@
 C_HEADER = """
 #include <stdio.h>
 #include <stddef.h>   /* for offsetof() */
+#include <stdint.h>   /* FreeBSD: for uint64_t */
 
 void dump(char* key, int value) {
     printf("%s: %d\\n", key, value);

Modified: pypy/branch/jit-unroll-loops/lib-python/conftest.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib-python/conftest.py	(original)
+++ pypy/branch/jit-unroll-loops/lib-python/conftest.py	Sat Dec 11 15:10:15 2010
@@ -139,7 +139,7 @@
     RegrTest('test_augassign.py', core=True),
     RegrTest('test_base64.py'),
     RegrTest('test_bastion.py'),
-    RegrTest('test_binascii.py'),
+    RegrTest('test_binascii.py', usemodules='binascii'),
 
     RegrTest('test_binhex.py'),
 

Modified: pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/msvccompiler.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/msvccompiler.py	(original)
+++ pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/msvccompiler.py	Sat Dec 11 15:10:15 2010
@@ -25,17 +25,20 @@
 from distutils import log
 from distutils.util import get_platform
 
-import _winreg
-
-RegOpenKeyEx = _winreg.OpenKeyEx
-RegEnumKey = _winreg.EnumKey
-RegEnumValue = _winreg.EnumValue
-RegError = _winreg.error
-
-HKEYS = (_winreg.HKEY_USERS,
-         _winreg.HKEY_CURRENT_USER,
-         _winreg.HKEY_LOCAL_MACHINE,
-         _winreg.HKEY_CLASSES_ROOT)
+try:
+    import _winreg
+except ImportError:
+    pass
+else:
+    RegOpenKeyEx = _winreg.OpenKeyEx
+    RegEnumKey = _winreg.EnumKey
+    RegEnumValue = _winreg.EnumValue
+    RegError = _winreg.error
+
+    HKEYS = (_winreg.HKEY_USERS,
+             _winreg.HKEY_CURRENT_USER,
+             _winreg.HKEY_LOCAL_MACHINE,
+             _winreg.HKEY_CLASSES_ROOT)
 
 VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
 VSEXPRESS_BASE = r"Software\Microsoft\VCExpress\%0.1f"

Modified: pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/tests/test_msvccompiler.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/tests/test_msvccompiler.py	(original)
+++ pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/tests/test_msvccompiler.py	Sat Dec 11 15:10:15 2010
@@ -11,11 +11,15 @@
         else:
             self.fail("could not find a suitable manifest")
 
+class MsvcCompilerSimplerTestCase(unittest.TestCase):
+    def test_import_module(self):
+        from distutils.msvccompiler import MSVCCompiler
+
 def test_suite():
     if sys.platform == 'win32':
         return unittest.makeSuite(MsvcCompilerTestCase)
     else:
-        return unittest.TestSuite([])
+        return unittest.makeSuite(MsvcCompilerSimplerTestCase)
 
 if __name__ == "__main__":
     unittest.main(defaultTest="test_suite")

Modified: pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/unixccompiler.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/unixccompiler.py	(original)
+++ pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/distutils/unixccompiler.py	Sat Dec 11 15:10:15 2010
@@ -121,7 +121,22 @@
                   }
 
     if sys.platform[:6] == "darwin":
+        import platform
+        if platform.machine() == 'i386':
+            if platform.architecture()[0] == '32bit':
+                arch = 'i386'
+            else:
+                arch = 'x86_64'
+        else:
+            # just a guess
+            arch = platform.machine()
         executables['ranlib'] = ["ranlib"]
+        executables['linker_so'] += ['-undefined', 'dynamic_lookup']
+
+        for k, v in executables.iteritems():
+            if v and v[0] == 'cc':
+                v += ['-arch', arch]
+
 
     # Needed for the filename generation methods provided by the base
     # class, CCompiler.  NB. whoever instantiates/uses a particular

Modified: pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/output/test_cProfile
==============================================================================
--- pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/output/test_cProfile	(original)
+++ pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/output/test_cProfile	Sat Dec 11 15:10:15 2010
@@ -14,66 +14,66 @@
         4    0.116    0.029    0.120    0.030 test_cProfile.py:78(helper1)
         2    0.000    0.000    0.140    0.070 test_cProfile.py:89(helper2_indirect)
         8    0.312    0.039    0.400    0.050 test_cProfile.py:93(helper2)
-        4    0.000    0.000    0.000    0.000 {append}
-        1    0.000    0.000    0.000    0.000 {disable}
        12    0.000    0.000    0.012    0.001 {hasattr}
+        4    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
+        1    0.000    0.000    0.000    0.000 {method 'disable' of 'Profile' objects}
         8    0.000    0.000    0.000    0.000 {range}
         4    0.000    0.000    0.000    0.000 {sys.exc_info}
 
 
    Ordered by: standard name
 
-Function                               called...
-                                           ncalls  tottime  cumtime
-<string>:1(<module>)                   ->       1    0.270    1.000  test_cProfile.py:30(testfunc)
-test_cProfile.py:103(subhelper)        ->      16    0.016    0.016  test_cProfile.py:115(__getattr__)
-                                                8    0.000    0.000  {range}
-test_cProfile.py:115(__getattr__)      ->
-test_cProfile.py:30(testfunc)          ->       1    0.014    0.130  test_cProfile.py:40(factorial)
-                                                2    0.040    0.600  test_cProfile.py:60(helper)
-test_cProfile.py:40(factorial)         ->    20/3    0.130    0.147  test_cProfile.py:40(factorial)
-                                               20    0.020    0.020  test_cProfile.py:53(mul)
-test_cProfile.py:53(mul)               ->
-test_cProfile.py:60(helper)            ->       4    0.116    0.120  test_cProfile.py:78(helper1)
-                                                2    0.000    0.140  test_cProfile.py:89(helper2_indirect)
-                                                6    0.234    0.300  test_cProfile.py:93(helper2)
-test_cProfile.py:78(helper1)           ->       4    0.000    0.000  {append}
-                                                4    0.000    0.004  {hasattr}
-                                                4    0.000    0.000  {sys.exc_info}
-test_cProfile.py:89(helper2_indirect)  ->       2    0.006    0.040  test_cProfile.py:40(factorial)
-                                                2    0.078    0.100  test_cProfile.py:93(helper2)
-test_cProfile.py:93(helper2)           ->       8    0.064    0.080  test_cProfile.py:103(subhelper)
-                                                8    0.000    0.008  {hasattr}
-{append}                               ->
-{disable}                              ->
-{hasattr}                              ->      12    0.012    0.012  test_cProfile.py:115(__getattr__)
-{range}                                ->
-{sys.exc_info}                         ->
+Function                                 called...
+                                             ncalls  tottime  cumtime
+<string>:1(<module>)                     ->       1    0.270    1.000  test_cProfile.py:30(testfunc)
+test_cProfile.py:103(subhelper)          ->      16    0.016    0.016  test_cProfile.py:115(__getattr__)
+                                                  8    0.000    0.000  {range}
+test_cProfile.py:115(__getattr__)        ->
+test_cProfile.py:30(testfunc)            ->       1    0.014    0.130  test_cProfile.py:40(factorial)
+                                                  2    0.040    0.600  test_cProfile.py:60(helper)
+test_cProfile.py:40(factorial)           ->    20/3    0.130    0.147  test_cProfile.py:40(factorial)
+                                                 20    0.020    0.020  test_cProfile.py:53(mul)
+test_cProfile.py:53(mul)                 ->
+test_cProfile.py:60(helper)              ->       4    0.116    0.120  test_cProfile.py:78(helper1)
+                                                  2    0.000    0.140  test_cProfile.py:89(helper2_indirect)
+                                                  6    0.234    0.300  test_cProfile.py:93(helper2)
+test_cProfile.py:78(helper1)             ->       4    0.000    0.004  {hasattr}
+                                                  4    0.000    0.000  {method 'append' of 'list' objects}
+                                                  4    0.000    0.000  {sys.exc_info}
+test_cProfile.py:89(helper2_indirect)    ->       2    0.006    0.040  test_cProfile.py:40(factorial)
+                                                  2    0.078    0.100  test_cProfile.py:93(helper2)
+test_cProfile.py:93(helper2)             ->       8    0.064    0.080  test_cProfile.py:103(subhelper)
+                                                  8    0.000    0.008  {hasattr}
+{hasattr}                                ->      12    0.012    0.012  test_cProfile.py:115(__getattr__)
+{method 'append' of 'list' objects}      ->
+{method 'disable' of 'Profile' objects}  ->
+{range}                                  ->
+{sys.exc_info}                           ->
 
 
    Ordered by: standard name
 
-Function                               was called by...
-                                           ncalls  tottime  cumtime
-<string>:1(<module>)                   <-
-test_cProfile.py:103(subhelper)        <-       8    0.064    0.080  test_cProfile.py:93(helper2)
-test_cProfile.py:115(__getattr__)      <-      16    0.016    0.016  test_cProfile.py:103(subhelper)
-                                               12    0.012    0.012  {hasattr}
-test_cProfile.py:30(testfunc)          <-       1    0.270    1.000  <string>:1(<module>)
-test_cProfile.py:40(factorial)         <-       1    0.014    0.130  test_cProfile.py:30(testfunc)
-                                             20/3    0.130    0.147  test_cProfile.py:40(factorial)
-                                                2    0.006    0.040  test_cProfile.py:89(helper2_indirect)
-test_cProfile.py:53(mul)               <-      20    0.020    0.020  test_cProfile.py:40(factorial)
-test_cProfile.py:60(helper)            <-       2    0.040    0.600  test_cProfile.py:30(testfunc)
-test_cProfile.py:78(helper1)           <-       4    0.116    0.120  test_cProfile.py:60(helper)
-test_cProfile.py:89(helper2_indirect)  <-       2    0.000    0.140  test_cProfile.py:60(helper)
-test_cProfile.py:93(helper2)           <-       6    0.234    0.300  test_cProfile.py:60(helper)
-                                                2    0.078    0.100  test_cProfile.py:89(helper2_indirect)
-{append}                               <-       4    0.000    0.000  test_cProfile.py:78(helper1)
-{disable}                              <-
-{hasattr}                              <-       4    0.000    0.004  test_cProfile.py:78(helper1)
-                                                8    0.000    0.008  test_cProfile.py:93(helper2)
-{range}                                <-       8    0.000    0.000  test_cProfile.py:103(subhelper)
-{sys.exc_info}                         <-       4    0.000    0.000  test_cProfile.py:78(helper1)
+Function                                 was called by...
+                                             ncalls  tottime  cumtime
+<string>:1(<module>)                     <-
+test_cProfile.py:103(subhelper)          <-       8    0.064    0.080  test_cProfile.py:93(helper2)
+test_cProfile.py:115(__getattr__)        <-      16    0.016    0.016  test_cProfile.py:103(subhelper)
+                                                 12    0.012    0.012  {hasattr}
+test_cProfile.py:30(testfunc)            <-       1    0.270    1.000  <string>:1(<module>)
+test_cProfile.py:40(factorial)           <-       1    0.014    0.130  test_cProfile.py:30(testfunc)
+                                               20/3    0.130    0.147  test_cProfile.py:40(factorial)
+                                                  2    0.006    0.040  test_cProfile.py:89(helper2_indirect)
+test_cProfile.py:53(mul)                 <-      20    0.020    0.020  test_cProfile.py:40(factorial)
+test_cProfile.py:60(helper)              <-       2    0.040    0.600  test_cProfile.py:30(testfunc)
+test_cProfile.py:78(helper1)             <-       4    0.116    0.120  test_cProfile.py:60(helper)
+test_cProfile.py:89(helper2_indirect)    <-       2    0.000    0.140  test_cProfile.py:60(helper)
+test_cProfile.py:93(helper2)             <-       6    0.234    0.300  test_cProfile.py:60(helper)
+                                                  2    0.078    0.100  test_cProfile.py:89(helper2_indirect)
+{hasattr}                                <-       4    0.000    0.004  test_cProfile.py:78(helper1)
+                                                  8    0.000    0.008  test_cProfile.py:93(helper2)
+{method 'append' of 'list' objects}      <-       4    0.000    0.000  test_cProfile.py:78(helper1)
+{method 'disable' of 'Profile' objects}  <-
+{range}                                  <-       8    0.000    0.000  test_cProfile.py:103(subhelper)
+{sys.exc_info}                           <-       4    0.000    0.000  test_cProfile.py:78(helper1)
 
 

Modified: pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/test_genexps.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/test_genexps.py	(original)
+++ pypy/branch/jit-unroll-loops/lib-python/modified-2.5.2/test/test_genexps.py	Sat Dec 11 15:10:15 2010
@@ -77,10 +77,10 @@
 Verify that parenthesis are required in a statement
 
     >>> def f(n):
-    ...     return i*i for i in xrange(n)
+    ...     return i*i for i in xrange(n) #doctest: +ELLIPSIS
     Traceback (most recent call last):
        ...
-    SyntaxError: invalid syntax
+    SyntaxError: invalid syntax...
 
 Verify that parenthesis are required when used as a keyword argument value
 

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/array.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/array.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/array.py	Sat Dec 11 15:10:15 2010
@@ -99,6 +99,9 @@
                 if len(value) > self._length_:
                     raise ValueError("Invalid length")
                 value = self(*value)
+            elif not isinstance(value, self):
+                raise TypeError("expected string or Unicode object, %s found"
+                                % (value.__class__.__name__,))
         else:
             if isinstance(value, tuple):
                 if len(value) > self._length_:
@@ -107,22 +110,43 @@
         return _CDataMeta.from_param(self, value)
 
 def array_get_slice_params(self, index):
-    if index.step is not None:
-        raise TypeError("3 arg slices not supported (for no reason)")
-    start = index.start or 0
-    stop = index.stop or self._length_
-    return start, stop
+    if hasattr(self, '_length_'):
+        start, stop, step = index.indices(self._length_)
+    else:
+        step = index.step
+        if step is None:
+            step = 1
+        start = index.start
+        stop = index.stop
+        if start is None:
+            if step > 0:
+                start = 0
+            else:
+                raise ValueError("slice start is required for step < 0")
+        if stop is None:
+            raise ValueError("slice stop is required")
+
+    return start, stop, step
 
 def array_slice_setitem(self, index, value):
-    start, stop = self._get_slice_params(index)
-    if stop - start != len(value):
+    start, stop, step = self._get_slice_params(index)
+
+    if ((step < 0 and stop >= start) or
+        (step > 0 and start >= stop)):
+        slicelength = 0
+    elif step < 0:
+        slicelength = (stop - start + 1) / step + 1
+    else:
+        slicelength = (stop - start - 1) / step + 1;
+
+    if slicelength != len(value):
         raise ValueError("Can only assign slices of the same length")
-    for i in range(start, stop):
-        self[i] = value[i - start]
+    for i, j in enumerate(range(start, stop, step)):
+        self[j] = value[i]
 
 def array_slice_getitem(self, index):
-    start, stop = self._get_slice_params(index)
-    l = [self[i] for i in range(start, stop)]
+    start, stop, step = self._get_slice_params(index)
+    l = [self[i] for i in range(start, stop, step)]
     letter = getattr(self._type_, '_type_', None)
     if letter == 'c':
         return "".join(l)
@@ -135,7 +159,8 @@
     _ffiargshape = 'P'
 
     def __init__(self, *args):
-        self._buffer = self._ffiarray(self._length_, autofree=True)
+        if not hasattr(self, '_buffer'):
+            self._buffer = self._ffiarray(self._length_, autofree=True)
         for i, arg in enumerate(args):
             self[i] = arg
 
@@ -162,9 +187,10 @@
             self._slice_setitem(index, value)
             return
         index = self._fix_index(index)
-        if ensure_objects(value) is not None:
-            store_reference(self, index, value._objects)
-        arg = self._type_._CData_value(value)
+        cobj = self._type_.from_param(value)
+        if ensure_objects(cobj) is not None:
+            store_reference(self, index, cobj._objects)
+        arg = cobj._get_buffer_value()
         if self._type_._fficompositesize is None:
             self._buffer[index] = arg
             # something more sophisticated, cannot set field directly
@@ -183,7 +209,7 @@
         return self._length_
 
     def _get_buffer_for_param(self):
-        return CArgObject(self._buffer.byptr())
+        return CArgObject(self, self._buffer.byptr())
 
     def _get_buffer_value(self):
         return self._buffer.buffer

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/basics.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/basics.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/basics.py	Sat Dec 11 15:10:15 2010
@@ -46,21 +46,6 @@
         else:
             return self.from_param(as_parameter)
 
-    def _CData_input(self, value):
-        """Used when data enters into ctypes from user code.  'value' is
-        some user-specified Python object, which is converted into a _rawffi
-        array of length 1 containing the same value according to the
-        type 'self'.
-        """
-        cobj = self.from_param(value)
-        return cobj, cobj._get_buffer_for_param()
-
-    def _CData_value(self, value):
-        cobj = self.from_param(value)
-        # we don't care here if this stuff will live afterwards, as we're
-        # interested only in value anyway
-        return cobj._get_buffer_value()
-
     def _CData_output(self, resbuffer, base=None, index=-1):
         #assert isinstance(resbuffer, _rawffi.ArrayInstance)
         """Used when data exits ctypes and goes into user code.
@@ -92,13 +77,23 @@
     """ simple wrapper around buffer, just for the case of freeing
     it afterwards
     """
-    def __init__(self, buffer):
+    def __init__(self, obj, buffer):
+        self._obj = obj
         self._buffer = buffer
 
     def __del__(self):
         self._buffer.free()
         self._buffer = None
 
+    def __repr__(self):
+        return '<CArgObject %r>' % (self._obj,)
+
+    def __eq__(self, other):
+        return self._obj == other
+
+    def __ne__(self, other):
+        return self._obj != other
+
 class _CData(object):
     """ The most basic object for all ctypes types
     """
@@ -128,7 +123,7 @@
         return buffer(self._buffer)
 
     def _get_b_base(self):
-        return self._objects
+        return self._base
     _b_base_ = property(_get_b_base)
     _b_needsfree_ = False
 

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/builtin.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/builtin.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/builtin.py	Sat Dec 11 15:10:15 2010
@@ -11,7 +11,8 @@
 def _string_at(addr, lgt):
     # address here can be almost anything
     import ctypes
-    arg = ctypes.c_void_p._CData_value(addr)
+    cobj = ctypes.c_void_p.from_param(addr)
+    arg = cobj._get_buffer_value()
     return _rawffi.charp2rawstring(arg, lgt)
 
 def set_conversion_mode(encoding, errors):
@@ -22,7 +23,8 @@
 
 def _wstring_at(addr, lgt):
     import ctypes
-    arg = ctypes.c_void_p._CData_value(addr)
+    cobj = ctypes.c_void_p.from_param(addr)
+    arg = cobj._get_buffer_value()
     # XXX purely applevel
     if lgt == -1:
         lgt = sys.maxint

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/function.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/function.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/function.py	Sat Dec 11 15:10:15 2010
@@ -35,6 +35,7 @@
 
     _argtypes_ = None
     _restype_ = None
+    _errcheck_ = None
     _flags_ = 0
     _ffiargshape = 'P'
     _ffishape = 'P'
@@ -53,7 +54,15 @@
         return self._argtypes_
     def _setargtypes(self, argtypes):
         self._ptr = None
-        self._argtypes_ = argtypes    
+        if argtypes is None:
+            self._argtypes_ = None
+        else:
+            for i, argtype in enumerate(argtypes):
+                if not hasattr(argtype, 'from_param'):
+                    raise TypeError(
+                        "item %d in _argtypes_ has no from_param method" % (
+                            i + 1,))
+            self._argtypes_ = argtypes
     argtypes = property(_getargtypes, _setargtypes)
 
     def _getrestype(self):
@@ -72,9 +81,24 @@
         del self._restype_
     restype = property(_getrestype, _setrestype, _delrestype)
 
+    def _geterrcheck(self):
+        return getattr(self, '_errcheck_', None)
+    def _seterrcheck(self, errcheck):
+        if not callable(errcheck):
+            raise TypeError("The errcheck attribute must be callable")
+        self._errcheck_ = errcheck
+    def _delerrcheck(self):
+        try:
+            del self._errcheck_
+        except AttributeError:
+            pass
+    errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck)
+
     def _ffishapes(self, args, restype):
         argtypes = [arg._ffiargshape for arg in args]
         if restype is not None:
+            if not isinstance(restype, _CDataMeta):
+                raise TypeError("invalid result type for callback function")
             restype = restype._ffiargshape
         else:
             restype = 'O' # void
@@ -140,6 +164,7 @@
     
     def __call__(self, *args):
         if self.callable is not None:
+            args = args[:len(self._argtypes_)]
             try:
                 res = self.callable(*args)
             except:
@@ -162,13 +187,29 @@
             thisarg = None
             
         if argtypes is None:
-            argtypes = self._guess_argtypes(args)
-        argtypes, argsandobjs = self._wrap_args(argtypes, args)
+            argtypes = []
+        args = self._convert_args(argtypes, args)
+        argtypes = [type(arg) for arg in args]
         
         restype = self._restype_
         funcptr = self._getfuncptr(argtypes, restype, thisarg)
-        resbuffer = funcptr(*[arg._buffer for _, arg in argsandobjs])
-        return self._build_result(restype, resbuffer, argtypes, argsandobjs)
+        resbuffer = funcptr(*[arg._get_buffer_for_param()._buffer
+                              for arg in args])
+        result = self._build_result(restype, resbuffer, argtypes, args)
+
+        # The 'errcheck' protocol
+        if self._errcheck_:
+            v = self._errcheck_(result, self, args)
+            # If the errcheck funtion failed, let it throw
+            # If the errcheck function returned callargs unchanged,
+            # continue normal processing.
+            # If the errcheck function returned something else,
+            # use that as result.
+            if v is not args:
+                result = v
+
+        return result
+
 
     def _getfuncptr(self, argtypes, restype, thisarg=None):
         if self._ptr is not None and argtypes is self._argtypes_:
@@ -212,31 +253,33 @@
             raise
 
     @staticmethod
-    def _guess_argtypes(args):
+    def _conv_param(argtype, arg, index):
         from ctypes import c_char_p, c_wchar_p, c_void_p, c_int
-        res = []
-        for arg in args:
-            if hasattr(arg, '_as_parameter_'):
-                arg = arg._as_parameter_
-            if isinstance(arg, str):
-                res.append(c_char_p)
-            elif isinstance(arg, unicode):
-                res.append(c_wchar_p)
-            elif isinstance(arg, _CData):
-                res.append(type(arg))
-            elif arg is None:
-                res.append(c_void_p)
-            #elif arg == 0:
-            #    res.append(c_void_p)
-            elif isinstance(arg, (int, long)):
-                res.append(c_int)
-            else:
-                raise TypeError("Don't know how to handle %s" % (arg,))
-        return res
+        if argtype is not None:
+            arg = argtype.from_param(arg)
+        if hasattr(arg, '_as_parameter_'):
+            arg = arg._as_parameter_
+
+        if isinstance(arg, _CData):
+            # The usual case when argtype is defined
+            cobj = arg
+        elif isinstance(arg, str):
+            cobj = c_char_p(arg)
+        elif isinstance(arg, unicode):
+            cobj = c_wchar_p(arg)
+        elif arg is None:
+            cobj = c_void_p()
+        elif isinstance(arg, (int, long)):
+            cobj = c_int(arg)
+        else:
+            raise TypeError("Don't know how to handle %s" % (arg,))
 
-    def _wrap_args(self, argtypes, args):
+        return cobj
+
+    def _convert_args(self, argtypes, args):
         wrapped_args = []
         consumed = 0
+
         for i, argtype in enumerate(argtypes):
             defaultvalue = None
             if i > 0 and self._paramflags is not None:
@@ -263,7 +306,7 @@
                     val = defaultvalue
                     if val is None:
                         val = 0
-                    wrapped = argtype._CData_input(val)
+                    wrapped = self._conv_param(argtype, val, consumed)
                     wrapped_args.append(wrapped)
                     continue
                 else:
@@ -278,23 +321,22 @@
                 raise TypeError("Not enough arguments")
 
             try:
-                wrapped = argtype._CData_input(arg)
-            except (UnicodeError, TypeError), e:
+                wrapped = self._conv_param(argtype, arg, consumed)
+            except (UnicodeError, TypeError, ValueError), e:
                 raise ArgumentError(str(e))
             wrapped_args.append(wrapped)
             consumed += 1
 
         if len(wrapped_args) < len(args):
             extra = args[len(wrapped_args):]
-            extra_types = self._guess_argtypes(extra)
-            for arg, argtype in zip(extra, extra_types):
+            argtypes = list(argtypes)
+            for i, arg in enumerate(extra):
                 try:
-                    wrapped = argtype._CData_input(arg)
-                except (UnicodeError, TypeError), e:
+                    wrapped = self._conv_param(None, arg, i)
+                except (UnicodeError, TypeError, ValueError), e:
                     raise ArgumentError(str(e))
                 wrapped_args.append(wrapped)
-            argtypes = list(argtypes) + extra_types
-        return argtypes, wrapped_args
+        return wrapped_args
 
     def _build_result(self, restype, resbuffer, argtypes, argsandobjs):
         """Build the function result:
@@ -307,7 +349,7 @@
         if self._com_index:
             if resbuffer[0] & 0x80000000:
                 raise get_com_error(resbuffer[0],
-                                    self._com_iid, argsandobjs[0][0])
+                                    self._com_iid, argsandobjs[0])
             else:
                 retval = int(resbuffer[0])
         elif restype is not None:
@@ -326,8 +368,8 @@
 
         results = []
         if self._paramflags:
-            for argtype, (obj, _), paramflag in zip(argtypes[1:], argsandobjs[1:],
-                                                    self._paramflags):
+            for argtype, obj, paramflag in zip(argtypes[1:], argsandobjs[1:],
+                                               self._paramflags):
                 if len(paramflag) == 2:
                     idlflag, name = paramflag
                 elif len(paramflag) == 3:

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/pointer.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/pointer.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/pointer.py	Sat Dec 11 15:10:15 2010
@@ -1,7 +1,8 @@
 
 import _rawffi
 from _ctypes.basics import _CData, _CDataMeta, cdata_from_address
-from _ctypes.basics import sizeof, byref, keepalive_key
+from _ctypes.basics import keepalive_key, store_reference, ensure_objects
+from _ctypes.basics import sizeof, byref
 from _ctypes.array import Array, array_get_slice_params, array_slice_getitem,\
      array_slice_setitem
 
@@ -55,7 +56,8 @@
     def set_type(self, TP):
         ffiarray = _rawffi.Array('P')
         def __init__(self, value=None):
-            self._buffer = ffiarray(1, autofree=True)
+            if not hasattr(self, '_buffer'):
+                self._buffer = ffiarray(1, autofree=True)
             if value is not None:
                 self.contents = value
         self._ffiarray = ffiarray
@@ -99,7 +101,10 @@
         return self._type_._CData_output(self._subarray(index), self, index)
 
     def __setitem__(self, index, value):
-        self._subarray(index)[0] = self._type_._CData_value(value)
+        cobj = self._type_.from_param(value)
+        if ensure_objects(cobj) is not None:
+            store_reference(self, index, cobj._objects)
+        self._subarray(index)[0] = cobj._get_buffer_value()
 
     def __nonzero__(self):
         return self._buffer[0] != 0
@@ -110,29 +115,32 @@
     if not (isinstance(tp, _CDataMeta) and tp._is_pointer_like()):
         raise TypeError("cast() argument 2 must be a pointer type, not %s"
                         % (tp,))
-    if isinstance(obj, Array):
-        ptr = tp.__new__(tp)
-        ptr._buffer = tp._ffiarray(1, autofree=True)
-        ptr._buffer[0] = obj._buffer
-        return ptr
     if isinstance(obj, (int, long)):
         result = tp()
         result._buffer[0] = obj
         return result
-    if obj is None:
+    elif obj is None:
         result = tp()
         return result
-    if not (isinstance(obj, _CData) and type(obj)._is_pointer_like()):
+    elif isinstance(obj, Array):
+        ptr = tp.__new__(tp)
+        ptr._buffer = tp._ffiarray(1, autofree=True)
+        ptr._buffer[0] = obj._buffer
+        result = ptr
+    elif not (isinstance(obj, _CData) and type(obj)._is_pointer_like()):
         raise TypeError("cast() argument 1 must be a pointer, not %s"
                         % (type(obj),))
-    result = tp()
+    else:
+        result = tp()
+        result._buffer[0] = obj._buffer[0]
 
     # The casted objects '_objects' member:
-    # It must certainly contain the source objects one.
+    # From now on, both objects will use the same dictionary
+    # It must certainly contain the source objects
     # It must contain the source object itself.
     if obj._ensure_objects() is not None:
-        result._objects = {keepalive_key(0): obj._objects,
-                           keepalive_key(1): obj}
+        result._objects = obj._objects
+        if isinstance(obj._objects, dict):
+            result._objects[id(obj)] =  obj
 
-    result._buffer[0] = obj._buffer[0]
     return result

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/primitive.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/primitive.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/primitive.py	Sat Dec 11 15:10:15 2010
@@ -132,8 +132,8 @@
                                              ConvMode.errors)
                     #self._objects = value
                     array = _rawffi.Array('c')(len(value)+1, value)
+                    self._objects = CArgObject(value, array)
                     value = array.buffer
-                    self._objects = {'0': CArgObject(array)}
                 elif value is None:
                     value = 0
                 self._buffer[0] = value
@@ -155,8 +155,8 @@
                                              ConvMode.errors)
                     #self._objects = value
                     array = _rawffi.Array('u')(len(value)+1, value)
+                    self._objects = CArgObject(value, array)
                     value = array.buffer
-                    self._objects = {'0': CArgObject(array)}
                 elif value is None:
                     value = 0
                 self._buffer[0] = value
@@ -174,8 +174,8 @@
             def _setvalue(self, value):
                 if isinstance(value, str):
                     array = _rawffi.Array('c')(len(value)+1, value)
+                    self._objects = CArgObject(value, array)
                     value = array.buffer
-                    self._objects = {'0': CArgObject(array)}
                 elif value is None:
                     value = 0
                 self._buffer[0] = value
@@ -271,7 +271,9 @@
 
     def _CData_output(self, resbuffer, base=None, index=-1):
         output = super(SimpleType, self)._CData_output(resbuffer, base, index)
-        return output.value
+        if self.__bases__[0] is _SimpleCData:
+            return output.value
+        return output
     
     def _sizeofinstances(self):
         return _rawffi.sizeof(self._type_)
@@ -287,14 +289,15 @@
     _type_ = 'i'
 
     def __init__(self, value=DEFAULT_VALUE):
-        self._buffer = self._ffiarray(1, autofree=True)
+        if not hasattr(self, '_buffer'):
+            self._buffer = self._ffiarray(1, autofree=True)
         if value is not DEFAULT_VALUE:
             self.value = value
 
     def _ensure_objects(self):
-        if self._type_ in 'zZ':
-            return self._objects
-        return None
+        if self._type_ not in 'zZP':
+            assert self._objects is None
+        return self._objects
 
     def _getvalue(self):
         return self._buffer[0]
@@ -312,7 +315,11 @@
         return self.value
 
     def __repr__(self):
-        return "%s(%r)" % (type(self).__name__, self.value)
+        if type(self).__bases__[0] is _SimpleCData:
+            return "%s(%r)" % (type(self).__name__, self.value)
+        else:
+            return "<%s object at 0x%x>" % (type(self).__name__,
+                                            id(self))
 
     def __nonzero__(self):
         return self._buffer[0] not in (0, '\x00')

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/structure.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/structure.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_ctypes/structure.py	Sat Dec 11 15:10:15 2010
@@ -34,9 +34,11 @@
         if not isinstance(tp, _CDataMeta):
             raise TypeError("Expected CData subclass, got %s" % (tp,))
     import ctypes
-    all_fields = _fields_[:]
-    for cls in inspect.getmro(superclass):
-        all_fields += getattr(cls, '_fields_', [])
+    all_fields = []
+    for cls in reversed(inspect.getmro(superclass)):
+        # The first field comes from the most base class
+        all_fields.extend(getattr(cls, '_fields_', []))
+    all_fields.extend(_fields_)
     names = [name for name, ctype in all_fields]
     rawfields = [(name, ctype._ffishape)
                  for name, ctype in all_fields]
@@ -168,7 +170,7 @@
 
     def __init__(self, *args, **kwds):
         if len(args) > len(self._names):
-            raise TypeError("too many arguments")
+            raise TypeError("too many initializers")
         for name, arg in zip(self._names, args):
             if name in kwds:
                 raise TypeError("duplicate value for argument %r" % (

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_hashlib.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_hashlib.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_hashlib.py	Sat Dec 11 15:10:15 2010
@@ -148,21 +148,29 @@
     return hash(ctx, name)
 
 # shortcut functions
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+ at builtinify
 def openssl_md5(string=''):
     return new('md5', string)
 
+ at builtinify
 def openssl_sha1(string=''):
     return new('sha1', string)
 
+ at builtinify
 def openssl_sha224(string=''):
     return new('sha224', string)
 
+ at builtinify
 def openssl_sha256(string=''):
     return new('sha256', string)
 
+ at builtinify
 def openssl_sha384(string=''):
     return new('sha384', string)
 
+ at builtinify
 def openssl_sha512(string=''):
     return new('sha512', string)
-

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_locale.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_locale.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_locale.py	Sat Dec 11 15:10:15 2010
@@ -11,6 +11,9 @@
 # load the platform-specific cache made by running locale.ctc.py
 from ctypes_config_cache._locale_cache import *
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
 
 # Ubuntu Gusty i386 structure
 class lconv(Structure):
@@ -158,6 +161,7 @@
     ul = ''.join(ul)
     string.letters = ul
 
+ at builtinify
 def setlocale(category, locale=None):
     "(integer,string=None) -> string. Activates/queries locale processing."
     if locale:
@@ -182,6 +186,7 @@
         groups.append(0)
     return groups
 
+ at builtinify
 def localeconv():
     "() -> dict. Returns numeric and monetary locale-specific parameters."
 
@@ -215,6 +220,7 @@
     }
     return result
 
+ at builtinify
 def strcoll(s1, s2):
     "string,string -> int. Compares two strings according to the locale."
 
@@ -233,6 +239,7 @@
     # Collate the strings.
     return _wcscoll(s1, s2)
 
+ at builtinify
 def strxfrm(s):
     "string -> string. Returns a string that behaves for cmp locale-aware."
 
@@ -246,6 +253,7 @@
         _strxfrm(buf, s, n2)
     return buf.value
 
+ at builtinify
 def getdefaultlocale():
     # TODO: Port code from CPython for Windows and Mac OS
     raise NotImplementedError()
@@ -267,26 +275,31 @@
         raise ValueError("unsupported langinfo constant")
 
 if HAS_LIBINTL:
+    @builtinify
     def gettext(msg):
         """gettext(msg) -> string
         Return translation of msg."""
         return _gettext(msg)
 
+    @builtinify
     def dgettext(domain, msg):
         """dgettext(domain, msg) -> string
         Return translation of msg in domain."""
         return _dgettext(domain, msg)
 
+    @builtinify
     def dcgettext(domain, msg, category):
         """dcgettext(domain, msg, category) -> string
         Return translation of msg in domain and category."""
         return _dcgettext(domain, msg, category)
 
+    @builtinify
     def textdomain(domain):
         """textdomain(domain) -> string
         Set the C library's textdomain to domain, returning the new domain."""
         return _textdomain(domain)
 
+    @builtinify
     def bindtextdomain(domain, dir):
         """bindtextdomain(domain, dir) -> string
         Bind the C library's domain to dir."""
@@ -297,6 +310,7 @@
         return dirname
 
     if HAS_BIND_TEXTDOMAIN_CODESET:
+        @builtinify
         def bind_textdomain_codeset(domain, codeset):
             """bind_textdomain_codeset(domain, codeset) -> string
             Bind the C library's domain to codeset."""

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_marshal.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_marshal.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_marshal.py	Sat Dec 11 15:10:15 2010
@@ -6,6 +6,10 @@
 import types
 from _codecs import utf_8_decode, utf_8_encode
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+
 TYPE_NULL     = '0'
 TYPE_NONE     = 'N'
 TYPE_FALSE    = 'F'
@@ -645,15 +649,18 @@
 
 version = 1
 
+ at builtinify
 def dump(x, f, version=version):
     # XXX 'version' is ignored, we always dump in a version-0-compatible format
     m = _Marshaller(f.write)
     m.dump(x)
 
+ at builtinify
 def load(f):
     um = _Unmarshaller(f.read)
     return um.load()
 
+ at builtinify
 def dumps(x, version=version):
     # XXX 'version' is ignored, we always dump in a version-0-compatible format
     buffer = []
@@ -661,6 +668,7 @@
     m.dump(x)
     return ''.join(buffer)
 
+ at builtinify
 def loads(s):
     um = _FastUnmarshaller(s)
     return um.load()

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_minimal_curses.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_minimal_curses.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_minimal_curses.py	Sat Dec 11 15:10:15 2010
@@ -35,18 +35,24 @@
 
 # ____________________________________________________________
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+ at builtinify
 def setupterm(termstr, fd):
     err = ctypes.c_int(0)
     result = clib.setupterm(termstr, fd, ctypes.byref(err))
     if result == ERR:
         raise error("setupterm() failed (err=%d)" % err.value)
 
+ at builtinify
 def tigetstr(cap):
     result = clib.tigetstr(cap)
     if ctypes.cast(result, ctypes.c_void_p).value == ERR:
         return None
     return ctypes.cast(result, ctypes.c_char_p).value
 
+ at builtinify
 def tparm(str, i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0):
     result = clib.tparm(str, i1, i2, i3, i4, i5, i6, i7, i8, i9)
     if result is None:

Modified: pypy/branch/jit-unroll-loops/lib_pypy/_pypy_interact.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/_pypy_interact.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/_pypy_interact.py	Sat Dec 11 15:10:15 2010
@@ -4,6 +4,13 @@
 
 
 def interactive_console(mainmodule=None):
+    # set sys.{ps1,ps2} just before invoking the interactive interpreter. This
+    # mimics what CPython does in pythonrun.c
+    if not hasattr(sys, 'ps1'):
+        sys.ps1 = '>>>> '
+    if not hasattr(sys, 'ps2'):
+        sys.ps2 = '.... '
+    #
     try:
         from _pypy_irc_topic import some_topic
         text = "And now for something completely different: ``%s''" % (
@@ -15,6 +22,7 @@
         print text
     except ImportError:
         pass
+    #
     try:
         from pyrepl.simple_interact import check
         if not check():

Modified: pypy/branch/jit-unroll-loops/lib_pypy/binascii.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/binascii.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/binascii.py	Sat Dec 11 15:10:15 2010
@@ -1,3 +1,9 @@
+"""A pure Python implementation of binascii.
+
+Rather slow and buggy in corner cases.
+PyPy provides an RPython version too.
+"""
+
 class Error(Exception):
     pass
 
@@ -277,7 +283,7 @@
         if (c > '~' or
             c == '=' or
             (header and c == '_') or
-            (c == '.' and linelen == 0 and (inp == len(data) or
+            (c == '.' and linelen == 0 and (inp+1 == len(data) or
                                             data[inp+1] == '\n' or
                                             data[inp+1] == '\r')) or
             (not istext and (c == '\r' or c == '\n')) or

Modified: pypy/branch/jit-unroll-loops/lib_pypy/cPickle.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/cPickle.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/cPickle.py	Sat Dec 11 15:10:15 2010
@@ -5,6 +5,10 @@
 from pickle import *
 from pickle import __doc__, __version__, format_version, compatible_formats
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+
 BadPickleGet = KeyError
 UnpickleableError = PicklingError
 
@@ -31,9 +35,11 @@
     def getvalue(self):
         return self.__f and self.__f.getvalue()
 
+ at builtinify
 def dump(obj, file, protocol=None):
     Pickler(file, protocol).dump(obj)
 
+ at builtinify
 def dumps(obj, protocol=None):
     file = StringIO()
     Pickler(file, protocol).dump(obj)

Modified: pypy/branch/jit-unroll-loops/lib_pypy/cmath.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/cmath.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/cmath.py	Sat Dec 11 15:10:15 2010
@@ -7,7 +7,10 @@
 
 import math
 from math import e, pi
-        
+
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
 
 # constants
 _one = complex(1., 0.)
@@ -24,6 +27,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def acos(x):
     """acos(x)
 
@@ -32,6 +36,7 @@
     return -(_prodi(log((x+(_i*sqrt((_one-(x*x))))))))
 
 
+ at builtinify
 def acosh(x):
     """acosh(x)
 
@@ -41,6 +46,7 @@
     return z+z
 
 
+ at builtinify
 def asin(x):
     """asin(x)
 
@@ -52,6 +58,7 @@
     return -(_prodi(log((sqrt_1_minus_x_sq+_prodi(x)))))
 
 
+ at builtinify
 def asinh(x):
     """asinh(x)
 
@@ -61,6 +68,7 @@
     return z+z
 
 
+ at builtinify
 def atan(x):
     """atan(x)
     
@@ -69,6 +77,7 @@
     return _halfi*log(((_i+x)/(_i-x)))
 
 
+ at builtinify
 def atanh(x):
     """atanh(x)
 
@@ -77,6 +86,7 @@
     return _half*log((_one+x)/(_one-x))
 
 
+ at builtinify
 def cos(x):
     """cos(x)
 
@@ -88,6 +98,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def cosh(x):
     """cosh(x)
     
@@ -99,6 +110,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def exp(x):
     """exp(x)
     
@@ -111,6 +123,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def log(x, base=None):
     """log(x)
 
@@ -125,6 +138,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def log10(x):
     """log10(x)
 
@@ -137,6 +151,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def sin(x):
     """sin(x)
 
@@ -148,6 +163,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def sinh(x):
     """sinh(x)
 
@@ -159,6 +175,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def sqrt(x):
     """sqrt(x)
 
@@ -184,6 +201,7 @@
 _sqrt_half = sqrt(_half)
 
 
+ at builtinify
 def tan(x):
     """tan(x)
 
@@ -204,6 +222,7 @@
     return complex(real, imag)
 
 
+ at builtinify
 def tanh(x):
     """tanh(x)
 

Modified: pypy/branch/jit-unroll-loops/lib_pypy/ctypes_support.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/ctypes_support.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/ctypes_support.py	Sat Dec 11 15:10:15 2010
@@ -25,7 +25,7 @@
     def _where_is_errno():
         return standard_c_lib.__errno_location()
 
-elif sys.platform == 'darwin':
+elif sys.platform in ('darwin', 'freebsd7', 'freebsd8', 'freebsd9'):
     standard_c_lib.__error.restype = ctypes.POINTER(ctypes.c_int)
     def _where_is_errno():
         return standard_c_lib.__error()

Modified: pypy/branch/jit-unroll-loops/lib_pypy/grp.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/grp.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/grp.py	Sat Dec 11 15:10:15 2010
@@ -9,6 +9,10 @@
 from ctypes import Structure, c_char_p, c_int, POINTER
 from ctypes_support import standard_c_lib as libc
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+
 gid_t = c_int
 
 class GroupStruct(Structure):
@@ -64,6 +68,7 @@
     return Group(res.contents.gr_name, res.contents.gr_passwd,
                  res.contents.gr_gid, mem)
 
+ at builtinify
 def getgrgid(gid):
     res = libc.getgrgid(gid)
     if not res:
@@ -71,6 +76,7 @@
         raise KeyError(gid)
     return _group_from_gstruct(res)
 
+ at builtinify
 def getgrnam(name):
     if not isinstance(name, str):
         raise TypeError("expected string")
@@ -79,6 +85,7 @@
         raise KeyError(name)
     return _group_from_gstruct(res)
 
+ at builtinify
 def getgrall():
     libc.setgrent()
     lst = []

Modified: pypy/branch/jit-unroll-loops/lib_pypy/hashlib.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/hashlib.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/hashlib.py	Sat Dec 11 15:10:15 2010
@@ -50,53 +50,30 @@
     'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
 
 """
+import sys
 try:
     import _hashlib
 except ImportError:
     _hashlib = None
 
-def __get_builtin_constructor(name):
-    if name in ('SHA1', 'sha1'):
-        import sha
-        return sha.new
-    elif name in ('MD5', 'md5'):
-        import md5
-        return md5.new
-    elif name in ('SHA256', 'sha256'):
-        import _sha256
-        return _sha256.sha256
-    elif name in ('SHA224', 'sha224'):
-        import _sha256
-        return _sha256.sha224
-    elif name in ('SHA512', 'sha512'):
-        import _sha512
-        return _sha512.sha512
-    elif name in ('SHA384', 'sha384'):
-        import _sha512
-        return _sha512.sha384
-    raise ValueError, "unsupported hash type"
-
 def __hash_new(name, string=''):
     """new(name, string='') - Return a new hashing object using the named algorithm;
     optionally initialized with a string.
     """
     try:
-        if _hashlib:
-            return _hashlib.new(name, string)
-    except ValueError:
-        # If the _hashlib module (OpenSSL) doesn't support the named
-        # hash, try using our builtin implementations.
-        # This allows for SHA224/256 and SHA384/512 support even though
-        # the OpenSSL library prior to 0.9.8 doesn't provide them.
-        pass
-
-    return __get_builtin_constructor(name)(string)
+        new = __byname[name]
+    except KeyError:
+        raise ValueError("unsupported hash type")
+    return new(string)
 
 new = __hash_new
 
-def _setfuncs():
-    # use the wrapper of the C implementation
+# ____________________________________________________________
+
+__byname = {}
 
+def __use_openssl_funcs():
+    # use the wrapper of the C implementation
     sslprefix = 'openssl_'
     for opensslfuncname, func in vars(_hashlib).items():
         if not opensslfuncname.startswith(sslprefix):
@@ -106,23 +83,41 @@
             # try them all, some may not work due to the OpenSSL
             # version not supporting that algorithm.
             func() 
-            # Use the C function directly (very fast)
-            globals()[funcname] = func 
+            # Use the C function directly (very fast, but with ctypes overhead)
+            __byname[funcname] = func
         except ValueError:
-            try:
-                # Use the builtin implementation directly (fast)
-                globals()[funcname] = __get_builtin_constructor(funcname) 
-            except ValueError:
-                # this one has no builtin implementation, don't define it
-                pass
+            pass
+
+def __use_builtin_funcs():
+    # look up the built-in versions (written in Python or RPython),
+    # and use the fastest one:
+    #  1. the one in RPython
+    #  2. the one from openssl (slower due to ctypes calling overhead)
+    #  3. the one in pure Python
+    if 'sha1' not in __byname or 'sha' in sys.builtin_module_names:
+        import sha
+        __byname['sha1'] = sha.new
+    if 'md5' not in __byname or 'md5' in sys.builtin_module_names:
+        import md5
+        __byname['md5'] = md5.new
+    if 'sha256' not in __byname:
+        import _sha256
+        __byname['sha256'] = _sha256.sha256
+    if 'sha224' not in __byname:
+        import _sha256
+        __byname['sha224'] = _sha256.sha224
+    if 'sha512' not in __byname:
+        import _sha512
+        __byname['sha512'] = _sha512.sha512
+    if 'sha384' not in __byname:
+        import _sha512
+        __byname['sha384'] = _sha512.sha384
+
+def __export_funcs():
+    for key, value in __byname.items():
+        globals()[key] = __byname[key.upper()] = value
 
 if _hashlib:
-    _setfuncs()
-else:
-    # lookup the C function to use directly for the named constructors
-    md5 = __get_builtin_constructor('md5')
-    sha1 = __get_builtin_constructor('sha1')
-    sha224 = __get_builtin_constructor('sha224')
-    sha256 = __get_builtin_constructor('sha256')
-    sha384 = __get_builtin_constructor('sha384')
-    sha512 = __get_builtin_constructor('sha512')
+    __use_openssl_funcs()
+__use_builtin_funcs()
+__export_funcs()

Modified: pypy/branch/jit-unroll-loops/lib_pypy/itertools.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/itertools.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/itertools.py	Sat Dec 11 15:10:15 2010
@@ -27,6 +27,9 @@
            'ifilterfalse', 'imap', 'islice', 'izip', 'repeat', 'starmap',
            'takewhile', 'tee']
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
 
 class chain(object):
     """Make an iterator that returns elements from the first iterable
@@ -565,7 +568,8 @@
     def __iter__(self):
         return self
 
-    
+
+ at builtinify
 def tee(iterable, n=2):
     """Return n independent iterators from a single iterable.
     Note : once tee() has made a split, the original iterable

Modified: pypy/branch/jit-unroll-loops/lib_pypy/msvcrt.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/msvcrt.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/msvcrt.py	Sat Dec 11 15:10:15 2010
@@ -17,6 +17,10 @@
 except AttributeError: # we are not on windows
     raise ImportError
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+
 open_osfhandle.argtypes = [ctypes.c_int, ctypes.c_int]
 open_osfhandle.restype = ctypes.c_int
 
@@ -34,6 +38,7 @@
 _locking.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int]
 _locking.restype = ctypes.c_int
 
+ at builtinify
 def locking(fd, mode, nbytes):
     '''lock or unlock a number of bytes in a file.'''
     rv = _locking(fd, mode, nbytes)

Modified: pypy/branch/jit-unroll-loops/lib_pypy/pwd.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/pwd.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/pwd.py	Sat Dec 11 15:10:15 2010
@@ -17,6 +17,10 @@
 from ctypes_support import standard_c_lib as libc
 from ctypes import Structure, POINTER, c_int, c_char_p
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+
 uid_t = c_int
 gid_t = c_int
 
@@ -79,10 +83,12 @@
 _endpwent.argtypes = None
 _endpwent.restype = None
 
+ at builtinify
 def mkpwent(pw):
     pw = pw.contents
     return struct_passwd(pw)
 
+ at builtinify
 def getpwuid(uid):
     """
     getpwuid(uid) -> (pw_name,pw_passwd,pw_uid,
@@ -95,6 +101,7 @@
         raise KeyError("getpwuid(): uid not found: %s" % uid)
     return mkpwent(pw)
 
+ at builtinify
 def getpwnam(name):
     """
     getpwnam(name) -> (pw_name,pw_passwd,pw_uid,
@@ -109,9 +116,10 @@
         raise KeyError("getpwname(): name not found: %s" % name)
     return mkpwent(pw)
 
+ at builtinify
 def getpwall():
     """
-    "getpwall() -> list_of_entries
+    getpwall() -> list_of_entries
     Return a list of all available password database entries, in arbitrary order.
     See pwd.__doc__ for more on password database entries.
     """

Modified: pypy/branch/jit-unroll-loops/lib_pypy/pyexpat.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/pyexpat.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/pyexpat.py	Sat Dec 11 15:10:15 2010
@@ -7,6 +7,9 @@
 # load the platform-specific cache made by running pyexpat.ctc.py
 from ctypes_config_cache._pyexpat_cache import *
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
 
 lib = ctypes.CDLL(ctypes.util.find_library('expat'))
 
@@ -425,9 +428,11 @@
         new_parser._set_unknown_encoding_handler()
         return new_parser
 
+ at builtinify
 def ErrorString(errno):
     return XML_ErrorString(errno)[:200]
 
+ at builtinify
 def ParserCreate(encoding=None, namespace_separator=None, intern=None):
     if (not isinstance(encoding, str) and
         not encoding is None):

Modified: pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/test_hashlib.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/test_hashlib.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/test_hashlib.py	Sat Dec 11 15:10:15 2010
@@ -2,10 +2,20 @@
 from ..ctypes_config_cache import rebuild
 rebuild.rebuild_one('hashlib.ctc.py')
 
+from . import hack___pypy__
 from .. import hashlib, _hashlib
 
 def test_unicode():
-    assert isinstance(hashlib.new('sha1', u'xxx'), _hashlib.hash)
+    assert isinstance(hashlib.new('sha256', u'xxx'), _hashlib.hash)
+
+pure_python_version = {
+    'md5': 'md5.new',
+    'sha1': 'sha.new',
+    'sha224': '_sha256.sha224',
+    'sha256': '_sha256.sha256',
+    'sha384': '_sha512.sha384',
+    'sha512': '_sha512.sha512',
+    }
 
 def test_attributes():
     for name, expected_size in {'md5': 16,
@@ -30,7 +40,10 @@
         assert hexdigest == h.hexdigest()
 
         # also test the pure Python implementation
-        h = hashlib.__get_builtin_constructor(name)('')
+        modname, constructor = pure_python_version[name].split('.')
+        mod = __import__('lib_pypy.' + modname, None, None, ['__doc__'])
+        builder = getattr(mod, constructor)
+        h = builder('')
         assert h.digest_size == expected_size
         assert h.digestsize == expected_size
         #

Modified: pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/test_structseq.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/test_structseq.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/pypy_test/test_structseq.py	Sat Dec 11 15:10:15 2010
@@ -1,6 +1,6 @@
 from __future__ import absolute_import
 import py
-from .._structseq import *
+from .._structseq import structseqfield, structseqtype
 
 
 class mydata:

Modified: pypy/branch/jit-unroll-loops/lib_pypy/readline.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/readline.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/readline.py	Sat Dec 11 15:10:15 2010
@@ -6,8 +6,4 @@
 are only stubs at the moment.
 """
 
-# Note that PyPy contains also a built-in module 'readline' which will hide
-# this one if compiled in.  However the built-in module is incomplete;
-# don't use it.
-
 from pyrepl.readline import *

Modified: pypy/branch/jit-unroll-loops/lib_pypy/resource.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/resource.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/resource.py	Sat Dec 11 15:10:15 2010
@@ -11,6 +11,10 @@
 from errno import EINVAL, EPERM
 import _structseq
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+
 class error(Exception):
     pass
 
@@ -77,6 +81,7 @@
     ru_nvcsw = _structseq.structseqfield(14)
     ru_nivcsw = _structseq.structseqfield(15)
 
+ at builtinify
 def rlimit_check_bounds(rlim_cur, rlim_max):
     if rlim_cur > rlim_t_max:
         raise ValueError("%d does not fit into rlim_t" % rlim_cur)
@@ -89,6 +94,7 @@
         ("rlim_max", rlim_t),
     )
 
+ at builtinify
 def getrusage(who):
     ru = _struct_rusage()
     ret = _getrusage(who, byref(ru))
@@ -116,6 +122,7 @@
         ru.ru_nivcsw,
         ))
 
+ at builtinify
 def getrlimit(resource):
     if not(0 <= resource < RLIM_NLIMITS):
         return ValueError("invalid resource specified")
@@ -127,6 +134,7 @@
         raise error(errno)
     return (rlim.rlim_cur, rlim.rlim_max)
 
+ at builtinify
 def setrlimit(resource, rlim):
     if not(0 <= resource < RLIM_NLIMITS):
         return ValueError("invalid resource specified")
@@ -143,6 +151,7 @@
         else:
             raise error(errno)
 
+ at builtinify
 def getpagesize():
     pagesize = 0
     if _getpagesize:

Modified: pypy/branch/jit-unroll-loops/lib_pypy/syslog.py
==============================================================================
--- pypy/branch/jit-unroll-loops/lib_pypy/syslog.py	(original)
+++ pypy/branch/jit-unroll-loops/lib_pypy/syslog.py	Sat Dec 11 15:10:15 2010
@@ -15,6 +15,10 @@
 from ctypes_support import standard_c_lib as libc
 from ctypes import c_int, c_char_p
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+
 # Real prototype is:
 # void syslog(int priority, const char *format, ...);
 # But we also need format ("%s") and one format argument (message)
@@ -34,9 +38,11 @@
 _setlogmask.argtypes = (c_int,)
 _setlogmask.restype = c_int
 
+ at builtinify
 def openlog(ident, option, facility):
     _openlog(ident, option, facility)
 
+ at builtinify
 def syslog(arg1, arg2=None):
     if arg2 is not None:
         priority, message = arg1, arg2
@@ -44,15 +50,19 @@
         priority, message = LOG_INFO, arg1
     _syslog(priority, "%s", message)
 
+ at builtinify
 def closelog():
     _closelog()
 
+ at builtinify
 def setlogmask(mask):
     return _setlogmask(mask)
 
+ at builtinify
 def LOG_MASK(pri):
     return (1 << pri)
 
+ at builtinify
 def LOG_UPTO(pri):
     return (1 << (pri + 1)) - 1
 

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/annrpython.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/annrpython.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/annrpython.py	Sat Dec 11 15:10:15 2010
@@ -145,7 +145,7 @@
         classdef.add_source_for_attribute(attr, classdef.classdesc)
         self.bookkeeper
         assert isinstance(s_result, annmodel.SomePBC)
-        olddesc = s_result.descriptions.iterkeys().next()
+        olddesc = s_result.any_description()
         desc = olddesc.bind_self(classdef)
         args = self.bookkeeper.build_args("simple_call", args_s[:])
         desc.consider_call_site(self.bookkeeper, desc.getcallfamily(), [desc],

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/binaryop.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/binaryop.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/binaryop.py	Sat Dec 11 15:10:15 2010
@@ -861,7 +861,7 @@
     def getitem((p, obj)):
         assert False,"ptr %r getitem index not an int: %r" % (p.ll_ptrtype, obj)
 
-    def setitem((p, obj)):
+    def setitem((p, obj), s_value):
         assert False,"ptr %r setitem index not an int: %r" % (p.ll_ptrtype, obj)
 
 class __extend__(pairtype(SomeObject, SomePtr)):

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	Sat Dec 11 15:10:15 2010
@@ -262,7 +262,7 @@
                                             args_s, s_result)
 
     def consider_call_site_for_pbc(self, s_callable, opname, args_s, s_result):
-        descs = s_callable.descriptions.keys()
+        descs = list(s_callable.descriptions)
         if not descs:
             return
         family = descs[0].getcallfamily()
@@ -590,7 +590,7 @@
         assert s_attr.is_constant()
         attr = s_attr.const
 
-        descs = pbc.descriptions.keys()
+        descs = list(pbc.descriptions)
         if not descs:
             return s_ImpossibleValue
 
@@ -633,7 +633,7 @@
         """Analyse a call to a SomePBC() with the given args (list of
         annotations).
         """
-        descs = pbc.descriptions.keys()
+        descs = list(pbc.descriptions)
         if not descs:
             return s_ImpossibleValue
         first = descs[0]

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/description.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/description.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/description.py	Sat Dec 11 15:10:15 2010
@@ -636,6 +636,24 @@
                     return self
         return None
 
+    def maybe_return_immutable_list(self, attr, s_result):
+        # hack: 'x.lst' where lst is listed in _immutable_fields_ as 'lst[*]'
+        # should really return an immutable list as a result.  Implemented
+        # by changing the result's annotation (but not, of course, doing an
+        # actual copy in the rtyper).  Tested in pypy.rpython.test.test_rlist,
+        # test_immutable_list_out_of_instance.
+        search = '%s[*]' % (attr,)
+        cdesc = self
+        while cdesc is not None:
+            if '_immutable_fields_' in cdesc.classdict:
+                if search in cdesc.classdict['_immutable_fields_'].value:
+                    s_result.listdef.never_resize()
+                    s_copy = s_result.listdef.offspring()
+                    s_copy.listdef.mark_as_immutable()
+                    return s_copy
+            cdesc = cdesc.basedesc
+        return s_result     # common case
+
     def consider_call_site(bookkeeper, family, descs, args, s_result):
         from pypy.annotation.model import SomeInstance, SomePBC, s_None
         if len(descs) == 1:
@@ -654,7 +672,7 @@
             if isinstance(s_init, SomePBC):
                 assert len(s_init.descriptions) == 1, (
                     "unexpected dynamic __init__?")
-                initfuncdesc = s_init.descriptions.keys()[0]
+                initfuncdesc, = s_init.descriptions
                 if isinstance(initfuncdesc, FunctionDesc):
                     initmethdesc = bookkeeper.getmethoddesc(initfuncdesc,
                                                             classdef,
@@ -782,8 +800,8 @@
                                                         desc.selfclassdef,
                                                         desc.name,
                                                         commonflags)
-                del descs[desc]
-                descs[newdesc] = None
+                descs.remove(desc)
+                descs.add(newdesc)
 
         # --- case 1 ---
         groups = {}
@@ -798,7 +816,7 @@
                     for desc2 in group:
                         cdef2 = desc2.selfclassdef
                         if cdef1 is not cdef2 and cdef1.issubclass(cdef2):
-                            del descs[desc1]
+                            descs.remove(desc1)
                             break
     simplify_desc_set = staticmethod(simplify_desc_set)
 

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/listdef.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/listdef.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/listdef.py	Sat Dec 11 15:10:15 2010
@@ -6,11 +6,16 @@
 class TooLateForChange(Exception):
     pass
 
+class ListChangeUnallowed(Exception):
+    pass
+
 class ListItem(object):
     mutated = False    # True for lists mutated after creation
     resized = False    # True for lists resized after creation
     range_step = None  # the step -- only for lists only created by a range()
     dont_change_any_more = False   # set to True when too late for changes
+    immutable = False  # for getattr out of _immutable_fields_ = ['attr[*]']
+    must_not_resize = False   # make_sure_not_resized()
 
     # what to do if range_step is different in merge.
     # - if one is a list (range_step is None), unify to a list.
@@ -26,7 +31,6 @@
         self.bookkeeper = bookkeeper
         self.itemof = {}  # set of all ListDefs using this ListItem
         self.read_locations = {}
-        self.dont_resize = False
         if bookkeeper is None:
             self.dont_change_any_more = True
 
@@ -34,12 +38,15 @@
         if not self.mutated:
             if self.dont_change_any_more:
                 raise TooLateForChange
+            self.immutable = False
             self.mutated = True
 
     def resize(self):
         if not self.resized:
-            if self.dont_change_any_more or self.dont_resize:
+            if self.dont_change_any_more:
                 raise TooLateForChange
+            if self.must_not_resize:
+                raise ListChangeUnallowed("resizing list")
             self.resized = True
 
     def setrangestep(self, step):
@@ -63,11 +70,13 @@
                     # things more general
                     self, other = other, self
 
-            if other.dont_resize:
-                if self.resized:                    
-                    raise TooLateForChange()
-                self.dont_resize = True
-            if other.mutated: self.mutate()
+            self.immutable &= other.immutable
+            if other.must_not_resize:
+                if self.resized:
+                    raise ListChangeUnallowed("list merge with a resized")
+                self.must_not_resize = True
+            if other.mutated:
+                self.mutate()
             if other.resized:
                 self.resize()
             if other.range_step != self.range_step:
@@ -176,9 +185,11 @@
         self.listitem.generalize(s_value)
 
     def __repr__(self):
-        return '<[%r]%s%s>' % (self.listitem.s_value,
+        return '<[%r]%s%s%s%s>' % (self.listitem.s_value,
                                self.listitem.mutated and 'm' or '',
-                               self.listitem.resized and 'r' or '')
+                               self.listitem.resized and 'r' or '',
+                               self.listitem.immutable and 'I' or '',
+                               self.listitem.must_not_resize and '!R' or '')
 
     def mutate(self):
         self.listitem.mutate()
@@ -189,13 +200,20 @@
 
     def never_resize(self):
         if self.listitem.resized:
-            raise TooLateForChange()
-        self.listitem.dont_resize = True
+            raise ListChangeUnallowed("list already resized")
+        self.listitem.must_not_resize = True
 
-    def never_mutate(self):
-        if self.listitem.resized or self.listitem.mutated:
-            raise TooLateForChange()
-        self.listitem.dont_change_any_more = True
+    def mark_as_immutable(self):
+        # Sets the 'immutable' flag.  Note that unlike "never resized",
+        # the immutable flag is only a hint.  It is cleared again e.g.
+        # when we merge with a "normal" list that doesn't have it.  It
+        # is thus expected to live only shortly, mostly for the case
+        # of writing 'x.list[n]'.
+        self.never_resize()
+        if not self.listitem.mutated:
+            self.listitem.immutable = True
+        #else: it's fine, don't set immutable=True at all (see
+        #      test_can_merge_immutable_list_with_regular_list)
 
 MOST_GENERAL_LISTDEF = ListDef(None, SomeObject())
 

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/model.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/model.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/model.py	Sat Dec 11 15:10:15 2010
@@ -356,8 +356,8 @@
     immutable = True
 
     def __init__(self, descriptions, can_be_None=False, subset_of=None):
-        # descriptions is a set of Desc instances.
-        descriptions = dict.fromkeys(descriptions)
+        # descriptions is a set of Desc instances
+        descriptions = set(descriptions)
         self.descriptions = descriptions
         self.can_be_None = can_be_None
         self.subset_of = subset_of
@@ -379,6 +379,9 @@
                 if desc.pyobj is not None:
                     self.const = desc.pyobj
 
+    def any_description(self):
+        return iter(self.descriptions).next()
+
     def getKind(self):
         "Return the common Desc class of all descriptions in this PBC."
         kinds = {}

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/specialize.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/specialize.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/specialize.py	Sat Dec 11 15:10:15 2010
@@ -345,7 +345,8 @@
             key.append(s.const)
         elif isinstance(s, SomePBC) and len(s.descriptions) == 1:
             # for test_specialize_arg_bound_method
-            key.append(s.descriptions.keys()[0])
+            desc, = s.descriptions
+            key.append(desc)
         else:
             raise Exception("specialize:arg(%d): argument not constant: %r"
                             % (i, s))

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/test/test_annrpython.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/test/test_annrpython.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/test/test_annrpython.py	Sat Dec 11 15:10:15 2010
@@ -10,7 +10,7 @@
 from pypy.translator.translator import graphof as tgraphof
 from pypy.annotation import policy
 from pypy.annotation import specialize
-from pypy.annotation.listdef import ListDef, TooLateForChange
+from pypy.annotation.listdef import ListDef, ListChangeUnallowed
 from pypy.annotation.dictdef import DictDef
 from pypy.objspace.flow.model import *
 from pypy.rlib.rarithmetic import r_uint, base_int, r_longlong, r_ulonglong
@@ -1010,7 +1010,7 @@
         bookkeeper = a.bookkeeper
 
         def getmdesc(bmeth):
-            return bookkeeper.immutablevalue(bmeth).descriptions.keys()[0]
+            return bookkeeper.immutablevalue(bmeth).any_description()
 
         mdescA_m = getmdesc(A().m)
         mdescC_m = getmdesc(C().m)
@@ -2862,7 +2862,7 @@
         assert s.items[0].flags == {'access_directly': True}
         assert isinstance(s.items[1], annmodel.SomePBC)
         assert len(s.items[1].descriptions) == 1
-        assert s.items[1].descriptions.keys()[0].flags == {'access_directly':
+        assert s.items[1].any_description().flags == {'access_directly':
                                                            True}
         assert isinstance(s.items[2], annmodel.SomeInstance)
         assert s.items[2].flags == {'access_directly': True}
@@ -3206,7 +3206,7 @@
             l.append(4)
 
         a = self.RPythonAnnotator()
-        py.test.raises(TooLateForChange, a.build_types, g, [])
+        py.test.raises(ListChangeUnallowed, a.build_types, g, [])
         assert called
 
     def test_listitem_no_mutating2(self):
@@ -3229,7 +3229,7 @@
 
         a = self.RPythonAnnotator()
         a.translator.config.translation.list_comprehension_operations = True
-        py.test.raises(TooLateForChange, a.build_types, fn, [int])
+        py.test.raises(ListChangeUnallowed, a.build_types, fn, [int])
 
     def test_listitem_never_resize(self):
         from pypy.rlib.debug import check_annotation
@@ -3243,7 +3243,7 @@
             check_annotation(l, checker)
 
         a = self.RPythonAnnotator()
-        py.test.raises(TooLateForChange, a.build_types, f, [])
+        py.test.raises(ListChangeUnallowed, a.build_types, f, [])
 
 
     def test_len_of_empty_list(self):
@@ -3357,6 +3357,87 @@
         # not a constant: both __enter__ and __exit__ have been annotated
         assert not s.is_constant()
 
+    def test_make_sure_not_resized(self):
+        from pypy.rlib.debug import make_sure_not_resized
+
+        def pycode(consts):
+            make_sure_not_resized(consts)
+        def build1():
+            return pycode(consts=[1])
+        def build2():
+            return pycode(consts=[0])
+        def fn():
+            build1()
+            build2()
+
+        a = self.RPythonAnnotator()
+        a.translator.config.translation.list_comprehension_operations = True
+        a.build_types(fn, [])
+        # assert did not raise ListChangeUnallowed
+
+    def test_return_immutable_list(self):
+        class A:
+            _immutable_fields_ = 'lst[*]'
+        def f(n):
+            a = A()
+            l1 = [n, 0]
+            l1[1] = n+1
+            a.lst = l1
+            return a.lst
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [int])
+        assert s.listdef.listitem.immutable
+
+    def test_immutable_list_is_actually_resized(self):
+        class A:
+            _immutable_fields_ = 'lst[*]'
+        def f(n):
+            a = A()
+            l1 = [n]
+            l1.append(n+1)
+            a.lst = l1
+            return a.lst
+
+        a = self.RPythonAnnotator()
+        py.test.raises(ListChangeUnallowed, a.build_types, f, [int])
+
+    def test_can_merge_immutable_list_with_regular_list(self):
+        class A:
+            _immutable_fields_ = 'lst[*]'
+        def foo(lst):
+            pass
+
+        def f(n):
+            a = A()
+            l1 = [n, 0]
+            l1[1] = n+1
+            a.lst = l1
+            if n > 0:
+                foo(a.lst)
+            else:
+                lst = [0]
+                lst[0] = n
+                foo(lst)
+
+        a = self.RPythonAnnotator()
+        a.build_types(f, [int])
+
+        def f(n):
+            a = A()
+            l1 = [n, 0]
+            l1[1] = n+1
+            a.lst = l1
+            if n > 0:
+                lst = [0]
+                lst[0] = n
+                foo(lst)
+            else:
+                foo(a.lst)
+
+        a = self.RPythonAnnotator()
+        a.build_types(f, [int])
+
 
 def g(n):
     return [0,1,2,n]

Modified: pypy/branch/jit-unroll-loops/pypy/annotation/unaryop.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/annotation/unaryop.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/annotation/unaryop.py	Sat Dec 11 15:10:15 2010
@@ -615,6 +615,9 @@
                     if basedef.classdesc.all_enforced_attrs is not None:
                         if attr in basedef.classdesc.all_enforced_attrs:
                             raise HarmlesslyBlocked("get enforced attr")
+            elif isinstance(s_result, SomeList):
+                s_result = ins.classdef.classdesc.maybe_return_immutable_list(
+                    attr, s_result)
             return s_result
         return SomeObject()
     getattr.can_only_throw = []

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	Sat Dec 11 15:10:15 2010
@@ -31,7 +31,7 @@
      "crypt", "signal", "_rawffi", "termios", "zlib",
      "struct", "md5", "sha", "bz2", "_minimal_curses", "cStringIO",
      "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
-     "_bisect"]
+     "_bisect", "binascii"]
 ))
 
 translation_modules = default_modules.copy()
@@ -76,6 +76,7 @@
     "_rawffi": [("objspace.usemodules.struct", True)],
     "cpyext": [("translation.secondaryentrypoints", "cpyext"),
                ("translation.shared", sys.platform == "win32")],
+    "_ffi": [("translation.jit_ffi", True)],
     }
 
 module_import_dependencies = {
@@ -161,7 +162,6 @@
                suggests=[("objspace.allworkingmodules", False)]),
 
     BoolOption("geninterp", "specify whether geninterp should be used",
-               cmdline=None,
                default=True),
 
     BoolOption("logbytecodes",

Modified: pypy/branch/jit-unroll-loops/pypy/config/translationoption.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/config/translationoption.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/config/translationoption.py	Sat Dec 11 15:10:15 2010
@@ -3,6 +3,7 @@
 from pypy.config.config import OptionDescription, BoolOption, IntOption, ArbitraryOption, FloatOption
 from pypy.config.config import ChoiceOption, StrOption, to_optparse, Config
 from pypy.config.config import ConfigError
+from pypy.config.support import detect_number_of_processors
 
 DEFL_INLINE_THRESHOLD = 32.4    # just enough to inline add__Int_Int()
 # and just small enough to prevend inlining of some rlist functions.
@@ -113,13 +114,10 @@
     ChoiceOption("jit_backend", "choose the backend for the JIT",
                  ["auto", "x86", "x86-without-sse2", "llvm"],
                  default="auto", cmdline="--jit-backend"),
-    ChoiceOption("jit_debug", "the amount of debugging dumps made by the JIT",
-                 ["off", "profile", "steps", "detailed"],
-                 default="profile",      # XXX for now
-                 cmdline="--jit-debug"),
     ChoiceOption("jit_profiler", "integrate profiler support into the JIT",
                  ["off", "oprofile"],
                  default="off"),
+    BoolOption("jit_ffi", "optimize libffi calls", default=False),
 
     # misc
     BoolOption("verbose", "Print extra information", default=False),
@@ -171,7 +169,7 @@
                default=False, negation=False),
     IntOption("make_jobs", "Specify -j argument to make for compilation"
               " (C backend only)",
-              cmdline="--make-jobs", default=1),
+              cmdline="--make-jobs", default=detect_number_of_processors()),
 
     # Flags of the TranslationContext:
     BoolOption("simplifying", "Simplify flow graphs", default=True),

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	Sat Dec 11 15:10:15 2010
@@ -336,13 +336,15 @@
         self.runtest_finish()
 
     def runtest_open(self):
-        leakfinder.start_tracking_allocations()
+        if not getattr(self.obj, 'dont_track_allocations', False):
+            leakfinder.start_tracking_allocations()
 
     def runtest_perform(self):
         super(PyPyTestFunction, self).runtest()
 
     def runtest_close(self):
-        if leakfinder.TRACK_ALLOCATIONS:
+        if (not getattr(self.obj, 'dont_track_allocations', False)
+            and leakfinder.TRACK_ALLOCATIONS):
             self._pypytest_leaks = leakfinder.stop_tracking_allocations(False)
         else:            # stop_tracking_allocations() already called
             self._pypytest_leaks = None

Modified: pypy/branch/jit-unroll-loops/pypy/doc/cpython_differences.txt
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/doc/cpython_differences.txt	(original)
+++ pypy/branch/jit-unroll-loops/pypy/doc/cpython_differences.txt	Sat Dec 11 15:10:15 2010
@@ -20,16 +20,21 @@
 
     __builtin__
     `__pypy__`_
+    _ast
+    _bisect
     _codecs
     _lsprof
     `_minimal_curses`_
     _random
     `_rawffi`_
+    _ssl
     _socket
     _sre
     _weakref
+    array
     bz2
     cStringIO
+    `cpyext`_
     crypt
     errno
     exceptions
@@ -72,7 +77,7 @@
 
 * Supported by being rewritten in pure Python (possibly using ``ctypes``):
   see the `lib_pypy/`_ directory.  Examples of modules that we
-  support this way: ``ctypes``, ``array``, ``cPickle``,
+  support this way: ``ctypes``, ``cPickle``,
   ``cStringIO``, ``cmath``, ``dbm`` (?), ``datetime``, ``binascii``...  
   Note that some modules are both in there and in the list above;
   by default, the built-in module is used (but can be disabled
@@ -80,11 +85,13 @@
 
 The extension modules (i.e. modules written in C, in the standard CPython)
 that are neither mentioned above nor in `lib_pypy/`_ are not available in PyPy.
+(You may have a chance to use them anyway with `cpyext`_.)
 
 .. the nonstandard modules are listed below...
 .. _`__pypy__`: __pypy__-module.html
 .. _`_rawffi`: ctypes-implementation.html
 .. _`_minimal_curses`: config/objspace.usemodules._minimal_curses.html
+.. _`cpyext`: http://morepypy.blogspot.com/2010/04/using-cpython-extension-modules-with.html
 .. _Stackless: stackless.html
 
 
@@ -129,12 +136,10 @@
 .. __: http://morepypy.blogspot.com/2008/02/python-finalizers-semantics-part-1.html
 .. __: http://morepypy.blogspot.com/2008/02/python-finalizers-semantics-part-2.html
 
-The built-in function ``id()`` returns numbers that are not addresses
-for most of PyPy's garbage collectors.
-This is most visible in the default repr: a typical PyPy object can
-pretend to be located ``at 0x00000009``.  This is just its ``id()``, not
-its real address (because an object can move around in some GCs). Calling
-``id`` a lot can lead to performance problem.
+Using the default GC called ``minimark``, the built-in function ``id()``
+works like it does in CPython.  With other GCs it returns numbers that
+are not real addresses (because an object can move around several times)
+and calling it a lot can lead to performance problem.
 
 Note that if you have a long chain of objects, each with a reference to
 the next one, and each with a __del__, PyPy's GC will perform badly.  On

Modified: pypy/branch/jit-unroll-loops/pypy/doc/faq.txt
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/doc/faq.txt	(original)
+++ pypy/branch/jit-unroll-loops/pypy/doc/faq.txt	Sat Dec 11 15:10:15 2010
@@ -47,7 +47,7 @@
 
 There is also an experimental support for CPython extension modules, so
 they'll run without change (from current observation, rather with little
-change) on trunk. It has been a part of 1.3 release, but support is still
+change) on trunk. It has been a part of 1.4 release, but support is still
 in alpha phase.
 
 .. _`extension modules`: cpython_differences.html#extension-modules

Modified: pypy/branch/jit-unroll-loops/pypy/doc/index.txt
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/doc/index.txt	(original)
+++ pypy/branch/jit-unroll-loops/pypy/doc/index.txt	Sat Dec 11 15:10:15 2010
@@ -8,7 +8,7 @@
 Getting into PyPy ... 
 =============================================
 
-* `Release 1.3`_: the latest official release
+* `Release 1.4`_: the latest official release
 
 * `PyPy Blog`_: news and status info about PyPy 
 
@@ -56,4 +56,4 @@
 .. _`Documentation`: docindex.html 
 .. _`Getting Started`: getting-started.html
 .. _papers: extradoc.html
-.. _`Release 1.3`: http://pypy.org/download.html
+.. _`Release 1.4`: http://pypy.org/download.html

Modified: pypy/branch/jit-unroll-loops/pypy/doc/release-1.4.0.txt
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/doc/release-1.4.0.txt	(original)
+++ pypy/branch/jit-unroll-loops/pypy/doc/release-1.4.0.txt	Sat Dec 11 15:10:15 2010
@@ -2,27 +2,58 @@
 PyPy 1.4: Ouroboros in practice
 ===============================
 
-Hello.
-
 We're pleased to announce the 1.4 release of PyPy. This is a major breakthrough
 in our long journey, as PyPy 1.4 is the first PyPy release that can translate
-itself faster than CPython. Starting today, we plan to start using PyPy for our
-own development.
+itself faster than CPython.  Starting today, we are using PyPy more for
+our every-day development.  So may you :) You can download it here:
+
+    http://pypy.org/download.html
+
+What is PyPy
+============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement
+for CPython. It's fast (`pypy 1.4 and cpython 2.6`_ comparison)
 
-Among other features, this release includes numerous performance improvements
-(which made fast self-hosting possible), a 64-bit JIT backend, as well as serious
-stabilization. As of now, we can consider the 32-bit version of PyPy stable enough
-to run in production.
+Among its new features, this release includes numerous performance improvements
+(which made fast self-hosting possible), a 64-bit JIT backend, as well
+as serious stabilization. As of now, we can consider the 32-bit and 64-bit
+linux versions of PyPy stable enough to run `in production`_.
+
+Numerous speed achievements are described on `our blog`_. Normalized speed
+charts comparing `pypy 1.4 and pypy 1.3`_ as well as `pypy 1.4 and cpython 2.6`_
+are available on benchmark website. For the impatient: yes, we got a lot faster!
 
 More highlights
 ===============
 
-* Virtualenv support: now PyPy is fully compatible with virtualenv_: note that
+* PyPy's built-in Just-in-Time compiler is fully transparent and
+  automatically generated; it now also has very reasonable memory
+  requirements.  The total memory used by a very complex and
+  long-running process (translating PyPy itself) is within 1.5x to
+  at most 2x the memory needed by CPython, for a speed-up of 2x.
+
+* More compact instances.  All instances are as compact as if
+  they had ``__slots__``.  This can give programs a big gain in
+  memory.  (In the example of translation above, we already have
+  carefully placed ``__slots__``, so there is no extra win.)
+
+* `Virtualenv support`_: now PyPy is fully compatible with virtualenv_: note that
   to use it, you need a recent version of virtualenv (>= 1.5).
 
 * Faster (and JITted) regular expressions - huge boost in speeding up
-  sre module.
+  the `re` module.
 
-* Faster (and JITted) calls to functions like map().
+* Other speed improvements, like JITted calls to functions like map().
 
 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
+.. _`Virtualenv support`: http://morepypy.blogspot.com/2010/08/using-virtualenv-with-pypy.html
+.. _`in production`: http://morepypy.blogspot.com/2010/11/running-large-radio-telescope-software.html
+.. _`our blog`: http://morepypy.blogspot.com
+.. _`pypy 1.4 and pypy 1.3`: http://speed.pypy.org/comparison/?exe=1%2B41,1%2B172&ben=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20&env=1&hor=false&bas=1%2B41&chart=normal+bars
+.. _`pypy 1.4 and cpython 2.6`: http://speed.pypy.org/comparison/?exe=2%2B35,1%2B172&ben=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20&env=1&hor=false&bas=2%2B35&chart=normal+bars
+
+Cheers,
+
+Carl Friedrich Bolz, Antonio Cuni, Maciej Fijalkowski,
+Amaury Forgeot d'Arc, Armin Rigo and the PyPy team

Modified: pypy/branch/jit-unroll-loops/pypy/doc/sprint-reports.txt
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/doc/sprint-reports.txt	(original)
+++ pypy/branch/jit-unroll-loops/pypy/doc/sprint-reports.txt	Sat Dec 11 15:10:15 2010
@@ -30,6 +30,17 @@
   * `Düsseldorf (October 2006)`_
   * `Leysin (January 2007)`_
   * `Hildesheim (Feb 2007)`_ (also `EU report writing sprint`_)
+  * `Göteborg (November 2007)`_
+  * `Leysin (January 2008)`_
+  * `Berlin (May 2008)`_
+  * `Vilnius after EuroPython (July 2008)`_
+  * `Düsseldorf (August 2008)`_
+  * `Wroclaw (February 2009)`_
+  * `Leysin (April 2009)`_
+  * `Göteborg (August 2009)`_
+  * `Düsseldorf (November 2009)`_
+  * `CERN (July 2010)`_
+  * `Düsseldorf (October 2010)`_
 
     .. _Hildesheim (Feb 2003): http://codespeak.net/pypy/extradoc/sprintinfo/HildesheimReport.html
     .. _Gothenburg (May 2003): http://codespeak.net/pypy/extradoc/sprintinfo/gothenburg-2003-sprintreport.txt
@@ -55,3 +66,15 @@
     .. _Hildesheim (Feb 2007): http://codespeak.net/pypy/extradoc/sprintinfo/trillke-2007/sprint-report.txt
     .. _`EU report writing sprint`: http://codespeak.net/pypy/extradoc/sprintinfo/trillke-2007/eu-report-sprint-report.txt
     .. _`PyCon/Dallas (Feb 2006)`: http://codespeak.net/pypy/extradoc/sprintinfo/pycon06/sprint-report.txt
+    .. _`Göteborg (November 2007)`: http://morepypy.blogspot.com/2007_11_01_archive.html
+    .. _`Leysin (January 2008)`: http://morepypy.blogspot.com/2008/01/leysin-winter-sport-sprint-started.html
+    .. _`Berlin (May 2008)`: http://morepypy.blogspot.com/2008_05_01_archive.html
+    .. _`Vilnius after EuroPython (July 2008)`: http://morepypy.blogspot.com/2008/07/europython-2008-pypy-talks-and-sprint.html
+    .. _`Düsseldorf (August 2008)`: http://morepypy.blogspot.com/2008_10_01_archive.html
+    .. _`Wroclaw (February 2009)`: http://morepypy.blogspot.com/2009/02/wroclaw-2009-sprint-progress-report.html
+    .. _`Leysin (April 2009)`: http://morepypy.blogspot.com/2009/04/leysin-sprint-report.html
+    .. _`Göteborg (August 2009)`: http://morepypy.blogspot.com/2009/08/gothenburg-jit-sprint-report.html
+    .. _`Düsseldorf (November 2009)`: http://morepypy.blogspot.com/2009/11/dusseldorf-sprint-report.html
+    .. _`CERN (July 2010)`: http://morepypy.blogspot.com/2010/07/cern-sprint-report-wrapping-c-libraries.html
+    .. _`Düsseldorf (October 2010)`: http://morepypy.blogspot.com/2010/10/dusseldorf-sprint-report-2010.html
+

Modified: pypy/branch/jit-unroll-loops/pypy/doc/statistic/release_dates.dat
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/doc/statistic/release_dates.dat	(original)
+++ pypy/branch/jit-unroll-loops/pypy/doc/statistic/release_dates.dat	Sat Dec 11 15:10:15 2010
@@ -7,3 +7,7 @@
 2006-06-25,"PyPy 0.9"
 2007-02-17,"PyPy 0.99"
 2007-03-27,"PyPy 1.0"
+2009-04-28,"PyPy 1.1"
+2010-03-12,"PyPy 1.2"
+2010-06-26,"PyPy 1.3"
+2010-11-26,"PyPy 1.4"

Modified: pypy/branch/jit-unroll-loops/pypy/doc/statistic/sprint_dates.dat
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/doc/statistic/sprint_dates.dat	(original)
+++ pypy/branch/jit-unroll-loops/pypy/doc/statistic/sprint_dates.dat	Sat Dec 11 15:10:15 2010
@@ -1,26 +1,39 @@
 PyPy sprints
 location, begin, end
 "Hildesheim",2003-02-17,2003-02-23
-"Gothenburg",2003-05-24,2003-05-31
-"LovainLaNeuve",2003-06-21,2003-06-24
+"Göteborg",2003-05-24,2003-05-31
+"Louvain-la-Neuve",2003-06-21,2003-06-24
 "Berlin",2003-09-29,2003-10-04
 "Amsterdam",2003-12-14,2003-12-21
-"Europython/Gothenburg",2004-06-01,2004-06-07
+"Europython/Göteborg",2004-06-01,2004-06-07
 "Vilnius",2004-11-15,2004-11-23
 "Leysin",2005-01-22,2005-01-29
 "PyCon/Washington",2005-03-19,2005-03-22
-"Europython/Gothenburg",2005-07-01,2005-07-07
+"Europython/Göteborg",2005-07-01,2005-07-07
 "Hildesheim",2005-07-25,2005-07-31
 "Heidelberg",2005-08-22,2005-08-29
 "Paris",2005-10-10,2005-10-16
-"Gothenburg",2005-12-05,2005-12-11
+"Göteborg",2005-12-05,2005-12-11
 "Mallorca",2006-01-23,2006-01-29
 "Pycon/Dallas",2006-02-27,2006-03-02
 "Louvain-la-Neuve",2006-03-06,2006-03-10
 "Japan",2006-04-23,2006-04-29
-"Duesseldorf",2006-06-02,2006-06-09
+"Düsseldorf",2006-06-02,2006-06-09
 "Europython/Genf",2006-07-06,2006-07-09
 "Limerick",2006-08-21,2006-08-27
-"Duesseldorf",2006-10-30,2006-11-05
+"Düsseldorf",2006-10-30,2006-11-05
 "Leysin",2007-01-08,2007-01-14
 "Hildesheim",2007-03-01,2007-03-05
+"Hildesheim",2007-03-18,2007-03-23
+"Bern",2007-10-22,2007-10-26
+"Göteborg",2007-11-19,2007-11-25
+"Leysin",2008-01-12,2008-01-19
+"Berlin",2008-05-17,2008-05-22
+"EuroPython/Vilnius",2008-07-10,2008-07-12
+"Düsseldorf",2008-08-05,2008-08-13
+"Wroclaw",2009-02-07,2009-02-14
+"Leysin",2009-04-14,2009-04-21
+"Göteborg",2009-08-18,2009-08-25
+"Düsseldorf",2009-11-06,2009-11-13
+"CERN",2010-07-05,2010-07-09
+"Düsseldorf",2010-10-25,2010-10-31

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	Sat Dec 11 15:10:15 2010
@@ -402,9 +402,10 @@
         space = self.space
         w_args = space.newtuple(self.arguments_w)
         w_kwds = space.newdict()
-        for i in range(len(self.keywords)):
-            space.setitem(w_kwds, space.wrap(self.keywords[i]),
-                                  self.keywords_w[i])
+        if self.keywords is not None:
+            for i in range(len(self.keywords)):
+                space.setitem(w_kwds, space.wrap(self.keywords[i]),
+                                      self.keywords_w[i])
         return w_args, w_kwds
 
 class ArgumentsForTranslation(Arguments):

Modified: pypy/branch/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	Sat Dec 11 15:10:15 2010
@@ -147,7 +147,7 @@
 
     __already_enqueued_for_destruction = False
 
-    def _enqueue_for_destruction(self, space):
+    def _enqueue_for_destruction(self, space, call_user_del=True):
         """Put the object in the destructor queue of the space.
         At a later, safe point in time, UserDelAction will use
         space.userdel() to call the object's app-level __del__ method.
@@ -160,7 +160,8 @@
                 return
             self.__already_enqueued_for_destruction = True
         self.clear_all_weakrefs()
-        space.user_del_action.register_dying_object(self)
+        if call_user_del:
+            space.user_del_action.register_dying_object(self)
 
     def _call_builtin_destructor(self):
         pass     # method overridden in typedef.py
@@ -861,14 +862,14 @@
 
     def call_args_and_c_profile(self, frame, w_func, args):
         ec = self.getexecutioncontext()
-        ec.c_call_trace(frame, w_func)
+        ec.c_call_trace(frame, w_func, args)
         try:
             w_res = self.call_args(w_func, args)
         except OperationError, e:
             w_value = e.get_w_value(self)
             ec.c_exception_trace(frame, w_value)
             raise
-        ec.c_return_trace(frame, w_func)
+        ec.c_return_trace(frame, w_func, args)
         return w_res
 
     def call_method(self, w_obj, methname, *arg_w):
@@ -1182,6 +1183,27 @@
                                  self.wrap("expected a 32-bit integer"))
         return value
 
+    def c_filedescriptor_w(self, w_fd):
+        try:
+            fd = self.c_int_w(w_fd)
+        except OperationError, e:
+            if not e.match(self, self.w_TypeError):
+                raise
+            try:
+                w_fileno = self.getattr(w_fd, self.wrap('fileno'))
+            except OperationError, e:
+                if e.match(self, self.w_AttributeError):
+                    raise OperationError(self.w_TypeError,
+                        self.wrap("argument must be an int, "
+                                  "or have a fileno() method."))
+                raise
+            w_fd = self.call_function(w_fileno)
+            fd = self.c_int_w(w_fd)
+        if fd < 0:
+            raise operationerrfmt(self.w_ValueError,
+                "file descriptor cannot be a negative integer (%d)", fd)
+        return fd
+
     def warn(self, msg, w_warningcls):
         self.appexec([self.wrap(msg), w_warningcls], """(msg, warningcls):
             import warnings

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	Sat Dec 11 15:10:15 2010
@@ -27,7 +27,6 @@
     def __init__(self, space):
         self.space = space
         self.topframeref = jit.vref_None
-        self.framestackdepth = 0
         # tracing: space.frame_trace_action.fire() must be called to ensure
         # that tracing occurs whenever self.w_tracefunc or self.is_tracing
         # is modified.
@@ -54,9 +53,6 @@
         return frame
 
     def enter(self, frame):
-        if self.framestackdepth > self.space.sys.recursionlimit:
-            raise self.space.prebuilt_recursion_error
-        self.framestackdepth += 1
         frame.f_backref = self.topframeref
         self.topframeref = jit.virtual_ref(frame)
 
@@ -66,7 +62,6 @@
                 self._trace(frame, 'leaveframe', self.space.w_None)
         finally:
             self.topframeref = frame.f_backref
-            self.framestackdepth -= 1
             jit.virtual_ref_finish(frame)
 
         if self.w_tracefunc is not None and not frame.hide():
@@ -80,7 +75,6 @@
 
         def __init__(self):
             self.topframe = None
-            self.framestackdepth = 0
             self.w_tracefunc = None
             self.profilefunc = None
             self.w_profilefuncarg = None
@@ -88,7 +82,6 @@
 
         def enter(self, ec):
             ec.topframeref = jit.non_virtual_ref(self.topframe)
-            ec.framestackdepth = self.framestackdepth
             ec.w_tracefunc = self.w_tracefunc
             ec.profilefunc = self.profilefunc
             ec.w_profilefuncarg = self.w_profilefuncarg
@@ -97,7 +90,6 @@
 
         def leave(self, ec):
             self.topframe = ec.gettopframe()
-            self.framestackdepth = ec.framestackdepth
             self.w_tracefunc = ec.w_tracefunc
             self.profilefunc = ec.profilefunc
             self.w_profilefuncarg = ec.w_profilefuncarg 
@@ -105,7 +97,6 @@
 
         def clear_framestack(self):
             self.topframe = None
-            self.framestackdepth = 0
 
         # the following interface is for pickling and unpickling
         def getstate(self, space):
@@ -121,33 +112,41 @@
                 self.topframe = space.interp_w(PyFrame, frames_w[-1])
             else:
                 self.topframe = None
-            self.framestackdepth = len(frames_w)
 
         def getframestack(self):
-            index = self.framestackdepth
-            lst = [None] * index
+            lst = []
             f = self.topframe
-            while index > 0:
-                index -= 1
-                lst[index] = f
+            while f is not None:
+                lst.append(f)
                 f = f.f_backref()
-            assert f is None
+            lst.reverse()
             return lst
         # coroutine: I think this is all, folks!
 
-    def c_call_trace(self, frame, w_func):
+    def c_call_trace(self, frame, w_func, args=None):
         "Profile the call of a builtin function"
-        if self.profilefunc is None:
-            frame.is_being_profiled = False
-        else:
-            self._trace(frame, 'c_call', w_func)
+        self._c_call_return_trace(frame, w_func, args, 'c_call')
 
-    def c_return_trace(self, frame, w_retval):
+    def c_return_trace(self, frame, w_func, args=None):
         "Profile the return from a builtin function"
+        self._c_call_return_trace(frame, w_func, args, 'c_return')
+
+    def _c_call_return_trace(self, frame, w_func, args, event):
         if self.profilefunc is None:
             frame.is_being_profiled = False
         else:
-            self._trace(frame, 'c_return', w_retval)
+            # undo the effect of the CALL_METHOD bytecode, which would be
+            # that even on a built-in method call like '[].append()',
+            # w_func is actually the unbound function 'append'.
+            from pypy.interpreter.function import FunctionWithFixedCode
+            if isinstance(w_func, FunctionWithFixedCode) and args is not None:
+                w_firstarg = args.firstarg()
+                if w_firstarg is not None:
+                    from pypy.interpreter.function import descr_function_get
+                    w_func = descr_function_get(self.space, w_func, w_firstarg,
+                                                self.space.type(w_firstarg))
+            #
+            self._trace(frame, event, w_func)
 
     def c_exception_trace(self, frame, w_exc):
         "Profile function called upon OperationError."

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/function.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/function.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/function.py	Sat Dec 11 15:10:15 2010
@@ -48,7 +48,7 @@
         return "<%s %s>" % (self.__class__.__name__, name)
 
     def call_args(self, args):
-        # delegate activation to code        
+        # delegate activation to code
         return self.getcode().funcrun(self, args)
 
     def call_obj_args(self, w_obj, args):
@@ -61,17 +61,17 @@
                 return _get_immutable_code(self)
             return jit.hint(self.code, promote=True)
         return self.code
-    
+
     def funccall(self, *args_w): # speed hack
         from pypy.interpreter import gateway
         from pypy.interpreter.pycode import PyCode
-        
+
         code = self.getcode() # hook for the jit
         nargs = len(args_w)
         fast_natural_arity = code.fast_natural_arity
         if nargs == fast_natural_arity:
             if nargs == 0:
-                assert isinstance(code, gateway.BuiltinCode0)                
+                assert isinstance(code, gateway.BuiltinCode0)
                 return code.fastcall_0(self.space, self)
             elif nargs == 1:
                 assert isinstance(code, gateway.BuiltinCode1)
@@ -80,22 +80,22 @@
                 assert isinstance(code, gateway.BuiltinCode2)
                 return code.fastcall_2(self.space, self, args_w[0], args_w[1])
             elif nargs == 3:
-                assert isinstance(code, gateway.BuiltinCode3)                
+                assert isinstance(code, gateway.BuiltinCode3)
                 return code.fastcall_3(self.space, self, args_w[0],
                                        args_w[1], args_w[2])
             elif nargs == 4:
-                assert isinstance(code, gateway.BuiltinCode4)                
+                assert isinstance(code, gateway.BuiltinCode4)
                 return code.fastcall_4(self.space, self, args_w[0],
                                        args_w[1], args_w[2], args_w[3])
         elif (nargs|PyCode.FLATPYCALL) == fast_natural_arity:
-            assert isinstance(code, PyCode)            
+            assert isinstance(code, PyCode)
             if nargs < 5:
                 new_frame = self.space.createframe(code, self.w_func_globals,
                                                    self.closure)
                 for i in funccallunrolling:
                     if i < nargs:
                         new_frame.fastlocals_w[i] = args_w[i]
-                return new_frame.run()                                    
+                return new_frame.run()
         elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1:
             assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
             return code.funcrun_obj(self, args_w[0],
@@ -106,9 +106,9 @@
     def funccall_valuestack(self, nargs, frame): # speed hack
         from pypy.interpreter import gateway
         from pypy.interpreter.pycode import PyCode
-            
+
         code = self.getcode() # hook for the jit
-        fast_natural_arity = code.fast_natural_arity        
+        fast_natural_arity = code.fast_natural_arity
         if nargs == fast_natural_arity:
             if nargs == 0:
                 assert isinstance(code, gateway.BuiltinCode0)
@@ -143,7 +143,7 @@
             w_obj = frame.peekvalue(nargs-1)
             args = frame.make_arguments(nargs-1)
             return code.funcrun_obj(self, w_obj, args)
-                    
+
         args = frame.make_arguments(nargs)
         return self.call_args(args)
 
@@ -155,8 +155,8 @@
         for i in xrange(nargs):
             w_arg = frame.peekvalue(nargs-1-i)
             new_frame.fastlocals_w[i] = w_arg
-            
-        return new_frame.run()                        
+
+        return new_frame.run()
 
     @jit.unroll_safe
     def _flat_pycall_defaults(self, code, nargs, frame, defs_to_load):
@@ -166,7 +166,7 @@
         for i in xrange(nargs):
             w_arg = frame.peekvalue(nargs-1-i)
             new_frame.fastlocals_w[i] = w_arg
-            
+
         defs_w = self.defs_w
         ndefs = len(defs_w)
         start = ndefs-defs_to_load
@@ -174,7 +174,7 @@
         for j in xrange(start, ndefs):
             new_frame.fastlocals_w[i] = defs_w[j]
             i += 1
-        return new_frame.run()                        
+        return new_frame.run()
 
     def getdict(self):
         if self.w_func_dict is None:
@@ -188,7 +188,7 @@
 
     # unwrapping is done through unwrap_specs in typedef.py
 
-    def descr_function__new__(space, w_subtype, w_code, w_globals, 
+    def descr_function__new__(space, w_subtype, w_code, w_globals,
                             w_name=None, w_argdefs=None, w_closure=None):
         code = space.interp_w(Code, w_code)
         if not space.is_true(space.isinstance(w_globals, space.w_dict)):
@@ -229,7 +229,7 @@
         return self.getrepr(self.space, 'function %s' % (self.name,))
 
 
-    # delicate   
+    # delicate
     _all = {'': None}
 
     def _freeze_(self):
@@ -260,7 +260,7 @@
             new_inst = mod.get('builtin_function')
             return space.newtuple([new_inst,
                                    space.newtuple([space.wrap(code.identifier)])])
-            
+
         new_inst = mod.get('func_new')
         w        = space.wrap
         if self.closure is None:
@@ -524,7 +524,7 @@
         space = self.space
         other = space.interpclass_w(w_other)
         if not isinstance(other, Method):
-            return space.w_False
+            return space.w_NotImplemented
         if self.w_instance is None:
             if other.w_instance is not None:
                 return space.w_False
@@ -562,7 +562,7 @@
         else:
             tup = [self.w_function, w_instance, self.w_class]
         return space.newtuple([new_inst, space.newtuple(tup)])
-        
+
 class StaticMethod(Wrappable):
     """The staticmethod objects."""
     _immutable_ = True
@@ -612,11 +612,9 @@
         self.w_func_dict = func.w_func_dict
         self.w_module = func.w_module
 
-    def descr_builtinfunction__new__(space, w_subtype, w_func):
-        func = space.interp_w(Function, w_func)
-        bltin = space.allocate_instance(BuiltinFunction, w_subtype)
-        BuiltinFunction.__init__(bltin, func)
-        return space.wrap(bltin)
+    def descr_builtinfunction__new__(space, w_subtype):
+        raise OperationError(space.w_TypeError,
+                     space.wrap("cannot create 'builtin_function' instances"))
 
     def descr_function_repr(self):
         return self.space.wrap('<built-in function %s>' % (self.name,))

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/gateway.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/gateway.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/gateway.py	Sat Dec 11 15:10:15 2010
@@ -1083,7 +1083,7 @@
             # these decorators are known to return the same function
             # object, we may ignore them
             assert '\n' in source
-            source = source[source.find('\n') + 1:]
+            source = source[source.find('\n') + 1:].lstrip()
         assert source.startswith("def "), "can only transform functions" 
         source = source[4:]
     p = source.find('(')

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/generator.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/generator.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/generator.py	Sat Dec 11 15:10:15 2010
@@ -10,7 +10,7 @@
     
     def __init__(self, frame):
         self.space = frame.space
-        self.frame = frame
+        self.frame = frame     # turned into None when frame_finished_execution
         self.running = False
 
     def descr__reduce__(self, space):
@@ -19,9 +19,13 @@
         mod      = space.interp_w(MixedModule, w_mod)
         new_inst = mod.get('generator_new')
         w        = space.wrap
+        if self.frame:
+            w_frame = w(self.frame)
+        else:
+            w_frame = space.w_None
 
         tup = [
-            w(self.frame),
+            w_frame,
             w(self.running),
             ]
 
@@ -41,7 +45,8 @@
         if self.running:
             raise OperationError(space.w_ValueError,
                                  space.wrap('generator already executing'))
-        if self.frame.frame_finished_execution:
+        frame = self.frame
+        if frame is None:
             # xxx a bit ad-hoc, but we don't want to go inside
             # execute_generator_frame() if the frame is actually finished
             if operr is None:
@@ -49,7 +54,7 @@
             raise operr
         # XXX it's not clear that last_instr should be promoted at all
         # but as long as it is necessary for call_assembler, let's do it early
-        last_instr = jit.hint(self.frame.last_instr, promote=True)
+        last_instr = jit.hint(frame.last_instr, promote=True)
         if last_instr == -1:
             if w_arg and not space.is_w(w_arg, space.w_None):
                 msg = "can't send non-None value to a just-started generator"
@@ -60,18 +65,19 @@
         self.running = True
         try:
             try:
-                w_result = self.frame.execute_generator_frame(w_arg, operr)
+                w_result = frame.execute_generator_frame(w_arg, operr)
             except OperationError:
                 # errors finish a frame
-                self.frame.frame_finished_execution = True
+                self.frame = None
                 raise
             # if the frame is now marked as finished, it was RETURNed from
-            if self.frame.frame_finished_execution:
+            if frame.frame_finished_execution:
+                self.frame = None
                 raise OperationError(space.w_StopIteration, space.w_None) 
             else:
                 return w_result     # YIELDed
         finally:
-            self.frame.f_backref = jit.vref_None
+            frame.f_backref = jit.vref_None
             self.running = False
 
     def descr_throw(self, w_type, w_val=None, w_tb=None):
@@ -115,7 +121,7 @@
             raise OperationError(space.w_RuntimeError, space.wrap(msg))
 
     def descr_gi_frame(space, self):
-        if not self.frame.frame_finished_execution:
+        if self.frame is not None and not self.frame.frame_finished_execution:
             return self.frame
         else:
             return space.w_None
@@ -125,15 +131,17 @@
         applevel __del__, which is called at a safe point after the
         interp-level __del__ enqueued the object for destruction
         """
-        # Only bother raising an exception if the frame is still not
-        # finished and finally or except blocks are present.
-        if not self.frame.frame_finished_execution:
+        self.descr_close()
+
+    def __del__(self):
+        # Only bother enqueuing self to raise an exception if the frame is
+        # still not finished and finally or except blocks are present.
+        must_call_close = False
+        if self.frame is not None:
             block = self.frame.lastblock
             while block is not None:
                 if not isinstance(block, LoopBlock):
-                    self.descr_close()
-                    return
+                    must_call_close = True
+                    break
                 block = block.previous
-
-    def __del__(self):
-        self._enqueue_for_destruction(self.space)
+        self._enqueue_for_destruction(self.space, must_call_close)

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/mixedmodule.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/mixedmodule.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/mixedmodule.py	Sat Dec 11 15:10:15 2010
@@ -13,6 +13,10 @@
 
     applevel_name = None
     expose__file__attribute = True
+
+    # The following attribute is None as long as the module has not been
+    # imported yet, and when it has been, it is mod.__dict__.items() just
+    # after startup().
     w_initialdict = None
 
     def __init__(self, space, w_name): 
@@ -26,8 +30,14 @@
         """This is called each time the module is imported or reloaded
         """
         if self.w_initialdict is not None:
+            # the module was already imported.  Refresh its content with
+            # the saved dict, as done with built-in and extension modules
+            # on CPython.
             space.call_method(self.w_dict, 'update', self.w_initialdict)
-        Module.init(self, space)
+        else:
+            Module.init(self, space)
+            if not self.lazy and self.w_initialdict is None:
+                self.w_initialdict = space.call_method(self.w_dict, 'items')
 
     def get_applevel_name(cls):
         """ NOT_RPYTHON """
@@ -96,6 +106,7 @@
 
     def _freeze_(self):
         self.getdict()
+        self.w_initialdict = None
         self.startup_called = False
         # hint for the annotator: Modules can hold state, so they are
         # not constant

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/pycode.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/pycode.py	Sat Dec 11 15:10:15 2010
@@ -15,7 +15,7 @@
     CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED,
     CO_GENERATOR, CO_CONTAINSGLOBALS)
 from pypy.rlib.rarithmetic import intmask
-from pypy.rlib.debug import make_sure_not_resized, make_sure_not_modified
+from pypy.rlib.debug import make_sure_not_resized
 from pypy.rlib import jit
 from pypy.rlib.objectmodel import compute_hash
 from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT
@@ -69,7 +69,7 @@
         self.co_stacksize = stacksize
         self.co_flags = flags
         self.co_code = code
-        self.co_consts_w = make_sure_not_modified(consts)
+        self.co_consts_w = consts
         self.co_names_w = [space.new_interned_str(aname) for aname in names]
         self.co_varnames = varnames
         self.co_freevars = freevars
@@ -269,7 +269,7 @@
         dis.dis(co)
 
     def fget_co_consts(space, self):
-        return space.newtuple(self.co_consts_w[:])
+        return space.newtuple(self.co_consts_w)
     
     def fget_co_names(space, self):
         return space.newtuple(self.co_names_w)
@@ -383,7 +383,7 @@
             w(self.co_stacksize), 
             w(self.co_flags),
             w(self.co_code), 
-            space.newtuple(self.co_consts_w[:]), 
+            space.newtuple(self.co_consts_w), 
             space.newtuple(self.co_names_w), 
             space.newtuple([w(v) for v in self.co_varnames]), 
             w(self.co_filename),

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/error.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/error.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/error.py	Sat Dec 11 15:10:15 2010
@@ -2,19 +2,22 @@
 class SyntaxError(Exception):
     """Base class for exceptions raised by the parser."""
 
-    def __init__(self, msg, lineno=0, offset=0, text=None, filename=None):
+    def __init__(self, msg, lineno=0, offset=0, text=None, filename=None,
+                 lastlineno=0):
         self.msg = msg
         self.lineno = lineno
         self.offset = offset
         self.text = text
         self.filename = filename
+        self.lastlineno = lastlineno
 
     def wrap_info(self, space):
         return space.newtuple([space.wrap(self.msg),
                                space.newtuple([space.wrap(self.filename),
                                                space.wrap(self.lineno),
                                                space.wrap(self.offset),
-                                               space.wrap(self.text)])])
+                                               space.wrap(self.text),
+                                               space.wrap(self.lastlineno)])])
 
     def __str__(self):
         return "%s at pos (%d, %d) in %r" % (self.__class__.__name__,
@@ -33,8 +36,9 @@
 
 class TokenError(SyntaxError):
 
-    def __init__(self, msg, line, lineno, column, tokens):
-        SyntaxError.__init__(self, msg, lineno, column, line)
+    def __init__(self, msg, line, lineno, column, tokens, lastlineno=0):
+        SyntaxError.__init__(self, msg, lineno, column, line,
+                             lastlineno=lastlineno)
         self.tokens = tokens
 
 class TokenIndentationError(IndentationError):

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/pytokenizer.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/pytokenizer.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/pytokenizer.py	Sat Dec 11 15:10:15 2010
@@ -78,6 +78,7 @@
     contline = None
     indents = [0]
     last_comment = ''
+    parenlevstart = (0, 0, "")
 
     # make the annotator happy
     endDFA = automata.DFA([], [])
@@ -85,7 +86,7 @@
     line = ''
     pos = 0
     lines.append("")
-    strstart = (0, 0)
+    strstart = (0, 0, "")
     for line in lines:
         lnum = lnum + 1
         pos, max = 0, len(line)
@@ -93,7 +94,8 @@
         if contstr:
             if not line:
                 raise TokenError("EOF while scanning triple-quoted string",
-                                 line, lnum-1, 0, token_list)
+                                 strstart[2], strstart[0], strstart[1]+1,
+                                 token_list, lnum)
             endmatch = endDFA.recognize(line)
             if endmatch >= 0:
                 pos = end = endmatch
@@ -146,6 +148,10 @@
 
         else:                                  # continued statement
             if not line:
+                if parenlev > 0:
+                    lnum1, start1, line1 = parenlevstart
+                    raise TokenError("parenthesis is never closed", line1,
+                                     lnum1, start1 + 1, token_list, lnum)
                 raise TokenError("EOF in multi-line statement", line,
                                  lnum, 0, token_list)
             continued = 0
@@ -187,7 +193,7 @@
                         token_list.append(tok)
                         last_comment = ''
                     else:
-                        strstart = (lnum, start)
+                        strstart = (lnum, start, line)
                         contstr = line[start:]
                         contline = line
                         break
@@ -195,7 +201,7 @@
                     token[:2] in single_quoted or \
                     token[:3] in single_quoted:
                     if token[-1] == '\n':                  # continued string
-                        strstart = (lnum, start)
+                        strstart = (lnum, start, line)
                         endDFA = (endDFAs[initial] or endDFAs[token[1]] or
                                    endDFAs[token[2]])
                         contstr, needcont = line[start:], 1
@@ -212,6 +218,8 @@
                     continued = 1
                 else:
                     if initial in '([{':
+                        if parenlev == 0:
+                            parenlevstart = (lnum, start, line)
                         parenlev = parenlev + 1
                     elif initial in ')]}':
                         parenlev = parenlev - 1
@@ -230,7 +238,7 @@
                     start = pos
                 if start<max and line[start] in single_quoted:
                     raise TokenError("EOL while scanning single-quoted string",
-                             line, lnum, start, token_list)
+                             line, lnum, start+1, token_list)
                 tok = (tokens.ERRORTOKEN, line[pos], lnum, pos, line)
                 token_list.append(tok)
                 last_comment = ''

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/test/test_pyparse.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/test/test_pyparse.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/pyparser/test/test_pyparse.py	Sat Dec 11 15:10:15 2010
@@ -64,12 +64,21 @@
         assert exc.lineno == 1
         assert exc.offset == 5
         assert exc.text.startswith("name another for")
-        exc = py.test.raises(SyntaxError, parse, "\"blah").value
+        exc = py.test.raises(SyntaxError, parse, "x = \"blah\n\n\n").value
         assert exc.msg == "EOL while scanning single-quoted string"
-        exc = py.test.raises(SyntaxError, parse, "'''\n").value
+        assert exc.lineno == 1
+        assert exc.offset == 5
+        exc = py.test.raises(SyntaxError, parse, "x = '''\n\n\n").value
         assert exc.msg == "EOF while scanning triple-quoted string"
+        assert exc.lineno == 1
+        assert exc.offset == 5
         for input in ("())", "(()", "((", "))"):
             py.test.raises(SyntaxError, parse, input)
+        exc = py.test.raises(SyntaxError, parse, "x = (\n\n(),\n(),").value
+        assert exc.msg == "parenthesis is never closed"
+        assert exc.lineno == 1
+        assert exc.offset == 5
+        assert exc.lastlineno == 5
 
     def test_is(self):
         self.parse("x is y")
@@ -91,6 +100,7 @@
         input = "def f():\n    pass\n  next_stmt"
         exc = py.test.raises(IndentationError, parse, input).value
         assert exc.msg == "unindent does not match any outer indentation level"
+        assert exc.lineno == 3
 
     def test_mac_newline(self):
         self.parse("this_is\ra_mac\rfile")

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	Sat Dec 11 15:10:15 2010
@@ -453,7 +453,11 @@
         assert set(args.keywords) == set(['a', 'b'])
         assert args.keywords_w[args.keywords.index('a')] == 2
         assert args.keywords_w[args.keywords.index('b')] == 3        
-                                 
+
+        args = Arguments(space, [1])
+        w_args, w_kwds = args.topacked()
+        assert w_args == (1, )
+        assert not w_kwds
 
 class TestErrorHandling(object):
     def test_missing_args(self):

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_compiler.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_compiler.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_compiler.py	Sat Dec 11 15:10:15 2010
@@ -68,6 +68,17 @@
         space.raises_w(space.w_SyntaxError, self.compiler.compile_command,
                        'if 1:\n  x\n y\n', '?', 'exec', 0)
 
+    def test_syntaxerror_attrs(self):
+        w_args = self.space.appexec([], r"""():
+            try:
+                exec 'if 1:\n  x\n y\n'
+            except SyntaxError, e:
+                return e.args
+        """)
+        assert self.space.unwrap(w_args) == (
+            'unindent does not match any outer indentation level',
+            (None, 3, 0, ' y\n'))
+
     def test_getcodeflags(self):
         code = self.compiler.compile('from __future__ import division\n',
                                      '<hello>', 'exec', 0)
@@ -908,3 +919,25 @@
             assert e.msg == 'unindent does not match any outer indentation level'
         else:
             raise Exception("DID NOT RAISE")
+
+
+    def test_repr_vs_str(self):
+        source1 = "x = (\n"
+        source2 = "x = (\n\n"
+        try:
+            exec source1
+        except SyntaxError, err1:
+            pass
+        else:
+            raise Exception("DID NOT RAISE")
+        try:
+            exec source2
+        except SyntaxError, err2:
+            pass
+        else:
+            raise Exception("DID NOT RAISE")
+        assert str(err1) != str(err2)
+        assert repr(err1) != repr(err2)
+        err3 = eval(repr(err1))
+        assert str(err3) == str(err1)
+        assert repr(err3) == repr(err1)

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	Sat Dec 11 15:10:15 2010
@@ -7,6 +7,10 @@
 
 
 class TestExecutionContext:
+    keywords = {}
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(**cls.keywords)
 
     def test_action(self):
 
@@ -77,29 +81,43 @@
         assert l == ['call', 'return', 'call', 'return']
 
     def test_llprofile_c_call(self):
+        from pypy.interpreter.function import Function, Method
         l = []
+        seen = []
+        space = self.space
         
-        def profile_func(space, w_arg, frame, event, w_aarg):
+        def profile_func(space, w_arg, frame, event, w_func):
             assert w_arg is space.w_None
             l.append(event)
+            if event == 'c_call':
+                seen.append(w_func)
 
-        space = self.space
-        space.getexecutioncontext().setllprofile(profile_func, space.w_None)
-
-        def check_snippet(snippet):
+        def check_snippet(snippet, expected_c_call):
+            del l[:]
+            del seen[:]
+            space.getexecutioncontext().setllprofile(profile_func,
+                                                     space.w_None)
             space.appexec([], """():
             %s
             return
             """ % snippet)
             space.getexecutioncontext().setllprofile(None, None)
             assert l == ['call', 'return', 'call', 'c_call', 'c_return', 'return']
-
-        check_snippet('l = []; l.append(42)')
-        check_snippet('max(1, 2)')
-        check_snippet('args = (1, 2); max(*args)')
-        check_snippet('max(1, 2, **{})')
-        check_snippet('args = (1, 2); max(*args, **{})')
-        check_snippet('abs(val=0)')
+            if isinstance(seen[0], Method):
+                found = 'method %s of %s' % (
+                    seen[0].w_function.name,
+                    seen[0].w_class.getname(space, '?'))
+            else:
+                assert isinstance(seen[0], Function)
+                found = 'builtin %s' % seen[0].name
+            assert found == expected_c_call
+
+        check_snippet('l = []; l.append(42)', 'method append of list')
+        check_snippet('max(1, 2)', 'builtin max')
+        check_snippet('args = (1, 2); max(*args)', 'builtin max')
+        check_snippet('max(1, 2, **{})', 'builtin max')
+        check_snippet('args = (1, 2); max(*args, **{})', 'builtin max')
+        check_snippet('abs(val=0)', 'builtin abs')
         
     def test_llprofile_c_exception(self):
         l = []
@@ -243,6 +261,13 @@
         """)
 
 
+class TestExecutionContextWithCallLikelyBuiltin(TestExecutionContext):
+    keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True}
+
+class TestExecutionContextWithCallMethod(TestExecutionContext):
+    keywords = {'objspace.opcodes.CALL_METHOD': True}
+
+
 class AppTestDelNotBlocked:
 
     def setup_method(self, meth):

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_function.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_function.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_function.py	Sat Dec 11 15:10:15 2010
@@ -6,7 +6,7 @@
 from pypy.interpreter.argument import Arguments
 
 
-class AppTestFunctionIntrospection: 
+class AppTestFunctionIntrospection:
     def test_attributes(self):
         globals()['__name__'] = 'mymodulename'
         def f(): pass
@@ -88,10 +88,10 @@
         def f(*args):
             return 42
             raises(TypeError, "dir.func_code = f.func_code")
-            raises(TypeError, "list.append.im_func.func_code = f.func_code") 
+            raises(TypeError, "list.append.im_func.func_code = f.func_code")
 
 
-class AppTestFunction: 
+class AppTestFunction:
     def test_simple_call(self):
         def func(arg1, arg2):
             return arg1, arg2
@@ -116,7 +116,7 @@
         assert res[2] == 333
 
         raises(TypeError, func)
-        raises(TypeError, func, 1, 2, 3, 4)        
+        raises(TypeError, func, 1, 2, 3, 4)
 
     def test_simple_varargs(self):
         def func(arg1, *args):
@@ -127,7 +127,7 @@
 
         res = func(23, *(42,))
         assert res[0] == 23
-        assert res[1] == (42,)        
+        assert res[1] == (42,)
 
     def test_simple_kwargs(self):
         def func(arg1, **kwargs):
@@ -205,7 +205,7 @@
             func(**{'self': 23})
             assert False
         except TypeError:
-            pass        
+            pass
 
     def test_kwargs_confusing_name(self):
         def func(self):    # 'self' conflicts with the interp-level
@@ -287,7 +287,7 @@
         # on function types
         raises(ValueError, type(f).__setstate__, f, (1, 2, 3))
 
-class AppTestMethod: 
+class AppTestMethod:
     def test_simple_call(self):
         class A(object):
             def func(self, arg2):
@@ -308,7 +308,7 @@
 
         res = a.func(*(42,))
         assert res[0] is a
-        assert res[1] == (42,)        
+        assert res[1] == (42,)
 
     def test_obscure_varargs(self):
         class A(object):
@@ -321,14 +321,14 @@
 
         res = a.func(*(42,))
         assert res[0] is a
-        assert res[1] == 42        
+        assert res[1] == 42
 
     def test_simple_kwargs(self):
         class A(object):
             def func(self, **kwargs):
                 return self, kwargs
         a = A()
-            
+
         res = a.func(value=42)
         assert res[0] is a
         assert res[1] == {'value': 42}
@@ -382,19 +382,19 @@
         assert hash(C.m) == hash(D.m)
         assert hash(c.m) == hash(c.m)
 
-    def test_method_repr(self): 
-        class A(object): 
-            def f(self): 
+    def test_method_repr(self):
+        class A(object):
+            def f(self):
                 pass
         assert repr(A.f) == "<unbound method A.f>"
-        assert repr(A().f).startswith("<bound method A.f of <") 
-        assert repr(A().f).endswith(">>") 
+        assert repr(A().f).startswith("<bound method A.f of <")
+        assert repr(A().f).endswith(">>")
         class B:
             def f(self):
                 pass
         assert repr(B.f) == "<unbound method B.f>"
         assert repr(B().f).startswith("<bound method B.f of <")
-        assert repr(A().f).endswith(">>") 
+        assert repr(A().f).endswith(">>")
 
 
     def test_method_call(self):
@@ -487,14 +487,33 @@
         def f(): pass
         raises(TypeError, new.instancemethod, f, None)
 
+    def test_empty_arg_kwarg_call(self):
+        def f():
+            pass
+
+        raises(TypeError, lambda: f(*0))
+        raises(TypeError, lambda: f(**0))
+
+    def test_method_equal(self):
+        class A(object):
+            def m(self):
+                pass
+
+        class X(object):
+            def __eq__(self, other):
+                return True
 
-class TestMethod: 
+        assert A().m == X()
+        assert X() == A().m
+
+
+class TestMethod:
     def setup_method(self, method):
         def c(self, bar):
             return bar
         code = PyCode._from_code(self.space, c.func_code)
         self.fn = Function(self.space, code, self.space.newdict())
-        
+
     def test_get(self):
         space = self.space
         w_meth = descr_function_get(space, self.fn, space.wrap(5), space.type(space.wrap(5)))
@@ -552,7 +571,7 @@
 
     def test_call_function(self):
         space = self.space
-        
+
         d = {}
         for i in range(10):
             args = "(" + ''.join(["a%d," % a for a in range(i)]) + ")"
@@ -574,14 +593,14 @@
                  code.funcrun = bomb
                  code.funcrun_obj = bomb
 
-            args_w = map(space.wrap, range(i))            
+            args_w = map(space.wrap, range(i))
             w_res = space.call_function(fn, *args_w)
             check = space.is_true(space.eq(w_res, space.wrap(res)))
             assert check
 
     def test_flatcall(self):
         space = self.space
-        
+
         def f(a):
             return a
         code = PyCode._from_code(self.space, f.func_code)
@@ -608,7 +627,7 @@
 
     def test_flatcall_method(self):
         space = self.space
-        
+
         def f(self, a):
             return a
         code = PyCode._from_code(self.space, f.func_code)
@@ -636,7 +655,7 @@
 
     def test_flatcall_default_arg(self):
         space = self.space
-        
+
         def f(a, b):
             return a+b
         code = PyCode._from_code(self.space, f.func_code)
@@ -665,7 +684,7 @@
 
     def test_flatcall_default_arg_method(self):
         space = self.space
-        
+
         def f(self, a, b):
             return a+b
         code = PyCode._from_code(self.space, f.func_code)
@@ -688,7 +707,7 @@
         y = A().m(x)
         b = A().m
         z = b(x)
-        return y+10*z 
+        return y+10*z
         """)
 
         assert space.eq_w(w_res, space.wrap(44))

Modified: pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_gateway.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_gateway.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/interpreter/test/test_gateway.py	Sat Dec 11 15:10:15 2010
@@ -578,6 +578,11 @@
         w_res = space.call_args(w_g, args)
         assert space.eq_w(w_res, space.wrap((-1, 0)))
 
+class AppTestPyTestMark:
+    @py.test.mark.unlikely_to_exist
+    def test_anything(self):
+        pass
+
 
 class TestPassThroughArguments:
     

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	Sat Dec 11 15:10:15 2010
@@ -31,7 +31,8 @@
                 'i86pc': 'x86',    # Solaris/Intel
                 'x86':   'x86',    # Apple
                 'Power Macintosh': 'ppc',
-                'x86_64': 'x86', 
+                'x86_64': 'x86',
+                'amd64': 'x86'     # freebsd
                 }[mach]
     except KeyError:
         return mach

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	Sat Dec 11 15:10:15 2010
@@ -4,6 +4,7 @@
 when executing on top of the llinterpreter.
 """
 
+import weakref
 from pypy.objspace.flow.model import Variable, Constant
 from pypy.annotation import model as annmodel
 from pypy.jit.metainterp.history import (ConstInt, ConstPtr,
@@ -161,6 +162,8 @@
 # ____________________________________________________________
 
 class CompiledLoop(object):
+    has_been_freed = False
+
     def __init__(self):
         self.inputargs = []
         self.operations = []
@@ -285,6 +288,11 @@
     del _variables[:]
     return _to_opaque(CompiledLoop())
 
+def mark_as_free(loop):
+    loop = _from_opaque(loop)
+    assert not loop.has_been_freed
+    loop.has_been_freed = True
+
 def compile_start_int_var(loop):
     return compile_start_ref_var(loop, lltype.Signed)
 
@@ -317,7 +325,7 @@
         raise ValueError("CALL_ASSEMBLER not supported")
     loop = _from_opaque(loop)
     op = loop.operations[-1]
-    op.descr = descr
+    op.descr = weakref.ref(descr)
 
 def compile_add_var(loop, intvar):
     loop = _from_opaque(loop)
@@ -436,6 +444,7 @@
         verbose = True
         self.opindex = 0
         while True:
+            assert not self.loop.has_been_freed
             op = self.loop.operations[self.opindex]
             args = [self.getenv(v) for v in op.args]
             if not op.is_final():
@@ -447,7 +456,10 @@
                     _stats.exec_conditional_jumps += 1
                     if op.jump_target is not None:
                         # a patched guard, pointing to further code
-                        args = [self.getenv(v) for v in op.fail_args if v]
+                        if op.fail_args:
+                            args = [self.getenv(v) for v in op.fail_args if v]
+                        else:
+                            args = []
                         assert len(op.jump_target.inputargs) == len(args)
                         self.env = dict(zip(op.jump_target.inputargs, args))
                         self.loop = op.jump_target
@@ -578,7 +590,12 @@
     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)
+        try:
+            stats = get_stats()
+        except AttributeError:
+            pass
+        else:
+            stats.add_merge_point_location(loc)
 
     def op_guard_true(self, _, value):
         if not value:
@@ -846,14 +863,22 @@
         finally:
             self._may_force = -1
 
-    def op_call_assembler(self, loop_token, *args):
+    def op_call_assembler(self, wref_loop_token, *args):
+        if we_are_translated():
+            raise ValueError("CALL_ASSEMBLER not supported")
+        return self._do_call_assembler(wref_loop_token, *args)
+
+    def _do_call_assembler(self, wref_loop_token, *args):
         global _last_exception
+        loop_token = wref_loop_token()
+        assert loop_token, "CALL_ASSEMBLER to a target that already died"
+        ctl = loop_token.compiled_loop_token
+        if hasattr(ctl, 'redirected'):
+            return self._do_call_assembler(ctl.redirected, *args)
         assert not self._forced
-        loop_token = self.cpu._redirected_call_assembler.get(loop_token,
-                                                             loop_token)
         self._may_force = self.opindex
         try:
-            inpargs = _from_opaque(loop_token._llgraph_compiled_version).inputargs
+            inpargs = _from_opaque(ctl.compiled_version).inputargs
             for i, inparg in enumerate(inpargs):
                 TYPE = inparg.concretetype
                 if TYPE is lltype.Signed:
@@ -1546,10 +1571,13 @@
         do_setfield_gc_int(vable, fielddescr.ofs, 0)
 
 def redirect_call_assembler(cpu, oldlooptoken, newlooptoken):
-    OLD = _from_opaque(oldlooptoken._llgraph_compiled_version).getargtypes()
-    NEW = _from_opaque(newlooptoken._llgraph_compiled_version).getargtypes()
+    oldclt = oldlooptoken.compiled_loop_token
+    newclt = newlooptoken.compiled_loop_token
+    OLD = _from_opaque(oldclt.compiled_version).getargtypes()
+    NEW = _from_opaque(newclt.compiled_version).getargtypes()
     assert OLD == NEW
-    cpu._redirected_call_assembler[oldlooptoken] = newlooptoken
+    assert not hasattr(oldclt, 'redirected')
+    oldclt.redirected = weakref.ref(newlooptoken)
 
 # ____________________________________________________________
 
@@ -1617,6 +1645,7 @@
 setannotation(compile_add_fail, annmodel.SomeInteger())
 setannotation(compile_add_fail_arg, annmodel.s_None)
 setannotation(compile_redirect_fail, annmodel.s_None)
+setannotation(mark_as_free, annmodel.s_None)
 
 setannotation(new_frame, s_Frame)
 setannotation(frame_clear, annmodel.s_None)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/llgraph/runner.py	Sat Dec 11 15:10:15 2010
@@ -102,7 +102,6 @@
         llimpl._llinterp = LLInterpreter(self.rtyper)
         self._future_values = []
         self._descrs = {}
-        self._redirected_call_assembler = {}
 
     def _freeze_(self):
         assert self.translate_support_code
@@ -118,22 +117,34 @@
             self._descrs[key] = descr
             return descr
 
-    def compile_bridge(self, faildescr, inputargs, operations, log=True):
+    def compile_bridge(self, faildescr, inputargs, operations,
+                       original_loop_token, log=True):
         c = llimpl.compile_start()
+        clt = original_loop_token.compiled_loop_token
+        clt.loop_and_bridges.append(c)
+        clt.compiling_a_bridge()
         self._compile_loop_or_bridge(c, inputargs, operations)
         old, oldindex = faildescr._compiled_fail
         llimpl.compile_redirect_fail(old, oldindex, c)
 
-    def compile_loop(self, inputargs, operations, loopdescr, log=True):
+    def compile_loop(self, inputargs, operations, looptoken, log=True):
         """In a real assembler backend, this should assemble the given
         list of operations.  Here we just generate a similar CompiledLoop
         instance.  The code here is RPython, whereas the code in llimpl
         is not.
         """
         c = llimpl.compile_start()
-        loopdescr._llgraph_compiled_version = c
+        clt = model.CompiledLoopToken(self, looptoken.number)
+        clt.loop_and_bridges = [c]
+        clt.compiled_version = c
+        looptoken.compiled_loop_token = clt
         self._compile_loop_or_bridge(c, inputargs, operations)
 
+    def free_loop_and_bridges(self, compiled_loop_token):
+        for c in compiled_loop_token.loop_and_bridges:
+            llimpl.mark_as_free(c)
+        model.AbstractCPU.free_loop_and_bridges(self, compiled_loop_token)
+
     def _compile_loop_or_bridge(self, c, inputargs, operations):
         var2index = {}
         for box in inputargs:
@@ -215,7 +226,7 @@
         if op.getopnum() == rop.JUMP:
             targettoken = op.getdescr()
             assert isinstance(targettoken, history.LoopToken)
-            compiled_version = targettoken._llgraph_compiled_version
+            compiled_version = targettoken.compiled_loop_token.compiled_version
             llimpl.compile_add_jump_target(c, compiled_version)
         elif op.getopnum() == rop.FINISH:
             faildescr = op.getdescr()
@@ -225,7 +236,7 @@
             assert False, "unknown operation"
 
     def _execute_token(self, loop_token):
-        compiled_version = loop_token._llgraph_compiled_version
+        compiled_version = loop_token.compiled_loop_token.compiled_version
         frame = llimpl.new_frame(self.is_oo, self)
         # setup the frame
         llimpl.frame_clear(frame, compiled_version)

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	Sat Dec 11 15:10:15 2010
@@ -15,6 +15,7 @@
 from pypy.jit.backend.llsupport.descr import GcCache, get_field_descr
 from pypy.jit.backend.llsupport.descr import GcPtrFieldDescr
 from pypy.jit.backend.llsupport.descr import get_call_descr
+from pypy.rpython.memory.gctransform import asmgcroot
 
 # ____________________________________________________________
 
@@ -35,6 +36,8 @@
         return False
     def has_write_barrier_class(self):
         return None
+    def freeing_block(self, start, stop):
+        pass
 
 # ____________________________________________________________
 
@@ -218,50 +221,120 @@
     LOC_EBP_PLUS  = 2
     LOC_EBP_MINUS = 3
 
-    GCMAP_ARRAY = rffi.CArray(llmemory.Address)
-    CALLSHAPE_ARRAY = rffi.CArray(rffi.UCHAR)
+    GCMAP_ARRAY = rffi.CArray(lltype.Signed)
+    CALLSHAPE_ARRAY_PTR = rffi.CArrayPtr(rffi.UCHAR)
 
     def __init__(self):
+        # '_gcmap' is an array of length '_gcmap_maxlength' of addresses.
+        # '_gcmap_curlength' tells how full the array really is.
+        # The addresses are actually grouped in pairs:
+        #     (addr-after-the-CALL-in-assembler, addr-of-the-call-shape).
+        # '_gcmap_deadentries' counts pairs marked dead (2nd item is NULL).
+        # '_gcmap_sorted' is True only if we know the array is sorted.
         self._gcmap = lltype.nullptr(self.GCMAP_ARRAY)
         self._gcmap_curlength = 0
         self._gcmap_maxlength = 0
+        self._gcmap_deadentries = 0
+        self._gcmap_sorted = True
 
     def initialize(self):
         # hack hack hack.  Remove these lines and see MissingRTypeAttribute
         # when the rtyper tries to annotate these methods only when GC-ing...
         self.gcmapstart()
         self.gcmapend()
+        self.gcmarksorted()
 
     def gcmapstart(self):
-        return llmemory.cast_ptr_to_adr(self._gcmap)
+        return rffi.cast(llmemory.Address, self._gcmap)
 
     def gcmapend(self):
         addr = self.gcmapstart()
         if self._gcmap_curlength:
-            addr += llmemory.sizeof(llmemory.Address)*self._gcmap_curlength
+            addr += rffi.sizeof(lltype.Signed) * self._gcmap_curlength
+            if not we_are_translated() and type(addr) is long:
+                from pypy.rpython.lltypesystem import ll2ctypes
+                addr = ll2ctypes._lladdress(addr)       # XXX workaround
         return addr
 
+    def gcmarksorted(self):
+        # Called by the GC when it is about to sort [gcmapstart():gcmapend()].
+        # Returns the previous sortedness flag -- i.e. returns True if it
+        # is already sorted, False if sorting is needed.
+        sorted = self._gcmap_sorted
+        self._gcmap_sorted = True
+        return sorted
+
     def put(self, retaddr, callshapeaddr):
         """'retaddr' is the address just after the CALL.
-        'callshapeaddr' is the address returned by encode_callshape()."""
+        'callshapeaddr' is the address of the raw 'shape' marker.
+        Both addresses are actually integers here."""
         index = self._gcmap_curlength
         if index + 2 > self._gcmap_maxlength:
-            self._enlarge_gcmap()
+            index = self._enlarge_gcmap()
         self._gcmap[index] = retaddr
         self._gcmap[index+1] = callshapeaddr
         self._gcmap_curlength = index + 2
+        self._gcmap_sorted = False
 
+    @rgc.no_collect
     def _enlarge_gcmap(self):
-        newlength = 250 + self._gcmap_maxlength * 2
-        newgcmap = lltype.malloc(self.GCMAP_ARRAY, newlength, flavor='raw',
-                                 track_allocation=False)
         oldgcmap = self._gcmap
-        for i in range(self._gcmap_curlength):
-            newgcmap[i] = oldgcmap[i]
-        self._gcmap = newgcmap
-        self._gcmap_maxlength = newlength
-        if oldgcmap:
-            lltype.free(oldgcmap, flavor='raw', track_allocation=False)
+        if self._gcmap_deadentries * 3 * 2 > self._gcmap_maxlength:
+            # More than 1/3rd of the entries are dead.  Don't actually
+            # enlarge the gcmap table, but just clean up the dead entries.
+            newgcmap = oldgcmap
+        else:
+            # Normal path: enlarge the array.
+            newlength = 250 + (self._gcmap_maxlength // 3) * 4
+            newgcmap = lltype.malloc(self.GCMAP_ARRAY, newlength, flavor='raw',
+                                     track_allocation=False)
+            self._gcmap_maxlength = newlength
+        #
+        j = 0
+        i = 0
+        end = self._gcmap_curlength
+        while i < end:
+            if oldgcmap[i + 1]:
+                newgcmap[j] = oldgcmap[i]
+                newgcmap[j + 1] = oldgcmap[i + 1]
+                j += 2
+            i += 2
+        self._gcmap_curlength = j
+        self._gcmap_deadentries = 0
+        if oldgcmap != newgcmap:
+            self._gcmap = newgcmap
+            if oldgcmap:
+                lltype.free(oldgcmap, flavor='raw', track_allocation=False)
+        return j
+
+    @rgc.no_collect
+    def freeing_block(self, start, stop):
+        # if [start:stop] is a raw block of assembler, then look up the
+        # corresponding gcroot markers, and mark them as freed now in
+        # self._gcmap by setting the 2nd address of every entry to NULL.
+        gcmapstart = self.gcmapstart()
+        gcmapend   = self.gcmapend()
+        if gcmapstart == gcmapend:
+            return
+        if not self.gcmarksorted():
+            asmgcroot.sort_gcmap(gcmapstart, gcmapend)
+        # A note about gcmarksorted(): the deletion we do here keeps the
+        # array sorted.  This avoids needing too many sort_gcmap()s.
+        # Indeed, freeing_block() is typically called many times in a row,
+        # so it will call sort_gcmap() at most the first time.
+        startaddr = rffi.cast(llmemory.Address, start)
+        stopaddr  = rffi.cast(llmemory.Address, stop)
+        item = asmgcroot.binary_search(gcmapstart, gcmapend, startaddr)
+        # 'item' points to one of the entries.  Because the whole array
+        # is sorted, we know that it points either to the first entry we
+        # want to kill, or to the previous entry.
+        if item.address[0] < startaddr:
+            item += asmgcroot.arrayitemsize    # go forward one entry
+            assert item == gcmapend or item.address[0] >= startaddr
+        while item != gcmapend and item.address[0] < stopaddr:
+            item.address[1] = llmemory.NULL
+            self._gcmap_deadentries += 1
+            item += asmgcroot.arrayitemsize
 
     def get_basic_shape(self, is_64_bit=False):
         # XXX: Should this code even really know about stack frame layout of
@@ -304,17 +377,15 @@
         assert reg_index > 0
         shape.append(chr(self.LOC_REG | (reg_index << 2)))
 
-    def compress_callshape(self, shape):
+    def compress_callshape(self, shape, datablockwrapper):
         # Similar to compress_callshape() in trackgcroot.py.
-        # XXX so far, we always allocate a new small array (we could regroup
-        # them inside bigger arrays) and we never try to share them.
+        # Returns an address to raw memory (as an integer).
         length = len(shape)
-        compressed = lltype.malloc(self.CALLSHAPE_ARRAY, length,
-                                   flavor='raw',
-                                   track_allocation=False)   # memory leak
+        rawaddr = datablockwrapper.malloc_aligned(length, 1)
+        p = rffi.cast(self.CALLSHAPE_ARRAY_PTR, rawaddr)
         for i in range(length):
-            compressed[length-1-i] = rffi.cast(rffi.UCHAR, shape[i])
-        return llmemory.cast_ptr_to_adr(compressed)
+            p[length-1-i] = rffi.cast(rffi.UCHAR, shape[i])
+        return rawaddr
 
 
 class WriteBarrierDescr(AbstractDescr):
@@ -379,6 +450,7 @@
             'layoutbuilder': self.layoutbuilder,
             'gcmapstart': lambda: gcrootmap.gcmapstart(),
             'gcmapend': lambda: gcrootmap.gcmapend(),
+            'gcmarksorted': lambda: gcrootmap.gcmarksorted(),
             }
         self.GCClass = self.layoutbuilder.GCClass
         self.moving_gc = self.GCClass.moving_gc
@@ -641,6 +713,9 @@
     def has_write_barrier_class(self):
         return WriteBarrierDescr
 
+    def freeing_block(self, start, stop):
+        self.gcrootmap.freeing_block(start, stop)
+
 # ____________________________________________________________
 
 def get_ll_description(gcdescr, translator=None, rtyper=None):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/llmodel.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/llmodel.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/llsupport/llmodel.py	Sat Dec 11 15:10:15 2010
@@ -17,7 +17,7 @@
 from pypy.jit.backend.llsupport.descr import get_call_descr
 from pypy.jit.backend.llsupport.descr import BaseIntCallDescr, GcPtrCallDescr
 from pypy.jit.backend.llsupport.descr import FloatCallDescr, VoidCallDescr
-from pypy.jit.backend.llsupport.ffisupport import get_call_descr_dynamic
+from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
 from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
 
 
@@ -52,6 +52,7 @@
         else:
             self._setup_exception_handling_untranslated()
         self.saved_exc_value = lltype.nullptr(llmemory.GCREF.TO)
+        self.asmmemmgr = AsmMemoryManager()
         self.setup()
         if translate_support_code:
             self._setup_on_leave_jitted_translated()
@@ -177,6 +178,15 @@
         self.saved_exc_value = lltype.nullptr(llmemory.GCREF.TO)
         return exc
 
+    def free_loop_and_bridges(self, compiled_loop_token):
+        AbstractCPU.free_loop_and_bridges(self, compiled_loop_token)
+        blocks = compiled_loop_token.asmmemmgr_blocks
+        if blocks is not None:
+            compiled_loop_token.asmmemmgr_blocks = None
+            for rawstart, rawstop in blocks:
+                self.gc_ll_descr.freeing_block(rawstart, rawstop)
+                self.asmmemmgr.free(rawstart, rawstop)
+
     # ------------------- helpers and descriptions --------------------
 
     @staticmethod
@@ -236,7 +246,9 @@
         return get_call_descr(self.gc_ll_descr, ARGS, RESULT, extrainfo)
 
     def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo=None):
-        return get_call_descr_dynamic(ffi_args, ffi_result, extrainfo)
+        from pypy.jit.backend.llsupport import ffisupport
+        return ffisupport.get_call_descr_dynamic(ffi_args, ffi_result,
+                                                 extrainfo)
 
     def get_overflow_error(self):
         ovf_vtable = self.cast_adr_to_int(self._ovf_error_vtable)

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	Sat Dec 11 15:10:15 2010
@@ -9,6 +9,7 @@
 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
+from pypy.rpython.memory.gctransform import asmgcroot
 
 def test_boehm():
     gc_ll_descr = GcLLDescr_boehm(None, None, None)
@@ -62,58 +63,169 @@
     for i in range(len(allocs)):
         assert addrs[i].address[0] == llmemory.cast_ptr_to_adr(allocs[i])
 
-def test_GcRootMap_asmgcc():
-    def frame_pos(n):
-        return -4*(4+n)
-    gcrootmap = GcRootMap_asmgcc()
-    num1 = frame_pos(-5)
-    num1a = num1|2
-    num2 = frame_pos(55)
-    num2a = ((-num2|3) >> 7) | 128
-    num2b = (-num2|3) & 127
-    shape = gcrootmap.get_basic_shape()
-    gcrootmap.add_ebp_offset(shape, num1)
-    gcrootmap.add_ebp_offset(shape, num2)
-    assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a])
-    gcrootmap.add_callee_save_reg(shape, 1)
-    assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
-                              4])
-    gcrootmap.add_callee_save_reg(shape, 2)
-    assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
-                              4, 8])
-    gcrootmap.add_callee_save_reg(shape, 3)
-    assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
-                              4, 8, 12])
-    gcrootmap.add_callee_save_reg(shape, 4)
-    assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
-                              4, 8, 12, 16])
-    #
-    shapeaddr = gcrootmap.compress_callshape(shape)
-    PCALLSHAPE = lltype.Ptr(GcRootMap_asmgcc.CALLSHAPE_ARRAY)
-    p = llmemory.cast_adr_to_ptr(shapeaddr, PCALLSHAPE)
-    for i, expected in enumerate([16, 12, 8, 4,
-                                  num2a, num2b, num1a, 0, 2, 15, 11, 7, 6]):
-        assert p[i] == expected
-    #
-    retaddr = rffi.cast(llmemory.Address, 1234567890)
-    gcrootmap.put(retaddr, shapeaddr)
-    assert gcrootmap._gcmap[0] == retaddr
-    assert gcrootmap._gcmap[1] == shapeaddr
-    assert gcrootmap.gcmapstart().address[0] == retaddr
-    #
-    # the same as before, but enough times to trigger a few resizes
-    expected_shapeaddr = {}
-    for i in range(1, 700):
+class TestGcRootMapAsmGcc:
+
+    def test_make_shapes(self):
+        def frame_pos(n):
+            return -4*(4+n)
+        gcrootmap = GcRootMap_asmgcc()
+        num1 = frame_pos(-5)
+        num1a = num1|2
+        num2 = frame_pos(55)
+        num2a = ((-num2|3) >> 7) | 128
+        num2b = (-num2|3) & 127
         shape = gcrootmap.get_basic_shape()
-        gcrootmap.add_ebp_offset(shape, frame_pos(i))
-        shapeaddr = gcrootmap.compress_callshape(shape)
-        expected_shapeaddr[i] = shapeaddr
-        retaddr = rffi.cast(llmemory.Address, 123456789 + i)
+        gcrootmap.add_ebp_offset(shape, num1)
+        gcrootmap.add_ebp_offset(shape, num2)
+        assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a])
+        gcrootmap.add_callee_save_reg(shape, 1)
+        assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
+                                  4])
+        gcrootmap.add_callee_save_reg(shape, 2)
+        assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
+                                  4, 8])
+        gcrootmap.add_callee_save_reg(shape, 3)
+        assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
+                                  4, 8, 12])
+        gcrootmap.add_callee_save_reg(shape, 4)
+        assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
+                                  4, 8, 12, 16])
+
+    def test_compress_callshape(self):
+        class FakeDataBlockWrapper:
+            def malloc_aligned(self, size, alignment):
+                assert alignment == 1    # here
+                assert size == 4
+                return rffi.cast(lltype.Signed, p)
+        datablockwrapper = FakeDataBlockWrapper()
+        p = lltype.malloc(rffi.CArray(lltype.Char), 4, immortal=True)
+        gcrootmap = GcRootMap_asmgcc()
+        shape = ['a', 'b', 'c', 'd']
+        gcrootmap.compress_callshape(shape, datablockwrapper)
+        assert p[0] == 'd'
+        assert p[1] == 'c'
+        assert p[2] == 'b'
+        assert p[3] == 'a'
+
+    def test_put_basic(self):
+        gcrootmap = GcRootMap_asmgcc()
+        retaddr = 1234567890
+        shapeaddr = 51627384
         gcrootmap.put(retaddr, shapeaddr)
-    for i in range(1, 700):
-        expected_retaddr = rffi.cast(llmemory.Address, 123456789 + i)
-        assert gcrootmap._gcmap[i*2+0] == expected_retaddr
-        assert gcrootmap._gcmap[i*2+1] == expected_shapeaddr[i]
+        assert gcrootmap._gcmap[0] == retaddr
+        assert gcrootmap._gcmap[1] == shapeaddr
+        p = rffi.cast(rffi.LONGP, gcrootmap.gcmapstart())
+        assert p[0] == retaddr
+        assert (gcrootmap.gcmapend() ==
+                gcrootmap.gcmapstart() + rffi.sizeof(lltype.Signed) * 2)
+
+    def test_put_resize(self):
+        # the same as before, but enough times to trigger a few resizes
+        gcrootmap = GcRootMap_asmgcc()
+        for i in range(700):
+            shapeaddr = i * 100 + 1
+            retaddr = 123456789 + i
+            gcrootmap.put(retaddr, shapeaddr)
+        for i in range(700):
+            assert gcrootmap._gcmap[i*2+0] == 123456789 + i
+            assert gcrootmap._gcmap[i*2+1] == i * 100 + 1
+
+    def test_remove_nulls(self):
+        expected = []
+        def check():
+            assert gcrootmap._gcmap_curlength == len(expected) * 2
+            for i, (a, b) in enumerate(expected):
+                assert gcrootmap._gcmap[i*2] == a
+                assert gcrootmap._gcmap[i*2+1] == b
+        #
+        gcrootmap = GcRootMap_asmgcc()
+        for i in range(700):
+            shapeaddr = i * 100       # 0 if i == 0
+            retaddr = 123456789 + i
+            gcrootmap.put(retaddr, shapeaddr)
+            if shapeaddr != 0:
+                expected.append((retaddr, shapeaddr))
+        # at the first resize, the 0 should be removed
+        check()
+        for repeat in range(10):
+            # now clear up half the entries
+            assert len(expected) == 699
+            for i in range(0, len(expected), 2):
+                gcrootmap._gcmap[i*2+1] = 0
+                gcrootmap._gcmap_deadentries += 1
+            expected = expected[1::2]
+            assert gcrootmap._gcmap_deadentries*6 > gcrootmap._gcmap_maxlength
+            # check that we can again insert 350 entries without a resize
+            oldgcmap = gcrootmap._gcmap
+            for i in range(0, 699, 2):
+                gcrootmap.put(515151 + i + repeat, 626262 + i)
+                expected.append((515151 + i + repeat, 626262 + i))
+            assert gcrootmap._gcmap == oldgcmap
+            check()
+
+    def test_freeing_block(self):
+        from pypy.jit.backend.llsupport import gc
+        class Asmgcroot:
+            arrayitemsize = 2 * llmemory.sizeof(llmemory.Address)
+            sort_count = 0
+            def sort_gcmap(self, gcmapstart, gcmapend):
+                self.sort_count += 1
+            def binary_search(self, gcmapstart, gcmapend, startaddr):
+                i = 0
+                while (i < gcrootmap._gcmap_curlength//2 and
+                       gcrootmap._gcmap[i*2] < startaddr):
+                    i += 1
+                if i > 0:
+                    i -= 1
+                assert 0 <= i < gcrootmap._gcmap_curlength//2
+                p = rffi.cast(rffi.CArrayPtr(llmemory.Address), gcmapstart)
+                p = rffi.ptradd(p, 2*i)
+                return llmemory.cast_ptr_to_adr(p)
+        saved = gc.asmgcroot
+        try:
+            gc.asmgcroot = Asmgcroot()
+            #
+            gcrootmap = GcRootMap_asmgcc()
+            gcrootmap._gcmap = lltype.malloc(gcrootmap.GCMAP_ARRAY,
+                                             1400, flavor='raw',
+                                             immortal=True)
+            for i in range(700):
+                gcrootmap._gcmap[i*2] = 1200000 + i
+                gcrootmap._gcmap[i*2+1] = i * 100 + 1
+            assert gcrootmap._gcmap_deadentries == 0
+            assert gc.asmgcroot.sort_count == 0
+            gcrootmap._gcmap_maxlength = 1400
+            gcrootmap._gcmap_curlength = 1400
+            gcrootmap._gcmap_sorted = False
+            #
+            gcrootmap.freeing_block(1200000 - 100, 1200000)
+            assert gcrootmap._gcmap_deadentries == 0
+            assert gc.asmgcroot.sort_count == 1
+            #
+            gcrootmap.freeing_block(1200000 + 100, 1200000 + 200)
+            assert gcrootmap._gcmap_deadentries == 100
+            assert gc.asmgcroot.sort_count == 1
+            for i in range(700):
+                if 100 <= i < 200:
+                    expected = 0
+                else:
+                    expected = i * 100 + 1
+                assert gcrootmap._gcmap[i*2] == 1200000 + i
+                assert gcrootmap._gcmap[i*2+1] == expected
+            #
+            gcrootmap.freeing_block(1200000 + 650, 1200000 + 750)
+            assert gcrootmap._gcmap_deadentries == 150
+            assert gc.asmgcroot.sort_count == 1
+            for i in range(700):
+                if 100 <= i < 200 or 650 <= i:
+                    expected = 0
+                else:
+                    expected = i * 100 + 1
+                assert gcrootmap._gcmap[i*2] == 1200000 + i
+                assert gcrootmap._gcmap[i*2+1] == expected
+        #
+        finally:
+            gc.asmgcroot = saved
 
 
 class FakeLLOp(object):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/model.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/model.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/model.py	Sat Dec 11 15:10:15 2010
@@ -1,3 +1,4 @@
+from pypy.rlib.debug import debug_start, debug_print, debug_stop
 from pypy.jit.metainterp import history, compile
 
 
@@ -7,17 +8,27 @@
     done_with_this_frame_int_v = -1
     done_with_this_frame_ref_v = -1
     done_with_this_frame_float_v = -1
+    total_compiled_loops = 0
+    total_compiled_bridges = 0
+    total_freed_loops = 0
+    total_freed_bridges = 0
 
     def __init__(self):
         self.fail_descr_list = []
+        self.fail_descr_free_list = []
 
     def get_fail_descr_number(self, descr):
         assert isinstance(descr, history.AbstractFailDescr)
         n = descr.index
         if n < 0:
             lst = self.fail_descr_list
-            n = len(lst)
-            lst.append(descr)
+            if len(self.fail_descr_free_list) > 0:
+                n = self.fail_descr_free_list.pop()
+                assert lst[n] is None
+                lst[n] = descr
+            else:
+                n = len(lst)
+                lst.append(descr)
             descr.index = n
         return n
 
@@ -35,12 +46,14 @@
 
     def compile_loop(self, inputargs, operations, looptoken, log=True):
         """Assemble the given loop.
-        Extra attributes should be put in the LoopToken to
-        point to the compiled loop in assembler.
+        Should create and attach a fresh CompiledLoopToken to
+        looptoken.compiled_loop_token and stick extra attributes
+        on it to point to the compiled loop in assembler.
         """
         raise NotImplementedError
 
-    def compile_bridge(self, faildescr, inputargs, operations, log=True):
+    def compile_bridge(self, faildescr, inputargs, operations,
+                       original_loop_token, log=True):
         """Assemble the bridge.
         The FailDescr is the descr of the original guard that failed.
         """
@@ -113,6 +126,28 @@
         oldlooptoken so that from now own they will call newlooptoken."""
         raise NotImplementedError
 
+    def free_loop_and_bridges(self, compiled_loop_token):
+        """This method is called to free resources (machine code,
+        references to resume guards, etc.) allocated by the compilation
+        of a loop and all bridges attached to it.  After this call, the
+        frontend cannot use this compiled loop any more; in fact, it
+        guarantees that at the point of the call to free_code_group(),
+        none of the corresponding assembler is currently running.
+        """
+        # The base class provides a limited implementation: freeing the
+        # resume descrs.  This is already quite helpful, because the
+        # resume descrs are the largest consumers of memory (about 3x
+        # more than the assembler, in the case of the x86 backend).
+        lst = self.fail_descr_list
+        # We expect 'compiled_loop_token' to be itself garbage-collected soon,
+        # but better safe than sorry: be ready to handle several calls to
+        # free_loop_and_bridges() for the same compiled_loop_token.
+        faildescr_indices = compiled_loop_token.faildescr_indices
+        compiled_loop_token.faildescr_indices = []
+        for n in faildescr_indices:
+            lst[n] = None
+        self.fail_descr_free_list.extend(faildescr_indices)
+
     @staticmethod
     def sizeof(S):
         raise NotImplementedError
@@ -237,3 +272,40 @@
 
     def force(self, force_token):
         raise NotImplementedError
+
+
+class CompiledLoopToken(object):
+    asmmemmgr_blocks = None
+    asmmemmgr_gcroots = 0
+
+    def __init__(self, cpu, number):
+        cpu.total_compiled_loops += 1
+        self.cpu = cpu
+        self.number = number
+        self.bridges_count = 0
+        # This growing list gives the 'descr_number' of all fail descrs
+        # that belong to this loop or to a bridge attached to it.
+        # Filled by the frontend calling record_faildescr_index().
+        self.faildescr_indices = []
+        debug_start("jit-mem-looptoken-alloc")
+        debug_print("allocating Loop #", self.number)
+        debug_stop("jit-mem-looptoken-alloc")
+
+    def record_faildescr_index(self, n):
+        self.faildescr_indices.append(n)
+
+    def compiling_a_bridge(self):
+        self.cpu.total_compiled_bridges += 1
+        self.bridges_count += 1
+        debug_start("jit-mem-looptoken-alloc")
+        debug_print("allocating Bridge #", self.bridges_count, "of Loop #", self.number)
+        debug_stop("jit-mem-looptoken-alloc")
+
+    def __del__(self):
+        debug_start("jit-mem-looptoken-free")
+        debug_print("freeing Loop #", self.number, 'with',
+                    self.bridges_count, 'attached bridges')
+        self.cpu.free_loop_and_bridges(self)
+        self.cpu.total_freed_loops += 1
+        self.cpu.total_freed_bridges += self.bridges_count
+        debug_stop("jit-mem-looptoken-free")

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	Sat Dec 11 15:10:15 2010
@@ -174,6 +174,8 @@
         assert not wr_i1() and not wr_guard()
 
     def test_compile_bridge(self):
+        self.cpu.total_compiled_loops = 0
+        self.cpu.total_compiled_bridges = 0
         i0 = BoxInt()
         i1 = BoxInt()
         i2 = BoxInt()
@@ -199,7 +201,7 @@
         ]
         bridge[1].setfailargs([i1b])
 
-        self.cpu.compile_bridge(faildescr1, [i1b], bridge)        
+        self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken)
 
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
@@ -207,6 +209,10 @@
         res = self.cpu.get_latest_value_int(0)
         assert res == 20
 
+        assert self.cpu.total_compiled_loops == 1
+        assert self.cpu.total_compiled_bridges == 1
+        return looptoken
+
     def test_compile_bridge_with_holes(self):
         i0 = BoxInt()
         i1 = BoxInt()
@@ -233,7 +239,7 @@
         ]
         bridge[1].setfailargs([i1b])
 
-        self.cpu.compile_bridge(faildescr1, [i1b], bridge)        
+        self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken)
 
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
@@ -1050,7 +1056,7 @@
             ResOperation(rop.JUMP, [f3] + fboxes2[1:], None, descr=looptoken),
         ]
 
-        self.cpu.compile_bridge(faildescr1, fboxes2, bridge)
+        self.cpu.compile_bridge(faildescr1, fboxes2, bridge, looptoken)
 
         for i in range(len(fboxes)):
             self.cpu.set_future_value_float(i, 13.5 + 6.73 * i)
@@ -1197,6 +1203,13 @@
         yield nan_and_infinity, rop.FLOAT_GT,  operator.gt,  all_cases_binary
         yield nan_and_infinity, rop.FLOAT_GE,  operator.ge,  all_cases_binary
 
+    def test_noops(self):
+        c_box = self.alloc_string("hi there").constbox()
+        c_nest = ConstInt(0)
+        self.execute_operation(rop.DEBUG_MERGE_POINT, [c_box, c_nest], 'void')
+        self.execute_operation(rop.JIT_DEBUG, [c_box, c_nest, c_nest,
+                                               c_nest, c_nest], 'void')
+
 
 class LLtypeBackendTest(BaseBackendTest):
 
@@ -2224,6 +2237,20 @@
             assert res.value == expected, (
                 "%r: got %r, expected %r" % (RESTYPE, res.value, expected))
 
+    def test_free_loop_and_bridges(self):
+        from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU
+        if not isinstance(self.cpu, AbstractLLCPU):
+            py.test.skip("not a subclass of llmodel.AbstractLLCPU")
+        if hasattr(self.cpu, 'setup_once'):
+            self.cpu.setup_once()
+        mem0 = self.cpu.asmmemmgr.total_mallocs
+        looptoken = self.test_compile_bridge()
+        mem1 = self.cpu.asmmemmgr.total_mallocs
+        self.cpu.free_loop_and_bridges(looptoken.compiled_loop_token)
+        mem2 = self.cpu.asmmemmgr.total_mallocs
+        assert mem2 < mem1
+        assert mem2 == mem0
+
 
 class OOtypeBackendTest(BaseBackendTest):
 

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/test/test_random.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/test/test_random.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/test/test_random.py	Sat Dec 11 15:10:15 2010
@@ -524,7 +524,7 @@
         self.prebuilt_ptr_consts = []
         self.r = r
         self.build_random_loop(cpu, builder_factory, r, startvars)
-        
+
     def build_random_loop(self, cpu, builder_factory, r, startvars):
 
         loop = TreeLoop('test_random_function')
@@ -685,11 +685,12 @@
             subloop.operations[-1] = jump_op
             self.guard_op = rl.guard_op
             self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts
+            self.loop.token.record_jump_to(rl.loop.token)
             self.dont_generate_more = True
         if r.random() < .05:
             return False
         self.builder.cpu.compile_bridge(fail_descr, fail_args,
-                                        subloop.operations)
+                                        subloop.operations, self.loop.token)
         return True
 
 def check_random_function(cpu, BuilderClass, r, num=None, max=None):

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	Sat Dec 11 15:10:15 2010
@@ -1,12 +1,13 @@
 import sys, os
 from pypy.jit.backend.llsupport import symbolic
+from pypy.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
 from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
 from pypy.jit.metainterp.history import (AbstractFailDescr, INT, REF, FLOAT,
                                          LoopToken)
 from pypy.rpython.lltypesystem import lltype, rffi, rstr, llmemory
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.annlowlevel import llhelper
-from pypy.tool.uid import fixid
+from pypy.jit.backend.model import CompiledLoopToken
 from pypy.jit.backend.x86.regalloc import (RegAlloc, X86RegisterManager,
                                            X86XMMRegisterManager, get_ebp_ofs,
                                            _get_scale)
@@ -30,10 +31,11 @@
 from pypy.jit.backend.x86 import rx86, regloc, codebuf
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.backend.x86.support import values_array
-from pypy.rlib.debug import debug_print
+from pypy.jit.backend.x86 import support
+from pypy.rlib.debug import (debug_print, debug_start, debug_stop,
+                             have_debug_prints)
 from pypy.rlib import rgc
 from pypy.jit.backend.x86.jump import remap_frame_layout
-from pypy.rlib.streamio import open_file_as_stream
 from pypy.jit.metainterp.history import ConstInt, BoxInt
 
 # darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0,
@@ -43,123 +45,17 @@
 def align_stack_words(words):
     return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1)
 
-class MachineCodeBlockWrapper(object):
-    MC_DEFAULT_SIZE = 1024*1024
-
-    def __init__(self, assembler, bigsize, profile_agent=None):
-        self.assembler = assembler
-        self.old_mcs = [] # keepalive
-        self.bigsize = bigsize
-        self._mc = self._instantiate_mc()
-        self.function_name = None
-        self.profile_agent = profile_agent
-        self.reset_reserved_bytes()
-
-    def _instantiate_mc(self): # hook for testing
-        return codebuf.MachineCodeBlock(self.bigsize)
-
-    def ensure_bytes_available(self, num_bytes):
-        if self.bytes_free() <= (self._reserved_bytes + num_bytes):
-            self.make_new_mc()
-
-    def reserve_bytes(self, num_bytes):
-        self.ensure_bytes_available(num_bytes)
-        self._reserved_bytes += num_bytes
-
-    def reset_reserved_bytes(self):
-        # XXX er.... pretty random number, just to be sure
-        #     not to write half-instruction
-        self._reserved_bytes = 64
-
-    def get_relative_pos(self):
-        return self._mc.get_relative_pos()
-
-    def overwrite(self, pos, listofchars):
-        return self._mc.overwrite(pos, listofchars)
-
-    def bytes_free(self):
-        return self._mc._size - self._mc.get_relative_pos()
-
-    def start_function(self, name):
-        self.function_name = name
-        self.start_pos = self._mc.get_relative_pos()
-
-    def end_function(self, done=True):
-        assert self.function_name is not None
-        size = self._mc.get_relative_pos() - self.start_pos
-        address = self.tell() - size
-        if self.profile_agent is not None:
-            self.profile_agent.native_code_written(self.function_name,
-                                                   address, size)
-        if done:
-            self.function_name = None
-
-    def make_new_mc(self):
-        new_mc = self._instantiate_mc()
-        debug_print('[new machine code block at', new_mc.tell(), ']')
-
-        if IS_X86_64:
-            # The scratch register is sometimes used as a temporary
-            # register, but the JMP below might clobber it. Rather than risk
-            # subtle bugs, we preserve the scratch register across the jump.
-            self._mc.PUSH_r(X86_64_SCRATCH_REG.value)
-            
-        self._mc.JMP(imm(new_mc.tell()))
-
-        if IS_X86_64:
-            # Restore scratch reg
-            new_mc.POP_r(X86_64_SCRATCH_REG.value)
-
-        if self.function_name is not None:
-            self.end_function(done=False)
-            self.start_pos = new_mc.get_relative_pos()
-
-        self.assembler.write_pending_failure_recoveries()
-
-        self._mc.done()
-        self.old_mcs.append(self._mc)
-        self._mc = new_mc
-    make_new_mc._dont_inline_ = True
-
-    def tell(self):
-        return self._mc.tell()
-
-    def done(self):
-        self._mc.done()
-
-def _new_method(name):
-    def method(self, *args):
-        if self.bytes_free() < self._reserved_bytes:
-            self.make_new_mc()
-        getattr(self._mc, name)(*args)    
-    method.func_name = name
-    return method
-
-for _name in rx86.all_instructions + regloc.all_extra_instructions:
-    setattr(MachineCodeBlockWrapper, _name, _new_method(_name))
-
-for name in dir(codebuf.MachineCodeBlock):
-    if name.upper() == name or name == "writechr":
-        setattr(MachineCodeBlockWrapper, name, _new_method(name))
 
 class GuardToken(object):
-    def __init__(self, faildescr, failargs, fail_locs, exc, desc_bytes):
+    def __init__(self, faildescr, failargs, fail_locs, exc):
         self.faildescr = faildescr
         self.failargs = failargs
         self.fail_locs = fail_locs
         self.exc = exc
-        self.desc_bytes = desc_bytes
-
-    def recovery_stub_size(self):
-        # XXX: 32 is pulled out of the air
-        return 32 + len(self.desc_bytes)
 
 DEBUG_COUNTER = lltype.Struct('DEBUG_COUNTER', ('i', lltype.Signed))
 
 class Assembler386(object):
-    mc = None
-    mc_size = MachineCodeBlockWrapper.MC_DEFAULT_SIZE
-    _float_constants = None
     _regalloc = None
     _output_loop_log = None
 
@@ -177,16 +73,18 @@
         self.fail_boxes_float = values_array(lltype.Float, failargs_limit)
         self.fail_ebp = 0
         self.loop_run_counters = []
-        # if we have 10000 loops, we have some other problems I guess
         self.float_const_neg_addr = 0
         self.float_const_abs_addr = 0
         self.malloc_fixedsize_slowpath1 = 0
         self.malloc_fixedsize_slowpath2 = 0
-        self.pending_guard_tokens = None
         self.memcpy_addr = 0
         self.setup_failure_recovery()
         self._debug = False
         self.debug_counter_descr = cpu.fielddescrof(DEBUG_COUNTER, 'i')
+        self.fail_boxes_count = 0
+        self._current_depths_cache = (0, 0)
+        self.datablockwrapper = None
+        self.teardown()
 
     def leave_jitted_hook(self):
         ptrs = self.fail_boxes_ptr.ar
@@ -196,67 +94,65 @@
     def set_debug(self, v):
         self._debug = v
 
-    def setup(self):
-        if self.mc is None:
-            # the address of the function called by 'new'
-            gc_ll_descr = self.cpu.gc_ll_descr
-            gc_ll_descr.initialize()
-            ll_new = gc_ll_descr.get_funcptr_for_new()
-            self.malloc_func_addr = rffi.cast(lltype.Signed, ll_new)
-            if gc_ll_descr.get_funcptr_for_newarray is not None:
-                ll_new_array = gc_ll_descr.get_funcptr_for_newarray()
-                self.malloc_array_func_addr = rffi.cast(lltype.Signed,
-                                                        ll_new_array)
-            if gc_ll_descr.get_funcptr_for_newstr is not None:
-                ll_new_str = gc_ll_descr.get_funcptr_for_newstr()
-                self.malloc_str_func_addr = rffi.cast(lltype.Signed,
-                                                      ll_new_str)
-            if gc_ll_descr.get_funcptr_for_newunicode is not None:
-                ll_new_unicode = gc_ll_descr.get_funcptr_for_newunicode()
-                self.malloc_unicode_func_addr = rffi.cast(lltype.Signed,
-                                                          ll_new_unicode)
-            self.memcpy_addr = self.cpu.cast_ptr_to_int(codebuf.memcpy_fn)
-            self.mc = MachineCodeBlockWrapper(self, self.mc_size, self.cpu.profile_agent)
-            self._build_failure_recovery(False)
-            self._build_failure_recovery(True)
-            if self.cpu.supports_floats:
-                self._build_failure_recovery(False, withfloats=True)
-                self._build_failure_recovery(True, withfloats=True)
-                codebuf.ensure_sse2_floats()
-                self._build_float_constants()
-            if hasattr(gc_ll_descr, 'get_malloc_fixedsize_slowpath_addr'):
-                self._build_malloc_fixedsize_slowpath()
-            s = os.environ.get('PYPYLOG')
-            if s:
-                if s.find(':') != -1:
-                    s = s.split(':')[-1]
-                self.set_debug(True)
-                self._output_loop_log = s + ".count"
-            # Intialize here instead of __init__ to prevent
-            # pending_guard_tokens from being considered a prebuilt object,
-            # which sometimes causes memory leaks since the prebuilt list is
-            # still considered a GC root after we re-assign
-            # pending_guard_tokens in write_pending_failure_recoveries
-            self.pending_guard_tokens = []
+    def setup_once(self):
+        # the address of the function called by 'new'
+        gc_ll_descr = self.cpu.gc_ll_descr
+        gc_ll_descr.initialize()
+        ll_new = gc_ll_descr.get_funcptr_for_new()
+        self.malloc_func_addr = rffi.cast(lltype.Signed, ll_new)
+        if gc_ll_descr.get_funcptr_for_newarray is not None:
+            ll_new_array = gc_ll_descr.get_funcptr_for_newarray()
+            self.malloc_array_func_addr = rffi.cast(lltype.Signed,
+                                                    ll_new_array)
+        if gc_ll_descr.get_funcptr_for_newstr is not None:
+            ll_new_str = gc_ll_descr.get_funcptr_for_newstr()
+            self.malloc_str_func_addr = rffi.cast(lltype.Signed,
+                                                  ll_new_str)
+        if gc_ll_descr.get_funcptr_for_newunicode is not None:
+            ll_new_unicode = gc_ll_descr.get_funcptr_for_newunicode()
+            self.malloc_unicode_func_addr = rffi.cast(lltype.Signed,
+                                                      ll_new_unicode)
+        self.memcpy_addr = self.cpu.cast_ptr_to_int(support.memcpy_fn)
+        self._build_failure_recovery(False)
+        self._build_failure_recovery(True)
+        if self.cpu.supports_floats:
+            self._build_failure_recovery(False, withfloats=True)
+            self._build_failure_recovery(True, withfloats=True)
+            support.ensure_sse2_floats()
+            self._build_float_constants()
+        if hasattr(gc_ll_descr, 'get_malloc_fixedsize_slowpath_addr'):
+            self._build_malloc_fixedsize_slowpath()
+        debug_start('jit-backend-counts')
+        self.set_debug(have_debug_prints())
+        debug_stop('jit-backend-counts')
+
+    def setup(self, looptoken):
+        assert self.memcpy_addr != 0, "setup_once() not called?"
+        self.pending_guard_tokens = []
+        self.mc = codebuf.MachineCodeBlockWrapper()
+        if self.datablockwrapper is None:
+            allblocks = self.get_asmmemmgr_blocks(looptoken)
+            self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr,
+                                                            allblocks)
+
+    def teardown(self):
+        self.pending_guard_tokens = None
+        self.mc = None
+        self.looppos = -1
+        self.currently_compiling_loop = None
 
     def finish_once(self):
         if self._debug:
-            output_log = self._output_loop_log
-            assert output_log is not None
-            f = open_file_as_stream(output_log, "w")
+            debug_start('jit-backend-counts')
             for i in range(len(self.loop_run_counters)):
-                name, struct = self.loop_run_counters[i]
-                f.write(str(name) + ":" +  str(struct.i) + "\n")
-            f.close()
+                struct = self.loop_run_counters[i]
+                debug_print(str(i) + ':' + str(struct.i))
+            debug_stop('jit-backend-counts')
 
     def _build_float_constants(self):
-        # 44 bytes: 32 bytes for the data, and up to 12 bytes for alignment
-        addr = lltype.malloc(rffi.CArray(lltype.Char), 44, flavor='raw',
-                             track_allocation=False)
-        if not we_are_translated():
-            self._keepalive_malloced_float_consts = addr
-        float_constants = rffi.cast(lltype.Signed, addr)
-        float_constants = (float_constants + 15) & ~15    # align to 16 bytes
+        datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr, [])
+        float_constants = datablockwrapper.malloc_aligned(32, alignment=16)
+        datablockwrapper.done()
         addr = rffi.cast(rffi.CArrayPtr(lltype.Char), float_constants)
         qword_padding = '\x00\x00\x00\x00\x00\x00\x00\x00'
         # 0x8000000000000000
@@ -271,45 +167,56 @@
 
     def _build_malloc_fixedsize_slowpath(self):
         # ---------- first helper for the slow path of malloc ----------
-        self.malloc_fixedsize_slowpath1 = self.mc.tell()
+        mc = codebuf.MachineCodeBlockWrapper()
         if self.cpu.supports_floats:          # save the XMM registers in
             for i in range(self.cpu.NUM_REGS):# the *caller* frame, from esp+8
-                self.mc.MOVSD_sx((WORD*2)+8*i, i)
-        self.mc.SUB_rr(edx.value, eax.value)       # compute the size we want
+                mc.MOVSD_sx((WORD*2)+8*i, i)
+        mc.SUB_rr(edx.value, eax.value)       # compute the size we want
         if IS_X86_32:
-            self.mc.MOV_sr(WORD, edx.value)        # save it as the new argument
+            mc.MOV_sr(WORD, edx.value)        # save it as the new argument
         elif IS_X86_64:
             # rdi can be clobbered: its content was forced to the stack
             # by _fastpath_malloc(), like all other save_around_call_regs.
-            self.mc.MOV_rr(edi.value, edx.value)
+            mc.MOV_rr(edi.value, edx.value)
 
         addr = self.cpu.gc_ll_descr.get_malloc_fixedsize_slowpath_addr()
-        self.mc.JMP(imm(addr))                    # tail call to the real malloc
+        mc.JMP(imm(addr))                    # tail call to the real malloc
+        rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+        self.malloc_fixedsize_slowpath1 = rawstart
         # ---------- second helper for the slow path of malloc ----------
-        self.malloc_fixedsize_slowpath2 = self.mc.tell()
+        mc = codebuf.MachineCodeBlockWrapper()
         if self.cpu.supports_floats:          # restore the XMM registers
             for i in range(self.cpu.NUM_REGS):# from where they were saved
-                self.mc.MOVSD_xs(i, (WORD*2)+8*i)
+                mc.MOVSD_xs(i, (WORD*2)+8*i)
         nursery_free_adr = self.cpu.gc_ll_descr.get_nursery_free_addr()
-        self.mc.MOV(edx, heap(nursery_free_adr))   # load this in EDX
-        self.mc.RET()
-        self.mc.done()
+        mc.MOV(edx, heap(nursery_free_adr))   # load this in EDX
+        mc.RET()
+        rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+        self.malloc_fixedsize_slowpath2 = rawstart
 
     def assemble_loop(self, inputargs, operations, looptoken, log):
-        """adds the following attributes to looptoken:
+        '''adds the following attributes to looptoken:
                _x86_loop_code       (an integer giving an address)
                _x86_bootstrap_code  (an integer giving an address)
-               _x86_direct_bootstrap_code
+               _x86_direct_bootstrap_code  ( "    "     "    "   )
                _x86_frame_depth
                _x86_param_depth
                _x86_arglocs
                _x86_debug_checksum
-        """
+        '''
+        # XXX this function is too longish and contains some code
+        # duplication with assemble_bridge().  Also, we should think
+        # about not storing on 'self' attributes that will live only
+        # for the duration of compiling one loop or a one bridge.
+
+        clt = CompiledLoopToken(self.cpu, looptoken.number)
+        looptoken.compiled_loop_token = clt
         if not we_are_translated():
             # Arguments should be unique
             assert len(set(inputargs)) == len(inputargs)
 
-        self.setup()
+        self.setup(looptoken)
+        self.currently_compiling_loop = looptoken
         funcname = self._find_debug_merge_point(operations)
         if log:
             self._register_counter()
@@ -319,43 +226,61 @@
         arglocs = regalloc.prepare_loop(inputargs, operations, looptoken)
         looptoken._x86_arglocs = arglocs
 
-        # profile support
-        name = "Loop # %s: %s" % (looptoken.number, funcname)
-        self.mc.start_function(name)
-        looptoken._x86_bootstrap_code = self.mc.tell()
-        adr_stackadjust = self._assemble_bootstrap_code(inputargs, arglocs)
-        curadr = self.mc.tell()
-        looptoken._x86_loop_code = curadr
+        bootstrappos = self.mc.get_relative_pos()
+        stackadjustpos = self._assemble_bootstrap_code(inputargs, arglocs)
+        self.looppos = self.mc.get_relative_pos()
         looptoken._x86_frame_depth = -1     # temporarily
         looptoken._x86_param_depth = -1     # temporarily        
         frame_depth, param_depth = self._assemble(regalloc, operations)
-        self._patch_stackadjust(adr_stackadjust, frame_depth+param_depth)
         looptoken._x86_frame_depth = frame_depth
         looptoken._x86_param_depth = param_depth
 
-        looptoken._x86_direct_bootstrap_code = self.mc.tell()
-        self._assemble_bootstrap_direct_call(arglocs, curadr,
+        directbootstrappos = self.mc.get_relative_pos()
+        self._assemble_bootstrap_direct_call(arglocs, self.looppos,
                                              frame_depth+param_depth)
-        #
-        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()
-        
-    def assemble_bridge(self, faildescr, inputargs, operations, log):
+        fullsize = self.mc.get_relative_pos()
+        #
+        rawstart = self.materialize_loop(looptoken)
+        debug_print("Loop #%d (%s) has address %x to %x" % (
+            looptoken.number, funcname,
+            rawstart + self.looppos,
+            rawstart + directbootstrappos))
+        self._patch_stackadjust(rawstart + stackadjustpos,
+                                frame_depth + param_depth)
+        self.patch_pending_failure_recoveries(rawstart)
+        #
+        looptoken._x86_bootstrap_code = rawstart + bootstrappos
+        looptoken._x86_loop_code = rawstart + self.looppos
+        looptoken._x86_direct_bootstrap_code = rawstart + directbootstrappos
+        self.teardown()
+        # oprofile support
+        if self.cpu.profile_agent is not None:
+            name = "Loop # %s: %s" % (looptoken.number, funcname)
+            self.cpu.profile_agent.native_code_written(name,
+                                                       rawstart, fullsize)
+
+    def assemble_bridge(self, faildescr, inputargs, operations,
+                        original_loop_token, log):
         if not we_are_translated():
             # Arguments should be unique
             assert len(set(inputargs)) == len(inputargs)
 
-        self.setup()
+        descr_number = self.cpu.get_fail_descr_number(faildescr)
+        try:
+            failure_recovery = self._find_failure_recovery_bytecode(faildescr)
+        except ValueError:
+            debug_print("Bridge out of guard", descr_number,
+                        "was already compiled!")
+            return
+
+        self.setup(original_loop_token)
         funcname = self._find_debug_merge_point(operations)
         if log:
             self._register_counter()
             operations = self._inject_debugging_code(faildescr, operations)
 
-        arglocs = self.rebuild_faillocs_from_descr(
-            faildescr._x86_failure_recovery_bytecode)
+        arglocs = self.rebuild_faillocs_from_descr(failure_recovery)
         if not we_are_translated():
             assert ([loc.assembler() for loc in arglocs] ==
                     [loc.assembler() for loc in faildescr._x86_debug_faillocs])
@@ -364,37 +289,63 @@
         regalloc.prepare_bridge(fail_depths, inputargs, arglocs,
                                 operations)
 
-        # oprofile support
-        descr_number = self.cpu.get_fail_descr_number(faildescr)
-        name = "Bridge # %s: %s" % (descr_number, funcname)
-        self.mc.start_function(name)
-
-        adr_bridge = self.mc.tell()
-        adr_stackadjust = self._patchable_stackadjust()
+        stackadjustpos = self._patchable_stackadjust()
         frame_depth, param_depth = self._assemble(regalloc, operations)
-        self._patch_stackadjust(adr_stackadjust, frame_depth+param_depth)
+        codeendpos = self.mc.get_relative_pos()
+        self.write_pending_failure_recoveries()
+        fullsize = self.mc.get_relative_pos()
+        #
+        rawstart = self.materialize_loop(original_loop_token)
+
+        debug_print("Bridge out of guard %d (%s) has address %x to %x" %
+                    (descr_number, funcname, rawstart, rawstart + codeendpos))
+        self._patch_stackadjust(rawstart + stackadjustpos,
+                                frame_depth + param_depth)
+        self.patch_pending_failure_recoveries(rawstart)
         if not we_are_translated():
             # for the benefit of tests
             faildescr._x86_bridge_frame_depth = frame_depth
             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 %d has address %x to %x" %
-                    (descr_number, adr_bridge, self.mc.tell()))
-        self.mc.end_function()
-        self.write_pending_failure_recoveries()
+        self.patch_jump_for_descr(faildescr, rawstart)
+        self.teardown()
+        # oprofile support
+        if self.cpu.profile_agent is not None:
+            name = "Bridge # %s: %s" % (descr_number, funcname)
+            self.cpu.profile_agent.native_code_written(name,
+                                                       rawstart, fullsize)
 
     def write_pending_failure_recoveries(self):
+        # for each pending guard, generate the code of the recovery stub
+        # at the end of self.mc.
         for tok in self.pending_guard_tokens:
-            # Okay to write to _mc because we've already made sure that
-            # there's enough space by "reserving" bytes.
-            addr = self.generate_quick_failure(self.mc._mc, tok.faildescr, tok.failargs, tok.fail_locs, tok.exc, tok.desc_bytes)
-            tok.faildescr._x86_adr_recovery_stub = addr
-            self.patch_jump_for_descr(tok.faildescr, addr)
+            tok.pos_recovery_stub = self.generate_quick_failure(tok)
 
-        self.pending_guard_tokens = []
-        self.mc.reset_reserved_bytes()
-        self.mc.done()
+    def patch_pending_failure_recoveries(self, rawstart):
+        # after we wrote the assembler to raw memory, set up
+        # tok.faildescr._x86_adr_jump_offset to contain the raw address of
+        # the 4-byte target field in the JMP/Jcond instruction, and patch
+        # the field in question to point (initially) to the recovery stub
+        for tok in self.pending_guard_tokens:
+            addr = rawstart + tok.pos_jump_offset
+            tok.faildescr._x86_adr_jump_offset = addr
+            relative_target = tok.pos_recovery_stub - (tok.pos_jump_offset + 4)
+            assert rx86.fits_in_32bits(relative_target)
+            p = rffi.cast(rffi.INTP, addr)
+            p[0] = rffi.cast(rffi.INT, relative_target)
+
+    def get_asmmemmgr_blocks(self, looptoken):
+        clt = looptoken.compiled_loop_token
+        if clt.asmmemmgr_blocks is None:
+            clt.asmmemmgr_blocks = []
+        return clt.asmmemmgr_blocks
+
+    def materialize_loop(self, looptoken):
+        self.datablockwrapper.done()      # finish using cpu.asmmemmgr
+        self.datablockwrapper = None
+        allblocks = self.get_asmmemmgr_blocks(looptoken)
+        return self.mc.materialize(self.cpu.asmmemmgr, allblocks,
+                                   self.cpu.gc_ll_descr.gcrootmap)
 
     def _find_debug_merge_point(self, operations):
 
@@ -409,29 +360,50 @@
 
     def _register_counter(self):
         if self._debug:
+            # YYY very minor leak -- we need the counters to stay alive
+            # forever, just because we want to report them at the end
+            # of the process
             struct = lltype.malloc(DEBUG_COUNTER, flavor='raw',
-                                   track_allocation=False)   # known to leak
+                                   track_allocation=False)
             struct.i = 0
-            self.loop_run_counters.append((len(self.loop_run_counters), struct))
-        
+            self.loop_run_counters.append(struct)
+
+    def _find_failure_recovery_bytecode(self, faildescr):
+        adr_jump_offset = faildescr._x86_adr_jump_offset
+        if adr_jump_offset == 0:
+            raise ValueError
+        # follow the JMP/Jcond
+        p = rffi.cast(rffi.INTP, adr_jump_offset)
+        adr_target = adr_jump_offset + 4 + rffi.cast(lltype.Signed, p[0])
+        # skip the CALL
+        if WORD == 4:
+            adr_target += 5     # CALL imm
+        else:
+            adr_target += 13    # MOV r11, imm; CALL *r11
+        return adr_target
+
     def patch_jump_for_descr(self, faildescr, adr_new_target):
         adr_jump_offset = faildescr._x86_adr_jump_offset
-        adr_recovery_stub = faildescr._x86_adr_recovery_stub
+        assert adr_jump_offset != 0
         offset = adr_new_target - (adr_jump_offset + 4)
         # If the new target fits within a rel32 of the jump, just patch
         # that. Otherwise, leave the original rel32 to the recovery stub in
         # place, but clobber the recovery stub with a jump to the real
         # target.
+        mc = codebuf.MachineCodeBlockWrapper()
         if rx86.fits_in_32bits(offset):
-            mc = codebuf.InMemoryCodeBuilder(adr_jump_offset, adr_jump_offset + 4)
             mc.writeimm32(offset)
+            mc.copy_to_raw_memory(adr_jump_offset)
         else:
-            # "mov r11, addr; jmp r11" is 13 bytes
-            mc = codebuf.InMemoryCodeBuilder(adr_recovery_stub, adr_recovery_stub + 13)
+            # "mov r11, addr; jmp r11" is 13 bytes, which fits in there
+            # because we always write "mov r11, addr; call *r11" in the
+            # first place.
             mc.MOV_ri(X86_64_SCRATCH_REG.value, adr_new_target)
             mc.JMP_r(X86_64_SCRATCH_REG.value)
-
-        mc.done()
+            p = rffi.cast(rffi.INTP, adr_jump_offset)
+            adr_target = adr_jump_offset + 4 + rffi.cast(lltype.Signed, p[0])
+            mc.copy_to_raw_memory(adr_target)
+        faildescr._x86_adr_jump_offset = 0    # means "patched"
 
     @specialize.argtype(1)
     def _inject_debugging_code(self, looptoken, operations):
@@ -442,7 +414,7 @@
                 s += op.getopnum()
             looptoken._x86_debug_checksum = s
             c_adr = ConstInt(rffi.cast(lltype.Signed,
-                                     self.loop_run_counters[-1][1]))
+                                       self.loop_run_counters[-1]))
             box = BoxInt()
             box2 = BoxInt()
             ops = [ResOperation(rop.GETFIELD_RAW, [c_adr],
@@ -451,19 +423,11 @@
                    ResOperation(rop.SETFIELD_RAW, [c_adr, box2],
                                 None, descr=self.debug_counter_descr)]
             operations = ops + operations
-            # # we need one register free (a bit of a hack, but whatever)
-            # self.mc.PUSH(eax)
-            # adr = rffi.cast(lltype.Signed, self.loop_run_counters[-1][1])
-            # self.mc.MOV(eax, heap(adr))
-            # self.mc.ADD(eax, imm1)
-            # self.mc.MOV(heap(adr), eax)
-            # self.mc.POP(eax)
         return operations
 
     def _assemble(self, regalloc, operations):
         self._regalloc = regalloc
         regalloc.walk_operations(operations)        
-        self.mc.done()
         if we_are_translated() or self.cpu.dont_keepalive_stuff:
             self._regalloc = None   # else keep it around for debugging
         frame_depth = regalloc.fm.frame_depth
@@ -479,30 +443,31 @@
     def _patchable_stackadjust(self):
         # stack adjustment LEA
         self.mc.LEA32_rb(esp.value, 0)
-        return self.mc.tell() - 4
+        return self.mc.get_relative_pos() - 4
 
-    def _patch_stackadjust(self, adr_lea, reserved_depth):
+    def _patch_stackadjust(self, adr_lea, allocated_depth):
         # patch stack adjustment LEA
-        mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 4)
-        # Compute the correct offset for the instruction LEA ESP, [EBP-4*words].
+        mc = codebuf.MachineCodeBlockWrapper()
+        # Compute the correct offset for the instruction LEA ESP, [EBP-4*words]
+        mc.writeimm32(self._get_offset_of_ebp_from_esp(allocated_depth))
+        mc.copy_to_raw_memory(adr_lea)
+
+    def _get_offset_of_ebp_from_esp(self, allocated_depth):
         # Given that [EBP] is where we saved EBP, i.e. in the last word
         # of our fixed frame, then the 'words' value is:
-        words = (self.cpu.FRAME_FIXED_SIZE - 1) + reserved_depth
-        # align, e.g. for Mac OS X        
+        words = (self.cpu.FRAME_FIXED_SIZE - 1) + allocated_depth
+        # align, e.g. for Mac OS X
         aligned_words = align_stack_words(words+2)-2 # 2 = EIP+EBP
-        mc.writeimm32(-WORD * aligned_words)
-        mc.done()
+        return -WORD * aligned_words
 
     def _call_header(self):
+        # NB. the shape of the frame is hard-coded in get_basic_shape() too.
+        # Also, make sure this is consistent with FRAME_FIXED_SIZE.
         self.mc.PUSH_r(ebp.value)
         self.mc.MOV_rr(ebp.value, esp.value)
         for regloc in self.cpu.CALLEE_SAVE_REGISTERS:
             self.mc.PUSH_r(regloc.value)
 
-        # NB. the shape of the frame is hard-coded in get_basic_shape() too.
-        # Also, make sure this is consistent with FRAME_FIXED_SIZE.
-        return self._patchable_stackadjust()
-
     def _call_footer(self):
         self.mc.LEA_rb(esp.value, -len(self.cpu.CALLEE_SAVE_REGISTERS) * WORD)
 
@@ -512,17 +477,16 @@
         self.mc.POP_r(ebp.value)
         self.mc.RET()
 
-    def _assemble_bootstrap_direct_call(self, arglocs, jmpadr, stackdepth):
+    def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth):
         if IS_X86_64:
-            return self._assemble_bootstrap_direct_call_64(arglocs, jmpadr, stackdepth)
+            return self._assemble_bootstrap_direct_call_64(arglocs, jmppos, stackdepth)
         # XXX pushing ebx esi and edi is a bit pointless, since we store
         #     all regsiters anyway, for the case of guard_not_forced
         # XXX this can be improved greatly. Right now it'll behave like
         #     a normal call
         nonfloatlocs, floatlocs = arglocs
-        # XXX not to repeat the logic, a bit around
-        adr_stackadjust = self._call_header()
-        self._patch_stackadjust(adr_stackadjust, stackdepth)
+        self._call_header()
+        self.mc.LEA_rb(esp.value, self._get_offset_of_ebp_from_esp(stackdepth))
         for i in range(len(nonfloatlocs)):
             loc = nonfloatlocs[i]
             if isinstance(loc, RegLoc):
@@ -544,9 +508,11 @@
                 self.mc.MOVSD_xb(xmmtmp.value, (1 + i) * 2 * WORD)
                 assert isinstance(loc, StackLoc)
                 self.mc.MOVSD_bx(loc.value, xmmtmp.value)
-        self.mc.JMP_l(jmpadr)
+        endpos = self.mc.get_relative_pos() + 5
+        self.mc.JMP_l(jmppos - endpos)
+        assert endpos == self.mc.get_relative_pos()
 
-    def _assemble_bootstrap_direct_call_64(self, arglocs, jmpadr, stackdepth):
+    def _assemble_bootstrap_direct_call_64(self, arglocs, jmppos, stackdepth):
         # XXX: Very similar to _emit_call_64
 
         src_locs = []
@@ -560,8 +526,8 @@
         unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0]
 
         nonfloatlocs, floatlocs = arglocs
-        adr_stackadjust = self._call_header()
-        self._patch_stackadjust(adr_stackadjust, stackdepth)
+        self._call_header()
+        self.mc.LEA_rb(esp.value, self._get_offset_of_ebp_from_esp(stackdepth))
 
         # The lists are padded with Nones
         assert len(nonfloatlocs) == len(floatlocs)
@@ -597,8 +563,9 @@
                 # clobber the scratch register
                 self.mc.MOV(loc, X86_64_SCRATCH_REG)
 
-        finaljmp = self.mc.tell()
-        self.mc.JMP(imm(jmpadr))
+        endpos = self.mc.get_relative_pos() + 5
+        self.mc.JMP_l(jmppos - endpos)
+        assert endpos == self.mc.get_relative_pos()
 
     def redirect_call_assembler(self, oldlooptoken, newlooptoken):
         # some minimal sanity checking
@@ -611,16 +578,17 @@
         # Ideally we should rather patch all existing CALLs, but well.
         oldadr = oldlooptoken._x86_direct_bootstrap_code
         target = newlooptoken._x86_direct_bootstrap_code
-        mc = codebuf.InMemoryCodeBuilder(oldadr, oldadr + 16)
+        mc = codebuf.MachineCodeBlockWrapper()
         mc.JMP(imm(target))
-        mc.done()
+        mc.copy_to_raw_memory(oldadr)
 
     def _assemble_bootstrap_code(self, inputargs, arglocs):
         nonfloatlocs, floatlocs = arglocs
-        adr_stackadjust = self._call_header()
+        self._call_header()
+        stackadjustpos = self._patchable_stackadjust()
         tmp = X86RegisterManager.all_regs[0]
         xmmtmp = X86XMMRegisterManager.all_regs[0]
-        self.mc._mc.begin_reuse_scratch_register()
+        self.mc.begin_reuse_scratch_register()
         for i in range(len(nonfloatlocs)):
             loc = nonfloatlocs[i]
             if loc is None:
@@ -652,8 +620,8 @@
                 self.mc.MOVSD(xmmtmp, heap(adr))
                 assert isinstance(loc, StackLoc)
                 self.mc.MOVSD_bx(loc.value, xmmtmp.value)
-        self.mc._mc.end_reuse_scratch_register()
-        return adr_stackadjust
+        self.mc.end_reuse_scratch_register()
+        return stackadjustpos
 
     def dump(self, text):
         if not self.verbose:
@@ -661,7 +629,8 @@
         _prev = Box._extended_display
         try:
             Box._extended_display = False
-            print >> sys.stderr, ' 0x%x  %s' % (fixid(self.mc.tell()), text)
+            pos = self.mc.get_relative_pos()
+            print >> sys.stderr, ' 0x%x  %s' % (pos, text)
         finally:
             Box._extended_display = _prev
 
@@ -721,7 +690,7 @@
                                          arglocs, resloc)
         if not we_are_translated():
             # must be added by the genop_guard_list[]()
-            assert hasattr(faildescr, '_x86_adr_jump_offset')
+            assert guard_token is self.pending_guard_tokens[-1]
 
     def regalloc_perform_guard(self, guard_op, faillocs, arglocs, resloc,
                                current_depths):
@@ -794,9 +763,6 @@
                                   result_loc):
             guard_opnum = guard_op.getopnum()
             self.mc.UCOMISD(arglocs[0], arglocs[1])
-            # 16 is enough space for the rel8 jumps below and the rel32
-            # jump in implement_guard
-            self.mc.ensure_bytes_available(16 + guard_token.recovery_stub_size())
             if guard_opnum == rop.GUARD_FALSE:
                 if need_jp:
                     self.mc.J_il8(rx86.Conditions['P'], 6)
@@ -964,9 +930,6 @@
     def genop_guard_float_ne(self, op, guard_op, guard_token, arglocs, result_loc):
         guard_opnum = guard_op.getopnum()
         self.mc.UCOMISD(arglocs[0], arglocs[1])
-        # 16 is enough space for the rel8 jumps below and the rel32
-        # jump in implement_guard
-        self.mc.ensure_bytes_available(16 + guard_token.recovery_stub_size())
         if guard_opnum == rop.GUARD_TRUE:
             self.mc.J_il8(rx86.Conditions['P'], 6)
             self.implement_guard(guard_token, 'E')
@@ -1290,13 +1253,11 @@
                 self.mc.CMP32_mi((locs[0].value, 0), expected_typeid)
 
     def genop_guard_guard_class(self, ign_1, guard_op, guard_token, locs, ign_2):
-        self.mc.ensure_bytes_available(256)
         self._cmp_guard_class(locs)
         self.implement_guard(guard_token, 'NE')
 
     def genop_guard_guard_nonnull_class(self, ign_1, guard_op,
                                         guard_token, locs, ign_2):
-        self.mc.ensure_bytes_available(256)
         self.mc.CMP(locs[0], imm1)
         # Patched below
         self.mc.J_il8(rx86.Conditions['B'], 0)
@@ -1305,7 +1266,7 @@
         # patch the JB above
         offset = self.mc.get_relative_pos() - jb_location
         assert 0 < offset <= 127
-        self.mc.overwrite(jb_location-1, [chr(offset)])
+        self.mc.overwrite(jb_location-1, chr(offset))
         #
         self.implement_guard(guard_token, 'NE')
 
@@ -1314,42 +1275,33 @@
         exc = (guard_opnum == rop.GUARD_EXCEPTION or
                guard_opnum == rop.GUARD_NO_EXCEPTION or
                guard_opnum == rop.GUARD_NOT_FORCED)
-        desc_bytes = self.failure_recovery_description(failargs, fail_locs)
-        return GuardToken(faildescr, failargs, fail_locs, exc, desc_bytes)
+        return GuardToken(faildescr, failargs, fail_locs, exc)
 
-    def generate_quick_failure(self, mc, faildescr, failargs, fail_locs, exc, desc_bytes):
+    def generate_quick_failure(self, guardtok):
         """Generate the initial code for handling a failure.  We try to
-        keep it as compact as possible.  The idea is that this code is
-        executed at most once (and very often, zero times); when
-        executed, it generates a more complete piece of code which can
-        really handle recovery from this particular failure.
+        keep it as compact as possible.
         """
-        fail_index = self.cpu.get_fail_descr_number(faildescr)
-        addr = mc.tell()
+        fail_index = self.cpu.get_fail_descr_number(guardtok.faildescr)
+        mc = self.mc
+        startpos = mc.get_relative_pos()
         withfloats = False
-        for box in failargs:
+        for box in guardtok.failargs:
             if box is not None and box.type == FLOAT:
                 withfloats = True
                 break
+        exc = guardtok.exc
         mc.CALL(imm(self.failure_recovery_code[exc + 2 * withfloats]))
         # write tight data that describes the failure recovery
-        faildescr._x86_failure_recovery_bytecode = mc.tell()
-        for byte in desc_bytes:
-            mc.writechr(ord(byte))
+        self.write_failure_recovery_description(mc, guardtok.failargs,
+                                                guardtok.fail_locs)
         # write the fail_index too
         mc.writeimm32(fail_index)
         # for testing the decoding, write a final byte 0xCC
         if not we_are_translated():
-            mc.writechr(0xCC)
-            faildescr._x86_debug_faillocs = [loc for loc in fail_locs
-                                                 if loc is not None]
-
-        # Make sure the recovery stub is at least 16 bytes long (for the
-        # case where we overwrite the recovery stub with a 64-bit absolute
-        # jump)
-        while mc.tell() - addr < 16:
-            mc.writechr(0x00)
-        return addr
+            mc.writechar('\xCC')
+            faillocs = [loc for loc in guardtok.fail_locs if loc is not None]
+            guardtok.faildescr._x86_debug_faillocs = faillocs
+        return startpos
 
     DESCR_REF       = 0x00
     DESCR_INT       = 0x01
@@ -1360,8 +1312,7 @@
     CODE_STOP       = 0 | DESCR_SPECIAL
     CODE_HOLE       = 4 | DESCR_SPECIAL
 
-    def failure_recovery_description(self, failargs, locs):
-        desc_bytes = []
+    def write_failure_recovery_description(self, mc, failargs, locs):
         for i in range(len(failargs)):
             arg = failargs[i]
             if arg is not None:
@@ -1381,19 +1332,14 @@
                     n = loc.value
                 n = kind + 4*n
                 while n > 0x7F:
-                    desc_bytes.append(chr((n & 0x7F) | 0x80))
+                    mc.writechar(chr((n & 0x7F) | 0x80))
                     n >>= 7
             else:
                 n = self.CODE_HOLE
-            desc_bytes.append(chr(n))
-        desc_bytes.append(chr(self.CODE_STOP))
+            mc.writechar(chr(n))
+        mc.writechar(chr(self.CODE_STOP))
         # assert that the fail_boxes lists are big enough
         assert len(failargs) <= self.fail_boxes_int.SIZE
-        return desc_bytes
-
-    def write_failure_recovery_description(self, mc, failargs, locs):
-        for byte in self.failure_recovery_description(failargs, locs):
-            mc.writechr(ord(byte))
 
     def rebuild_faillocs_from_descr(self, bytecode):
         from pypy.jit.backend.x86.regalloc import X86FrameManager
@@ -1531,10 +1477,8 @@
                                          self.failure_recovery_func)
         failure_recovery_func = rffi.cast(lltype.Signed,
                                           failure_recovery_func)
-        mc = self.mc._mc
-        # Assume that we are called at the beginning, when there is no risk
-        # that 'mc' runs out of space.  Checked by asserts in mc.write().
-        recovery_addr = mc.tell()
+        mc = codebuf.MachineCodeBlockWrapper()
+        self.mc = mc
 
         # Push all general purpose registers
         for gpr in range(self.cpu.NUM_REGS-1, -1, -1):
@@ -1585,11 +1529,12 @@
         # above.
 
         self._call_footer()
-        self.mc.done()
-        self.failure_recovery_code[exc + 2 * withfloats] = recovery_addr
+        rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+        self.failure_recovery_code[exc + 2 * withfloats] = rawstart
+        self.mc = None
 
     def generate_failure(self, fail_index, locs, exc, locs_are_ref):
-        self.mc._mc.begin_reuse_scratch_register()
+        self.mc.begin_reuse_scratch_register()
         for i in range(len(locs)):
             loc = locs[i]
             if isinstance(loc, RegLoc):
@@ -1616,7 +1561,7 @@
                         adr = self.fail_boxes_int.get_addr_for_num(i)
                     self.mc.MOV(eax, loc)
                     self.mc.MOV(heap(adr), eax)
-        self.mc._mc.end_reuse_scratch_register()
+        self.mc.end_reuse_scratch_register()
 
         # we call a provided function that will
         # - call our on_leave_jitted_hook which will mark
@@ -1632,17 +1577,13 @@
         self._call_footer()
 
     def implement_guard(self, guard_token, condition=None):
-        self.mc.reserve_bytes(guard_token.recovery_stub_size())
-        self.pending_guard_tokens.append(guard_token)
-        # These jumps are patched later, the mc.tell() are just
-        # dummy values.  Also, use self.mc._mc to avoid triggering a
-        # "buffer full" exactly here.
-        mc = self.mc._mc
+        # These jumps are patched later.
         if condition:
-            mc.J_il(rx86.Conditions[condition], mc.tell())
+            self.mc.J_il(rx86.Conditions[condition], 0)
         else:
-            mc.JMP_l(mc.tell())
-        guard_token.faildescr._x86_adr_jump_offset = mc.tell() - 4
+            self.mc.JMP_l(0)
+        guard_token.pos_jump_offset = self.mc.get_relative_pos() - 4
+        self.pending_guard_tokens.append(guard_token)
 
     def genop_call(self, op, arglocs, resloc):
         sizeloc = arglocs[0]
@@ -1697,7 +1638,6 @@
         # Write a call to the direct_bootstrap_code of the target assembler
         self._emit_call(imm(descr._x86_direct_bootstrap_code), arglocs, 2,
                         tmp=eax)
-        self.mc.ensure_bytes_available(256)
         if op.result is None:
             assert result_loc is None
             value = self.cpu.done_with_this_frame_void_v
@@ -1733,7 +1673,7 @@
         # Path B: fast path.  Must load the return value, and reset the token
         offset = jmp_location - je_location
         assert 0 < offset <= 127
-        self.mc.overwrite(je_location - 1, [chr(offset)])
+        self.mc.overwrite(je_location - 1, chr(offset))
         #
         # Reset the vable token --- XXX really too much special logic here:-(
         if jd.index_of_virtualizable >= 0:
@@ -1768,7 +1708,7 @@
         # Here we join Path A and Path B again
         offset = self.mc.get_relative_pos() - jmp_location
         assert 0 <= offset <= 127
-        self.mc.overwrite(jmp_location - 1, [chr(offset)])
+        self.mc.overwrite(jmp_location - 1, chr(offset))
         self.mc.CMP_bi(FORCE_INDEX_OFS, 0)
         self.implement_guard(guard_token, 'L')
 
@@ -1783,9 +1723,6 @@
             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)
         self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later
@@ -1828,7 +1765,7 @@
         # patch the JZ above
         offset = self.mc.get_relative_pos() - jz_location
         assert 0 < offset <= 127
-        self.mc.overwrite(jz_location-1, [chr(offset)])
+        self.mc.overwrite(jz_location-1, chr(offset))
 
     def genop_force_token(self, op, arglocs, resloc):
         # RegAlloc.consider_force_token ensures this:
@@ -1851,18 +1788,21 @@
         gcrootmap = self.cpu.gc_ll_descr.gcrootmap
         if gcrootmap:
             mark = self._regalloc.get_mark_gc_roots(gcrootmap)
-            gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()), mark)
+            self.mc.insert_gcroot_marker(mark)
 
     def target_arglocs(self, loop_token):
         return loop_token._x86_arglocs
 
     def closing_jump(self, loop_token):
-        self.mc.JMP(imm(loop_token._x86_loop_code))
+        if loop_token is self.currently_compiling_loop:
+            curpos = self.mc.get_relative_pos() + 5
+            self.mc.JMP_l(self.looppos - curpos)
+        else:
+            self.mc.JMP(imm(loop_token._x86_loop_code))
 
     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))
         self.mc.CMP(edx, heap(nursery_top_adr))
@@ -1890,7 +1830,7 @@
 
         offset = self.mc.get_relative_pos() - jmp_adr
         assert 0 < offset <= 127
-        self.mc.overwrite(jmp_adr-1, [chr(offset)])
+        self.mc.overwrite(jmp_adr-1, chr(offset))
         # on 64-bits, 'tid' is a value that fits in 31 bits
         self.mc.MOV_mi((eax.value, 0), tid)
         self.mc.MOV(heap(nursery_free_adr), edx)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/regalloc.py	Sat Dec 11 15:10:15 2010
@@ -60,32 +60,6 @@
         r15: 5,
     }
 
-class FloatConstants(object):
-    BASE_CONSTANT_SIZE = 1000
-
-    def __init__(self):
-        self.cur_array_free = 0
-        self.const_id = 0
-
-    def _get_new_array(self):
-        n = self.BASE_CONSTANT_SIZE
-        # known to leak
-        self.cur_array = lltype.malloc(rffi.CArray(lltype.Float), n,
-                                       flavor='raw', track_allocation=False)
-        self.cur_array_free = n
-    _get_new_array._dont_inline_ = True
-
-    def record_float(self, floatval):
-        if self.cur_array_free == 0:
-            self._get_new_array()
-        arr = self.cur_array
-        n = self.cur_array_free - 1
-        arr[n] = floatval
-        self.cur_array_free = n
-        self.const_id += 1
-        return (self.const_id, rffi.cast(lltype.Signed, arr) + n * 8)
-
-
 class X86XMMRegisterManager(RegisterManager):
 
     box_types = [FLOAT]
@@ -93,20 +67,11 @@
     # we never need lower byte I hope
     save_around_call_regs = all_regs
 
-    def __init__(self, longevity, frame_manager=None, assembler=None):
-        RegisterManager.__init__(self, longevity, frame_manager=frame_manager,
-                                 assembler=assembler)
-        if assembler is None:
-            self.float_constants = FloatConstants()
-        else:
-            if assembler._float_constants is None:
-                assembler._float_constants = FloatConstants()
-            self.float_constants = assembler._float_constants
-
     def convert_to_imm(self, c):
-        const_id, adr = self.float_constants.record_float(c.getfloat())
-        return ConstFloatLoc(adr, const_id)
-        
+        adr = self.assembler.datablockwrapper.malloc_aligned(8, 8)
+        rffi.cast(rffi.CArrayPtr(rffi.DOUBLE), adr)[0] = c.getfloat()
+        return ConstFloatLoc(adr)
+
     def after_call(self, v):
         # the result is stored in st0, but we don't have this around,
         # so genop_call will move it to some frame location immediately
@@ -320,11 +285,22 @@
     def locs_for_fail(self, guard_op):
         return [self.loc(v) for v in guard_op.getfailargs()]
 
+    def get_current_depth(self):
+        # return (self.fm.frame_depth, self.param_depth), but trying to share
+        # the resulting tuple among several calls
+        arg0 = self.fm.frame_depth
+        arg1 = self.param_depth
+        result = self.assembler._current_depths_cache
+        if result[0] != arg0 or result[1] != arg1:
+            result = (arg0, arg1)
+            self.assembler._current_depths_cache = result
+        return result
+
     def perform_with_guard(self, op, guard_op, arglocs, result_loc):
         faillocs = self.locs_for_fail(guard_op)
         self.rm.position += 1
         self.xrm.position += 1
-        current_depths = (self.fm.frame_depth, self.param_depth)
+        current_depths = self.get_current_depth()
         self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs,
                                                    arglocs, result_loc,
                                                    current_depths)
@@ -340,7 +316,7 @@
                                                       arglocs))
             else:
                 self.assembler.dump('%s(%s)' % (guard_op, arglocs))
-        current_depths = (self.fm.frame_depth, self.param_depth)                
+        current_depths = self.get_current_depth()
         self.assembler.regalloc_perform_guard(guard_op, faillocs, arglocs,
                                               result_loc,
                                               current_depths)
@@ -1097,7 +1073,8 @@
             if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)):
                 assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX
                 gcrootmap.add_callee_save_reg(shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg])
-        return gcrootmap.compress_callshape(shape)
+        return gcrootmap.compress_callshape(shape,
+                                            self.assembler.datablockwrapper)
 
     def consider_force_token(self, op):
         loc = self.rm.force_allocate_reg(op.result)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/regloc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/regloc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/regloc.py	Sat Dec 11 15:10:15 2010
@@ -177,24 +177,15 @@
 
 class ConstFloatLoc(AssemblerLocation):
     # XXX: We have to use this class instead of just AddressLoc because
-    # AddressLoc is "untyped" and also we to have need some sort of unique
-    # identifier that we can use in _getregkey (for jump.py)
-
+    # we want a width of 8  (... I think.  Check this!)
     _immutable_ = True
-
     width = 8
 
-    def __init__(self, address, const_id):
+    def __init__(self, address):
         self.value = address
-        self.const_id = const_id
 
     def __repr__(self):
-        return '<ConstFloatLoc(%s, %s)>' % (self.value, self.const_id)
-
-    def _getregkey(self):
-        # XXX: 1000 is kind of magic: We just don't want to be confused
-        # with any registers
-        return 1000 + self.const_id
+        return '<ConstFloatLoc @%s>' % (self.value,)
 
     def location_code(self):
         return 'j'
@@ -334,9 +325,9 @@
                 if code == possible_code:
                     val = getattr(loc, "value_" + possible_code)()
                     if possible_code == 'i':
-                        offset = intmask(val - (self.tell() + 5))
-                        if rx86.fits_in_32bits(offset):
+                        if self.WORD == 4:
                             _rx86_getattr(self, name + "_l")(val)
+                            self.add_pending_relocation()
                         else:
                             assert self.WORD == 8
                             self._load_scratch(val)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/runner.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/runner.py	Sat Dec 11 15:10:15 2010
@@ -44,6 +44,7 @@
 
     def setup_once(self):
         self.profile_agent.startup()
+        self.assembler.setup_once()
 
     def finish_once(self):
         self.assembler.finish_once()
@@ -53,9 +54,12 @@
         self.assembler.assemble_loop(inputargs, operations, looptoken,
                                      log=log)
 
-    def compile_bridge(self, faildescr, inputargs, operations, log=True):
+    def compile_bridge(self, faildescr, inputargs, operations,
+                       original_loop_token, log=True):
+        clt = original_loop_token.compiled_loop_token
+        clt.compiling_a_bridge()
         self.assembler.assemble_bridge(faildescr, inputargs, operations,
-                                       log=log)
+                                       original_loop_token, log=log)
 
     def set_future_value_int(self, index, intvalue):
         self.assembler.fail_boxes_int.setitem(index, intvalue)
@@ -124,8 +128,8 @@
         assert fail_index >= 0, "already forced!"
         faildescr = self.get_fail_descr_from_number(fail_index)
         rffi.cast(TP, addr_of_force_index)[0] = -1
-        bytecode = rffi.cast(rffi.UCHARP,
-                             faildescr._x86_failure_recovery_bytecode)
+        frb = self.assembler._find_failure_recovery_bytecode(faildescr)
+        bytecode = rffi.cast(rffi.UCHARP, frb)
         # start of "no gc operation!" block
         fail_index_2 = self.assembler.grab_frame_values(
             bytecode,
@@ -165,17 +169,12 @@
 CPU = CPU386
 
 # silence warnings
-
-history.LoopToken._x86_param_depth = 0
-history.LoopToken._x86_arglocs = (None, None)
-history.LoopToken._x86_frame_depth = 0
-history.LoopToken._x86_bootstrap_code = 0
-history.LoopToken._x86_direct_bootstrap_code = 0
-history.LoopToken._x86_failure_recovery_bytecode = 0
-history.LoopToken._x86_loop_code = 0
-history.LoopToken._x86_current_depths = (0, 0)
-
-compile._DoneWithThisFrameDescr._x86_current_depths = (0, 0)
-compile._DoneWithThisFrameDescr._x86_failure_recovery_bytecode = 0
-compile._DoneWithThisFrameDescr._x86_adr_jump_offset = 0
-
+##history.LoopToken._x86_param_depth = 0
+##history.LoopToken._x86_arglocs = (None, None)
+##history.LoopToken._x86_frame_depth = 0
+##history.LoopToken._x86_bootstrap_code = 0
+##history.LoopToken._x86_direct_bootstrap_code = 0
+##history.LoopToken._x86_loop_code = 0
+##history.LoopToken._x86_debug_checksum = 0
+##compile.AbstractFailDescr._x86_current_depths = (0, 0)
+##compile.AbstractFailDescr._x86_adr_jump_offset = 0

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/rx86.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/rx86.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/rx86.py	Sat Dec 11 15:10:15 2010
@@ -137,10 +137,9 @@
 # ____________________________________________________________
 # Emit an immediate displacement (relative to the cur insn)
 
-def encode_relative(mc, target, _, orbyte):
+def encode_relative(mc, relative_target, _, orbyte):
     assert orbyte == 0
-    offset = intmask(target - (mc.tell() + 4))
-    mc.writeimm32(offset)
+    mc.writeimm32(relative_target)
     return 0
 
 def relative(argnum):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/support.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/support.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/support.py	Sat Dec 11 15:10:15 2010
@@ -1,4 +1,7 @@
+import sys
 from pypy.rpython.lltypesystem import lltype, rffi, llmemory
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
 
 def values_array(TP, size):
     ATP = lltype.GcArray(TP)
@@ -23,3 +26,22 @@
             return True
 
     return ValuesArray()
+
+# ____________________________________________________________
+
+memcpy_fn = rffi.llexternal('memcpy', [llmemory.Address, llmemory.Address,
+                                       rffi.SIZE_T], lltype.Void,
+                            sandboxsafe=True, _nowrapper=True)
+
+# ____________________________________________________________
+
+if sys.platform == 'win32':
+    ensure_sse2_floats = lambda : None
+else:
+    _sse2_eci = ExternalCompilationInfo(
+        compile_extra = ['-msse2', '-mfpmath=sse'],
+        separate_module_sources = ['void PYPY_NO_OP(void) {}'],
+        )
+    ensure_sse2_floats = rffi.llexternal('PYPY_NO_OP', [], lltype.Void,
+                                         compilation_info=_sse2_eci,
+                                         sandboxsafe=True)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_assembler.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_assembler.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_assembler.py	Sat Dec 11 15:10:15 2010
@@ -1,5 +1,5 @@
 from pypy.jit.backend.x86.regloc import *
-from pypy.jit.backend.x86.assembler import Assembler386, MachineCodeBlockWrapper
+from pypy.jit.backend.x86.assembler import Assembler386
 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs
 from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT
 from pypy.rlib.rarithmetic import intmask
@@ -19,28 +19,10 @@
         return 42
 
 class FakeMC:
-    def __init__(self, base_address=0):
+    def __init__(self):
         self.content = []
-        self._size = 100
-        self.base_address = base_address
-    def writechr(self, n):
-        self.content.append(n)
-    def tell(self):
-        return self.base_address + len(self.content)
-    def get_relative_pos(self):
-        return len(self.content)
-    def JMP(self, *args):
-        self.content.append(("JMP", args))
-    def done(self):
-        pass
-    def PUSH_r(self, reg):
-        pass
-    def POP_r(self, reg):
-        pass
-
-class FakeAssembler:
-    def write_pending_failure_recoveries(self):
-        pass
+    def writechar(self, char):
+        self.content.append(ord(char))
 
 def test_write_failure_recovery_description():
     assembler = Assembler386(FakeCPU())
@@ -255,41 +237,3 @@
         assert assembler.fail_boxes_int.getitem(i) == expected_ints[i]
         assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i]
         assert assembler.fail_boxes_float.getitem(i) == expected_floats[i]
-
-class FakeProfileAgent(object):
-    def __init__(self):
-        self.functions = []
-
-    def native_code_written(self, name, address, size):
-        self.functions.append((name, address, size))
-
-class FakeMCWrapper(MachineCodeBlockWrapper):
-    count = 0
-    def _instantiate_mc(self):
-        self.count += 1
-        return FakeMC(200 * (self.count - 1))
-
-def test_mc_wrapper_profile_agent():
-    agent = FakeProfileAgent()
-    assembler = FakeAssembler()
-    mc = FakeMCWrapper(assembler, 100, agent)
-    mc.start_function("abc")
-    mc.writechr("x")
-    mc.writechr("x")
-    mc.writechr("x")
-    mc.writechr("x")
-    mc.end_function()
-    assert agent.functions == [("abc", 0, 4)]
-    mc.writechr("x")
-    mc.start_function("cde")
-    mc.writechr("x")
-    mc.writechr("x")
-    mc.writechr("x")
-    mc.writechr("x")
-    mc.end_function()
-    assert agent.functions == [("abc", 0, 4), ("cde", 5, 4)]
-    mc.start_function("xyz")
-    for i in range(50):
-        mc.writechr("x")
-    mc.end_function()
-    assert agent.functions == [("abc", 0, 4), ("cde", 5, 4), ("xyz", 9, 29), ("xyz", 200, 22)]

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_gc_integration.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_gc_integration.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_gc_integration.py	Sat Dec 11 15:10:15 2010
@@ -33,7 +33,8 @@
     def add_callee_save_reg(self, shape, reg_index):
         index_to_name = { 1: 'ebx', 2: 'esi', 3: 'edi' }
         shape.append(index_to_name[reg_index])
-    def compress_callshape(self, shape):
+    def compress_callshape(self, shape, datablockwrapper):
+        assert datablockwrapper == 'fakedatablockwrapper'
         assert shape[0] == 'shape'
         return ['compressed'] + shape[1:]
 
@@ -58,7 +59,9 @@
 
     def test_mark_gc_roots(self):
         cpu = CPU(None, None)
+        cpu.setup_once()
         regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False)))
+        regalloc.assembler.datablockwrapper = 'fakedatablockwrapper'
         boxes = [BoxPtr() for i in range(len(X86RegisterManager.all_regs))]
         longevity = {}
         for box in boxes:
@@ -90,6 +93,7 @@
     
     cpu = CPU(None, None)
     cpu.gc_ll_descr = MockGcDescr(False)
+    cpu.setup_once()
     
     S = lltype.GcForwardReference()
     S.become(lltype.GcStruct('S', ('field', lltype.Ptr(S)),
@@ -214,6 +218,7 @@
         cpu = CPU(None, None)
         cpu.vtable_offset = WORD
         cpu.gc_ll_descr = GCDescrFastpathMalloc()
+        cpu.setup_once()
 
         NODE = lltype.Struct('node', ('tid', lltype.Signed),
                                      ('value', lltype.Signed))

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regalloc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regalloc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regalloc.py	Sat Dec 11 15:10:15 2010
@@ -9,7 +9,7 @@
 from pypy.jit.backend.llsupport.descr import GcCache
 from pypy.jit.backend.detect_cpu import getcpuclass
 from pypy.jit.backend.x86.regalloc import RegAlloc, X86RegisterManager,\
-     FloatConstants, is_comparison_or_ovf_op
+     is_comparison_or_ovf_op
 from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64
 from pypy.jit.tool.oparser import parse
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
@@ -41,7 +41,10 @@
         self.movs = []
         self.performs = []
         self.lea = []
-        self.cpu = cpu or CPU(None, None)
+        if cpu is None:
+            cpu = CPU(None, None)
+            cpu.setup_once()
+        self.cpu = cpu
         if gc_ll_descr is None:
             gc_ll_descr = MockGcDescr(False)
         self.cpu.gc_ll_descr = gc_ll_descr
@@ -76,6 +79,7 @@
 
 class BaseTestRegalloc(object):
     cpu = CPU(None, None)
+    cpu.setup_once()
 
     def raising_func(i):
         if i:
@@ -166,7 +170,8 @@
         assert ([box.type for box in bridge.inputargs] ==
                 [box.type for box in guard_op.getfailargs()])
         faildescr = guard_op.getdescr()
-        self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations)
+        self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations,
+                                loop.token)
         return bridge
 
     def run(self, loop):
@@ -515,16 +520,6 @@
         self.interpret(ops, [0.1, .2, .3, .4, .5, .6, .7, .8, .9])
         assert self.getfloats(9) == [.1+.2, .9+3.5, .3, .4, .5, .6, .7, .8, .9]
 
-    def test_float_overflow_const_list(self):
-        ops = ['[f0]']
-        BASE_CONSTANT_SIZE = FloatConstants.BASE_CONSTANT_SIZE
-        for i in range(BASE_CONSTANT_SIZE * 2):
-            ops.append('f%d = float_add(f%d, 3.5)' % (i + 1, i))
-        ops.append('finish(f%d)' % (BASE_CONSTANT_SIZE * 2))
-        ops = "\n".join(ops)
-        self.interpret(ops, [0.1])
-        assert abs(self.getfloat(0) - (BASE_CONSTANT_SIZE * 2) * 3.5 - 0.1) < 0.00001
-
     def test_lt_const(self):
         ops = '''
         [f0]

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regalloc2.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regalloc2.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regalloc2.py	Sat Dec 11 15:10:15 2010
@@ -19,6 +19,7 @@
         ResOperation(rop.FINISH, [v4, v3], None, descr=BasicFailDescr()),
         ]
     cpu = CPU(None, None)
+    cpu.setup_once()
     looptoken = LoopToken()
     cpu.compile_loop(inputargs, operations, looptoken)
     cpu.set_future_value_int(0, 9)
@@ -41,6 +42,7 @@
         ResOperation(rop.FINISH, [v4, v3, tmp5], None, descr=BasicFailDescr()),
             ]
     cpu = CPU(None, None)
+    cpu.setup_once()
     looptoken = LoopToken()
     cpu.compile_loop(inputargs, operations, looptoken)
     cpu.set_future_value_int(0, -10)
@@ -137,6 +139,7 @@
         ResOperation(rop.FINISH, [v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38], None, descr=BasicFailDescr()),
             ]
     cpu = CPU(None, None)
+    cpu.setup_once()
     looptoken = LoopToken()
     cpu.compile_loop(inputargs, operations, looptoken)
     cpu.set_future_value_int(0, -13)
@@ -251,6 +254,7 @@
         ResOperation(rop.FINISH, [v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37], None, descr=BasicFailDescr()),
             ]
     cpu = CPU(None, None)
+    cpu.setup_once()
     looptoken = LoopToken()
     cpu.compile_loop(inputargs, operations, looptoken)
     cpu.set_future_value_int(0, 17)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regloc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regloc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_regloc.py	Sat Dec 11 15:10:15 2010
@@ -1,4 +1,4 @@
-import struct
+import struct, sys
 from pypy.jit.backend.x86.regloc import *
 from pypy.jit.backend.x86.test.test_rx86 import CodeBuilder32, CodeBuilder64, assert_encodes_as
 from pypy.jit.backend.x86.assembler import heap
@@ -37,26 +37,36 @@
     assert_encodes_as(cb64, "CMP16", (ecx, ImmedLoc(12345)), '\x66\x81\xF9\x39\x30')
     assert_encodes_as(cb64, "CMP16", (AddressLoc(r13, ImmedLoc(0), 0, 0), ImmedLoc(12345)), '\x66\x41\x81\x7D\x00\x39\x30')
 
-def test_jmp_wraparound():
-    if not IS_X86_32:
-        py.test.skip()
-
-    pos_addr = intmask(0x7FFFFF00)
-    neg_addr = intmask(0x800000BB)
-
-    # JMP to "negative" address from "positive" address
-    s = cb32()
-    s.base_address = pos_addr
-    s.JMP(ImmedLoc(neg_addr))
-    expected_ofs = neg_addr - (pos_addr+5)
-    assert s.getvalue() == '\xE9' + struct.pack("<i", expected_ofs)
-
-    # JMP to a "positive" address from a "negative" address
-    s = cb32()
-    s.base_address = neg_addr
-    s.JMP(ImmedLoc(pos_addr))
-    expected_ofs = pos_addr - (neg_addr+5)
-    assert s.getvalue() == '\xE9' + struct.pack("<i", expected_ofs)
+def test_relocation():
+    from pypy.rpython.lltypesystem import lltype, rffi
+    from pypy.jit.backend.x86 import codebuf
+    for target in [0x01020304, 0x0102030405060708]:
+        if target > sys.maxint:
+            continue
+        mc = codebuf.MachineCodeBlockWrapper()
+        mc.CALL(ImmedLoc(target))
+        length = mc.get_relative_pos()
+        buf = lltype.malloc(rffi.CCHARP.TO, length, flavor='raw')
+        rawstart = rffi.cast(lltype.Signed, buf)
+        if IS_X86_32:
+            assert length == 5
+            assert mc.relocations == [5]
+            expected = "\xE8" + struct.pack('<i', target - (rawstart + 5))
+        elif IS_X86_64:
+            assert mc.relocations == []
+            if target <= 0x7fffffff:
+                assert length == 10
+                expected = (
+                    "\x49\xC7\xC3\x04\x03\x02\x01"  # MOV %r11, target
+                    "\x41\xFF\xD3")                 # CALL *%r11
+            else:
+                assert length == 13
+                expected = (
+                    "\x49\xBB\x08\x07\x06\x05\x04\x03\x02\x01" # MOV %r11, targ
+                    "\x41\xFF\xD3")                 # CALL *%r11
+        mc.copy_to_raw_memory(rawstart)
+        assert ''.join([buf[i] for i in range(length)]) == expected
+        lltype.free(buf, flavor='raw')
 
 
 class Test64Bits:

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	Sat Dec 11 15:10:15 2010
@@ -33,6 +33,7 @@
     
     def setup_method(self, meth):
         self.cpu = CPU(rtyper=None, stats=FakeStats())
+        self.cpu.setup_once()
 
     def test_execute_ptr_operation(self):
         cpu = self.cpu
@@ -81,7 +82,7 @@
         # relative addressing to work properly.
         addr = rffi.cast(lltype.Signed, addr)
         
-        self.cpu.assembler.setup()
+        self.cpu.assembler.setup_once()
         self.cpu.assembler.malloc_func_addr = addr
         ofs = symbolic.get_field_token(rstr.STR, 'chars', False)[0]
 
@@ -329,7 +330,11 @@
                         assert result != expected
 
     def test_compile_bridge_check_profile_info(self):
-        from pypy.jit.backend.x86.test.test_assembler import FakeProfileAgent
+        class FakeProfileAgent(object):
+            def __init__(self):
+                self.functions = []
+            def native_code_written(self, name, address, size):
+                self.functions.append((name, address, size))
         self.cpu.profile_agent = agent = FakeProfileAgent()
 
         i0 = BoxInt()
@@ -338,6 +343,7 @@
         faildescr1 = BasicFailDescr(1)
         faildescr2 = BasicFailDescr(2)
         looptoken = LoopToken()
+        looptoken.number = 17
         class FakeString(object):
             def __init__(self, val):
                 self.val = val
@@ -356,7 +362,7 @@
         operations[3].setfailargs([i1])
         self.cpu.compile_loop(inputargs, operations, looptoken)
         name, loopaddress, loopsize = agent.functions[0]
-        assert name == "Loop # 0: hello"
+        assert name == "Loop # 17: hello"
         assert loopaddress <= looptoken._x86_loop_code
         assert loopsize >= 40 # randomish number
 
@@ -370,7 +376,7 @@
         ]
         bridge[1].setfailargs([i1b])
 
-        self.cpu.compile_bridge(faildescr1, [i1b], bridge)        
+        self.cpu.compile_bridge(faildescr1, [i1b], bridge, looptoken)
         name, address, size = agent.functions[1]
         assert name == "Bridge # 0: bye"
         # Would be exactly ==, but there are some guard failure recovery
@@ -397,104 +403,15 @@
         assert res.value == 4.0
 
 
-class TestX86OverflowMC(TestX86):
-
-    def setup_method(self, meth):
-        self.cpu = CPU(rtyper=None, stats=FakeStats())
-        self.cpu.assembler.mc_size = 1024
-
-    def test_overflow_mc(self):
-        ops = []
-        base_v = BoxInt()
-        v = base_v
-        for i in range(1024):
-            next_v = BoxInt()
-            ops.append(ResOperation(rop.INT_ADD, [v, ConstInt(1)], next_v))
-            v = next_v
-        ops.append(ResOperation(rop.FINISH, [v], None,
-                                descr=BasicFailDescr()))
-        looptoken = LoopToken()
-        self.cpu.assembler.setup()
-        old_mc_mc = self.cpu.assembler.mc._mc
-        self.cpu.compile_loop([base_v], ops, looptoken)
-        assert self.cpu.assembler.mc._mc != old_mc_mc   # overflowed
-        self.cpu.set_future_value_int(0, base_v.value)
-        self.cpu.execute_token(looptoken)
-        assert self.cpu.get_latest_value_int(0) == 1024
-
-    def test_overflow_guard_float_cmp(self):
-        # The float comparisons on x86 tend to use small relative jumps,
-        # which may run into trouble if they fall on the edge of a
-        # MachineCodeBlock change.
-        a = BoxFloat(1.0)
-        b = BoxFloat(2.0)
-        failed = BoxInt(41)
-        finished = BoxInt(42)
-
-        # We select guards that will always succeed, so that execution will
-        # continue through the entire set of comparisions
-        ops_to_test = (
-            (rop.FLOAT_LT, [a, b], rop.GUARD_TRUE),
-            (rop.FLOAT_LT, [b, a], rop.GUARD_FALSE),
-
-            (rop.FLOAT_LE, [a, a], rop.GUARD_TRUE),
-            (rop.FLOAT_LE, [a, b], rop.GUARD_TRUE),
-            (rop.FLOAT_LE, [b, a], rop.GUARD_FALSE),
-
-            (rop.FLOAT_EQ, [a, a], rop.GUARD_TRUE),
-            (rop.FLOAT_EQ, [a, b], rop.GUARD_FALSE),
-
-            (rop.FLOAT_NE, [a, b], rop.GUARD_TRUE),
-            (rop.FLOAT_NE, [a, a], rop.GUARD_FALSE),
-
-            (rop.FLOAT_GT, [b, a], rop.GUARD_TRUE),
-            (rop.FLOAT_GT, [a, b], rop.GUARD_FALSE),
-
-            (rop.FLOAT_GE, [a, a], rop.GUARD_TRUE),
-            (rop.FLOAT_GE, [b, a], rop.GUARD_TRUE),
-            (rop.FLOAT_GE, [a, b], rop.GUARD_FALSE),
-        )
-
-        for float_op, args, guard_op in ops_to_test:
-            ops = []
-
-            for i in range(200):
-                cmp_result = BoxInt()
-                ops.append(ResOperation(float_op, args, cmp_result))
-                ops.append(ResOperation(guard_op, [cmp_result], None, descr=BasicFailDescr()))
-                ops[-1].setfailargs([failed])
-
-            ops.append(ResOperation(rop.FINISH, [finished], None, descr=BasicFailDescr()))
-
-            looptoken = LoopToken()
-            self.cpu.compile_loop([a, b, failed, finished], ops, looptoken)
-            self.cpu.set_future_value_float(0, a.value)
-            self.cpu.set_future_value_float(1, b.value)
-            self.cpu.set_future_value_int(2, failed.value)
-            self.cpu.set_future_value_int(3, finished.value)
-            self.cpu.execute_token(looptoken)
-
-            # Really just a sanity check. We're actually interested in
-            # whether the test segfaults.
-            assert self.cpu.get_latest_value_int(0) == finished.value
-
-    def test_overflow_guard_exception(self):
-        for i in range(50):
-            self.test_exceptions()
-
-
 class TestDebuggingAssembler(object):
     def setup_method(self, meth):
-        self.pypylog = os.environ.get('PYPYLOG', None)
-        self.logfile = str(udir.join('x86_runner.log'))
-        os.environ['PYPYLOG'] = "mumble:" + self.logfile
         self.cpu = CPU(rtyper=None, stats=FakeStats())
-
-    def teardown_method(self, meth):
-        if self.pypylog is not None:
-            os.environ['PYPYLOG'] = self.pypylog
+        self.cpu.setup_once()
 
     def test_debugger_on(self):
+        from pypy.tool.logparser import parse_log_file, extract_category
+        from pypy.rlib import debug
+        
         loop = """
         [i0]
         debug_merge_point('xyz', 0)
@@ -504,17 +421,19 @@
         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)
-        # check debugging info
-        name, struct = self.cpu.assembler.loop_run_counters[0]
-        assert name == 0       # 'xyz'
-        assert struct.i == 10
-        self.cpu.finish_once()
-        lines = py.path.local(self.logfile + ".count").readlines()
-        assert lines[0] == '0:10\n'  # '10      xyz\n'
+        debug._log = dlog = debug.DebugLog()
+        try:
+            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)
+            # check debugging info
+            struct = self.cpu.assembler.loop_run_counters[0]
+            assert struct.i == 10
+            self.cpu.finish_once()
+        finally:
+            debug._log = None
+        assert ('jit-backend-counts', [('debug_print', '0:10')]) in dlog
 
     def test_debugger_checksum(self):
         loop = """

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_rx86.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_rx86.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_rx86.py	Sat Dec 11 15:10:15 2010
@@ -5,7 +5,6 @@
 class CodeBuilderMixin(object):
     def __init__(self):
         self.buffer = []
-        self.base_address = 0x76543210
 
     def writechar(self, c):
         assert isinstance(c, str) and len(c) == 1
@@ -14,9 +13,6 @@
     def getvalue(self):
         return ''.join(self.buffer)
 
-    def tell(self):
-        return self.base_address + len(self.buffer)
-
 def assert_encodes_as(code_builder_cls, insn_name, args, expected_encoding):
     s = code_builder_cls()
     getattr(s, insn_name)(*args)
@@ -104,21 +100,18 @@
 
 def test_call_l(s=None):
     s = s or CodeBuilder32()
-    s.CALL_l(0x01234567)
-    ofs = 0x01234567 - (0x76543210+5)
-    assert s.getvalue() == '\xE8' + struct.pack("<i", ofs)
+    s.CALL_l(0x01234567)   # relative offset
+    assert s.getvalue() == '\xE8' + struct.pack("<i", 0x01234567)
 
 def test_jmp_l():
     s = CodeBuilder32()
-    s.JMP_l(0x01234567)
-    ofs = 0x01234567 - (0x76543210+5)
-    assert s.getvalue() == '\xE9' + struct.pack("<i", ofs)
+    s.JMP_l(0x01234567)   # relative offset
+    assert s.getvalue() == '\xE9' + struct.pack("<i", 0x01234567)
 
 def test_j_il():
     s = CodeBuilder32()
-    s.J_il(5, 0x01234567)
-    ofs = 0x01234567 - (0x76543210+6)
-    assert s.getvalue() == '\x0F\x85' + struct.pack("<i", ofs)
+    s.J_il(5, 0x01234567)   # relative offset
+    assert s.getvalue() == '\x0F\x85' + struct.pack("<i", 0x01234567)
 
 def test_set_ir():
     s = CodeBuilder32()

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zll_random.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zll_random.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zll_random.py	Sat Dec 11 15:10:15 2010
@@ -6,9 +6,7 @@
 
 def test_stress():
     cpu = CPU(None, None)
+    cpu.setup_once()
     r = Random()
     for i in range(1000):
         check_random_function(cpu, LLtypeOperationBuilder, r, i, 1000)
-
-
-

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zmath.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zmath.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/test/test_zmath.py	Sat Dec 11 15:10:15 2010
@@ -4,7 +4,7 @@
 import py, math
 from pypy.module.math.test import test_direct
 from pypy.translator.c.test.test_genc import compile
-from pypy.jit.backend.x86.codebuf import ensure_sse2_floats
+from pypy.jit.backend.x86.support import ensure_sse2_floats
 
 
 def get_test_case((fnname, args, expected)):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/valgrind.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/valgrind.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/backend/x86/valgrind.py	Sat Dec 11 15:10:15 2010
@@ -27,4 +27,4 @@
 
 def discard_translations(data, size):
     if we_are_translated() and VALGRIND_DISCARD_TRANSLATIONS is not None:
-        VALGRIND_DISCARD_TRANSLATIONS(llmemory.cast_ptr_to_adr(data), size)
+        VALGRIND_DISCARD_TRANSLATIONS(llmemory.cast_int_to_adr(data), size)

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	Sat Dec 11 15:10:15 2010
@@ -95,15 +95,8 @@
             else:
                 v_obj = op.args[1].concretetype
                 graphs = v_obj._lookup_graphs(op.args[0].value)
-            if graphs is not None:
-                result = []
-                for graph in graphs:
-                    if is_candidate(graph):
-                        result.append(graph)
-                if result:
-                    return result  # common case: look inside these graphs,
-                                   # and ignore the others if there are any
-            else:
+            #
+            if graphs is None:
                 # special case: handle the indirect call that goes to
                 # the 'instantiate' methods.  This check is a bit imprecise
                 # but it's not too bad if we mistake a random indirect call
@@ -112,7 +105,16 @@
                 CALLTYPE = op.args[0].concretetype
                 if (op.opname == 'indirect_call' and len(op.args) == 2 and
                     CALLTYPE == rclass.OBJECT_VTABLE.instantiate):
-                    return list(self._graphs_of_all_instantiate())
+                    graphs = list(self._graphs_of_all_instantiate())
+            #
+            if graphs is not None:
+                result = []
+                for graph in graphs:
+                    if is_candidate(graph):
+                        result.append(graph)
+                if result:
+                    return result  # common case: look inside these graphs,
+                                   # and ignore the others if there are any
         # residual call case: we don't need to look into any graph
         return None
 

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	Sat Dec 11 15:10:15 2010
@@ -24,6 +24,7 @@
 
 
 class Transformer(object):
+    vable_array_vars = None
 
     def __init__(self, cpu=None, callcontrol=None, portal_jd=None):
         self.cpu = cpu
@@ -38,7 +39,6 @@
     def optimize_block(self, block):
         if block.operations == ():
             return
-        self.immutable_arrays = {}
         self.vable_array_vars = {}
         self.vable_flags = {}
         renamings = {}
@@ -83,6 +83,7 @@
         self.follow_constant_exit(block)
         self.optimize_goto_if_not(block)
         for link in block.exits:
+            self._check_no_vable_array(link.args)
             self._do_renaming_on_link(renamings, link)
 
     def _do_renaming(self, rename, op):
@@ -100,6 +101,28 @@
                 op.args[i] = ListOfKind(v.kind, newlst)
         return op
 
+    def _check_no_vable_array(self, list):
+        if not self.vable_array_vars:
+            return
+        for v in list:
+            if v in self.vable_array_vars:
+                raise AssertionError(
+                    "A virtualizable array is passed around; it should\n"
+                    "only be used immediately after being read.  Note\n"
+                    "that a possible cause is indexing with an index not\n"
+                    "known non-negative, or catching IndexError, or\n"
+                    "not inlining at all (for tests: use listops=True).\n"
+                    "Occurred in: %r" % self.graph)
+            # extra expanation: with the way things are organized in
+            # rpython/rlist.py, the ll_getitem becomes a function call
+            # that is typically meant to be inlined by the JIT, but
+            # this does not work with vable arrays because
+            # jtransform.py expects the getfield and the getarrayitem
+            # to be in the same basic block.  It works a bit as a hack
+            # for simple cases where we performed the backendopt
+            # inlining before (even with a very low threshold, because
+            # there is _always_inline_ on the relevant functions).
+
     def _do_renaming_on_link(self, rename, link):
         for i, v in enumerate(link.args):
             if isinstance(v, Variable):
@@ -170,9 +193,12 @@
         else:
             return rewrite(self, op)
 
-    def rewrite_op_same_as(self, op): pass
-    def rewrite_op_cast_pointer(self, op): pass
-    def rewrite_op_cast_opaque_ptr(self, op): pass   # rlib.rerased
+    def rewrite_op_same_as(self, op):
+        if op.args[0] in self.vable_array_vars:
+            self.vable_array_vars[op.result]= self.vable_array_vars[op.args[0]]
+
+    rewrite_op_cast_pointer = rewrite_op_same_as
+    rewrite_op_cast_opaque_ptr = rewrite_op_same_as   # rlib.rerased
     def rewrite_op_cast_primitive(self, op): pass
     def rewrite_op_cast_bool_to_int(self, op): pass
     def rewrite_op_cast_bool_to_uint(self, op): pass
@@ -257,6 +283,7 @@
            The name is one of '{residual,direct}_call_{r,ir,irf}_{i,r,f,v}'."""
         if args is None:
             args = op.args[1:]
+        self._check_no_vable_array(args)
         lst_i, lst_r, lst_f = self.make_three_lists(args)
         reskind = getkind(op.result.concretetype)[0]
         if lst_f or reskind == 'f': kinds = 'irf'
@@ -398,6 +425,7 @@
     rewrite_op_int_lshift_ovf  = _do_builtin_call
     rewrite_op_int_abs         = _do_builtin_call
     rewrite_op_gc_identityhash = _do_builtin_call
+    rewrite_op_gc_id           = _do_builtin_call
 
     # ----------
     # getfield/setfield/mallocs etc.
@@ -524,17 +552,14 @@
                                                 arrayfielddescr,
                                                 arraydescr)
             return []
-        # check for deepfrozen structures that force constant-folding
-        immut = v_inst.concretetype.TO._immutable_field(c_fieldname.value)
-        if immut:
+        # check for _immutable_fields_ hints
+        if v_inst.concretetype.TO._immutable_field(c_fieldname.value):
             if (self.callcontrol is not None and
                 self.callcontrol.could_be_green_field(v_inst.concretetype.TO,
                                                       c_fieldname.value)):
                 pure = '_greenfield'
             else:
                 pure = '_pure'
-            if immut == "[*]":
-                self.immutable_arrays[op.result] = True
         else:
             pure = ''
         argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
@@ -843,9 +868,16 @@
             "general mix-up of jitdrivers?")
         ops = self.promote_greens(op.args[2:], jitdriver)
         num_green_args = len(jitdriver.greens)
+        redlists = self.make_three_lists(op.args[2+num_green_args:])
+        for redlist in redlists:
+            for v in redlist:
+                assert isinstance(v, Variable), (
+                    "Constant specified red in jit_merge_point()")
+            assert len(dict.fromkeys(redlist)) == len(list(redlist)), (
+                "duplicate red variable on jit_merge_point()")
         args = ([Constant(self.portal_jd.index, lltype.Signed)] +
                 self.make_three_lists(op.args[2:2+num_green_args]) +
-                self.make_three_lists(op.args[2+num_green_args:]))
+                redlists)
         op1 = SpaceOperation('jit_merge_point', args, None)
         op2 = SpaceOperation('-live-', [], None)
         # ^^^ we need a -live- for the case of do_recursive_call()
@@ -924,21 +956,19 @@
         # base hints on the name of the ll function, which is a bit xxx-ish
         # but which is safe for now
         assert func.func_name.startswith('ll_')
+        # check that we have carefully placed the oopspec in
+        # pypy/rpython/rlist.py.  There should not be an oopspec on
+        # a ll_getitem or ll_setitem that expects a 'func' argument.
+        # The idea is that a ll_getitem/ll_setitem with dum_checkidx
+        # should get inlined by the JIT, so that we see the potential
+        # 'raise IndexError'.
+        assert 'func' not in func.func_code.co_varnames
         non_negative = '_nonneg' in func.func_name
         fast = '_fast' in func.func_name
-        if fast:
-            can_raise = False
-            non_negative = True
-        else:
-            tag = op.args[1].value
-            assert tag in (rlist.dum_nocheck, rlist.dum_checkidx)
-            can_raise = tag != rlist.dum_nocheck
-        return non_negative, can_raise
+        return non_negative or fast
 
     def _prepare_list_getset(self, op, descr, args, checkname):
-        non_negative, can_raise = self._get_list_nonneg_canraise_flags(op)
-        if can_raise:
-            raise NotSupported("list operation can raise")
+        non_negative = self._get_list_nonneg_canraise_flags(op)
         if non_negative:
             return args[1], []
         else:
@@ -950,9 +980,8 @@
             return v_posindex, [op0, op1]
 
     def _prepare_void_list_getset(self, op):
-        non_negative, can_raise = self._get_list_nonneg_canraise_flags(op)
-        if can_raise:
-            raise NotSupported("list operation can raise")
+        # sanity check:
+        self._get_list_nonneg_canraise_flags(op)
 
     def _get_initial_newlist_length(self, op, args):
         # normalize number of arguments to the 'newlist' function
@@ -997,7 +1026,7 @@
         v_index, extraop = self._prepare_list_getset(op, arraydescr, args,
                                                      'check_neg_index')
         extra = getkind(op.result.concretetype)[0]
-        if pure or args[0] in self.immutable_arrays:
+        if pure:
             extra = 'pure_' + extra
         op = SpaceOperation('getarrayitem_gc_%s' % extra,
                             [args[0], arraydescr, v_index], op.result)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/codewriter/regalloc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/regalloc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/regalloc.py	Sat Dec 11 15:10:15 2010
@@ -36,7 +36,7 @@
                             if isinstance(v1, Variable):
                                 die_at[v1] = i
                 if op.result is not None:
-                    die_at[op.result] = i
+                    die_at[op.result] = i + 1
             if isinstance(block.exitswitch, tuple):
                 for x in block.exitswitch:
                     die_at.pop(x, None)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/codewriter/support.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/support.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/support.py	Sat Dec 11 15:10:15 2010
@@ -168,6 +168,9 @@
 def _ll_1_gc_identityhash(x):
     return lltype.identityhash(x)
 
+def _ll_1_gc_id(ptr):
+    return llop.gc_id(lltype.Signed, ptr)
+
 def _ll_1_jit_force_virtual(inst):
     return llop.jit_force_virtual(lltype.typeOf(inst), inst)
 
@@ -548,6 +551,9 @@
 def get_identityhash_oopspec(op):
     return 'gc_identityhash', op.args
 
+def get_gcid_oopspec(op):
+    return 'gc_id', op.args
+
 
 RENAMED_ADT_NAME = {
     'list': {
@@ -578,6 +584,8 @@
         return get_oostring_oopspec(op)
     elif op.opname == 'gc_identityhash':
         return get_identityhash_oopspec(op)
+    elif op.opname == 'gc_id':
+        return get_gcid_oopspec(op)
     else:
         raise ValueError(op.opname)
 

Modified: pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_codewriter.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_codewriter.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_codewriter.py	Sat Dec 11 15:10:15 2010
@@ -152,6 +152,42 @@
     assert 'B2' in names
     assert 'dont_look' in names
 
+def test_instantiate_with_unreasonable_attr():
+    # It is possible to have in real code the instantiate() function for
+    # a class be dont-look-inside.  This is caused by the code that
+    # initialize the instance attributes: if one attribute has a strange
+    # type, the whole function is disabled.  Check that it still works.
+    class MyFakePolicy:
+        def look_inside_graph(self, graph):
+            name = graph.name
+            return not (name.startswith('instantiate_') and
+                        name.endswith('A2'))
+    class A1:
+        pass
+    class A2(A1):
+        pass
+    def f(n):
+        if n > 5:
+            x = A1
+        else:
+            x = A2
+        x()
+    rtyper = support.annotate(f, [35])
+    maingraph = rtyper.annotator.translator.graphs[0]
+    cw = CodeWriter(FakeCPU(rtyper), [FakeJitDriverSD(maingraph)])
+    cw.find_all_graphs(MyFakePolicy())
+    cw.make_jitcodes(verbose=True)
+    #
+    names = [jitcode.name for jitcode in cw.assembler.indirectcalltargets]
+    assert len(names) == 1
+    assert names[0].startswith('instantiate_') and names[0].endswith('A1')
+    #
+    print cw.assembler.list_of_addr2name
+    names = dict.fromkeys([value
+                           for key, value in cw.assembler.list_of_addr2name])
+    assert 'A1' in names
+    assert 'A2' in names
+
 def test_int_abs():
     def f(n):
         return abs(n)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_list.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_list.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_list.py	Sat Dec 11 15:10:15 2010
@@ -56,9 +56,8 @@
     if '/' in oopspec_name:
         oopspec_name, property = oopspec_name.split('/')
         def force_flags(op):
-            if property == 'NONNEG':   return True, False
-            if property == 'NEG':      return False, False
-            if property == 'CANRAISE': return False, True
+            if property == 'NONNEG':   return True
+            if property == 'NEG':      return False
             raise ValueError(property)
         tr._get_list_nonneg_canraise_flags = force_flags
     op = SpaceOperation('direct_call',
@@ -122,9 +121,6 @@
                      check_neg_index %r0, <ArrayDescr>, %i0 -> %i1
                      getarrayitem_gc_i %r0, <ArrayDescr>, %i1 -> %i2
                  """)
-    builtin_test('list.getitem/CANRAISE',
-                 [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
-                 lltype.Signed, NotSupported)
 
 def test_fixed_getitem_foldable():
     builtin_test('list.getitem_foldable/NONNEG',
@@ -139,9 +135,6 @@
                      check_neg_index %r0, <ArrayDescr>, %i0 -> %i1
                      getarrayitem_gc_pure_i %r0, <ArrayDescr>, %i1 -> %i2
                  """)
-    builtin_test('list.getitem_foldable/CANRAISE',
-                 [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
-                 lltype.Signed, NotSupported)
 
 def test_fixed_setitem():
     builtin_test('list.setitem/NONNEG', [varoftype(FIXEDLIST),
@@ -158,10 +151,6 @@
                      check_neg_index %r0, <ArrayDescr>, %i0 -> %i1
                      setarrayitem_gc_i %r0, <ArrayDescr>, %i1, %i2
                  """)
-    builtin_test('list.setitem/CANRAISE', [varoftype(FIXEDLIST),
-                                           varoftype(lltype.Signed),
-                                           varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_fixed_len():
     builtin_test('list.len', [varoftype(FIXEDLIST)], lltype.Signed,
@@ -206,9 +195,6 @@
         check_resizable_neg_index %r0, <FieldDescr length>, %i0 -> %i1
         getlistitem_gc_i %r0, <FieldDescr items>, <ArrayDescr>, %i1 -> %i2
                  """)
-    builtin_test('list.getitem/CANRAISE',
-                 [varoftype(VARLIST), varoftype(lltype.Signed)],
-                 lltype.Signed, NotSupported)
 
 def test_resizable_setitem():
     builtin_test('list.setitem/NONNEG', [varoftype(VARLIST),
@@ -225,10 +211,6 @@
         check_resizable_neg_index %r0, <FieldDescr length>, %i0 -> %i1
         setlistitem_gc_i %r0, <FieldDescr items>, <ArrayDescr>, %i1, %i2
                  """)
-    builtin_test('list.setitem/CANRAISE', [varoftype(VARLIST),
-                                           varoftype(lltype.Signed),
-                                           varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_resizable_len():
     builtin_test('list.len', [varoftype(VARLIST)], lltype.Signed,

Modified: pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_regalloc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_regalloc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_regalloc.py	Sat Dec 11 15:10:15 2010
@@ -281,22 +281,22 @@
         # this used to produce bogus code, containing these two
         # lines in the following broken order:
         #    last_exc_value -> %r0
-        #    ref_copy %r0 -> %r2    -- but expect to read the old value of %r0!
+        #    ref_copy %r0 -> %r1    -- but expect to read the old value of %r0!
         self.check_assembler(graph, """
             residual_call_r_r $<* fn bar>, <Descr>, R[%r0] -> %r1
             -live-
-            residual_call_ir_r $<* fn g>, <Descr>, I[%i0], R[] -> %r2
+            residual_call_ir_r $<* fn g>, <Descr>, I[%i0], R[] -> %r1
             -live-
             catch_exception L1
-            ref_return %r2
+            ref_return %r1
             ---
             L1:
             goto_if_exception_mismatch $<* struct object_vtable>, L2
-            ref_copy %r0 -> %r2
+            ref_copy %r0 -> %r1
             last_exc_value -> %r0
             residual_call_r_r $<* fn foo>, <Descr>, R[%r0] -> %r0
             -live-
-            ref_return %r2
+            ref_return %r1
             ---
             L2:
             reraise

Modified: pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_void_list.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_void_list.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/codewriter/test/test_void_list.py	Sat Dec 11 15:10:15 2010
@@ -51,9 +51,6 @@
     builtin_test('list.getitem/NEG',
                  [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
                  lltype.Void, "")
-    builtin_test('list.getitem/CANRAISE',
-                 [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_fixed_getitem_foldable():
     builtin_test('list.getitem_foldable/NONNEG',
@@ -62,9 +59,6 @@
     builtin_test('list.getitem_foldable/NEG',
                  [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
                  lltype.Void, "")
-    builtin_test('list.getitem_foldable/CANRAISE',
-                 [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_fixed_setitem():
     builtin_test('list.setitem/NONNEG', [varoftype(FIXEDLIST),
@@ -75,10 +69,6 @@
                                       varoftype(lltype.Signed),
                                       varoftype(lltype.Void)],
                  lltype.Void, "")
-    builtin_test('list.setitem/CANRAISE', [varoftype(FIXEDLIST),
-                                           varoftype(lltype.Signed),
-                                           varoftype(lltype.Void)],
-                 lltype.Void, NotSupported)
 
 def test_fixed_len():
     builtin_test('list.len', [varoftype(FIXEDLIST)], lltype.Signed,
@@ -115,9 +105,6 @@
     builtin_test('list.getitem/NEG',
                  [varoftype(VARLIST), varoftype(lltype.Signed)],
                  lltype.Void, "")
-    builtin_test('list.getitem/CANRAISE',
-                 [varoftype(VARLIST), varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_resizable_setitem():
     builtin_test('list.setitem/NONNEG', [varoftype(VARLIST),
@@ -128,10 +115,6 @@
                                       varoftype(lltype.Signed),
                                       varoftype(lltype.Void)],
                  lltype.Void, "")
-    builtin_test('list.setitem/CANRAISE', [varoftype(VARLIST),
-                                           varoftype(lltype.Signed),
-                                           varoftype(lltype.Void)],
-                 lltype.Void, NotSupported)
 
 def test_resizable_len():
     builtin_test('list.len', [varoftype(VARLIST)], lltype.Signed,

Modified: pypy/branch/jit-unroll-loops/pypy/jit/conftest.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/conftest.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/conftest.py	Sat Dec 11 15:10:15 2010
@@ -1,7 +1,5 @@
 import py
 
-option = py.test.config.option
-
 def pytest_addoption(parser):
     group = parser.getgroup("JIT options")
     group.addoption('--slow', action="store_true",

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	Sat Dec 11 15:10:15 2010
@@ -1,4 +1,4 @@
-
+import weakref
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.ootypesystem import ootype
 from pypy.objspace.flow.model import Constant, Variable
@@ -46,6 +46,32 @@
     loop_token.outermost_jitdriver_sd = jitdriver_sd
     return loop_token
 
+def record_loop_or_bridge(loop):
+    """Do post-backend recordings and cleanups on 'loop'.
+    """
+    # get the original loop token (corresponding to 'loop', or if that is
+    # a bridge, to the loop that this bridge belongs to)
+    looptoken = loop.token
+    assert looptoken is not None
+    wref = weakref.ref(looptoken)
+    for op in loop.operations:
+        descr = op.getdescr()
+        if isinstance(descr, ResumeDescr):
+            descr.wref_original_loop_token = wref   # stick it there
+            n = descr.index
+            if n >= 0:       # we also record the resumedescr number
+                looptoken.compiled_loop_token.record_faildescr_index(n)
+        elif isinstance(descr, LoopToken):
+            # for a JUMP or a CALL_ASSEMBLER: record it as a potential jump.
+            # (the following test is not enough to prevent more complicated
+            # cases of cycles, but at least it helps in simple tests of
+            # test_memgr.py)
+            if descr is not looptoken:
+                looptoken.record_jump_to(descr)
+            op.setdescr(None)    # clear reference, mostly for tests
+    # mostly for tests: make sure we don't keep a reference to the LoopToken
+    loop.token = None
+
 # ____________________________________________________________
 
 def compile_new_loop(metainterp, old_loop_tokens, greenkey, start,
@@ -82,15 +108,18 @@
 
     if loop.preamble.operations is not None:
         send_loop_to_backend(metainterp_sd, loop, "loop")
+        record_loop_or_bridge(loop)
         if full_preamble_needed or not loop.preamble.token.short_preamble:
             send_loop_to_backend(metainterp_sd, loop.preamble, "entry bridge")
             insert_loop_token(old_loop_tokens, loop.preamble.token)
+            record_loop_or_bridge(loop.preamble)
             jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
                 greenkey, loop.preamble.token)
         return loop.preamble.token
     else:
         send_loop_to_backend(metainterp_sd, loop, "loop")
         insert_loop_token(old_loop_tokens, loop_token)
+        record_loop_or_bridge(loop)
         jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
             greenkey, loop.token)
         return loop_token
@@ -133,8 +162,11 @@
         else:
             loop._ignore_during_counting = True
     metainterp_sd.log("compiled new " + type)
+    if metainterp_sd.warmrunnerdesc is not None:    # for tests
+        metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token)
 
-def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations):
+def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations,
+                           original_loop_token):
     n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
     metainterp_sd.logger_ops.log_bridge(inputargs, operations, n)
     if not we_are_translated():
@@ -143,7 +175,8 @@
     metainterp_sd.profiler.start_backend()
     debug_start("jit-backend")
     try:
-        metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations)
+        metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations,
+                                         original_loop_token)
     finally:
         debug_stop("jit-backend")
     metainterp_sd.profiler.end_backend()
@@ -240,9 +273,6 @@
     CNT_FLOAT = -0x60000000
     CNT_MASK  =  0x1FFFFFFF
 
-    def __init__(self, metainterp_sd):
-        self.metainterp_sd = metainterp_sd
-
     def store_final_boxes(self, guard_op, boxes):
         guard_op.setfailargs(boxes)
         self.guard_opnum = guard_op.getopnum()
@@ -327,12 +357,14 @@
 
     def compile_and_attach(self, metainterp, new_loop):
         # We managed to create a bridge.  Attach the new operations
-        # to the corrsponding guard_op and compile from there
+        # to the corresponding guard_op and compile from there
+        assert metainterp.resumekey_original_loop_token is not None
+        new_loop.token = metainterp.resumekey_original_loop_token
         inputargs = metainterp.history.inputargs
         if not we_are_translated():
             self._debug_suboperations = new_loop.operations
         send_bridge_to_backend(metainterp.staticdata, self, inputargs,
-                               new_loop.operations)
+                               new_loop.operations, new_loop.token)
 
     def copy_all_attrbutes_into(self, res):
         # XXX a bit ugly to have to list them all here
@@ -344,14 +376,14 @@
         res.rd_pendingfields = self.rd_pendingfields
 
     def _clone_if_mutable(self):
-        res = ResumeGuardDescr(self.metainterp_sd)
+        res = ResumeGuardDescr()
         self.copy_all_attrbutes_into(res)
         return res
 
 class ResumeGuardForcedDescr(ResumeGuardDescr):
 
     def __init__(self, metainterp_sd, jitdriver_sd):
-        ResumeGuardDescr.__init__(self, metainterp_sd)
+        self.metainterp_sd = metainterp_sd
         self.jitdriver_sd = jitdriver_sd
 
     def handle_fail(self, metainterp_sd, jitdriver_sd):
@@ -495,6 +527,8 @@
         metainterp_sd = metainterp.staticdata
         jitdriver_sd = metainterp.jitdriver_sd
         redargs = new_loop.inputargs
+        # We make a new LoopToken for this entry bridge, and stick it
+        # to every guard in the loop.
         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")
@@ -502,12 +536,14 @@
         jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
             self.original_greenkey,
             new_loop_token)
-        # store the new loop in compiled_merge_points too
+        # store the new loop in compiled_merge_points_wref too
         old_loop_tokens = metainterp.get_compiled_merge_points(
             self.original_greenkey)
         # it always goes at the end of the list, as it is the most
         # general loop token
         old_loop_tokens.append(new_loop_token)
+        metainterp.set_compiled_merge_points(self.original_greenkey,
+                                             old_loop_tokens)
 
     def reset_counter_from_failure(self):
         pass
@@ -543,6 +579,7 @@
         prepare_last_operation(new_loop, target_loop_token)
         resumekey.compile_and_attach(metainterp, new_loop)
         compile_known_target_bridges(metainterp, new_loop)
+        record_loop_or_bridge(new_loop)
     return target_loop_token
 
 # For backends that not supports emitting guards with preset jump
@@ -564,6 +601,7 @@
                     descr._debug_suboperations = mini.operations
                 send_bridge_to_backend(metainterp.staticdata, descr,
                                        mini.inputargs, mini.operations)
+                record_loop_or_bridge(mini)
 
 
 def prepare_last_operation(new_loop, target_loop_token):
@@ -591,7 +629,8 @@
 
 propagate_exception_descr = PropagateExceptionDescr()
 
-def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redboxes):
+def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redboxes,
+                         memory_manager=None):
     """Make a LoopToken that corresponds to assembler code that just
     calls back the interpreter.  Used temporarily: a fully compiled
     version of the code may end up replacing it.
@@ -631,4 +670,6 @@
         ]
     operations[1].setfailargs([])
     cpu.compile_loop(inputargs, operations, loop_token, log=False)
+    if memory_manager is not None:    # for tests
+        memory_manager.keep_loop_alive(loop_token)
     return loop_token

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/history.py	Sat Dec 11 15:10:15 2010
@@ -4,8 +4,7 @@
 from pypy.rpython.ootypesystem import ootype
 from pypy.rlib.objectmodel import we_are_translated, r_dict, Symbolic
 from pypy.rlib.objectmodel import compute_hash, compute_unique_id
-from pypy.rlib.rarithmetic import intmask
-from pypy.tool.uid import uid
+from pypy.rlib.rarithmetic import intmask, r_int64
 from pypy.conftest import option
 
 from pypy.jit.metainterp.resoperation import ResOperation, rop
@@ -745,14 +744,28 @@
     terminating = False # see TerminatingLoopToken in compile.py
     outermost_jitdriver_sd = None
     # and more data specified by the backend when the loop is compiled
-    number = 0
+    number = -1
+    generation = r_int64(0)
+    # one purpose of LoopToken is to keep alive the CompiledLoopToken
+    # returned by the backend.  When the LoopToken goes away, the
+    # CompiledLoopToken has its __del__ called, which frees the assembler
+    # memory and the ResumeGuards.
+    compiled_loop_token = None
 
-    def __init__(self, number=0):
-        self.number = number
+    def __init__(self):
+        # For memory management of assembled loops
+        self._keepalive_target_looktokens = {}      # set of other LoopTokens
+
+    def record_jump_to(self, target_loop_token):
+        self._keepalive_target_looktokens[target_loop_token] = None
+
+    def __repr__(self):
+        return '<Loop %d, gen=%d>' % (self.number, self.generation)
 
     def repr_of_descr(self):
         return '<Loop%d>' % self.number
 
+
 class TreeLoop(object):
     inputargs = None
     operations = None

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/jitprof.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/jitprof.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/jitprof.py	Sat Dec 11 15:10:15 2010
@@ -2,9 +2,9 @@
 """ A small helper module for profiling JIT
 """
 
-import os
 import time
-from pypy.rlib.debug import debug_print
+from pypy.rlib.debug import debug_print, debug_start, debug_stop
+from pypy.rlib.debug import have_debug_prints
 from pypy.jit.metainterp.jitexc import JitException
 
 counters="""
@@ -24,6 +24,10 @@
 NVIRTUALS
 NVHOLES
 NVREUSED
+TOTAL_COMPILED_LOOPS
+TOTAL_COMPILED_BRIDGES
+TOTAL_FREED_LOOPS
+TOTAL_FREED_BRIDGES
 """
 
 def _setup():
@@ -35,6 +39,7 @@
 _setup()
 
 JITPROF_LINES = ncounters + 1 + 1 # one for TOTAL, 1 for calls, update if needed
+_CPU_LINES = 4       # the last 4 lines are stored on the cpu
 
 class BaseProfiler(object):
     pass
@@ -48,9 +53,6 @@
     def finish(self):
         pass
 
-    def set_printing(self, printing):
-        pass
-
     def start_tracing(self):
         pass
 
@@ -90,23 +92,19 @@
     counters = None
     calls = 0
     current = None
-    printing = True
+    cpu = None
 
     def start(self):
         self.starttime = self.timer()
         self.t1 = self.starttime
         self.times = [0, 0]
-        self.counters = [0] * ncounters
+        self.counters = [0] * (ncounters - _CPU_LINES)
         self.calls = 0
         self.current = []
 
     def finish(self):
         self.tk = self.timer()
-        if self.printing:
-            self.print_stats()
-
-    def set_printing(self, printing):
-        self.printing = printing
+        self.print_stats()
 
     def _start(self, event):
         t0 = self.t1
@@ -154,6 +152,12 @@
             self.calls += 1
 
     def print_stats(self):
+        debug_start("jit-summary")
+        if have_debug_prints():
+            self._print_stats()
+        debug_stop("jit-summary")
+
+    def _print_stats(self):
         cnt = self.counters
         tim = self.times
         calls = self.calls
@@ -161,8 +165,8 @@
         self._print_line_time("Backend", cnt[BACKEND],   tim[BACKEND])
         self._print_intline("Running asm", cnt[RUNNING])
         self._print_intline("Blackhole", cnt[BLACKHOLE])
-        line = "TOTAL:      \t\t%f\n" % (self.tk - self.starttime, )
-        os.write(2, line)
+        line = "TOTAL:      \t\t%f" % (self.tk - self.starttime, )
+        debug_print(line)
         self._print_intline("ops", cnt[OPS])
         self._print_intline("recorded ops", cnt[RECORDED_OPS])
         self._print_intline("  calls", calls)
@@ -176,17 +180,26 @@
         self._print_intline("nvirtuals", cnt[NVIRTUALS])
         self._print_intline("nvholes", cnt[NVHOLES])
         self._print_intline("nvreused", cnt[NVREUSED])
+        cpu = self.cpu
+        if cpu is not None:   # for some tests
+            self._print_intline("Total # of loops",
+                                cpu.total_compiled_loops)
+            self._print_intline("Total # of bridges",
+                                cpu.total_compiled_bridges)
+            self._print_intline("Freed # of loops",
+                                cpu.total_freed_loops)
+            self._print_intline("Freed # of bridges",
+                                cpu.total_freed_bridges)
 
     def _print_line_time(self, string, i, tim):
-        final = "%s:%s\t%d\t%f\n" % (string, " " * max(0, 13-len(string)), i, tim)
-        os.write(2, final)
+        final = "%s:%s\t%d\t%f" % (string, " " * max(0, 13-len(string)), i, tim)
+        debug_print(final)
 
     def _print_intline(self, string, i):
         final = string + ':' + " " * max(0, 16-len(string))
-        final += '\t' + str(i) + '\n'
-        os.write(2, final)
-        
-        
+        final += '\t' + str(i)
+        debug_print(final)
+
 
 class BrokenProfilerData(JitException):
     pass

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/optimizeopt/__init__.py	Sat Dec 11 15:10:15 2010
@@ -3,7 +3,6 @@
 from pypy.jit.metainterp.optimizeopt.intbounds import OptIntBounds
 from pypy.jit.metainterp.optimizeopt.virtualize import OptVirtualize
 from pypy.jit.metainterp.optimizeopt.heap import OptHeap
-from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall
 from pypy.jit.metainterp.optimizeopt.string import OptString
 from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble
 
@@ -17,6 +16,10 @@
                      OptVirtualize(),
                      opt_str,
                      OptHeap(),
+                    ]
+    if metainterp_sd.jit_ffi:
+        from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall
+        optimizations = optimizations + [
                      OptFfiCall(),
                     ]
 

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	Sat Dec 11 15:10:15 2010
@@ -379,6 +379,10 @@
             return CVAL_ZERO
 
     def propagate_all_forward(self):
+        self.exception_might_have_happened = True
+        # ^^^ at least at the start of bridges.  For loops, we could set
+        # it to False, but we probably don't care
+        self.newoperations = []
         self.i = 0
         while self.i < len(self.loop.operations):
             op = self.loop.operations[self.i]

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	Sat Dec 11 15:10:15 2010
@@ -14,11 +14,10 @@
 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
+from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE
 from pypy.jit.metainterp.jitexc import JitException, get_llexception
 from pypy.rlib.rarithmetic import intmask
 from pypy.rlib.objectmodel import specialize
-from pypy.rlib.jit import DEBUG_OFF, DEBUG_PROFILE, DEBUG_STEPS, DEBUG_DETAILED
 from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
 from pypy.jit.codewriter import heaptracker
 from pypy.jit.metainterp.optimizeutil import RetraceLoop
@@ -95,6 +94,18 @@
             else: raise AssertionError(argcode)
             outvalue[startindex+i] = reg
 
+    def _put_back_list_of_boxes(self, outvalue, startindex, position):
+        code = self.bytecode
+        length = ord(code[position])
+        position += 1
+        for i in range(length):
+            index = ord(code[position+i])
+            box = outvalue[startindex+i]
+            if   box.type == history.INT:   self.registers_i[index] = box
+            elif box.type == history.REF:   self.registers_r[index] = box
+            elif box.type == history.FLOAT: self.registers_f[index] = box
+            else: raise AssertionError(box.type)
+
     def get_current_position_info(self):
         return self.jitcode.get_live_vars_info(self.pc)
 
@@ -602,8 +613,10 @@
         virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
         arrayindex = vinfo.array_field_by_descrs[arrayfielddescr]
         index = indexbox.getint()
-        if index < 0:
-            index += vinfo.get_array_length(virtualizable, arrayindex)
+        # Support for negative index: disabled
+        # (see codewriter/jtransform.py, _check_no_vable_array).
+        #if index < 0:
+        #    index += vinfo.get_array_length(virtualizable, arrayindex)
         assert 0 <= index < vinfo.get_array_length(virtualizable, arrayindex)
         return vinfo.get_index_in_array(virtualizable, arrayindex, index)
 
@@ -815,8 +828,9 @@
         for i in range(num_green_args):
             assert isinstance(varargs[i], Const)
 
-    @arguments("orgpc", "int", "boxes3", "boxes3")
-    def opimpl_jit_merge_point(self, orgpc, jdindex, greenboxes, redboxes):
+    @arguments("orgpc", "int", "boxes3", "jitcode_position", "boxes3")
+    def opimpl_jit_merge_point(self, orgpc, jdindex, greenboxes,
+                               jcposition, redboxes):
         any_operation = len(self.metainterp.history.operations) > 0
         jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
         self.verify_green_args(jitdriver_sd, greenboxes)
@@ -844,6 +858,10 @@
             self.pc = orgpc
             self.metainterp.reached_loop_header(greenboxes, redboxes)
             self.pc = saved_pc
+            # no exception, which means that the jit_merge_point did not
+            # close the loop.  We have to put the possibly-modified list
+            # 'redboxes' back into the registers where it comes from.
+            put_back_list_of_boxes3(self, jcposition, redboxes)
         else:
             # warning! careful here.  We have to return from the current
             # frame containing the jit_merge_point, and then use
@@ -1053,7 +1071,7 @@
             resumedescr = compile.ResumeGuardForcedDescr(metainterp_sd,
                                                    metainterp.jitdriver_sd)
         else:
-            resumedescr = compile.ResumeGuardDescr(metainterp_sd)
+            resumedescr = compile.ResumeGuardDescr()
         guard_op = metainterp.history.record(opnum, moreargs, None,
                                              descr=resumedescr)
         virtualizable_boxes = None
@@ -1199,7 +1217,8 @@
     logger_ops = None
 
     def __init__(self, cpu, options,
-                 ProfilerClass=EmptyProfiler, warmrunnerdesc=None):
+                 ProfilerClass=EmptyProfiler, warmrunnerdesc=None,
+                 jit_ffi=True):
         self.cpu = cpu
         self.stats = self.cpu.stats
         self.options = options
@@ -1207,7 +1226,9 @@
         self.logger_ops = Logger(self, guard_number=True)
 
         self.profiler = ProfilerClass()
+        self.profiler.cpu = cpu
         self.warmrunnerdesc = warmrunnerdesc
+        self.jit_ffi = jit_ffi
 
         backendmodule = self.cpu.__module__
         backendmodule = backendmodule.split('.')[-2]
@@ -1325,6 +1346,11 @@
                     return jitcode
             return None
 
+    def try_to_free_some_loops(self):
+        # Increase here the generation recorded by the memory manager.
+        if self.warmrunnerdesc is not None:       # for tests
+            self.warmrunnerdesc.memory_manager.next_generation()
+
     # ---------------- logging ------------------------
 
     def log(self, msg):
@@ -1627,6 +1653,7 @@
         self.staticdata._setup_once()
         self.staticdata.profiler.start_tracing()
         assert jitdriver_sd is self.jitdriver_sd
+        self.staticdata.try_to_free_some_loops()
         self.create_empty_history()
         try:
             original_boxes = self.initialize_original_boxes(jitdriver_sd, *args)
@@ -1655,10 +1682,15 @@
         debug_start('jit-tracing')
         self.staticdata.profiler.start_tracing()
         assert isinstance(key, compile.ResumeGuardDescr)
+        # store the resumekey.wref_original_loop_token() on 'self' to make
+        # sure that it stays alive as long as this MetaInterp
+        self.resumekey_original_loop_token = key.wref_original_loop_token()
+        self.staticdata.try_to_free_some_loops()
         self.initialize_state_from_guard_failure(key)
         try:
             return self._handle_guard_failure(key)
         finally:
+            self.resumekey_original_loop_token = None
             self.staticdata.profiler.end_tracing()
             debug_stop('jit-tracing')
 
@@ -1668,6 +1700,8 @@
         self.seen_loop_header_for_jdindex = -1
         try:
             self.prepare_resume_from_failure(key.guard_opnum)
+            if self.resumekey_original_loop_token is None:   # very rare case
+                raise SwitchToBlackhole(ABORT_BRIDGE)
             self.interpret()
         except GenerateMergePoint, gmp:
             return self.designate_target_loop(gmp)
@@ -1803,10 +1837,15 @@
             raise NotImplementedError(opname[opnum])
 
     def get_compiled_merge_points(self, greenkey):
+        """Get the list of looptokens corresponding to the greenkey.
+        Turns the (internal) list of weakrefs into regular refs.
+        """
         cell = self.jitdriver_sd.warmstate.jit_cell_at_key(greenkey)
-        if cell.compiled_merge_points is None:
-            cell.compiled_merge_points = []
-        return cell.compiled_merge_points
+        return cell.get_compiled_merge_points()
+
+    def set_compiled_merge_points(self, greenkey, looptokens):
+        cell = self.jitdriver_sd.warmstate.jit_cell_at_key(greenkey)
+        cell.set_compiled_merge_points(looptokens)
 
     def compile(self, original_boxes, live_arg_boxes, start):
         num_green_args = self.jitdriver_sd.num_green_args
@@ -1817,6 +1856,7 @@
         loop_token = compile.compile_new_loop(self, old_loop_tokens,
                                               greenkey, start)
         if loop_token is not None: # raise if it *worked* correctly
+            self.set_compiled_merge_points(greenkey, old_loop_tokens)
             raise GenerateMergePoint(live_arg_boxes, loop_token)
         self.history.operations.pop()     # remove the JUMP
         # FIXME: Why is self.history.inputargs not restored?
@@ -2345,6 +2385,8 @@
                 else:
                     raise AssertionError("bad argcode")
                 position += 1
+            elif argtype == "jitcode_position":
+                value = position
             else:
                 raise AssertionError("bad argtype: %r" % (argtype,))
             args += (value,)
@@ -2389,3 +2431,15 @@
     argtypes = unrolling_iterable(unboundmethod.argtypes)
     handler.func_name = 'handler_' + name
     return handler
+
+def put_back_list_of_boxes3(frame, position, newvalue):
+    code = frame.bytecode
+    length1 = ord(code[position])
+    position2 = position + 1 + length1
+    length2 = ord(code[position2])
+    position3 = position2 + 1 + length2
+    length3 = ord(code[position3])
+    assert len(newvalue) == length1 + length2 + length3
+    frame._put_back_list_of_boxes(newvalue, 0, position)
+    frame._put_back_list_of_boxes(newvalue, length1, position2)
+    frame._put_back_list_of_boxes(newvalue, length1 + length2, position3)

Modified: pypy/branch/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	Sat Dec 11 15:10:15 2010
@@ -19,7 +19,11 @@
     from pypy.jit.metainterp import simple_optimize
 
     class FakeJitCell:
-        compiled_merge_points = None
+        __compiled_merge_points = []
+        def get_compiled_merge_points(self):
+            return self.__compiled_merge_points[:]
+        def set_compiled_merge_points(self, lst):
+            self.__compiled_merge_points = lst
 
     class FakeWarmRunnerState:
         def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
@@ -35,7 +39,6 @@
         optimize_bridge = staticmethod(simple_optimize.optimize_bridge)
 
         trace_limit = sys.maxint
-        debug_level = 2
 
     func._jit_unroll_safe_ = True
     rtyper = support.annotate(func, values, type_system=type_system)
@@ -1996,6 +1999,29 @@
         res = self.meta_interp(f, [5, 2])
         assert 4 < res < 14
 
+    def test_compute_identity_hash(self):
+        from pypy.rlib.objectmodel import compute_identity_hash
+        class A(object):
+            pass
+        def f():
+            a = A()
+            return compute_identity_hash(a) == compute_identity_hash(a)
+        res = self.interp_operations(f, [])
+        assert res
+        # a "did not crash" kind of test
+
+    def test_compute_unique_id(self):
+        from pypy.rlib.objectmodel import compute_unique_id
+        class A(object):
+            pass
+        def f():
+            a1 = A()
+            a2 = A()
+            return (compute_unique_id(a1) == compute_unique_id(a1) and
+                    compute_unique_id(a1) != compute_unique_id(a2))
+        res = self.interp_operations(f, [])
+        assert res
+
 
 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	Sat Dec 11 15:10:15 2010
@@ -39,7 +39,6 @@
 
 class FakeState:
     optimize_loop = staticmethod(nounroll_optimize.optimize_loop)
-    debug_level = 0
 
     def attach_unoptimized_bridge_from_interp(*args):
         pass
@@ -54,6 +53,8 @@
 
     stats = Stats()
     profiler = jitprof.EmptyProfiler()
+    warmrunnerdesc = None
+    jit_ffi = False
     def log(self, msg, event_kind=None):
         pass
 
@@ -207,14 +208,12 @@
         class ExitFrameWithExceptionRef(Exception):
             pass
     FakeMetaInterpSD.cpu = cpu
-    class FakeJitDriverSD:
-        pass
     cpu.set_future_value_int(0, -156)
     cpu.set_future_value_int(1, -178)
     cpu.set_future_value_int(2, -190)
     fail_descr = cpu.execute_token(loop_token)
     try:
-        fail_descr.handle_fail(FakeMetaInterpSD(), FakeJitDriverSD())
+        fail_descr.handle_fail(FakeMetaInterpSD(), None)
     except FakeMetaInterpSD.ExitFrameWithExceptionRef, e:
         assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.args[1]) == llexc
     else:

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

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_fficall.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_fficall.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_fficall.py	Sat Dec 11 15:10:15 2010
@@ -40,6 +40,6 @@
                 n += 1
             return res
         #
-        res = self.meta_interp(f, [0])
+        res = self.meta_interp(f, [0], jit_ffi=True)
         return res
 

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_list.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_list.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_list.py	Sat Dec 11 15:10:15 2010
@@ -188,6 +188,26 @@
         assert res == f(4)
         self.check_loops(call=0, getfield_gc=0)
 
+    def test_fold_indexerror(self):
+        jitdriver = JitDriver(greens = [], reds = ['total', 'n', 'lst'])
+        def f(n):
+            lst = []
+            total = 0
+            while n > 0:
+                jitdriver.can_enter_jit(lst=lst, n=n, total=total)
+                jitdriver.jit_merge_point(lst=lst, n=n, total=total)
+                lst.append(n)
+                try:
+                    total += lst[n]
+                except IndexError:
+                    total += 1000
+                n -= 1
+            return total
+
+        res = self.meta_interp(f, [15], listops=True)
+        assert res == f(15)
+        self.check_loops(guard_exception=0)
+
 class TestOOtype(ListTests, OOJitMixin):
     pass
 

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	Sat Dec 11 15:10:15 2010
@@ -14,11 +14,20 @@
 
 def capturing(func, *args, **kwds):
     log_stream = StringIO()
-    debug._stderr = log_stream
+    class MyDebugLog:
+        def debug_print(self, *args):
+            for arg in args:
+                print >> log_stream, arg,
+            print >> log_stream
+        def debug_start(self, *args):
+            pass
+        def debug_stop(self, *args):
+            pass
     try:
+        debug._log = MyDebugLog()
         func(*args, **kwds)
     finally:
-        debug._stderr = sys.stderr
+        debug._log = None
     return log_stream.getvalue()
 
 class Logger(logger.Logger):
@@ -112,7 +121,8 @@
         equaloplists(loop.operations, oloop.operations)
 
     def test_jump(self):
-        namespace = {'target': LoopToken(3)}
+        namespace = {'target': LoopToken()}
+        namespace['target'].number = 3
         inp = '''
         [i0]
         jump(i0, descr=target)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizefficall.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizefficall.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_optimizefficall.py	Sat Dec 11 15:10:15 2010
@@ -32,6 +32,7 @@
 
 
 class TestFfiCall(BaseTestBasic, LLtypeMixin):
+    jit_ffi = True
 
     class namespace:
         cpu = LLtypeMixin.cpu

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	Sat Dec 11 15:10:15 2010
@@ -21,11 +21,12 @@
 
 class FakeMetaInterpStaticData(object):
 
-    def __init__(self, cpu):
+    def __init__(self, cpu, jit_ffi=False):
         self.cpu = cpu
         self.profiler = EmptyProfiler()
         self.options = Fake()
         self.globaldata = Fake()
+        self.jit_ffi = jit_ffi
 
 def test_store_final_boxes_in_guard():
     from pypy.jit.metainterp.compile import ResumeGuardDescr
@@ -34,7 +35,7 @@
     b1 = BoxInt()
     opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu),
                                 None)
-    fdescr = ResumeGuardDescr(None)
+    fdescr = ResumeGuardDescr()
     op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr)
     # setup rd data
     fi0 = resume.FrameInfo(None, "code0", 11)
@@ -141,6 +142,7 @@
     return sorted(boxes, key=lambda box: _kind2count[box.type])
 
 class BaseTestOptimizeOpt(BaseTest):
+    jit_ffi = False
 
     def invent_fail_descr(self, fail_args):
         if fail_args is None:
@@ -169,7 +171,7 @@
         loop.preamble = TreeLoop('preamble')
         loop.preamble.inputargs = loop.inputargs
         loop.preamble.token = LoopToken()
-        metainterp_sd = FakeMetaInterpStaticData(self.cpu)
+        metainterp_sd = FakeMetaInterpStaticData(self.cpu, self.jit_ffi)
         if hasattr(self, 'vrefinfo'):
             metainterp_sd.virtualref_info = self.vrefinfo
         if hasattr(self, 'callinfocollection'):
@@ -882,8 +884,12 @@
         i3 = call(i2, descr=nonwritedescr)
         jump(i1)       # the exception is considered lost when we loop back
         """
+        # note that 'guard_no_exception' at the very start must be kept
+        # around: bridges may start with one.  (In case of loops we could
+        # remove it, but we probably don't care.)
         expected = """
         [i]
+        guard_no_exception() []
         i1 = int_add(i, 3)
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
@@ -2227,6 +2233,15 @@
         """
         self.optimize_loop(ops, expected, preamble)
 
+    def test_bug_4(self):
+        ops = """
+        [p9]
+        p30 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(ConstPtr(myptr), p9, descr=nextdescr)
+        jump(p30)
+        """
+        self.optimize_loop(ops, 'Not', ops)
+
     def test_invalid_loop_1(self):
         ops = """
         [p1]

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_pyjitpl.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_pyjitpl.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_pyjitpl.py	Sat Dec 11 15:10:15 2010
@@ -17,6 +17,7 @@
     portal.setup(None)
     class FakeStaticData:
         cpu = None
+        warmrunnerdesc = None
 
     metainterp = pyjitpl.MetaInterp(FakeStaticData(), None)
     metainterp.framestack = []
@@ -53,6 +54,7 @@
 def test_remove_consts_and_duplicates():
     class FakeStaticData:
         cpu = None
+        warmrunnerdesc = None
     def is_another_box_like(box, referencebox):
         assert box is not referencebox
         assert isinstance(box, referencebox.clonebox().__class__)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_recursive.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_recursive.py	Sat Dec 11 15:10:15 2010
@@ -927,12 +927,16 @@
                                             x=x)
                 frame.s = hint(frame.s, promote=True)
                 n -= 1
-                x += frame.l[frame.s]
+                s = frame.s
+                assert s >= 0
+                x += frame.l[s]
                 frame.s += 1
                 if codeno == 0:
                     subframe = Frame([n, n+1, n+2, n+3], 0)
                     x += f(1, 10, 1, subframe)
-                x += frame.l[frame.s]
+                s = frame.s
+                assert s >= 0
+                x += frame.l[s]
                 x += len(frame.l)
                 frame.s -= 1
             return x
@@ -1142,6 +1146,19 @@
             res = self.meta_interp(main, [], inline=True, trace_limit=tlimit)
             assert ''.join(res.chars) == 'ABCDEFGHIabcdefghijJ' * 5
 
+    def test_no_duplicates_bug(self):
+        driver = JitDriver(greens = ['codeno'], reds = ['i'],
+                           get_printable_location = lambda codeno: str(codeno))
+        def portal(codeno, i):
+            while i > 0:
+                driver.can_enter_jit(codeno=codeno, i=i)
+                driver.jit_merge_point(codeno=codeno, i=i)
+                if codeno > 0:
+                    break
+                portal(i, i)
+                i -= 1
+        self.meta_interp(portal, [0, 10], inline=True)
+
 
 class TestLLtype(RecursiveTests, LLJitMixin):
     pass

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_virtualizable.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_virtualizable.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_virtualizable.py	Sat Dec 11 15:10:15 2010
@@ -481,9 +481,13 @@
                 myjitdriver.jit_merge_point(frame=frame, n=n, x=x)
                 frame.s = hint(frame.s, promote=True)
                 n -= 1
-                x += frame.l[frame.s]
+                s = frame.s
+                assert s >= 0
+                x += frame.l[s]
                 frame.s += 1
-                x += frame.l[frame.s]
+                s = frame.s
+                assert s >= 0
+                x += frame.l[s]
                 x += len(frame.l)
                 frame.s -= 1
             return x
@@ -995,7 +999,9 @@
                 jitdriver.can_enter_jit(frame=frame, n=n)
                 jitdriver.jit_merge_point(frame=frame, n=n)
                 popped = frame.stack[frame.stackpos]
-                frame.stackpos -= 1
+                sp = frame.stackpos - 1
+                assert sp >= 0
+                frame.stackpos = sp
                 to_push = intmask(popped * 3)
                 frame.stack[frame.stackpos] = to_push
                 frame.stackpos += 1

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_warmspot.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_warmspot.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_warmspot.py	Sat Dec 11 15:10:15 2010
@@ -132,91 +132,6 @@
         assert state.optimize_loop is optimize.optimize_loop
         assert state.optimize_bridge is optimize.optimize_bridge
 
-    def test_static_debug_level(self, capfd):
-        py.test.skip("debug_level is being deprecated")
-        from pypy.rlib.jit import DEBUG_PROFILE, DEBUG_OFF, DEBUG_STEPS
-        from pypy.jit.metainterp.jitprof import EmptyProfiler, Profiler
-        
-        myjitdriver = JitDriver(greens = [], reds = ['n'])
-        def f(n):
-            while n > 0:
-                myjitdriver.can_enter_jit(n=n)
-                myjitdriver.jit_merge_point(n=n)
-                n -= 1
-            return n
-
-        capfd.readouterr()
-        self.meta_interp(f, [10], debug_level=DEBUG_OFF,
-                                  ProfilerClass=Profiler)
-        out, err = capfd.readouterr()
-        assert not 'ENTER' in err
-        assert not 'LEAVE' in err
-        assert not "Running asm" in err
-        self.meta_interp(f, [10], debug_level=DEBUG_PROFILE,
-                                  ProfilerClass=Profiler)
-        out, err = capfd.readouterr()
-        assert not 'ENTER' in err
-        assert not 'LEAVE' in err
-        assert not 'compiled new' in err
-        assert "Running asm" in err
-
-        self.meta_interp(f, [10], debug_level=DEBUG_STEPS,
-                                  ProfilerClass=Profiler)
-        out, err = capfd.readouterr()
-        assert 'ENTER' in err
-        assert 'LEAVE' in err
-        assert "Running asm" in err
-
-        self.meta_interp(f, [10], debug_level=DEBUG_STEPS,
-                                  ProfilerClass=EmptyProfiler)
-        out, err = capfd.readouterr()
-        assert 'ENTER' in err
-        assert 'LEAVE' in err
-        assert not "Running asm" in err
-
-    def test_set_param_debug(self):
-        py.test.skip("debug_level is being deprecated")
-        from pypy.rlib.jit import DEBUG_PROFILE, DEBUG_OFF, DEBUG_STEPS
-        from pypy.jit.metainterp.jitprof import EmptyProfiler, Profiler
-        
-        myjitdriver = JitDriver(greens = [], reds = ['n'])
-        def f(n):
-            while n > 0:
-                myjitdriver.can_enter_jit(n=n)
-                myjitdriver.jit_merge_point(n=n)
-                n -= 1
-            return n
-
-        def main(n, debug):
-            myjitdriver.set_param("debug", debug)
-            print f(n)
-
-        outerr = py.io.StdCaptureFD()
-        self.meta_interp(main, [10, DEBUG_OFF], debug_level=DEBUG_STEPS,
-                                                ProfilerClass=Profiler)
-        out, errf = outerr.done()
-        err = errf.read()
-        assert not 'ENTER' in err
-        assert not 'LEAVE' in err
-        assert not "Running asm" in err
-        outerr = py.io.StdCaptureFD()
-        self.meta_interp(main, [10, DEBUG_PROFILE], debug_level=DEBUG_STEPS,
-                                                    ProfilerClass=Profiler)
-        out, errf = outerr.done()
-        err = errf.read()
-        assert not 'ENTER' in err
-        assert not 'LEAVE' in err
-        assert not 'compiled new' in err
-        assert "Running asm" in err
-        outerr = py.io.StdCaptureFD()
-        self.meta_interp(main, [10, DEBUG_STEPS], debug_level=DEBUG_OFF,
-                                                  ProfilerClass=Profiler)
-        out, errf = outerr.done()
-        err = errf.read()
-        assert 'ENTER' in err
-        assert 'LEAVE' in err
-        assert "Running asm" in err
-
     def test_unwanted_loops(self):
         mydriver = JitDriver(reds = ['n', 'total', 'm'], greens = [])
 
@@ -378,23 +293,30 @@
         exc_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
         cls.exc_vtable = exc_vtable
 
-        class FakeFailDescr(object):
+        class FakeLoopToken:
             def __init__(self, no):
                 self.no = no
+                self.generation = 0
+
+        class FakeFailDescr(object):
+            def __init__(self, looptoken):
+                assert isinstance(looptoken, FakeLoopToken)
+                self.looptoken = looptoken
             
             def handle_fail(self, metainterp_sd, jitdrivers_sd):
-                if self.no == 0:
+                no = self.looptoken.no
+                if no == 0:
                     raise metainterp_sd.warmrunnerdesc.DoneWithThisFrameInt(3)
-                if self.no == 1:
+                if no == 1:
                     raise metainterp_sd.warmrunnerdesc.ContinueRunningNormally(
                         [0], [], [], [1], [], [])
-                if self.no == 3:
+                if no == 3:
                     exc = lltype.malloc(OBJECT)
                     exc.typeptr = exc_vtable
                     raise metainterp_sd.warmrunnerdesc.ExitFrameWithExceptionRef(
                         metainterp_sd.cpu,
                         lltype.cast_opaque_ptr(llmemory.GCREF, exc))
-                return self.no
+                return self.looptoken
 
         class FakeDescr:
             def as_vtable_size_descr(self):
@@ -419,11 +341,11 @@
             sizeof       = nodescr
 
             def get_fail_descr_from_number(self, no):
-                return FakeFailDescr(no)
+                return FakeFailDescr(FakeLoopToken(no))
 
             def execute_token(self, token):
-                assert token == 2
-                return FakeFailDescr(1)
+                assert token.no == 2
+                return FakeFailDescr(FakeLoopToken(1))
 
         driver = JitDriver(reds = ['red'], greens = ['green'])
         

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_warmstate.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_warmstate.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/test/test_warmstate.py	Sat Dec 11 15:10:15 2010
@@ -99,6 +99,8 @@
                                          lltype.Float], lltype.Void))
     class FakeWarmRunnerDesc:
         rtyper = FakeRTyper()
+        cpu = None
+        memory_manager = None
     class FakeJitDriverSD:
         _get_jitcell_at_ptr = llhelper(GETTER, getter)
         _set_jitcell_at_ptr = llhelper(SETTER, setter)
@@ -126,6 +128,7 @@
             future_values[j] = "float", value
     class FakeWarmRunnerDesc:
         cpu = FakeCPU()
+        memory_manager = None
     class FakeJitDriverSD:
         _red_args_types = ["int", "float"]
         virtualizable_info = None
@@ -154,16 +157,20 @@
         _get_jitcell_at_ptr = None
     state = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = state.make_jitcell_getter()
+    class FakeLoopToken(object):
+        pass
+    looptoken = FakeLoopToken()
     state.attach_unoptimized_bridge_from_interp([ConstInt(5),
                                                  ConstFloat(2.25)],
-                                                "entry loop token")
+                                                looptoken)
     cell1 = get_jitcell(True, 5, 2.25)
     assert cell1.counter < 0
-    assert cell1.entry_loop_token == "entry loop token"
+    assert cell1.get_entry_loop_token() is looptoken
 
 def test_make_jitdriver_callbacks_1():
     class FakeWarmRunnerDesc:
         cpu = None
+        memory_manager = None
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed, lltype.Float]
         _get_printable_location_ptr = None
@@ -189,6 +196,7 @@
     class FakeWarmRunnerDesc:
         rtyper = None
         cpu = None
+        memory_manager = None
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed, lltype.Float]
         _get_printable_location_ptr = llhelper(GET_LOCATION, get_location)
@@ -211,6 +219,7 @@
     class FakeWarmRunnerDesc:
         rtyper = None
         cpu = None
+        memory_manager = None
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed, lltype.Float]
         _get_printable_location_ptr = None
@@ -233,6 +242,7 @@
     class FakeWarmRunnerDesc:
         rtyper = None
         cpu = None
+        memory_manager = None
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed, lltype.Float]
         _get_printable_location_ptr = None

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	Sat Dec 11 15:10:15 2010
@@ -12,11 +12,12 @@
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.debug import debug_print, fatalerror
+from pypy.rlib.debug import debug_start, debug_stop
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.translator.simplify import get_funcobj, get_functype
 from pypy.translator.unsimplify import call_final_function
 
-from pypy.jit.metainterp import history, pyjitpl, gc
+from pypy.jit.metainterp import history, pyjitpl, gc, memmgr
 from pypy.jit.metainterp.pyjitpl import MetaInterpStaticData, MetaInterp
 from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
 from pypy.jit.metainterp.jitprof import Profiler, EmptyProfiler
@@ -24,21 +25,17 @@
 from pypy.jit.metainterp.jitdriver import JitDriverStaticData
 from pypy.jit.codewriter import support, codewriter
 from pypy.jit.codewriter.policy import JitPolicy
-from pypy.rlib.jit import DEBUG_STEPS, DEBUG_DETAILED, DEBUG_OFF, DEBUG_PROFILE
 
 # ____________________________________________________________
 # Bootstrapping
 
-def apply_jit(translator, backend_name="auto", debug_level=DEBUG_STEPS,
-              inline=False,
-              **kwds):
+def apply_jit(translator, backend_name="auto", inline=False, **kwds):
     if 'CPUClass' not in kwds:
         from pypy.jit.backend.detect_cpu import getcpuclass
         kwds['CPUClass'] = getcpuclass(backend_name)
-    if debug_level > DEBUG_OFF:
-        ProfilerClass = Profiler
-    else:
-        ProfilerClass = EmptyProfiler
+    ProfilerClass = Profiler
+    # Always use Profiler here, which should have a very low impact.
+    # Otherwise you can try with ProfilerClass = EmptyProfiler.
     warmrunnerdesc = WarmRunnerDesc(translator,
                                     translate_support_code=True,
                                     listops=True,
@@ -47,7 +44,6 @@
                                     **kwds)
     for jd in warmrunnerdesc.jitdrivers_sd:
         jd.warmstate.set_param_inlining(inline)
-        jd.warmstate.set_param_debug(debug_level)
     warmrunnerdesc.finish()
     translator.warmrunnerdesc = warmrunnerdesc    # for later debugging
 
@@ -66,7 +62,7 @@
 
 def jittify_and_run(interp, graph, args, repeat=1,
                     backendopt=False, trace_limit=sys.maxint,
-                    debug_level=DEBUG_STEPS, inline=False, **kwds):
+                    inline=False, loop_longevity=0, **kwds):
     from pypy.config.config import ConfigError
     translator = interp.typer.annotator.translator
     try:
@@ -83,7 +79,7 @@
         jd.warmstate.set_param_trace_eagerness(2)    # for tests
         jd.warmstate.set_param_trace_limit(trace_limit)
         jd.warmstate.set_param_inlining(inline)
-        jd.warmstate.set_param_debug(debug_level)
+        jd.warmstate.set_param_loop_longevity(loop_longevity)
     warmrunnerdesc.finish()
     res = interp.eval_graph(graph, args)
     if not kwds.get('translate_support_code', False):
@@ -148,9 +144,11 @@
 class WarmRunnerDesc(object):
 
     def __init__(self, translator, policy=None, backendopt=True, CPUClass=None,
-                 optimizer=None, ProfilerClass=EmptyProfiler, **kwds):
+                 optimizer=None, ProfilerClass=EmptyProfiler,
+                 jit_ffi=None, **kwds):
         pyjitpl._warmrunnerdesc = self   # this is a global for debugging only!
         self.set_translator(translator)
+        self.memory_manager = memmgr.MemoryManager()
         self.build_cpu(CPUClass, **kwds)
         self.find_portals()
         self.codewriter = codewriter.CodeWriter(self.cpu, self.jitdrivers_sd)
@@ -162,8 +160,10 @@
         self.check_access_directly_sanity(graphs)
         if backendopt:
             self.prejit_optimizations(policy, graphs)
+        elif self.opt.listops:
+            self.prejit_optimizations_minimal_inline(policy, graphs)
 
-        self.build_meta_interp(ProfilerClass)
+        self.build_meta_interp(ProfilerClass, jit_ffi)
         self.make_args_specifications()
         #
         from pypy.jit.metainterp.virtualref import VirtualRefInfo
@@ -259,6 +259,10 @@
                               remove_asserts=True,
                               really_remove_asserts=True)
 
+    def prejit_optimizations_minimal_inline(self, policy, graphs):
+        from pypy.translator.backendopt.inline import auto_inline_graphs
+        auto_inline_graphs(self.translator, graphs, 0.01)
+
     def build_cpu(self, CPUClass, translate_support_code=False,
                   no_stats=False, **kwds):
         assert CPUClass is not None
@@ -277,11 +281,14 @@
                        translate_support_code, gcdescr=self.gcdescr)
         self.cpu = cpu
 
-    def build_meta_interp(self, ProfilerClass):
+    def build_meta_interp(self, ProfilerClass, jit_ffi=None):
+        if jit_ffi is None:
+            jit_ffi = self.translator.config.translation.jit_ffi
         self.metainterp_sd = MetaInterpStaticData(self.cpu,
                                                   self.opt,
                                                   ProfilerClass=ProfilerClass,
-                                                  warmrunnerdesc=self)
+                                                  warmrunnerdesc=self,
+                                                  jit_ffi=jit_ffi)
 
     def make_virtualizable_infos(self):
         vinfos = {}
@@ -713,7 +720,7 @@
                     loop_token = fail_descr.handle_fail(self.metainterp_sd, jd)
                 except JitException, e:
                     return handle_jitexception(e)
-                fail_descr = self.cpu.execute_token(loop_token)
+                fail_descr = self.execute_token(loop_token)
 
         jd._assembler_call_helper = assembler_call_helper # for debugging
         jd._assembler_helper_ptr = self.helper_func(
@@ -807,3 +814,10 @@
             py.test.skip("rewrite_force_virtual: port it to ootype")
         all_graphs = self.translator.graphs
         vrefinfo.replace_force_virtual_with_call(all_graphs)
+
+    # ____________________________________________________________
+
+    def execute_token(self, loop_token):
+        fail_descr = self.cpu.execute_token(loop_token)
+        self.memory_manager.keep_loop_alive(loop_token)
+        return fail_descr

Modified: pypy/branch/jit-unroll-loops/pypy/jit/metainterp/warmstate.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/metainterp/warmstate.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/metainterp/warmstate.py	Sat Dec 11 15:10:15 2010
@@ -1,4 +1,4 @@
-import sys
+import sys, weakref
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.annlowlevel import hlstr, llstr, cast_base_ptr_to_instance
@@ -9,7 +9,6 @@
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.jit import (PARAMETERS, OPTIMIZER_SIMPLE, OPTIMIZER_FULL,
                            OPTIMIZER_NO_UNROLL)
-from pypy.rlib.jit import DEBUG_PROFILE
 from pypy.rlib.jit import BaseJitCell
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
 from pypy.jit.metainterp import history
@@ -150,9 +149,34 @@
     #     counter == -1: there is an entry bridge for this cell
     #     counter == -2: tracing is currently going on for this cell
     counter = 0
-    compiled_merge_points = None
+    compiled_merge_points_wref = None    # list of weakrefs to LoopToken
     dont_trace_here = False
-    entry_loop_token = None
+    wref_entry_loop_token = None         # (possibly) one weakref to LoopToken
+
+    def get_compiled_merge_points(self):
+        result = []
+        if self.compiled_merge_points_wref is not None:
+            for wref in self.compiled_merge_points_wref:
+                looptoken = wref()
+                if looptoken is not None:
+                    result.append(looptoken)
+        return result
+
+    def set_compiled_merge_points(self, looptokens):
+        self.compiled_merge_points_wref = [self._makeref(token)
+                                           for token in looptokens]
+
+    def get_entry_loop_token(self):
+        if self.wref_entry_loop_token is not None:
+            return self.wref_entry_loop_token()
+        return None
+
+    def set_entry_loop_token(self, looptoken):
+        self.wref_entry_loop_token = self._makeref(looptoken)
+
+    def _makeref(self, looptoken):
+        assert looptoken is not None
+        return weakref.ref(looptoken)
 
 # ____________________________________________________________
 
@@ -165,6 +189,8 @@
         "NOT_RPYTHON"
         self.warmrunnerdesc = warmrunnerdesc
         self.jitdriver_sd = jitdriver_sd
+        if warmrunnerdesc is not None:       # for tests
+            self.cpu = warmrunnerdesc.cpu
         try:
             self.profiler = warmrunnerdesc.metainterp_sd.profiler
         except AttributeError:       # for tests
@@ -176,7 +202,7 @@
             meth(default_value)
 
     def set_param_threshold(self, threshold):
-        if threshold < 0:
+        if threshold <= 0:
             self.increment_threshold = 0   # never reach the THRESHOLD_LIMIT
             return
         if threshold < 2:
@@ -209,10 +235,11 @@
         else:
             raise ValueError("unknown optimizer")
 
-    def set_param_debug(self, value):
-        self.debug_level = value
-        if self.profiler is not None:
-            self.profiler.set_printing(value >= DEBUG_PROFILE)
+    def set_param_loop_longevity(self, value):
+        # note: it's a global parameter, not a per-jitdriver one
+        if (self.warmrunnerdesc is not None and
+            self.warmrunnerdesc.memory_manager is not None):   # all for tests
+            self.warmrunnerdesc.memory_manager.set_max_age(value)
 
     def disable_noninlinable_function(self, greenkey):
         cell = self.jit_cell_at_key(greenkey)
@@ -225,12 +252,15 @@
     def attach_unoptimized_bridge_from_interp(self, greenkey,
                                               entry_loop_token):
         cell = self.jit_cell_at_key(greenkey)
-        cell.counter = -1
-        old_token = cell.entry_loop_token
-        cell.entry_loop_token = entry_loop_token
+        old_token = cell.get_entry_loop_token()
+        cell.set_entry_loop_token(entry_loop_token)
+        cell.counter = -1       # valid entry bridge attached
         if old_token is not None:
-            cpu = self.warmrunnerdesc.cpu
-            cpu.redirect_call_assembler(old_token, entry_loop_token)
+            self.cpu.redirect_call_assembler(old_token, entry_loop_token)
+            # entry_loop_token is also kept alive by any loop that used
+            # to point to old_token.  Actually freeing old_token early
+            # is a pointless optimization (it is tiny).
+            old_token.record_jump_to(entry_loop_token)
 
     # ----------
 
@@ -239,7 +269,8 @@
         if hasattr(self, 'maybe_compile_and_run'):
             return self.maybe_compile_and_run
 
-        metainterp_sd = self.warmrunnerdesc.metainterp_sd
+        warmrunnerdesc = self.warmrunnerdesc
+        metainterp_sd = warmrunnerdesc.metainterp_sd
         jitdriver_sd = self.jitdriver_sd
         vinfo = jitdriver_sd.virtualizable_info
         index_of_virtualizable = jitdriver_sd.index_of_virtualizable
@@ -297,23 +328,27 @@
                 assert cell.counter == -1
                 if not confirm_enter_jit(*args):
                     return
+                loop_token = cell.get_entry_loop_token()
+                if loop_token is None:   # it was a weakref that has been freed
+                    cell.counter = 0
+                    return
                 # machine code was already compiled for these greenargs
                 # get the assembler and fill in the boxes
                 set_future_values(*args[num_green_args:])
-                loop_token = cell.entry_loop_token
 
             # ---------- execute assembler ----------
             while True:     # until interrupted by an exception
                 metainterp_sd.profiler.start_running()
                 debug_start("jit-running")
-                fail_descr = metainterp_sd.cpu.execute_token(loop_token)
+                fail_descr = warmrunnerdesc.execute_token(loop_token)
                 debug_stop("jit-running")
                 metainterp_sd.profiler.end_running()
+                loop_token = None     # for test_memmgr
                 if vinfo is not None:
                     vinfo.reset_vable_token(virtualizable)
                 loop_token = fail_descr.handle_fail(metainterp_sd,
                                                     jitdriver_sd)
-       
+
         maybe_compile_and_run._dont_inline_ = True
         self.maybe_compile_and_run = maybe_compile_and_run
         return maybe_compile_and_run
@@ -459,7 +494,7 @@
 
         warmrunnerdesc = self.warmrunnerdesc
         jitdriver_sd   = self.jitdriver_sd
-        cpu = warmrunnerdesc.cpu
+        cpu = self.cpu
         vinfo = jitdriver_sd.virtualizable_info
         red_args_types = unrolling_iterable(jitdriver_sd._red_args_types)
         #
@@ -508,10 +543,11 @@
         if hasattr(self, 'get_location_str'):
             return
         #
+        warmrunnerdesc = self.warmrunnerdesc
         unwrap_greenkey = self.make_unwrap_greenkey()
         jit_getter = self.make_jitcell_getter()
         jd = self.jitdriver_sd
-        cpu = self.warmrunnerdesc.cpu
+        cpu = self.cpu
 
         def can_inline_greenargs(*greenargs):
             if can_never_inline(*greenargs):
@@ -529,11 +565,16 @@
         def get_assembler_token(greenkey, redboxes):
             # 'redboxes' is only used to know the types of red arguments
             cell = self.jit_cell_at_key(greenkey)
-            if cell.entry_loop_token is None:
+            entry_loop_token = cell.get_entry_loop_token()
+            if entry_loop_token is None:
                 from pypy.jit.metainterp.compile import compile_tmp_callback
-                cell.entry_loop_token = compile_tmp_callback(cpu, jd, greenkey,
-                                                             redboxes)
-            return cell.entry_loop_token
+                if cell.counter == -1:    # used to be a valid entry bridge,
+                    cell.counter = 0      # but was freed in the meantime.
+                memmgr = warmrunnerdesc.memory_manager
+                entry_loop_token = compile_tmp_callback(cpu, jd, greenkey,
+                                                        redboxes, memmgr)
+                cell.set_entry_loop_token(entry_loop_token)
+            return entry_loop_token
         self.get_assembler_token = get_assembler_token
         
         #

Modified: pypy/branch/jit-unroll-loops/pypy/jit/tl/spli/interpreter.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tl/spli/interpreter.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tl/spli/interpreter.py	Sat Dec 11 15:10:15 2010
@@ -105,26 +105,32 @@
         self.stack_depth += 1
 
     def pop(self):
-        self.stack_depth -= 1
-        val = self.value_stack[self.stack_depth]
-        self.value_stack[self.stack_depth] = None
+        sd = self.stack_depth - 1
+        assert sd >= 0
+        self.stack_depth = sd
+        val = self.value_stack[sd]
+        self.value_stack[sd] = None
         return val
 
     def pop_many(self, n):
         return [self.pop() for i in range(n)]
 
     def peek(self):
-        return self.value_stack[self.stack_depth - 1]
+        sd = self.stack_depth - 1
+        assert sd >= 0
+        return self.value_stack[sd]
 
     def POP_TOP(self, _, next_instr, code):
         self.pop()
         return next_instr
 
     def LOAD_FAST(self, name_index, next_instr, code):
+        assert name_index >= 0
         self.push(self.locals[name_index])
         return next_instr
 
     def STORE_FAST(self, name_index, next_instr, code):
+        assert name_index >= 0
         self.locals[name_index] = self.pop()
         return next_instr
 

Modified: pypy/branch/jit-unroll-loops/pypy/jit/tl/tl.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tl/tl.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tl/tl.py	Sat Dec 11 15:10:15 2010
@@ -16,32 +16,40 @@
     def __init__(self, size):
         self = hint(self, access_directly=True, fresh_virtualizable=True)
         self.stack = [0] * size
-        self.stackpos = 0
+        self.stackpos = 0        # always store a known-nonneg integer here
 
     def append(self, elem):
         self.stack[self.stackpos] = elem
         self.stackpos += 1
 
     def pop(self):
-        self.stackpos -= 1
-        if self.stackpos < 0:
+        stackpos = self.stackpos - 1
+        if stackpos < 0:
             raise IndexError
-        return self.stack[self.stackpos]
+        self.stackpos = stackpos     # always store a known-nonneg integer here
+        return self.stack[stackpos]
 
     def pick(self, i):
-        self.append(self.stack[self.stackpos - i - 1])
+        n = self.stackpos - i - 1
+        assert n >= 0
+        self.append(self.stack[n])
 
     def put(self, i):
         elem = self.pop()
-        self.stack[self.stackpos - i - 1] = elem
+        n = self.stackpos - i - 1
+        assert n >= 0
+        self.stack[n] = elem
 
     def roll(self, r):
         if r < -1:
             i = self.stackpos + r
             if i < 0:
                 raise IndexError
-            elem = self.stack[self.stackpos - 1]
+            n = self.stackpos - 1
+            assert n >= 0
+            elem = self.stack[n]
             for j in range(self.stackpos - 2, i - 1, -1):
+                assert j >= 0
                 self.stack[j + 1] = self.stack[j]
             self.stack[i] = elem
         elif r > 1:
@@ -51,7 +59,9 @@
             elem = self.stack[i]
             for j in range(i, self.stackpos - 1):
                 self.stack[j] = self.stack[j + 1]
-            self.stack[self.stackpos - 1] = elem
+            n = self.stackpos - 1
+            assert n >= 0
+            self.stack[n] = elem
 
 
 def make_interp(supports_call):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/tool/jitoutput.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tool/jitoutput.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tool/jitoutput.py	Sat Dec 11 15:10:15 2010
@@ -27,6 +27,10 @@
     (('nvirtuals',), '^nvirtuals:\s+(\d+)$'),
     (('nvholes',), '^nvholes:\s+(\d+)$'),
     (('nvreused',), '^nvreused:\s+(\d+)$'),
+    (('total_compiled_loops',),   '^Total # of loops:\s+(\d+)$'),
+    (('total_compiled_bridges',), '^Total # of bridges:\s+(\d+)$'),
+    (('total_freed_loops',),      '^Freed # of loops:\s+(\d+)$'),
+    (('total_freed_bridges',),    '^Freed # of bridges:\s+(\d+)$'),
     ]
 
 class Ops(object):

Modified: pypy/branch/jit-unroll-loops/pypy/jit/tool/loopcounter.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tool/loopcounter.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tool/loopcounter.py	Sat Dec 11 15:10:15 2010
@@ -7,32 +7,41 @@
 import py
 import sys
 import optparse
+import re
 
 def get_timestamp(line):
-    import re
     match = re.match(r'\[([0-9a-f]*)\] .*', line)
     return int(match.group(1), 16)
 
-def main(logfile, options):
-    log = open(logfile)
+def count_loops_and_bridges(log):
     loops = 0
     bridges = 0
     time0 = None
-    print 'timestamp,total,loops,bridges'
-    for line in log:
+    lines = iter(log)
+    for line in lines:
         if time0 is None and line.startswith('['):
             time0 = get_timestamp(line)
-        if '{jit-log-opt-' in line:
-            time_now = get_timestamp(line)
-            if '{jit-log-opt-loop' in line:
+        if '{jit-mem-looptoken-' in line:
+            time_now = get_timestamp(line) - time0
+            text = lines.next()
+            if text.startswith('allocating Loop #'):
                 loops += 1
-            elif '{jit-log-opt-bridge' in line:
+            elif text.startswith('allocating Bridge #'):
                 bridges += 1
+            elif text.startswith('freeing Loop #'):
+                match = re.match('freeing Loop # .* with ([0-9]*) attached bridges\n', text)
+                loops -=1
+                bridges -= int(match.group(1))
             else:
-                assert False, 'unknown category %s' % line
+                assert False, 'unknown line' % line
             total = loops+bridges
-            timestamp = time_now - time0
-            print '%d,%d,%d,%d' % (timestamp, total, loops, bridges)
+            yield (time_now, total, loops, bridges)
+
+def main(logfile, options):
+    print 'timestamp,total,loops,bridges'
+    log = open(logfile)
+    for timestamp, total, loops, bridges in count_loops_and_bridges(log):
+        print '%d,%d,%d,%d' % (timestamp, total, loops, bridges)        
 
 if __name__ == '__main__':
     parser = optparse.OptionParser(usage="%prog loopfile [options]")
@@ -40,5 +49,4 @@
     if len(args) != 1:
         parser.print_help()
         sys.exit(2)
-
     main(args[0], options)

Modified: pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_jitoutput.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_jitoutput.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/jit/tool/test/test_jitoutput.py	Sat Dec 11 15:10:15 2010
@@ -1,10 +1,11 @@
 
 import py
 from pypy.jit.metainterp.warmspot import ll_meta_interp
-from pypy.rlib.jit import JitDriver, DEBUG_PROFILE
+from pypy.rlib.jit import JitDriver
 from pypy.jit.backend.llgraph import runner
 from pypy.jit.metainterp.jitprof import Profiler, JITPROF_LINES
 from pypy.jit.tool.jitoutput import parse_prof
+from pypy.tool.logparser import parse_log, extract_category
 
 def test_really_run():
     """ This test checks whether output of jitprof did not change.
@@ -21,13 +22,15 @@
     cap = py.io.StdCaptureFD()
     try:
         ll_meta_interp(f, [10], CPUClass=runner.LLtypeCPU, type_system='lltype',
-                       ProfilerClass=Profiler, debug_level=DEBUG_PROFILE)
+                       ProfilerClass=Profiler)
     finally:
         out, err = cap.reset()
-    err = "\n".join(err.splitlines()[-JITPROF_LINES:])
-    print err
-    assert err.count("\n") == JITPROF_LINES - 1
-    info = parse_prof(err)
+
+    log = parse_log(err.splitlines(True))
+    err_sections = list(extract_category(log, 'jit-summary'))
+    [err1] = err_sections    # there should be exactly one jit-summary
+    assert err1.count("\n") == JITPROF_LINES
+    info = parse_prof(err1)
     # assert did not crash
     # asserts below are a bit delicate, possibly they might be deleted
     assert info.tracing_no == 1
@@ -60,6 +63,10 @@
 nvirtuals:              13
 nvholes:                14
 nvreused:               15
+Total # of loops:       100
+Total # of bridges:     300
+Freed # of loops:       99
+Freed # of bridges:     299
 '''
 
 def test_parse():

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	Sat Dec 11 15:10:15 2010
@@ -11,6 +11,11 @@
         'internal_repr'             : 'interp_magic.internal_repr',
         'bytebuffer'                : 'bytebuffer.bytebuffer',
         'identity_dict'             : 'interp_identitydict.W_IdentityDict',
+        'debug_start'               : 'interp_debug.debug_start',
+        'debug_print'               : 'interp_debug.debug_print',
+        'debug_stop'                : 'interp_debug.debug_stop',
+        'debug_print_once'          : 'interp_debug.debug_print_once',
+        'builtinify'                : 'interp_magic.builtinify',
     }
 
     def setup_after_space_initialization(self):

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	Sat Dec 11 15:10:15 2010
@@ -51,3 +51,9 @@
     return space.newtuple([space.newint(cache.hits.get(name, 0)),
                            space.newint(cache.misses.get(name, 0))])
 mapdict_cache_counter.unwrap_spec = [ObjSpace, str]
+
+def builtinify(space, w_func):
+    from pypy.interpreter.function import Function, BuiltinFunction
+    func = space.interp_w(Function, w_func)
+    bltn = BuiltinFunction(func)
+    return space.wrap(bltn)

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	Sat Dec 11 15:10:15 2010
@@ -21,3 +21,18 @@
     def test_cpumodel(self):
         import __pypy__
         assert hasattr(__pypy__, 'cpumodel')
+
+    def test_builtinify(self):
+        import __pypy__
+        class A(object):
+            a = lambda *args: args
+            b = __pypy__.builtinify(a)
+        my = A()
+        assert my.a() == (my,)
+        assert my.b() == ()
+        assert A.a(my) == (my,)
+        assert A.b(my) == (my,)
+        assert A.a.im_func(my) == (my,)
+        assert not hasattr(A.b, 'im_func')
+        assert A.a is not A.__dict__['a']
+        assert A.b is A.__dict__['b']

Modified: pypy/branch/jit-unroll-loops/pypy/module/_lsprof/interp_lsprof.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/_lsprof/interp_lsprof.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/_lsprof/interp_lsprof.py	Sat Dec 11 15:10:15 2010
@@ -163,8 +163,11 @@
     if isinstance(w_arg, Method):
         w_function = w_arg.w_function
         class_name = w_arg.w_class.getname(space, '?')
-        assert isinstance(w_function, Function)
-        return "{method '%s' of '%s' objects}" % (w_function.name, class_name)
+        if isinstance(w_function, Function):
+            name = w_function.name
+        else:
+            name = '?'
+        return "{method '%s' of '%s' objects}" % (name, class_name)
     elif isinstance(w_arg, Function):
         if w_arg.w_module is None:
             module = ''
@@ -176,7 +179,8 @@
                 module += '.'
         return '{%s%s}' % (module, w_arg.name)
     else:
-        return '{!!!unknown!!!}'
+        class_name = space.type(w_arg).getname(space, '?')
+        return "{'%s' object}" % (class_name,)
     
 def lsprof_call(space, w_self, frame, event, w_arg):
     assert isinstance(w_self, W_Profiler)

Modified: pypy/branch/jit-unroll-loops/pypy/module/_lsprof/test/test_cprofile.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/_lsprof/test/test_cprofile.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/_lsprof/test/test_cprofile.py	Sat Dec 11 15:10:15 2010
@@ -2,9 +2,10 @@
 from pypy.conftest import gettestobjspace, option
 
 class AppTestCProfile(object):
+    keywords = {}
 
     def setup_class(cls):
-        space = gettestobjspace(usemodules=('_lsprof',))
+        space = gettestobjspace(usemodules=('_lsprof',), **cls.keywords)
         cls.w_expected_output = space.wrap(expected_output)
         cls.space = space
         cls.w_file = space.wrap(__file__)
@@ -148,6 +149,12 @@
         finally:
             sys.path.pop(0)
 
+
+class AppTestWithDifferentBytecodes(AppTestCProfile):
+    keywords = {'objspace.opcodes.CALL_LIKELY_BUILTIN': True,
+                'objspace.opcodes.CALL_METHOD': True}
+
+
 expected_output = {}
 expected_output['print_stats'] = """\
          126 function calls (106 primitive calls) in 1.000 CPU seconds
@@ -165,11 +172,11 @@
         2    0.000    0.000    0.140    0.070 profilee.py:84(helper2_indirect)
         8    0.312    0.039    0.400    0.050 profilee.py:88(helper2)
         8    0.064    0.008    0.080    0.010 profilee.py:98(subhelper)
-        4    0.000    0.000    0.000    0.000 {.*append.*}
+        4    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
         1    0.000    0.000    0.000    0.000 {.*disable.*}
-       12    0.000    0.000    0.012    0.001 {hasattr.*}
-        8    0.000    0.000    0.000    0.000 {range.*}
-        4    0.000    0.000    0.000    0.000 {sys.exc_info.*}
+       12    0.000    0.000    0.012    0.001 {hasattr}
+        8    0.000    0.000    0.000    0.000 {range}
+        4    0.000    0.000    0.000    0.000 {sys.exc_info}
 
 
 """

Modified: pypy/branch/jit-unroll-loops/pypy/module/_minimal_curses/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/_minimal_curses/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/_minimal_curses/__init__.py	Sat Dec 11 15:10:15 2010
@@ -4,7 +4,7 @@
     try:
         import _minimal_curses as _curses   # when running on top of pypy-c
     except ImportError:
-        import py; py.test.skip("no _curses module")    # no _curses at all
+        raise ImportError("no _curses or _minimal_curses module")  # no _curses at all
 
 from pypy.interpreter.mixedmodule import MixedModule
 from pypy.module._minimal_curses import fficurses

Modified: pypy/branch/jit-unroll-loops/pypy/module/_pickle_support/maker.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/_pickle_support/maker.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/_pickle_support/maker.py	Sat Dec 11 15:10:15 2010
@@ -67,11 +67,12 @@
     return space.wrap(tb)
 traceback_new.unwrap_spec = [ObjSpace]
 
-def generator_new(space, frame, running):
+def generator_new(space, w_frame, running):
+    frame = space.interp_w(PyFrame, w_frame, can_be_None=True)
     new_generator = GeneratorIterator(frame)
     new_generator.running = running
     return space.wrap(new_generator)
-generator_new.unwrap_spec = [ObjSpace, PyFrame, int]
+generator_new.unwrap_spec = [ObjSpace, W_Root, int]
 
 def xrangeiter_new(space, current, remaining, step):
     from pypy.module.__builtin__.functional import W_XRangeIterator

Modified: pypy/branch/jit-unroll-loops/pypy/module/_stackless/interp_coroutine.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/_stackless/interp_coroutine.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/_stackless/interp_coroutine.py	Sat Dec 11 15:10:15 2010
@@ -304,16 +304,19 @@
 
 def w_descr__framestack(space, self):
     assert isinstance(self, AppCoroutine)
-    index = self.subctx.framestackdepth
-    if not index:
-        return space.newtuple([])
-    items = [None] * index
+    counter = 0
     f = self.subctx.topframe
-    while index > 0:
-        index -= 1
-        items[index] = space.wrap(f)
+    while f is not None:
+        counter += 1
         f = f.f_backref()
-    assert f is None
+    items = [None] * counter
+    f = self.subctx.topframe
+    while f is not None:
+        counter -= 1
+        assert counter >= 0
+        items[counter] = space.wrap(f)
+        f = f.f_backref()
+    assert counter == 0
     return space.newtuple(items)
 
 def makeStaticMethod(module, classname, funcname):

Modified: pypy/branch/jit-unroll-loops/pypy/module/array/test/test_array.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/array/test/test_array.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/array/test/test_array.py	Sat Dec 11 15:10:15 2010
@@ -64,6 +64,7 @@
             raises(TypeError, self.array, tc, None)
 
     def test_value_range(self):
+        import sys
         values = (-129, 128, -128, 127, 0, 255, -1, 256,
                   -32768, 32767, -32769, 32768, 65535, 65536,
                   -2147483647, -2147483648, 2147483647, 4294967295, 4294967296,
@@ -88,7 +89,12 @@
                 a.append(v)
             for i, v in enumerate(ok * 2):
                 assert a[i] == v
-                assert type(a[i]) is pt
+                assert type(a[i]) is pt or (
+                    # A special case: we return ints in Array('I') on 64-bits,
+                    # whereas CPython returns longs.  The difference is
+                    # probably acceptable.
+                    tc == 'I' and
+                    sys.maxint > 2147483647 and type(a[i]) is int)
             for v in ok:
                 a[1] = v
                 assert a[0] == ok[0]

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/__init__.py	Sat Dec 11 15:10:15 2010
@@ -69,6 +69,7 @@
 import pypy.module.cpyext.weakrefobject
 import pypy.module.cpyext.funcobject
 import pypy.module.cpyext.classobject
+import pypy.module.cpyext.pypyintf
 
 # now that all rffi_platform.Struct types are registered, configure them
 api.configure_types()

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	Sat Dec 11 15:10:15 2010
@@ -321,6 +321,8 @@
     'PyCObject_Type', 'init_pycobject',
 
     'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer',
+
+    'PyStructSequence_InitType', 'PyStructSequence_New',
 ]
 TYPES = {}
 GLOBALS = { # this needs to include all prebuilt pto, otherwise segfaults occur
@@ -845,6 +847,7 @@
                                source_dir / "bufferobject.c",
                                source_dir / "object.c",
                                source_dir / "cobject.c",
+                               source_dir / "structseq.c",
                                ],
         separate_module_sources = [code, struct_source],
         export_symbols=export_symbols_eci,

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	Sat Dec 11 15:10:15 2010
@@ -4,8 +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, render_immortal
-from pypy.module.cpyext.state import State
+from pypy.module.cpyext.typeobject import PyTypeObjectPtr
 from pypy.interpreter.error import OperationError
 from pypy.tool.sourcetools import func_renamer
 
@@ -25,48 +24,26 @@
     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
 
-def datetimeAPI_dealloc(space):
-    "Used in tests only, to please the refcount checker"
-    if we_are_translated():
-        return
-    datetimeAPI = space.fromcache(State).datetimeAPI
-    if datetimeAPI is None:
-        return
-    space.fromcache(State).datetimeAPI = None
-    Py_DecRef(space, rffi.cast(PyObject, datetimeAPI.c_DateType))
-    Py_DecRef(space, rffi.cast(PyObject, datetimeAPI.c_DateTimeType))
-    Py_DecRef(space, rffi.cast(PyObject, datetimeAPI.c_TimeType))
-    Py_DecRef(space, rffi.cast(PyObject, datetimeAPI.c_DeltaType))
-    lltype.free(datetimeAPI, flavor='raw')
-
 PyDateTime_Date = PyObject
 PyDateTime_Time = PyObject
 PyDateTime_DateTime = PyObject

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/include/Python.h	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/include/Python.h	Sat Dec 11 15:10:15 2010
@@ -8,6 +8,8 @@
 # include <stddef.h>
 # include <limits.h>
 # include <math.h>
+# include <errno.h>
+# include <unistd.h>
 # define Py_DEPRECATED(VERSION_UNUSED) __attribute__((__deprecated__))
 # define PyAPI_FUNC(RTYPE) RTYPE
 # define PyAPI_DATA(RTYPE) extern RTYPE
@@ -103,6 +105,7 @@
 #include "sliceobject.h"
 #include "datetime.h"
 #include "pystate.h"
+#include "fileobject.h"
 
 // XXX This shouldn't be included here
 #include "structmember.h"
@@ -120,4 +123,8 @@
 #define PyDoc_STR(str) ""
 #endif
 
+/* PyPy does not implement --with-fpectl */
+#define PyFPE_START_PROTECT(err_string, leave_stmt)
+#define PyFPE_END_PROTECT(v)
+
 #endif

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/intobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/intobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/intobject.py	Sat Dec 11 15:10:15 2010
@@ -1,5 +1,6 @@
 
 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.interpreter.error import OperationError
 from pypy.module.cpyext.api import (cpython_api, PyObject, CANNOT_FAIL,
                                     build_type_checkers, Py_ssize_t)
 
@@ -19,6 +20,9 @@
     already one, and then return its value. If there is an error, -1 is
     returned, and the caller should check PyErr_Occurred() to find out whether
     there was an error, or whether the value just happened to be -1."""
+    if w_obj is None:
+        raise OperationError(space.w_TypeError,
+                             space.wrap("an integer is required, got NULL"))
     return space.int_w(space.int(w_obj))
 
 @cpython_api([PyObject], lltype.Unsigned, error=-1)
@@ -26,6 +30,9 @@
     """Return a C unsigned long representation of the contents of pylong.
     If pylong is greater than ULONG_MAX, an OverflowError is
     raised."""
+    if w_obj is None:
+        raise OperationError(space.w_TypeError,
+                             space.wrap("an integer is required, got NULL"))
     return space.uint_w(space.int(w_obj))
 
 @cpython_api([PyObject], lltype.Signed, error=CANNOT_FAIL)
@@ -39,6 +46,9 @@
     PyLongObject, if it is not already one, and then return its value as
     Py_ssize_t.
     """
+    if w_obj is None:
+        raise OperationError(space.w_TypeError,
+                             space.wrap("an integer is required, got NULL"))
     return space.int_w(w_obj) # XXX this is wrong on win64
 
 @cpython_api([Py_ssize_t], PyObject)
@@ -48,4 +58,3 @@
     returned.
     """
     return space.wrap(ival) # XXX this is wrong on win64
-

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/object.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/object.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/object.py	Sat Dec 11 15:10:15 2010
@@ -2,12 +2,13 @@
 from pypy.module.cpyext.api import (
     cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
     PyVarObject, Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
-    Py_GE, CONST_STRING, FILEP, fwrite)
+    Py_GE, CONST_STRING, FILEP, fwrite, build_type_checkers)
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, create_ref, from_ref, Py_IncRef, Py_DecRef,
     track_reference, get_typedescr, RefcountState)
 from pypy.module.cpyext.typeobject import PyTypeObjectPtr
 from pypy.module.cpyext.pyerrors import PyErr_NoMemory, PyErr_BadInternalCall
+from pypy.module._file.interp_file import W_File
 from pypy.objspace.std.objectobject import W_ObjectObject
 from pypy.objspace.std.typeobject import W_TypeObject
 from pypy.interpreter.error import OperationError
@@ -428,6 +429,34 @@
         rffi.free_nonmovingbuffer(data, buf)
     return 0
 
+PyFile_Check, PyFile_CheckExact = build_type_checkers("File", W_File)
+
+ at cpython_api([PyObject, rffi.INT_real], PyObject)
+def PyFile_GetLine(space, w_obj, n):
+    """
+    Equivalent to p.readline([n]), this function reads one line from the
+    object p.  p may be a file object or any object with a readline()
+    method.  If n is 0, exactly one line is read, regardless of the length of
+    the line.  If n is greater than 0, no more than n bytes will be read
+    from the file; a partial line can be returned.  In both cases, an empty string
+    is returned if the end of the file is reached immediately.  If n is less than
+    0, however, one line is read regardless of length, but EOFError is
+    raised if the end of the file is reached immediately."""
+    try:
+        w_readline = space.getattr(w_obj, space.wrap('readline'))
+    except OperationError:
+        raise OperationError(
+            space.w_TypeError, space.wrap(
+            "argument must be a file, or have a readline() method."))
+
+    n = rffi.cast(lltype.Signed, n)
+    if space.is_true(space.gt(space.wrap(n), space.wrap(0))):
+        return space.call_function(w_readline, space.wrap(n))
+    elif space.is_true(space.lt(space.wrap(n), space.wrap(0))):
+        return space.call_function(w_readline)
+    else:
+        # XXX Raise EOFError as specified
+        return space.call_function(w_readline)
 @cpython_api([CONST_STRING, CONST_STRING], PyObject)
 def PyFile_FromString(space, filename, mode):
     """
@@ -437,4 +466,3 @@
     w_filename = space.wrap(rffi.charp2str(filename))
     w_mode = space.wrap(rffi.charp2str(mode))
     return space.call_method(space.builtin, 'file', w_filename, w_mode)
-

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/pyerrors.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/pyerrors.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/pyerrors.py	Sat Dec 11 15:10:15 2010
@@ -5,7 +5,7 @@
 from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL, CONST_STRING
 from pypy.module.exceptions.interp_exceptions import W_RuntimeWarning
 from pypy.module.cpyext.pyobject import (
-    PyObject, PyObjectP, make_ref, Py_DecRef, borrow_from)
+    PyObject, PyObjectP, make_ref, from_ref, Py_DecRef, borrow_from)
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext.import_ import PyImport_Import
 from pypy.rlib.rposix import get_errno
@@ -80,6 +80,21 @@
     Py_DecRef(space, w_value)
     Py_DecRef(space, w_traceback)
 
+ at cpython_api([PyObjectP, PyObjectP, PyObjectP], lltype.Void)
+def PyErr_NormalizeException(space, exc_p, val_p, tb_p):
+    """Under certain circumstances, the values returned by PyErr_Fetch() below
+    can be "unnormalized", meaning that *exc is a class object but *val is
+    not an instance of the  same class.  This function can be used to instantiate
+    the class in that case.  If the values are already normalized, nothing happens.
+    The delayed normalization is implemented to improve performance."""
+    operr = OperationError(from_ref(space, exc_p[0]),
+                           from_ref(space, val_p[0]))
+    operr.normalize_exception(space)
+    Py_DecRef(space, exc_p[0])
+    Py_DecRef(space, val_p[0])
+    exc_p[0] = make_ref(space, operr.w_type)
+    val_p[0] = make_ref(space, operr.get_w_value(space))
+
 @cpython_api([], lltype.Void)
 def PyErr_BadArgument(space):
     """This is a shorthand for PyErr_SetString(PyExc_TypeError, message), where
@@ -114,10 +129,29 @@
     function around a system call can write return PyErr_SetFromErrno(type);
     when the system call returns an error.
     Return value: always NULL."""
+    PyErr_SetFromErrnoWithFilename(space, w_type,
+                                   lltype.nullptr(rffi.CCHARP.TO))
+
+ at cpython_api([PyObject, rffi.CCHARP], PyObject)
+def PyErr_SetFromErrnoWithFilename(space, w_type, llfilename):
+    """Similar to PyErr_SetFromErrno(), with the additional behavior that if
+    filename is not NULL, it is passed to the constructor of type as a third
+    parameter.  In the case of exceptions such as IOError and OSError,
+    this is used to define the filename attribute of the exception instance.
+    Return value: always NULL."""
     # XXX Doesn't actually do anything with PyErr_CheckSignals.
     errno = get_errno()
     msg = os.strerror(errno)
-    w_error = space.call_function(w_type, space.wrap(errno), space.wrap(msg))
+    if llfilename:
+        w_filename = rffi.charp2str(llfilename)
+        w_error = space.call_function(w_type,
+                                      space.wrap(errno),
+                                      space.wrap(msg),
+                                      space.wrap(w_filename))
+    else:
+        w_error = space.call_function(w_type,
+                                      space.wrap(errno),
+                                      space.wrap(msg))
     raise OperationError(w_type, w_error)
 
 @cpython_api([], rffi.INT_real, error=-1)

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/pythonrun.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/pythonrun.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/pythonrun.py	Sat Dec 11 15:10:15 2010
@@ -1,6 +1,16 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.state import State
 
 @cpython_api([], rffi.INT_real, error=CANNOT_FAIL)
 def Py_IsInitialized(space):
     return 1
+
+ at cpython_api([], rffi.CCHARP, error=CANNOT_FAIL)
+def Py_GetProgramName(space):
+    """
+    Return the program name set with Py_SetProgramName(), or the default.
+    The returned string points into static storage; the caller should not modify its
+    value."""
+    return space.fromcache(State).get_programname()
+

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/sequence.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/sequence.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/sequence.py	Sat Dec 11 15:10:15 2010
@@ -116,6 +116,14 @@
     This is the equivalent of the Python expression o1 + o2."""
     return space.add(w_o1, w_o2)
 
+ at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
+def PySequence_Contains(space, w_obj, w_value):
+    """Determine if o contains value.  If an item in o is equal to value,
+    return 1, otherwise return 0. On error, return -1.  This is
+    equivalent to the Python expression value in o."""
+    w_res = space.contains(w_obj, w_value)
+    return space.int_w(w_res)
+
 @cpython_api([PyObject], PyObject)
 def PySeqIter_New(space, w_seq):
     """Return an iterator that works with a general sequence object, seq.  The

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/slotdefs.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/slotdefs.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/slotdefs.py	Sat Dec 11 15:10:15 2010
@@ -6,7 +6,7 @@
     unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
     getattrfunc, setattrofunc, lenfunc, ssizeargfunc, ssizessizeargfunc,
     ssizeobjargproc, iternextfunc, initproc, richcmpfunc, hashfunc,
-    descrgetfunc, descrsetfunc)
+    descrgetfunc, descrsetfunc, objobjproc)
 from pypy.module.cpyext.pyobject import from_ref
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.module.cpyext.state import State
@@ -156,6 +156,15 @@
     if rffi.cast(lltype.Signed, res) == -1:
         space.fromcache(State).check_and_raise_exception(always=True)
 
+def wrap_objobjproc(space, w_self, w_args, func):
+    func_target = rffi.cast(objobjproc, func)
+    check_num_args(space, w_args, 1)
+    w_value, = space.fixedview(w_args)
+    res = generic_cpy_call(space, func_target, w_self, w_value)
+    if rffi.cast(lltype.Signed, res) == -1:
+        space.fromcache(State).check_and_raise_exception(always=True)
+    return space.wrap(res)
+
 def wrap_ssizessizeargfunc(space, w_self, w_args, func):
     func_target = rffi.cast(ssizessizeargfunc, func)
     check_num_args(space, w_args, 2)

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/src/getargs.c
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/src/getargs.c	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/src/getargs.c	Sat Dec 11 15:10:15 2010
@@ -453,6 +453,7 @@
 			strncpy(msgbuf, "is not retrievable", bufsize);
 			return msgbuf;
 		}
+                PyPy_Borrow(arg, item);
 		msg = convertitem(item, &format, p_va, flags, levels+1, 
 				  msgbuf, bufsize, freelist);
 		/* PySequence_GetItem calls tp->sq_item, which INCREFs */

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/state.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/state.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/state.py	Sat Dec 11 15:10:15 2010
@@ -5,11 +5,10 @@
 
 
 class State:
-    datetimeAPI = None # used in tests
-
     def __init__(self, space):
         self.space = space
         self.reset()
+        self.programname = lltype.nullptr(rffi.CCHARP.TO)
 
     def reset(self):
         from pypy.module.cpyext.modsupport import PyMethodDef
@@ -43,3 +42,16 @@
         if always:
             raise OperationError(self.space.w_SystemError, self.space.wrap(
                 "Function returned an error result without setting an exception"))
+
+    def get_programname(self):
+        if not self.programname:
+            space = self.space
+            argv = space.sys.get('argv')
+            if space.int_w(space.len(argv)):
+                argv0 = space.getitem(argv, space.wrap(0))
+                progname = space.str_w(argv0)
+            else:
+                progname = "pypy"
+            self.programname = rffi.str2charp(progname)
+            lltype.render_immortal(self.programname)
+        return self.programname

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/stubs.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/stubs.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/stubs.py	Sat Dec 11 15:10:15 2010
@@ -668,24 +668,6 @@
     """
     raise NotImplementedError
 
- at cpython_api([PyObjectP, PyObjectP, PyObjectP], lltype.Void)
-def PyErr_NormalizeException(space, exc, val, tb):
-    """Under certain circumstances, the values returned by PyErr_Fetch() below
-    can be "unnormalized", meaning that *exc is a class object but *val is
-    not an instance of the  same class.  This function can be used to instantiate
-    the class in that case.  If the values are already normalized, nothing happens.
-    The delayed normalization is implemented to improve performance."""
-    raise NotImplementedError
-
- at cpython_api([PyObject, rffi.CCHARP], PyObject)
-def PyErr_SetFromErrnoWithFilename(space, type, filename):
-    """Similar to PyErr_SetFromErrno(), with the additional behavior that if
-    filename is not NULL, it is passed to the constructor of type as a third
-    parameter.  In the case of exceptions such as IOError and OSError,
-    this is used to define the filename attribute of the exception instance.
-    Return value: always NULL."""
-    raise NotImplementedError
-
 @cpython_api([rffi.INT_real], PyObject)
 def PyErr_SetFromWindowsErr(space, ierr):
     """This is a convenience function to raise WindowsError. If called with
@@ -809,21 +791,6 @@
     successful invocation of Py_EnterRecursiveCall()."""
     raise NotImplementedError
 
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyFile_Check(space, p):
-    """Return true if its argument is a PyFileObject or a subtype of
-    PyFileObject.
-    
-    Allowed subtypes to be accepted."""
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyFile_CheckExact(space, p):
-    """Return true if its argument is a PyFileObject, but not a subtype of
-    PyFileObject.
-    """
-    raise NotImplementedError
-
 @cpython_api([FILE, rffi.CCHARP, rffi.CCHARP, rffi.INT_real], PyObject)
 def PyFile_FromFile(space, fp, name, mode, close):
     """Create a new PyFileObject from the already-open standard C file
@@ -857,22 +824,6 @@
     """
     raise NotImplementedError
 
- at cpython_api([PyObject, rffi.INT_real], PyObject)
-def PyFile_GetLine(space, p, n):
-    """
-    
-    
-    
-    Equivalent to p.readline([n]), this function reads one line from the
-    object p.  p may be a file object or any object with a readline()
-    method.  If n is 0, exactly one line is read, regardless of the length of
-    the line.  If n is greater than 0, no more than n bytes will be read
-    from the file; a partial line can be returned.  In both cases, an empty string
-    is returned if the end of the file is reached immediately.  If n is less than
-    0, however, one line is read regardless of length, but EOFError is
-    raised if the end of the file is reached immediately."""
-    raise NotImplementedError
-
 @cpython_api([PyObject], PyObject)
 def PyFile_Name(space, p):
     """Return the name of the file specified by p as a string object."""
@@ -1431,17 +1382,6 @@
     raise NotImplementedError
 
 @cpython_api([], rffi.CCHARP, error=CANNOT_FAIL)
-def Py_GetProgramName(space, ):
-    """
-    
-    
-    
-    Return the program name set with Py_SetProgramName(), or the default.
-    The returned string points into static storage; the caller should not modify its
-    value."""
-    raise NotImplementedError
-
- at cpython_api([], rffi.CCHARP, error=CANNOT_FAIL)
 def Py_GetPrefix(space, ):
     """Return the prefix for installed platform-independent files. This is derived
     through a number of complicated rules from the program name set with
@@ -2289,13 +2229,6 @@
     in your code for properly supporting 64-bit systems."""
     raise NotImplementedError
 
- at cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
-def PySequence_Contains(space, o, value):
-    """Determine if o contains value.  If an item in o is equal to value,
-    return 1, otherwise return 0. On error, return -1.  This is
-    equivalent to the Python expression value in o."""
-    raise NotImplementedError
-
 @cpython_api([PyObject, PyObject], Py_ssize_t, error=-1)
 def PySequence_Index(space, o, value):
     """Return the first index i for which o[i] == value.  On error, return

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_arraymodule.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_arraymodule.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_arraymodule.py	Sat Dec 11 15:10:15 2010
@@ -14,6 +14,7 @@
         arr.append(4)
         assert arr.tolist() == [1, 2, 3, 4]
         assert len(arr) == 4
+        self.cleanup_references()
 
     def test_iter(self):
         module = self.import_module(name='array')
@@ -22,6 +23,7 @@
         for i in arr: 
             sum += i
         assert sum == 6
+        self.cleanup_references()
 
     def test_index(self):
         module = self.import_module(name='array')
@@ -32,6 +34,7 @@
         assert arr.tolist() == [1,2,4]
         arr[2] = 99
         assert arr.tolist() == [1,2,99]
+        self.cleanup_references()
 
     def test_slice_get(self):
         module = self.import_module(name='array')
@@ -40,3 +43,4 @@
         assert arr[1:].tolist() == [2,3,4]
         assert arr[:2].tolist() == [1,2]
         assert arr[1:3].tolist() == [2,3]
+        self.cleanup_references()

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	Sat Dec 11 15:10:15 2010
@@ -1,10 +1,12 @@
 import sys
+import weakref
 import os.path
 
 import py
 
 from pypy.conftest import gettestobjspace
 from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app
 from pypy.rpython.lltypesystem import rffi, lltype, ll2ctypes
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.translator import platform
@@ -79,6 +81,23 @@
     self.frozen_ll2callocations = set(ll2ctypes.ALLOCATED.values())
 
 class LeakCheckingTest(object):
+    @staticmethod
+    def cleanup_references(space):
+        state = space.fromcache(RefcountState)
+
+        import gc; gc.collect()
+        # Clear all lifelines, objects won't resurrect
+        for w_obj, obj in state.lifeline_dict._dict.items():
+            if w_obj not in state.py_objects_w2r:
+                state.lifeline_dict.set(w_obj, None)
+            del obj
+        import gc; gc.collect()
+
+        for w_obj in state.non_heaptypes_w:
+            Py_DecRef(space, w_obj)
+        state.non_heaptypes_w[:] = []
+        state.reset_borrowed_references()
+
     def check_and_print_leaks(self):
         # check for sane refcnts
         import gc
@@ -89,13 +108,6 @@
         lost_objects_w = identity_dict()
         lost_objects_w.update((key, None) for key in self.frozen_refcounts.keys())
 
-        # Clear all lifelines, objects won't resurrect
-        for w_obj, obj in state.lifeline_dict._dict.items():
-            if w_obj not in state.py_objects_w2r:
-                state.lifeline_dict.set(w_obj, None)
-            del obj
-        gc.collect()
-
         for w_obj, obj in state.py_objects_w2r.iteritems():
             base_refcnt = self.frozen_refcounts.get(w_obj)
             delta = obj.c_ob_refcnt
@@ -105,7 +117,12 @@
             if delta != 0:
                 leaking = True
                 print >>sys.stderr, "Leaking %r: %i references" % (w_obj, delta)
-                lifeline = state.lifeline_dict.get(w_obj)
+                try:
+                    weakref.ref(w_obj)
+                except TypeError:
+                    lifeline = None
+                else:
+                    lifeline = state.lifeline_dict.get(w_obj)
                 if lifeline is not None:
                     refcnt = lifeline.pyo.c_ob_refcnt
                     if refcnt > 0:
@@ -137,6 +154,8 @@
         state = cls.space.fromcache(RefcountState)
         state.non_heaptypes_w[:] = []
 
+        cls.w_cleanup_references = cls.space.wrap(interp2app(cls.cleanup_references))
+
     def compile_module(self, name, **kwds):
         """
         Build an extension module linked against the cpyext api library.
@@ -256,13 +275,7 @@
     def teardown_method(self, func):
         for name in self.imported_module_names:
             self.unimport_module(name)
-        state = self.space.fromcache(RefcountState)
-        for w_obj in state.non_heaptypes_w:
-            Py_DecRef(self.space, w_obj)
-        state.non_heaptypes_w[:] = []
-        state.reset_borrowed_references()
-        from pypy.module.cpyext import cdatetime
-        cdatetime.datetimeAPI_dealloc(self.space)
+        self.cleanup_references(self.space)
         if self.check_and_print_leaks():
             assert False, "Test leaks or loses object(s)."
 
@@ -669,3 +682,19 @@
         assert mod.get_names() == ('cell', 'module', 'property',
                                    'staticmethod',
                                    'builtin_function_or_method')
+
+    def test_get_programname(self):
+        mod = self.import_extension('foo', [
+            ('get_programname', 'METH_NOARGS',
+             '''
+             char* name1 = Py_GetProgramName();
+             char* name2 = Py_GetProgramName();
+             if (name1 != name2)
+                 Py_RETURN_FALSE;
+             return PyString_FromString(name1);
+             '''
+             ),
+            ])
+        p = mod.get_programname()
+        print p
+        assert 'py' in p

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_datetime.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_datetime.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_datetime.py	Sat Dec 11 15:10:15 2010
@@ -92,9 +92,20 @@
                                      PyDateTimeAPI->TimeType,
                                      PyDateTimeAPI->DeltaType);
              """),
+            ("clear_types", "METH_NOARGS",
+             """
+                 Py_DECREF(PyDateTimeAPI->DateType);
+                 Py_DECREF(PyDateTimeAPI->DateTimeType);
+                 Py_DECREF(PyDateTimeAPI->TimeType);
+                 Py_DECREF(PyDateTimeAPI->DeltaType);
+                 Py_RETURN_NONE;
+             """
+             )
             ])
         import datetime
         assert module.get_types() == (datetime.date,
                                       datetime.datetime,
                                       datetime.time,
                                       datetime.timedelta)
+        module.clear_types()
+        self.cleanup_references()

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_intobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_intobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_intobject.py	Sat Dec 11 15:10:15 2010
@@ -19,6 +19,10 @@
         assert api.PyErr_Occurred() is space.w_TypeError
         api.PyErr_Clear()
 
+        assert api.PyInt_AsLong(None) == -1
+        assert api.PyErr_Occurred() is space.w_TypeError
+        api.PyErr_Clear()
+
         assert api.PyInt_AsUnsignedLong(space.wrap(sys.maxint)) == sys.maxint
         assert api.PyInt_AsUnsignedLong(space.wrap(-5)) == sys.maxint * 2 + 1
         assert api.PyErr_Occurred() is space.w_ValueError

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_object.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_object.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_object.py	Sat Dec 11 15:10:15 2010
@@ -4,7 +4,7 @@
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import Py_LT, Py_LE, Py_NE, Py_EQ,\
-    Py_GE, Py_GT
+    Py_GE, Py_GT, fopen, fclose, fwrite
 from pypy.tool.udir import udir
 
 class TestObject(BaseApiTest):
@@ -188,10 +188,45 @@
         rffi.free_charp(filename)
         rffi.free_charp(mode)
 
+        assert api.PyFile_Check(w_file)
+        assert api.PyFile_CheckExact(w_file)
+        assert not api.PyFile_Check(space.wrap("text"))
+
         space.call_method(w_file, "write", space.wrap("text"))
         space.call_method(w_file, "close")
         assert (udir / "_test_file").read() == "text"
 
+    def test_file_getline(self, space, api):
+        filename = rffi.str2charp(str(udir / "_test_file"))
+
+        mode = rffi.str2charp("w")
+        w_file = api.PyFile_FromString(filename, mode)
+        space.call_method(w_file, "write",
+                          space.wrap("line1\nline2\nline3\nline4"))
+        space.call_method(w_file, "close")
+
+        rffi.free_charp(mode)
+        mode = rffi.str2charp("r")
+        w_file = api.PyFile_FromString(filename, mode)
+        rffi.free_charp(filename)
+        rffi.free_charp(mode)
+
+        w_line = api.PyFile_GetLine(w_file, 0)
+        assert space.str_w(w_line) == "line1\n"
+
+        w_line = api.PyFile_GetLine(w_file, 4)
+        assert space.str_w(w_line) == "line"
+
+        w_line = api.PyFile_GetLine(w_file, 0)
+        assert space.str_w(w_line) == "2\n"
+
+        # XXX We ought to raise an EOFError here, but don't
+        w_line = api.PyFile_GetLine(w_file, -1)
+        # assert api.PyErr_Occurred() is space.w_EOFError
+        assert space.str_w(w_line) == "line3\n"
+
+        space.call_method(w_file, "close")
+
 class AppTestObject(AppTestCpythonExtensionBase):
     def setup_class(cls):
         AppTestCpythonExtensionBase.setup_class.im_func(cls)

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_pyerrors.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_pyerrors.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_pyerrors.py	Sat Dec 11 15:10:15 2010
@@ -129,6 +129,41 @@
             ])
         assert module.check_error()
 
+
+    def test_normalize(self):
+        module = self.import_extension('foo', [
+            ("check_error", "METH_NOARGS",
+             '''
+             PyObject *type, *val, *tb;
+             PyErr_SetString(PyExc_TypeError, "message");
+
+             PyErr_Fetch(&type, &val, &tb);
+             if (type != PyExc_TypeError)
+                 Py_RETURN_FALSE;
+             if (!PyString_Check(val))
+                 Py_RETURN_FALSE;
+             /* Normalize */
+             PyErr_NormalizeException(&type, &val, &tb);
+             if (type != PyExc_TypeError)
+                 Py_RETURN_FALSE;
+             if (val->ob_type != PyExc_TypeError)
+                 Py_RETURN_FALSE;
+
+             /* Normalize again */
+             PyErr_NormalizeException(&type, &val, &tb);
+             if (type != PyExc_TypeError)
+                 Py_RETURN_FALSE;
+             if (val->ob_type != PyExc_TypeError)
+                 Py_RETURN_FALSE;
+
+             PyErr_Restore(type, val, tb);
+             PyErr_Clear();
+             Py_RETURN_TRUE;
+             '''
+             ),
+            ])
+        assert module.check_error()
+
     def test_SetFromErrno(self):
         import sys
         if sys.platform != 'win32':
@@ -149,3 +184,26 @@
         except OSError, e:
             assert e.errno == errno.EBADF
             assert e.strerror == os.strerror(errno.EBADF)
+            assert e.filename == None
+
+    def test_SetFromErrnoWithFilename(self):
+        import sys
+        if sys.platform != 'win32':
+            skip("callbacks through ll2ctypes modify errno")
+        import errno, os
+
+        module = self.import_extension('foo', [
+                ("set_from_errno", "METH_NOARGS",
+                 '''
+                 errno = EBADF;
+                 PyErr_SetFromErrnoWithFilename(PyExc_OSError, "blyf");
+                 return NULL;
+                 '''),
+                ],
+                prologue="#include <errno.h>")
+        try:
+            module.set_from_errno()
+        except OSError, e:
+            assert e.filename == "blyf"
+            assert e.errno == errno.EBADF
+            assert e.strerror == os.strerror(errno.EBADF)

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_sequence.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_sequence.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_sequence.py	Sat Dec 11 15:10:15 2010
@@ -70,3 +70,11 @@
         assert space.unwrap(space.next(w_iter)) == 2
         exc = raises(OperationError, space.next, w_iter)
         assert exc.value.match(space, space.w_StopIteration)
+
+    def test_contains(self, space, api):
+        w_t = space.wrap((1, 'ha'))
+        assert api.PySequence_Contains(w_t, space.wrap(u'ha'))
+        assert not api.PySequence_Contains(w_t, space.wrap(2))
+        assert api.PySequence_Contains(space.w_None, space.wrap(2)) == -1
+        assert api.PyErr_Occurred()
+        api.PyErr_Clear()

Modified: pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_typeobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_typeobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/cpyext/test/test_typeobject.py	Sat Dec 11 15:10:15 2010
@@ -20,6 +20,7 @@
         assert type(obj) is module.fooType
         print "type of obj has type", type(type(obj))
         print "type of type of obj has type", type(type(type(obj)))
+        self.cleanup_references()
 
     def test_typeobject_method_descriptor(self):
         module = self.import_module(name='foo')
@@ -38,6 +39,7 @@
         print obj.foo
         assert obj.foo == 42
         assert obj.int_member == obj.foo
+        self.cleanup_references()
 
     def test_typeobject_data_member(self):
         module = self.import_module(name='foo')
@@ -54,6 +56,7 @@
         raises(SystemError, "obj.broken_member = 42")
         assert module.fooType.broken_member.__doc__ is None
         assert module.fooType.object_member.__doc__ == "A Python object."
+        self.cleanup_references()
 
     def test_typeobject_object_member(self):
         module = self.import_module(name='foo')
@@ -74,6 +77,7 @@
 
         obj.set_foo = 32
         assert obj.foo == 32
+        self.cleanup_references()
 
     def test_typeobject_string_member(self):
         module = self.import_module(name='foo')
@@ -91,6 +95,7 @@
         assert obj.char_member == "a"
         raises(TypeError, "obj.char_member = 'spam'")
         raises(TypeError, "obj.char_member = 42")
+        self.cleanup_references()
 
     def test_staticmethod(self):
         module = self.import_module(name="foo")
@@ -98,6 +103,7 @@
         assert obj.foo == 42
         obj2 = obj.create()
         assert obj2.foo == 42
+        self.cleanup_references()
 
     def test_new(self):
         module = self.import_module(name='foo')
@@ -118,7 +124,8 @@
                 return self
         assert fuu2(u"abc").baz().escape()
         raises(TypeError, module.fooType.object_member.__get__, 1)
-    
+        self.cleanup_references()
+
     def test_init(self):
         module = self.import_module(name="foo")
         newobj = module.FuuType()
@@ -137,6 +144,7 @@
         newobj = Fuu2()
         assert newobj.get_val() == 42
         assert newobj.foobar == 32
+        self.cleanup_references()
 
     def test_metatype(self):
         module = self.import_module(name='foo')
@@ -145,6 +153,7 @@
         assert isinstance(x, type)
         assert isinstance(x, module.MetaType)
         x()
+        self.cleanup_references()
 
     def test_metaclass_compatible(self):
         # metaclasses should not conflict here
@@ -153,7 +162,9 @@
         assert type(module.fooType).__mro__ == (type, object)
         y = module.MetaType('other', (module.fooType,), {})
         assert isinstance(y, module.MetaType)
-        y()
+        x = y()
+        del x, y
+        self.cleanup_references()
 
     def test_sre(self):
         module = self.import_module(name='_sre')
@@ -172,17 +183,21 @@
         assert "groupdict" in dir(m)
         re._cache.clear()
         re._cache_repl.clear()
+        del prog, m
+        self.cleanup_references()
 
     def test_init_error(self):
         module = self.import_module("foo")
         raises(ValueError, module.InitErrType)
-    
+        self.cleanup_references()
+
     def test_cmps(self):
         module = self.import_module("comparisons")
         cmpr = module.CmpType()
         assert cmpr == 3
         assert cmpr != 42
-    
+        self.cleanup_references()
+
     def test_hash(self):
         module = self.import_module("comparisons")
         cmpr = module.CmpType()
@@ -191,6 +206,7 @@
         d[cmpr] = 72
         assert d[cmpr] == 72
         assert d[3] == 72
+        self.cleanup_references()
 
     def test_descriptor(self):
         module = self.import_module("foo")
@@ -205,6 +221,7 @@
         assert obj.y == (prop, 2)
         del obj.x
         assert obj.z == prop
+        self.cleanup_references()
 
     def test_tp_dict(self):
         foo = self.import_module("foo")
@@ -226,6 +243,7 @@
             ])
         obj = foo.new()
         assert module.read_tp_dict(obj) == foo.fooType.copy
+        self.cleanup_references()
 
 
 class TestTypes(BaseApiTest):

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	Sat Dec 11 15:10:15 2010
@@ -24,7 +24,7 @@
 from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
 from pypy.module.cpyext.typeobjectdefs import (
     PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
-    PyNumberMethods)
+    PyNumberMethods, PySequenceMethods)
 from pypy.module.cpyext.slotdefs import (
     slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
 from pypy.interpreter.error import OperationError
@@ -136,6 +136,8 @@
             if not struct:
                 if slot_names[0] == 'c_tp_as_number':
                     STRUCT_TYPE = PyNumberMethods
+                elif slot_names[0] == 'c_tp_as_sequence':
+                    STRUCT_TYPE = PySequenceMethods
                 else:
                     raise AssertionError(
                         "Structure not allocated: %s" % (slot_names[0],))
@@ -392,6 +394,8 @@
             lltype.free(obj_pto.c_tp_as_buffer, flavor='raw')
         if obj_pto.c_tp_as_number:
             lltype.free(obj_pto.c_tp_as_number, flavor='raw')
+        if obj_pto.c_tp_as_sequence:
+            lltype.free(obj_pto.c_tp_as_sequence, flavor='raw')
         Py_DecRef(space, base_pyo)
         rffi.free_charp(obj_pto.c_tp_name)
         PyObject_dealloc(space, obj)
@@ -433,12 +437,6 @@
     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:
@@ -544,25 +542,12 @@
     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.
@@ -599,7 +584,8 @@
 
     if w_obj.is_cpytype():
         Py_DecRef(space, pto.c_tp_dict)
-        pto.c_tp_dict = make_ref(space, w_obj.getdict())
+        w_dict = space.newdict(from_strdict_shared=w_obj.dict_w)
+        pto.c_tp_dict = make_ref(space, w_dict)
 
 @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
 def PyType_IsSubtype(space, a, b):

Modified: pypy/branch/jit-unroll-loops/pypy/module/exceptions/interp_exceptions.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/exceptions/interp_exceptions.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/exceptions/interp_exceptions.py	Sat Dec 11 15:10:15 2010
@@ -452,6 +452,7 @@
         self.w_text     = space.w_None
         self.w_msg      = space.wrap('')
         self.w_print_file_and_line = space.w_None # what's that?
+        self.w_lastlineno = space.w_None          # this is a pypy extension
         W_BaseException.__init__(self, space)
 
     def descr_init(self, space, args_w):
@@ -459,11 +460,16 @@
         if len(args_w) > 0:
             self.w_msg = args_w[0]
         if len(args_w) == 2:
-            values_w = space.fixedview(args_w[1], 4)
-            self.w_filename = values_w[0]
-            self.w_lineno   = values_w[1]
-            self.w_offset   = values_w[2]
-            self.w_text     = values_w[3]
+            values_w = space.fixedview(args_w[1])
+            if len(values_w) > 0: self.w_filename   = values_w[0]
+            if len(values_w) > 1: self.w_lineno     = values_w[1]
+            if len(values_w) > 2: self.w_offset     = values_w[2]
+            if len(values_w) > 3: self.w_text       = values_w[3]
+            if len(values_w) > 4:
+                self.w_lastlineno = values_w[4]   # PyPy extension
+                # kill the extra items from args_w to prevent undesired effects
+                args_w = args_w[:]
+                args_w[1] = space.newtuple(values_w[:4])
         W_BaseException.descr_init(self, space, args_w)
     descr_init.unwrap_spec = ['self', ObjSpace, 'args_w']
 
@@ -472,29 +478,52 @@
             if type(self.msg) is not str:
                 return str(self.msg)
 
+            lineno = None
             buffer = self.msg
             have_filename = type(self.filename) is str
-            have_lineno = type(self.lineno) is int
+            if type(self.lineno) is int:
+                if (type(self.lastlineno) is int and
+                       self.lastlineno > self.lineno):
+                    lineno = 'lines %d-%d' % (self.lineno, self.lastlineno)
+                else:
+                    lineno = 'line %d' % (self.lineno,)
             if have_filename:
                 import os
                 fname = os.path.basename(self.filename or "???")
-                if have_lineno:
-                    buffer = "%s (%s, line %ld)" % (self.msg, fname, self.lineno)
+                if lineno:
+                    buffer = "%s (%s, %s)" % (self.msg, fname, lineno)
                 else:
                     buffer ="%s (%s)" % (self.msg, fname)
-            elif have_lineno:
-                buffer = "%s (line %ld)" % (self.msg, self.lineno)
+            elif lineno:
+                buffer = "%s (%s)" % (self.msg, lineno)
             return buffer
         """)
 
     descr_str.unwrap_spec = ['self', ObjSpace]
 
+    def descr_repr(self, space):
+        if (len(self.args_w) == 2
+            and not space.is_w(self.w_lastlineno, space.w_None)
+            and space.int_w(space.len(self.args_w[1])) == 4):
+            # fake a 5-element tuple in the repr, suitable for calling
+            # __init__ again
+            values_w = space.fixedview(self.args_w[1])
+            w_tuple = space.newtuple(values_w + [self.w_lastlineno])
+            args_w = [self.args_w[0], w_tuple]
+            args_repr = space.str_w(space.repr(space.newtuple(args_w)))
+            clsname = self.getclass(space).getname(space, '?')
+            return space.wrap(clsname + args_repr)
+        else:
+            return W_StandardError.descr_repr(self, space)
+    descr_repr.unwrap_spec = ['self', ObjSpace]
+
 W_SyntaxError.typedef = TypeDef(
     'SyntaxError',
     W_StandardError.typedef,
     __new__ = _new(W_SyntaxError),
     __init__ = interp2app(W_SyntaxError.descr_init),
     __str__ = interp2app(W_SyntaxError.descr_str),
+    __repr__ = interp2app(W_SyntaxError.descr_repr),
     __doc__ = W_SyntaxError.__doc__,
     __module__ = 'exceptions',
     msg      = readwrite_attrproperty_w('w_msg', W_SyntaxError),
@@ -504,6 +533,7 @@
     text     = readwrite_attrproperty_w('w_text', W_SyntaxError),
     print_file_and_line = readwrite_attrproperty_w('w_print_file_and_line',
                                                    W_SyntaxError),
+    lastlineno = readwrite_attrproperty_w('w_lastlineno', W_SyntaxError),
 )
 
 W_FutureWarning = _new_exception('FutureWarning', W_Warning,

Modified: pypy/branch/jit-unroll-loops/pypy/module/fcntl/test/test_fcntl.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/fcntl/test/test_fcntl.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/fcntl/test/test_fcntl.py	Sat Dec 11 15:10:15 2010
@@ -63,7 +63,7 @@
         if sys.platform in ('netbsd1', 'netbsd2', 'netbsd3', 
                             'Darwin1.2', 'darwin',
                             'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
-                            'freebsd6', 'freebsd7', 
+                            'freebsd6', 'freebsd7', 'freebsd8', 'freebsd9',
                             'bsdos2', 'bsdos3', 'bsdos4',
                             'openbsd', 'openbsd2', 'openbsd3'):
             if struct.calcsize('l') == 8:
@@ -159,7 +159,7 @@
 
         if "linux" in sys.platform:
             TIOCGPGRP = 0x540f
-        elif "darwin" in sys.platform or "freebsd6" == sys.platform:
+        elif "darwin" in sys.platform or "freebsd" in sys.platform:
             TIOCGPGRP = 0x40047477
         else:
             skip("don't know how to test ioctl() on this platform")

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	Sat Dec 11 15:10:15 2010
@@ -76,7 +76,7 @@
 
     return SEARCH_ERROR, None, None
 
-if sys.platform in ['linux2', 'freebsd']:
+if sys.platform == 'linux2' or 'freebsd' in sys.platform:
     def case_ok(filename):
         return True
 else:
@@ -529,7 +529,7 @@
             space.sys.setmodule(w_module)
             raise
     finally:
-        space.reloading_modules.clear()
+        del space.reloading_modules[modulename]
 
 
 # __________________________________________________________________

Modified: pypy/branch/jit-unroll-loops/pypy/module/itertools/interp_itertools.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/itertools/interp_itertools.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/itertools/interp_itertools.py	Sat Dec 11 15:10:15 2010
@@ -391,7 +391,8 @@
         self.iterators_w = iterators_w
         self.current_iterator = 0
         self.num_iterators = len(iterators_w)
-        self.started = False
+        if self.num_iterators > 0:
+            self.w_it = iterators_w[0]
 
     def iter_w(self):
         return self.space.wrap(self)
@@ -399,26 +400,23 @@
     def next_w(self):
         if self.current_iterator >= self.num_iterators:
             raise OperationError(self.space.w_StopIteration, self.space.w_None)
-        if not self.started:
-            self.current_iterator = 0
-            self.w_it = self.iterators_w[self.current_iterator]
-            self.started = True
+        try:
+            return self.space.next(self.w_it)
+        except OperationError, e:
+            return self._handle_error(e)
 
+    def _handle_error(self, e):
         while True:
+            if not e.match(self.space, self.space.w_StopIteration):
+                raise e
+            self.current_iterator += 1
+            if self.current_iterator >= self.num_iterators:
+                raise e
+            self.w_it = self.iterators_w[self.current_iterator]
             try:
-                w_obj = self.space.next(self.w_it)
+                return self.space.next(self.w_it)
             except OperationError, e:
-                if e.match(self.space, self.space.w_StopIteration):
-                    self.current_iterator += 1
-                    if self.current_iterator >= self.num_iterators:
-                        raise OperationError(self.space.w_StopIteration, self.space.w_None)
-                    else:
-                        self.w_it = self.iterators_w[self.current_iterator]
-                else:
-                    raise
-            else:
-                break
-        return w_obj
+                pass   # loop back to the start of _handle_error(e)
 
 def W_Chain___new__(space, w_subtype, args_w):
     return space.wrap(W_Chain(space, args_w))
@@ -446,8 +444,10 @@
 
     def __init__(self, space, w_fun, args_w):
         self.space = space
-        self.identity_fun = (self.space.is_w(w_fun, space.w_None))
-        self.w_fun = w_fun
+        if self.space.is_w(w_fun, space.w_None):
+            self.w_fun = None
+        else:
+            self.w_fun = w_fun
 
         iterators_w = []
         i = 0
@@ -470,12 +470,26 @@
         return self.space.wrap(self)
 
     def next_w(self):
-        w_objects = self.space.newtuple([self.space.next(w_it) for w_it in self.iterators_w])
-        if self.identity_fun:
+        # common case: 1 or 2 arguments
+        iterators_w = self.iterators_w
+        length = len(iterators_w)
+        if length == 1:
+            objects = [self.space.next(iterators_w[0])]
+        elif length == 2:
+            objects = [self.space.next(iterators_w[0]),
+                       self.space.next(iterators_w[1])]
+        else:
+            objects = self._get_objects()
+        w_objects = self.space.newtuple(objects)
+        if self.w_fun is None:
             return w_objects
         else:
             return self.space.call(self.w_fun, w_objects)
 
+    def _get_objects(self):
+        # the loop is out of the way of the JIT
+        return [self.space.next(w_elem) for w_elem in self.iterators_w]
+
 
 def W_IMap___new__(space, w_subtype, w_fun, args_w):
     if len(args_w) == 0:
@@ -769,15 +783,7 @@
             raise OperationError(self.space.w_StopIteration, self.space.w_None)
 
         if not self.new_group:
-            # Consume unwanted input until we reach the next group
-            try:
-                while True:
-                    self.group_next(self.index)
-
-            except StopIteration:
-                pass
-            if self.exhausted:
-                raise OperationError(self.space.w_StopIteration, self.space.w_None)
+            self._consume_unwanted_input()
 
         if not self.started:
             self.started = True
@@ -799,6 +805,16 @@
         w_iterator = self.space.wrap(W_GroupByIterator(self.space, self.index, self))
         return self.space.newtuple([self.w_key, w_iterator])
 
+    def _consume_unwanted_input(self):
+        # Consume unwanted input until we reach the next group
+        try:
+            while True:
+                self.group_next(self.index)
+        except StopIteration:
+            pass
+        if self.exhausted:
+            raise OperationError(self.space.w_StopIteration, self.space.w_None)
+
     def group_next(self, group_index):
         if group_index < self.index:
             raise StopIteration

Modified: pypy/branch/jit-unroll-loops/pypy/module/posix/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/posix/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/posix/__init__.py	Sat Dec 11 15:10:15 2010
@@ -77,6 +77,8 @@
         interpleveldefs['fsync'] = 'interp_posix.fsync'
     if hasattr(os, 'fdatasync'):
         interpleveldefs['fdatasync'] = 'interp_posix.fdatasync'
+    if hasattr(os, 'fchdir'):
+        interpleveldefs['fchdir'] = 'interp_posix.fchdir'
     if hasattr(os, 'putenv'):
         interpleveldefs['putenv'] = 'interp_posix.putenv'
     if hasattr(posix, 'unsetenv'): # note: emulated in os
@@ -96,6 +98,8 @@
         interpleveldefs['fork'] = 'interp_posix.fork'
     if hasattr(os, 'openpty'):
         interpleveldefs['openpty'] = 'interp_posix.openpty'
+    if hasattr(os, 'forkpty'):
+        interpleveldefs['forkpty'] = 'interp_posix.forkpty'
     if hasattr(os, 'waitpid'):
         interpleveldefs['waitpid'] = 'interp_posix.waitpid'
     if hasattr(os, 'execv'):
@@ -109,6 +113,8 @@
         interpleveldefs['sysconf_names'] = 'space.wrap(os.sysconf_names)'
     if hasattr(os, 'ttyname'):
         interpleveldefs['ttyname'] = 'interp_posix.ttyname'
+    if hasattr(os, 'getloadavg'):
+        interpleveldefs['getloadavg'] = 'interp_posix.getloadavg'
 
     for name in ['setsid', 'getuid', 'geteuid', 'getgid', 'getegid', 'setuid',
                  'seteuid', 'setgid', 'setegid', 'getpgrp', 'setpgrp',

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	Sat Dec 11 15:10:15 2010
@@ -4,6 +4,7 @@
 from pypy.rlib.rarithmetic import r_longlong
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2
+from pypy.interpreter.error import operationerrfmt
 from pypy.rpython.module.ll_os import RegisterOs
 from pypy.rpython.module import ll_os_stat
 from pypy.rpython.lltypesystem import rffi, lltype
@@ -151,19 +152,29 @@
         raise wrap_oserror(space, e) 
 ftruncate.unwrap_spec = [ObjSpace, "c_int", r_longlong]
 
-def fsync(space, fd):
+def fsync(space, w_fd):
+    fd = space.c_filedescriptor_w(w_fd)
     try:
         os.fsync(fd)
     except OSError, e:
         raise wrap_oserror(space, e)
-fsync.unwrap_spec = [ObjSpace, "c_int"]
+fsync.unwrap_spec = [ObjSpace, W_Root]
 
-def fdatasync(space, fd):
+def fdatasync(space, w_fd):
+    fd = space.c_filedescriptor_w(w_fd)
     try:
         os.fdatasync(fd)
     except OSError, e:
         raise wrap_oserror(space, e)
-fdatasync.unwrap_spec = [ObjSpace, "c_int"]
+fdatasync.unwrap_spec = [ObjSpace, W_Root]
+
+def fchdir(space, w_fd):
+    fd = space.c_filedescriptor_w(w_fd)
+    try:
+        os.fchdir(fd)
+    except OSError, e:
+        raise wrap_oserror(space, e)
+fchdir.unwrap_spec = [ObjSpace, W_Root]
 
 # ____________________________________________________________
 
@@ -608,6 +619,14 @@
         raise wrap_oserror(space, e)
     return space.newtuple([space.wrap(master_fd), space.wrap(slave_fd)])
 
+def forkpty(space):
+    try:
+        pid, master_fd = os.forkpty()
+    except OSError, e:
+        raise wrap_oserror(space, e)
+    return space.newtuple([space.wrap(pid),
+                           space.wrap(master_fd)])
+
 def waitpid(space, pid, options):
     """ waitpid(pid, options) -> (pid, status)
     
@@ -955,6 +974,17 @@
     return space.w_None
 chown.unwrap_spec = [ObjSpace, str, "c_nonnegint", "c_nonnegint"]
 
+def getloadavg(space):
+    try:
+        load = os.getloadavg()
+    except OSError, e:
+        raise OperationError(space.w_OSError,
+                             space.wrap("Load averages are unobtainable"))
+    return space.newtuple([space.wrap(load[0]),
+                           space.wrap(load[1]),
+                           space.wrap(load[2])])
+getloadavg.unwrap_spec = [ObjSpace]
+
 if _WIN:
     from pypy.rlib import rwin32
 

Modified: pypy/branch/jit-unroll-loops/pypy/module/posix/test/test_posix2.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/posix/test/test_posix2.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/posix/test/test_posix2.py	Sat Dec 11 15:10:15 2010
@@ -331,6 +331,22 @@
             data = os.read(master_fd, 100)
             assert data.startswith('x')
 
+    if hasattr(__import__(os.name), "forkpty"):
+        def test_forkpty(self):
+            import sys
+            os = self.posix
+            childpid, master_fd = os.forkpty()
+            assert isinstance(childpid, int)
+            assert isinstance(master_fd, int)
+            if childpid == 0:
+                data = os.read(0, 100)
+                if data.startswith('abc'):
+                    os._exit(42)
+                else:
+                    os._exit(43)
+            os.write(master_fd, 'abc\n')
+            _, status = os.waitpid(childpid, 0)
+            assert status >> 8 == 42
 
     if hasattr(__import__(os.name), "execv"):
         def test_execv(self):
@@ -505,6 +521,14 @@
                 assert os.WIFEXITED(status)
                 assert os.WEXITSTATUS(status) == exit_status
 
+    if hasattr(os, 'getloadavg'):
+        def test_os_getloadavg(self):
+            os = self.posix
+            l0, l1, l2 = os.getloadavg()
+            assert type(l0) is float and l0 >= 0.0
+            assert type(l1) is float and l0 >= 0.0
+            assert type(l2) is float and l0 >= 0.0
+
     if hasattr(os, 'fsync'):
         def test_fsync(self):
             os = self.posix
@@ -512,30 +536,42 @@
             try:
                 fd = f.fileno()
                 os.fsync(fd)
-            finally:
+                os.fsync(long(fd))
+                os.fsync(f)     # <- should also work with a file, or anything
+            finally:            #    with a fileno() method
                 f.close()
-            try:
-                os.fsync(fd)
-            except OSError:
-                pass
-            else:
-                raise AssertionError("os.fsync didn't raise")
+            raises(OSError, os.fsync, fd)
+            raises(ValueError, os.fsync, -1)
 
     if hasattr(os, 'fdatasync'):
         def test_fdatasync(self):
             os = self.posix
-            f = open(self.path2)
+            f = open(self.path2, "w")
             try:
                 fd = f.fileno()
                 os.fdatasync(fd)
             finally:
                 f.close()
+            raises(OSError, os.fdatasync, fd)
+            raises(ValueError, os.fdatasync, -1)
+
+    if hasattr(os, 'fchdir'):
+        def test_fchdir(self):
+            os = self.posix
+            localdir = os.getcwd()
             try:
-                os.fdatasync(fd)
-            except OSError:
-                pass
-            else:
-                raise AssertionError("os.fdatasync didn't raise")
+                os.mkdir(self.path2 + 'dir')
+                fd = os.open(self.path2 + 'dir', os.O_RDONLY)
+                try:
+                    os.fchdir(fd)
+                    mypath = os.getcwd()
+                finally:
+                    os.close(fd)
+                assert mypath.endswith('test_posix2-dir')
+                raises(OSError, os.fchdir, fd)
+                raises(ValueError, os.fchdir, -1)
+            finally:
+                os.chdir(localdir)
 
     def test_largefile(self):
         os = self.posix

Modified: pypy/branch/jit-unroll-loops/pypy/module/pyexpat/interp_pyexpat.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/pyexpat/interp_pyexpat.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/pyexpat/interp_pyexpat.py	Sat Dec 11 15:10:15 2010
@@ -329,7 +329,7 @@
         if self.returns_unicode:
             return space.call_function(
                 space.getattr(space.wrap(s), space.wrap("decode")),
-                space.wrap(self.encoding),
+                space.wrap("utf-8"),
                 space.wrap("strict"))
         else:
             return space.wrap(s)

Modified: pypy/branch/jit-unroll-loops/pypy/module/pyexpat/test/test_parser.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/pyexpat/test/test_parser.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/pyexpat/test/test_parser.py	Sat Dec 11 15:10:15 2010
@@ -15,3 +15,17 @@
         assert res == 1
 
         raises(pyexpat.ExpatError, p.Parse, "3")
+
+    def test_encoding(self):
+        import pyexpat
+        for encoding_arg in (None, 'utf-8', 'iso-8859-1'):
+            for namespace_arg in (None, '{'):
+                print encoding_arg, namespace_arg
+                p = pyexpat.ParserCreate(encoding_arg, namespace_arg)
+                data = []
+                p.CharacterDataHandler = lambda s: data.append(s)
+                encoding = encoding_arg is None and 'utf-8' or encoding_arg
+
+                res = p.Parse(u"<xml>\u00f6</xml>".encode(encoding), isfinal=True)
+                assert res == 1
+                assert data == [u"\u00f6"]

Modified: pypy/branch/jit-unroll-loops/pypy/module/pypyjit/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/pypyjit/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/pypyjit/__init__.py	Sat Dec 11 15:10:15 2010
@@ -15,6 +15,5 @@
         # add the 'defaults' attribute
         from pypy.rlib.jit import PARAMETERS
         space = self.space
-        # XXX this is not really the default compiled into a pypy-c-jit XXX
         w_obj = space.wrap(PARAMETERS)
         space.setattr(space.wrap(self), space.wrap('defaults'), w_obj)

Modified: pypy/branch/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	Sat Dec 11 15:10:15 2010
@@ -12,19 +12,13 @@
         if '.' in modname:
             modname, _ = modname.split('.', 1)
         if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions',
-                       'imp', 'sys', 'array', '_ffi']:
+                       'imp', 'sys', 'array', '_ffi', 'itertools', 'operator']:
             return True
         return False
 
     def look_inside_function(self, func):
-        # 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':
-                return False
         if mod == 'pypy.rlib.rbigint' or mod == 'pypy.rlib.rlocale':
             return False
         if '_geninterp_' in func.func_globals: # skip all geninterped stuff

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	Sat Dec 11 15:10:15 2010
@@ -4,7 +4,7 @@
 
 def test_id_any():
     from pypy.objspace.std.default import id__ANY
-    assert not pypypolicy.look_inside_function(id__ANY)
+    assert pypypolicy.look_inside_function(id__ANY)
 
 def test_bigint():
     from pypy.rlib.rbigint import rbigint

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	Sat Dec 11 15:10:15 2010
@@ -688,6 +688,32 @@
         ''', 3000, ([0], 2000*3))
         assert len(self.loops) == 1
 
+    def test_getattr_with_dynamic_attribute(self):
+        self.run_source('''
+        class A(object):
+            pass
+
+        l = ["x", "y"]
+
+        def main(arg):
+            sum = 0
+            a = A()
+            a.a1 = 0
+            a.a2 = 0
+            a.a3 = 0
+            a.a4 = 0
+            a.a5 = 0 # workaround, because the first five attributes need a promotion
+            a.x = 1
+            a.y = 2
+            i = 0
+            while i < 2000:
+                name = l[i % 2]
+                sum += getattr(a, name)
+                i += 1
+            return sum
+        ''', 3000, ([0], 3000))
+        assert len(self.loops) == 1
+
     def test_blockstack_virtualizable(self):
         self.run_source('''
         from pypyjit import residual_call
@@ -731,11 +757,9 @@
                 i = t2[3]
                 del t2
             return i
-        ''', 100, ([], 100))
+        ''', 40, ([], 100))
         bytecode, = self.get_by_bytecode('BINARY_SUBSCR')
-        assert len(bytecode.get_opnames('new_array')) == 1
-        # XXX I would like here to say that it's 0, but unfortunately
-        #     call that can raise is not exchanged into getarrayitem_gc
+        assert len(bytecode.get_opnames('new_array')) == 0
 
     def test_overflow_checking(self):
         startvalue = sys.maxint - 2147483647
@@ -919,11 +943,14 @@
     def test_array_sum(self):
         for tc, maxops in zip('bhilBHILfd', (38,) * 6 + (40, 40, 41, 38)):
             res = 19352859
-            if tc in 'IL':
+            if tc == 'L':
                 res = long(res)
             elif tc in 'fd':
                 res = float(res)
-            
+            elif tc == 'I' and sys.maxint == 2147483647:
+                res = long(res)
+                # note: in CPython we always get longs here, even on 64-bits
+
             self.run_source('''
             from array import array
 
@@ -971,11 +998,14 @@
             print '='*65
             print '='*20, 'running test for tc=%r' % (tc,), '='*20
             res = 73574560
-            if tc in 'IL':
+            if tc == 'L':
                 res = long(res)
             elif tc in 'fd':
                 res = float(res)
-            
+            elif tc == 'I' and sys.maxint == 2147483647:
+                res = long(res)
+                # note: in CPython we always get longs here, even on 64-bits
+
             self.run_source('''
             from array import array
 

Modified: pypy/branch/jit-unroll-loops/pypy/module/select/interp_select.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/select/interp_select.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/select/interp_select.py	Sat Dec 11 15:10:15 2010
@@ -12,37 +12,17 @@
 unregistering file descriptors, and then polling them for I/O events."""
     return Poll()
 
-def as_fd_w(space, w_fd):
-    if not space.is_true(space.isinstance(w_fd, space.w_int)):
-        try:
-            w_fileno = space.getattr(w_fd, space.wrap('fileno'))
-        except OperationError, e:
-            if e.match(space, space.w_AttributeError):
-                raise OperationError(space.w_TypeError,
-                                     space.wrap("argument must be an int, or have a fileno() method."))
-            raise
-        w_fd = space.call_function(w_fileno)
-        if not space.is_true(space.isinstance(w_fd, space.w_int)):
-            raise OperationError(space.w_TypeError,
-                                 space.wrap('filneo() return a non-integer'))
-        
-    fd = space.int_w(w_fd)
-    if fd < 0:
-        raise operationerrfmt(space.w_ValueError,
-            "file descriptor cannot be a negative integer (%d)", fd)
-    return fd
-
 class Poll(Wrappable):
     def __init__(self):
         self.fddict = {}
 
     def register(self, space, w_fd, events=defaultevents):
-        fd = as_fd_w(space, w_fd)
+        fd = space.c_filedescriptor_w(w_fd)
         self.fddict[fd] = events
     register.unwrap_spec = ['self', ObjSpace, W_Root, int]
 
     def unregister(self, space, w_fd):
-        fd = as_fd_w(space, w_fd)
+        fd = space.c_filedescriptor_w(w_fd)
         try:
             del self.fddict[fd]
         except KeyError:
@@ -113,9 +93,9 @@
     iwtd_w = space.listview(w_iwtd)
     owtd_w = space.listview(w_owtd)
     ewtd_w = space.listview(w_ewtd)
-    iwtd = [as_fd_w(space, w_f) for w_f in iwtd_w]
-    owtd = [as_fd_w(space, w_f) for w_f in owtd_w]
-    ewtd = [as_fd_w(space, w_f) for w_f in ewtd_w]
+    iwtd = [space.c_filedescriptor_w(w_f) for w_f in iwtd_w]
+    owtd = [space.c_filedescriptor_w(w_f) for w_f in owtd_w]
+    ewtd = [space.c_filedescriptor_w(w_f) for w_f in ewtd_w]
     iwtd_d = {}
     owtd_d = {}
     ewtd_d = {}

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	Sat Dec 11 15:10:15 2010
@@ -60,8 +60,6 @@
         'pypy_svn_url'          : 'version.get_svn_url(space)',
         'subversion'            : 'version.get_subversion_info(space)',
         'hexversion'            : 'version.get_hexversion(space)',
-        'ps1'                   : 'space.wrap(">>>> ")', 
-        'ps2'                   : 'space.wrap(".... ")', 
 
         'displayhook'           : 'hook.displayhook', 
         '__displayhook__'       : 'hook.__displayhook__', 

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

Modified: pypy/branch/jit-unroll-loops/pypy/module/sys/test/test_initialpath.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/sys/test/test_initialpath.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/sys/test/test_initialpath.py	Sat Dec 11 15:10:15 2010
@@ -15,4 +15,5 @@
 def test_stdlib_in_prefix(tmpdir):
     dirs = build_hierarchy(tmpdir)
     path = getinitialpath(str(tmpdir))
-    assert path == map(str, dirs)
+    # we get at least 'dirs', and maybe more (e.g. plat-linux2)
+    assert path[:len(dirs)] == map(str, dirs)

Modified: pypy/branch/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	Sat Dec 11 15:10:15 2010
@@ -41,27 +41,21 @@
         f = ec.getnextframe_nohidden(f)
     return space.wrap(f)
 
-# directly from the C code in ceval.c, might be moved somewhere else.
-
 def setrecursionlimit(space, w_new_limit):
-    """Set the maximum depth of the Python interpreter stack to n.  This
-limit prevents infinite recursion from causing an overflow of the C
-stack and crashing Python.  The highest possible limit is platform
-dependent."""
+    """DEPRECATED on PyPy. Will issue warning and not work
+    """
     new_limit = space.int_w(w_new_limit)
     if new_limit <= 0:
         raise OperationError(space.w_ValueError,
                              space.wrap("recursion limit must be positive"))
     # global recursion_limit
     # we need to do it without writing globals.
+    space.warn('setrecursionlimit deprecated', space.w_DeprecationWarning)
     space.sys.recursionlimit = new_limit
 
 def getrecursionlimit(space):
-    """Return the current value of the recursion limit, the maximum depth
-    of the Python interpreter stack.  This limit prevents infinite
-    recursion from causing an overflow of the C stack and crashing Python.
+    """DEPRECATED on PyPy. Will issue warning and not work
     """
-
     return space.wrap(space.sys.recursionlimit)
 
 def setcheckinterval(space, interval):

Modified: pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_cast.py	Sat Dec 11 15:10:15 2010
@@ -82,8 +82,11 @@
     def test_cast_functype(self):
         # make sure we can cast function type
         my_sqrt = lib.my_sqrt
+        saved_objects = my_sqrt._objects.copy()
         sqrt = cast(cast(my_sqrt, c_void_p), CFUNCTYPE(c_double, c_double))
         assert sqrt(4.0) == 2.0
         assert not cast(0, CFUNCTYPE(c_int))
-
-        
+        #
+        assert sqrt._objects is my_sqrt._objects   # on CPython too
+        my_sqrt._objects.clear()
+        my_sqrt._objects.update(saved_objects)

Modified: pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_guess_argtypes.py	Sat Dec 11 15:10:15 2010
@@ -11,21 +11,23 @@
         py.test.skip("pypy white-box test")
     from _ctypes.function import CFuncPtr
 
-    guess = CFuncPtr._guess_argtypes
+    def guess(value):
+        cobj = CFuncPtr._conv_param(None, value, 0)
+        return type(cobj)
 
-    assert guess([13]) == [c_int]
-    assert guess([0]) == [c_int]
-    assert guess(['xca']) == [c_char_p]
-    assert guess([None]) == [c_void_p]
-    assert guess([c_int(3)]) == [c_int]
-    assert guess([u'xca']) == [c_wchar_p]
+    assert guess(13) == c_int
+    assert guess(0) == c_int
+    assert guess('xca') == c_char_p
+    assert guess(None) == c_void_p
+    assert guess(c_int(3)) == c_int
+    assert guess(u'xca') == c_wchar_p
 
     class Stuff:
         pass
     s = Stuff()
     s._as_parameter_ = None
     
-    assert guess([s]) == [c_void_p]
+    assert guess(s) == c_void_p
 
 def test_guess_unicode():
     if not hasattr(sys, 'pypy_translation_info') and sys.platform != 'win32':

Modified: pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_keepalive.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_keepalive.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/module/test_lib_pypy/ctypes_tests/test_keepalive.py	Sat Dec 11 15:10:15 2010
@@ -99,7 +99,7 @@
     def test_primitive(self):
         if not hasattr(sys, 'pypy_translation_info'):
             py.test.skip("pypy white-box test")
-        assert c_char_p("abc")._objects['0']._buffer[0] == "a"
+        assert c_char_p("abc")._objects._buffer[0] == "a"
         assert c_int(3)._objects is None
 
     def test_pointer_to_pointer(self):
@@ -123,7 +123,7 @@
             pass
         cf = CFUNCTYPE(c_int, c_int)(f)
         p1 = cast(cf, c_void_p)
-        assert p1._objects == {'1': cf, '0': {'0': cf}}
+        assert p1._objects == {id(cf): cf, '0': cf}
 
     def test_array_of_struct_with_pointer(self):
         class S(Structure):
@@ -221,7 +221,7 @@
         import gc; gc.collect()
         print 'x =', repr(x)
         assert x.value == 'hellohello'
-        assert x._objects.keys() == ['0']
+        assert x._objects == 'hellohello'
         #
         class datum(Structure):
             _fields_ = [

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/complexobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/complexobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/complexobject.py	Sat Dec 11 15:10:15 2010
@@ -23,90 +23,92 @@
         """ representation for debugging purposes """
         return "<W_ComplexObject(%f,%f)>" % (w_self.realval, w_self.imagval)
 
-registerimplementation(W_ComplexObject)
-
-c_1 = (1.0, 0.0)
+    def sub(self, other):
+        return W_ComplexObject(self.realval - other.realval,
+                               self.imagval - other.imagval)
+
+    def mul(self, other):
+        r = self.realval * other.realval - self.imagval * other.imagval
+        i = self.realval * other.imagval + self.imagval * other.realval
+        return W_ComplexObject(r, i)
+
+    def div(self, other):
+        r1, i1 = self.realval, self.imagval
+        r2, i2 = other.realval, other.imagval
+        if r2 < 0:
+            abs_r2 = - r2
+        else:
+            abs_r2 = r2
+        if i2 < 0:
+            abs_i2 = - i2
+        else:
+            abs_i2 = i2
+        if abs_r2 >= abs_i2:
+            if abs_r2 == 0.0:
+                raise ZeroDivisionError
+            else:
+                ratio = i2 / r2
+                denom = r2 + i2 * ratio
+                rr = (r1 + i1 * ratio) / denom
+                ir = (i1 - r1 * ratio) / denom
+        else:
+            ratio = r2 / i2
+            denom = r2 * ratio + i2
+            assert i2 != 0.0
+            rr = (r1 * ratio + i1) / denom
+            ir = (i1 * ratio - r1) / denom
+        return W_ComplexObject(rr,ir)
+
+    def divmod(self, other):
+        w_div = self.div(other)
+        div = math.floor(w_div.realval)
+        w_mod = self.sub(
+            W_ComplexObject(other.realval * div, other.imagval * div))
+        return (W_ComplexObject(div, 0), w_mod)
+
+    def pow(self, other):
+        r1, i1 = self.realval, self.imagval
+        r2, i2 = other.realval, other.imagval
+        if r2 == 0.0 and i2 == 0.0:
+            rr, ir = 1, 0
+        elif r1 == 0.0 and i1 == 0.0:
+            if i2 != 0.0 or r2 < 0.0:
+                raise ZeroDivisionError
+            rr, ir = (0.0, 0.0)
+        else:
+            vabs = math.hypot(r1,i1)
+            len = math.pow(vabs,r2)
+            at = math.atan2(i1,r1)
+            phase = at * r2
+            if i2 != 0.0:
+                len /= math.exp(at * i2)
+                phase += i2 * math.log(vabs)
+            rr = len * math.cos(phase)
+            ir = len * math.sin(phase)
+        return W_ComplexObject(rr, ir)
+
+    def pow_int(self, n):
+        if n > 100 or n < -100:
+            return self.pow(W_ComplexObject(1.0 * n, 0.0))
+        elif n > 0:
+            return self.pow_positive_int(n)
+        else:
+            return w_one.div(self.pow_positive_int(-n))
 
-def _sum(c1, c2):
-    return (c1[0]+c2[0],c1[1]+c2[1])
+    def pow_positive_int(self, n):
+        mask = 1
+        w_result = w_one
+        while mask > 0 and n >= mask:
+            if n & mask:
+                w_result = w_result.mul(self)
+            mask <<= 1
+            self = self.mul(self)
 
-def _diff(c1, c2):
-    return (c1[0]-c2[0],c1[1]-c2[1])
+        return w_result
 
-def _prod(c1, c2):
-    r = c1[0]*c2[0] - c1[1]*c2[1]
-    i = c1[0]*c2[1] + c1[1]*c2[0]
-    return (r,i)
-
-def _quot(c1,c2):
-    r1, i1 = c1
-    r2, i2 = c2
-    if r2 < 0:
-        abs_r2 = - r2
-    else:
-        abs_r2 = r2
-    if i2 < 0:
-        abs_i2 = - i2
-    else:
-        abs_i2 = i2
-    if abs_r2 >= abs_i2:
-        if abs_r2 == 0.0:
-            raise ZeroDivisionError
-        else:
-            ratio = i2 / r2
-            denom = r2 + i2 * ratio
-            rr = (r1 + i1 * ratio) / denom
-            ir = (i1 - r1 * ratio) / denom
-    else:
-        ratio = r2 / i2
-        denom = r2 * ratio + i2
-        assert i2 != 0.0
-        rr = (r1 * ratio + i1) / denom
-        ir = (i1 * ratio - r1) / denom
-    return (rr,ir)
-
-def _pow(c1,c2):
-    r1, i1 = c1
-    r2, i2 = c2
-    if r2 == 0.0 and i2 == 0.0:
-        rr, ir = c_1
-    elif r1 == 0.0 and i1 == 0.0:
-        if i2 != 0.0 or r2 < 0.0:
-            raise ZeroDivisionError
-        rr, ir = (0.0, 0.0)
-    else:
-        vabs = math.hypot(r1,i1)
-        len = math.pow(vabs,r2)
-        at = math.atan2(i1,r1)
-        phase = at * r2
-        if i2 != 0.0:
-            len /= math.exp(at * i2)
-            phase += i2 * math.log(vabs)
-        rr = len * math.cos(phase)
-        ir = len * math.sin(phase)
-    return (rr, ir)
-
-def _powu(c,n):
-    mask = 1;
-    rr, ir = c_1
-    rp = c[0]
-    ip = c[1]
-    while mask > 0 and n >= mask:
-        if n & mask:
-            rr, ir = _prod((rr, ir), (rp, ip))
-        mask <<= 1
-        rp, ip = _prod((rp, ip), (rp, ip))
-
-    return (rr, ir)
-
-def _powi(c,n):
-    if n > 100 or n < -100:
-        return _pow(c,(1.0 * n, 0.0))
-    elif n > 0:
-        return _powu(c, n)
-    else:
-        return _quot(c_1, _powu(c, -n))
+registerimplementation(W_ComplexObject)
 
+w_one = W_ComplexObject(1, 0)
 
 
 def delegate_Bool2Complex(space, w_bool):
@@ -126,38 +128,25 @@
     return W_ComplexObject(w_float.floatval, 0.0)
 
 def hash__Complex(space, w_value):
-    #this is straight out of CPython complex implementation
-
     hashreal = _hash_float(space, w_value.realval)
-    if hashreal == -1:
-        return space.newint(-1)
     hashimg = _hash_float(space, w_value.imagval)
-    if hashimg == -1:
-        return space.newint(-1)
     combined = hashreal + 1000003 * hashimg
-    if (combined == -1):
-        combined = -2
     return space.newint(combined)
 
-def _w2t(space, w_complex):
-    "convert an interplevel complex object to a tuple representation"
-    return w_complex.realval, w_complex.imagval
-
-def _t2w(space, c):
-    return W_ComplexObject(c[0], c[1])
-
 def add__Complex_Complex(space, w_complex1, w_complex2):
-    return _t2w(space, _sum(_w2t(space, w_complex1), _w2t(space, w_complex2)))
+    return W_ComplexObject(w_complex1.realval + w_complex2.realval,
+                           w_complex1.imagval + w_complex2.imagval)
 
 def sub__Complex_Complex(space, w_complex1, w_complex2):
-    return _t2w(space, _diff(_w2t(space, w_complex1), _w2t(space, w_complex2)))
+    return W_ComplexObject(w_complex1.realval - w_complex2.realval,
+                           w_complex1.imagval - w_complex2.imagval)
 
 def mul__Complex_Complex(space, w_complex1, w_complex2):
-    return _t2w(space, _prod(_w2t(space, w_complex1), _w2t(space, w_complex2)))
+    return w_complex1.mul(w_complex2)
 
 def div__Complex_Complex(space, w_complex1, w_complex2):
     try:
-        return _t2w(space, _quot(_w2t(space, w_complex1), _w2t(space, w_complex2)))
+        return w_complex1.div(w_complex2)
     except ZeroDivisionError, e:
         raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
 
@@ -165,49 +154,38 @@
 
 def mod__Complex_Complex(space, w_complex1, w_complex2):
     try:
-        div = _quot(_w2t(space, w_complex1), _w2t(space, w_complex2))
+        return w_complex1.divmod(w_complex2)[1]
     except ZeroDivisionError, e:
-        raise OperationError(space.w_ZeroDivisionError, space.wrap("complex remainder"))
-    div = (math.floor(div[0]), 0.0)
-    mod = _diff(_w2t(space, w_complex1), _prod(_w2t(space, w_complex2), div))
-
-    return _t2w(space, mod)
+        raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
 
 def divmod__Complex_Complex(space, w_complex1, w_complex2):
     try:
-        div = _quot(_w2t(space, w_complex1), _w2t(space, w_complex2))
+        div, mod = w_complex1.divmod(w_complex2)
     except ZeroDivisionError, e:
-        raise OperationError(space.w_ZeroDivisionError, space.wrap("complex divmod()"))
-    div = (math.floor(div[0]), 0.0)
-    mod = _diff(_w2t(space, w_complex1), _prod(_w2t(space, w_complex2), div))
-    w_div = _t2w(space, div)
-    w_mod = _t2w(space, mod)
-    return space.newtuple([w_div, w_mod])
+        raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
+    return space.newtuple([div, mod])
 
 def floordiv__Complex_Complex(space, w_complex1, w_complex2):
+    # don't care about the slight slowdown you get from using divmod
     try:
-        div = _quot(_w2t(space, w_complex1), _w2t(space, w_complex2))
+        return w_complex1.divmod(w_complex2)[0]
     except ZeroDivisionError, e:
-        raise OperationError(space.w_ZeroDivisionError, space.wrap("complex floordiv()"))
-    div = (math.floor(div[0]), 0.0)
-    return _t2w(space, div)
+        raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
 
-def pow__Complex_Complex_ANY(space, w_complex1, w_complex2, thirdArg):
+def pow__Complex_Complex_ANY(space, w_complex, w_exponent, thirdArg):
     if not space.is_w(thirdArg, space.w_None):
         raise OperationError(space.w_ValueError, space.wrap('complex modulo'))
+    int_exponent = int(w_exponent.realval)
     try:
-        v = _w2t(space, w_complex1)
-        exponent = _w2t(space, w_complex2)
-        int_exponent = int(exponent[0])
-        if exponent[1] == 0.0 and exponent[0] == int_exponent:
-            p = _powi(v, int_exponent)
+        if w_exponent.imagval == 0.0 and w_exponent.realval == int_exponent:
+            w_p = w_complex.pow_int(int_exponent)
         else:
-            p = _pow(v, exponent)
+            w_p = w_complex.pow(w_exponent)
     except ZeroDivisionError:
         raise OperationError(space.w_ZeroDivisionError, space.wrap("0.0 to a negative or complex power"))
     except OverflowError:
         raise OperationError(space.w_OverflowError, space.wrap("complex exponentiation"))
-    return _t2w(space, p)
+    return w_p
 
 def neg__Complex(space, w_complex):
     return W_ComplexObject(-w_complex.realval, -w_complex.imagval)

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/complextype.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/complextype.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/complextype.py	Sat Dec 11 15:10:15 2010
@@ -1,7 +1,7 @@
 from pypy.interpreter import gateway
 from pypy.interpreter.error import OperationError
 from pypy.objspace.std.register_all import register_all
-from pypy.objspace.std.strutil import interp_string_to_float, ParseStringError
+from pypy.objspace.std.strutil import string_to_float, ParseStringError
 from pypy.objspace.std.noneobject import W_NoneObject
 from pypy.objspace.std.stdtypedef import GetSetProperty, StdTypeDef
 from pypy.objspace.std.stdtypedef import StdObjSpaceMultiMethod
@@ -131,8 +131,8 @@
         except ValueError:
             raise OperationError(space.w_ValueError, space.wrap(ERR_MALFORMED))
         try:
-            realval = interp_string_to_float(space, realstr)
-            imagval = interp_string_to_float(space, imagstr)
+            realval = string_to_float(realstr)
+            imagval = string_to_float(imagstr)
         except ParseStringError:
             raise OperationError(space.w_ValueError, space.wrap(ERR_MALFORMED))
         else:

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/floattype.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/floattype.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/floattype.py	Sat Dec 11 15:10:15 2010
@@ -2,7 +2,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.objspace.std.stdtypedef import StdTypeDef
 from pypy.objspace.std.strutil import ParseStringError
-from pypy.objspace.std.strutil import interp_string_to_float
+from pypy.objspace.std.strutil import string_to_float
 
 def descr__new__(space, w_floattype, w_x=0.0):
     from pypy.objspace.std.floatobject import W_FloatObject
@@ -10,7 +10,7 @@
     if space.is_true(space.isinstance(w_value, space.w_str)):
         strvalue = space.str_w(w_value)
         try:
-            value = interp_string_to_float(space, strvalue)
+            value = string_to_float(strvalue)
         except ParseStringError, e:
             raise OperationError(space.w_ValueError,
                                  space.wrap(e.msg))
@@ -21,7 +21,7 @@
             from unicodeobject import unicode_to_decimal_w
         strvalue = unicode_to_decimal_w(space, w_value)
         try:
-            value = interp_string_to_float(space, strvalue)
+            value = string_to_float(strvalue)
         except ParseStringError, e:
             raise OperationError(space.w_ValueError,
                                  space.wrap(e.msg))

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/longobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/longobject.py	Sat Dec 11 15:10:15 2010
@@ -45,19 +45,6 @@
     fromrarith_int._annspecialcase_ = "specialize:argtype(0)"
     fromrarith_int = staticmethod(fromrarith_int)
 
-    def fromdecimalstr(s):
-        return W_LongObject(rbigint.fromdecimalstr(s))
-    fromdecimalstr = staticmethod(fromdecimalstr)
-
-    def _count_bits(self):
-        return self.num._count_bits()
-
-    def is_odd(self):
-        return self.num.is_odd()
-
-    def get_sign(self):
-        return self.num.sign
-
 registerimplementation(W_LongObject)
 
 # bool-to-long

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	Sat Dec 11 15:10:15 2010
@@ -42,11 +42,23 @@
         return None
 
     def index(self, selector):
-        if (self.space.config.objspace.std.withmethodcache and 
-                not jit.we_are_jitted()):
-            return self._index_cache(selector)
+        if jit.we_are_jitted():
+            # hack for the jit:
+            # the _index method is pure too, but its argument is never
+            # constant, because it is always a new tuple
+            return self._index_jit_pure(selector[0], selector[1])
         else:
-            return self._index(selector)
+            return self._index_indirection(selector)
+
+    @jit.purefunction
+    def _index_jit_pure(self, name, index):
+        return self._index_indirection((name, index))
+
+    @jit.dont_look_inside
+    def _index_indirection(self, selector):
+        if (self.space.config.objspace.std.withmethodcache):
+            return self._index_cache(selector)
+        return self._index(selector)
 
     @jit.dont_look_inside
     def _index_cache(self, selector):
@@ -498,10 +510,11 @@
 
         def _mapdict_read_storage(self, index):
             assert index >= 0
-            for i in rangenmin1:
-                if index == i:
-                    erased = getattr(self, "_value%s" % i)
-                    return rerased.unerase(erased, W_Root)
+            if index < nmin1:
+                for i in rangenmin1:
+                    if index == i:
+                        erased = getattr(self, "_value%s" % i)
+                        return rerased.unerase(erased, W_Root)
             if self._has_storage_list():
                 return self._mapdict_get_storage_list()[index - nmin1]
             erased = getattr(self, "_value%s" % nmin1)

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/objspace.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/objspace.py	Sat Dec 11 15:10:15 2010
@@ -9,7 +9,7 @@
 from pypy.objspace.descroperation import DescrOperation, raiseattrerror
 from pypy.rlib.objectmodel import instantiate, r_dict, specialize
 from pypy.rlib.debug import make_sure_not_resized
-from pypy.rlib.rarithmetic import base_int
+from pypy.rlib.rarithmetic import base_int, widen
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.jit import hint
 from pypy.tool.sourcetools import func_with_new_name
@@ -176,7 +176,11 @@
             #print 'wrapping', x, '->', w_result
             return w_result
         if isinstance(x, base_int):
-            return W_LongObject.fromrarith_int(x)
+            x = widen(x)
+            if isinstance(x, int):
+                return self.newint(x)
+            else:
+                return W_LongObject.fromrarith_int(x)
 
         # _____ below here is where the annotator should not get _____
 
@@ -372,7 +376,7 @@
                     self, w_obj, expected_length)[:])
         if expected_length != -1 and len(t) != expected_length:
             raise self._wrap_expected_length(expected_length, len(t))
-        return t
+        return make_sure_not_resized(t)
 
     def fixedview_unroll(self, w_obj, expected_length=-1):
         return self.fixedview(w_obj, expected_length, unroll=True)

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/strutil.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/strutil.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/strutil.py	Sat Dec 11 15:10:15 2010
@@ -150,7 +150,7 @@
 del calc_mantissa_bits
 MANTISSA_DIGITS = len(str( (1L << MANTISSA_BITS)-1 )) + 1
 
-def interp_string_to_float(space, s):
+def string_to_float(s):
     """
     Conversion of string to float.
     This version tries to only raise on invalid literals.
@@ -162,10 +162,9 @@
     s = strip_spaces(s)
 
     if not s:
-        raise OperationError(space.w_ValueError, space.wrap(
-            "empty string for float()"))
+        raise ParseStringError("empty string for float()")
+
 
-    
     low = s.lower()
     if low == "-inf":
         return -INFINITY
@@ -204,68 +203,56 @@
     if len(digits) == 0:
         digits = '0'
 
-    # a few abbreviations
-    from pypy.objspace.std import longobject
-    mklong = longobject.W_LongObject.fromint
-    d2long = longobject.W_LongObject.fromdecimalstr
-    adlong = longobject.add__Long_Long
-    longup = longobject.pow__Long_Long_None
-    multip = longobject.mul__Long_Long
-    divide = longobject.div__Long_Long
-    lshift = longobject.lshift__Long_Long
-    rshift = longobject.rshift__Long_Long
-
     # 4) compute the exponent and truncate to +-400
     if not exponent:
         exponent = '0'
-    w_le = d2long(exponent)
-    w_le = adlong(space, w_le, mklong(space, dexp))
+    long_exponent = rbigint.fromdecimalstr(exponent)
+    long_exponent = long_exponent.add(rbigint.fromint(dexp))
     try:
-        e = w_le.toint()
+        e = long_exponent.toint()
     except OverflowError:
         # XXX poking at internals
-        e = w_le.num.sign * 400
-    if e >= 400:
-        e = 400
-    elif e <= -400:
-        e = -400
+        e = long_exponent.sign * 400
+    else:
+        if e >= 400:
+            e = 400
+        elif e <= -400:
+            e = -400
 
     # 5) compute the value using long math and proper rounding.
-    w_lr = d2long(digits)
-    w_10 = mklong(space, 10)
-    w_1 = mklong(space, 1)
+    b_digits = rbigint.fromdecimalstr(digits)
+    b_10 = rbigint.fromint(10)
+    b_1 = rbigint.fromint(1)
     if e >= 0:
         bits = 0
-        w_pten = longup(space, w_10, mklong(space, e), space.w_None)
-        w_m = multip(space, w_lr, w_pten)
+        b_power_of_ten = b_10.pow(rbigint.fromint(e))
+        b_mantissa = b_digits.mul(b_power_of_ten)
     else:
         # compute a sufficiently large scale
         prec = MANTISSA_DIGITS * 2 + 22 # 128, maybe
         bits = - (int(math.ceil(-e / math.log10(2.0) - 1e-10)) + prec)
-        w_scale = lshift(space, w_1, mklong(space, -bits))
-        w_pten = longup(space, w_10, mklong(space, -e), None)
-        w_tmp = multip(space, w_lr, w_scale)
-        w_m = divide(space, w_tmp, w_pten)
+        b_scale = b_1.lshift(-bits)
+        b_power_of_ten = b_10.pow(rbigint.fromint(-e))
+        b_mantissa = b_digits.mul(b_scale).div(b_power_of_ten)
 
     # we now have a fairly large mantissa.
     # Shift it and round the last bit.
 
     # first estimate the bits and do a big shift
-    mbits = w_m._count_bits()
+    mbits = b_mantissa._count_bits()
     needed = MANTISSA_BITS
     if mbits > needed:
         if mbits > needed+1:
             shifted = mbits - (needed+1)
-            w_m = rshift(space, w_m, mklong(space, shifted))
+            b_mantissa = b_mantissa.rshift(shifted)
             bits += shifted
         # do the rounding
         bits += 1
-        round = w_m.is_odd()
-        w_m = rshift(space, w_m, w_1)
-        w_m = adlong(space, w_m, mklong(space, round))
+        round = b_mantissa.is_odd()
+        b_mantissa = b_mantissa.rshift(1).add(rbigint.fromint(round))
 
     try:
-        r = math.ldexp(w_m.tofloat(), bits)
+        r = math.ldexp(b_mantissa.tofloat(), bits)
         # XXX I guess we do not check for overflow in ldexp as we agreed to!
         if r == 2*r and r != 0.0:
             raise OverflowError

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_complexobject.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_complexobject.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_complexobject.py	Sat Dec 11 15:10:15 2010
@@ -1,5 +1,6 @@
 import py
-from pypy.objspace.std import complexobject as cobj
+from pypy.objspace.std.complexobject import W_ComplexObject, \
+    pow__Complex_Complex_ANY
 from pypy.objspace.std import complextype as cobjtype
 from pypy.objspace.std.multimethod import FailedToImplement
 from pypy.objspace.std.stringobject import W_StringObject
@@ -11,7 +12,7 @@
 
     def _test_instantiation(self):
         def _t_complex(r=0.0,i=0.0):
-            c = cobj.W_ComplexObject(r, i)
+            c = W_ComplexObject(r, i)
             assert c.real == float(r) and c.imag == float(i)
         pairs = (
             (1, 1),
@@ -38,21 +39,31 @@
         test_cparse('.e+5', '.e+5', '0.0')
 
     def test_pow(self):
-        assert cobj._pow((0.0,2.0),(0.0,0.0)) == (1.0,0.0)
-        assert cobj._pow((0.0,0.0),(2.0,0.0)) == (0.0,0.0)
-        rr, ir = cobj._pow((0.0,1.0),(2.0,0.0))
+        def _pow((r1, i1), (r2, i2)):
+            w_res = W_ComplexObject(r1, i1).pow(W_ComplexObject(r2, i2))
+            return w_res.realval, w_res.imagval
+        assert _pow((0.0,2.0),(0.0,0.0)) == (1.0,0.0)
+        assert _pow((0.0,0.0),(2.0,0.0)) == (0.0,0.0)
+        rr, ir = _pow((0.0,1.0),(2.0,0.0))
         assert abs(-1.0 - rr) < EPS
         assert abs(0.0 - ir) < EPS
 
-        assert cobj._powu((0.0,2.0),0) == (1.0,0.0)
-        assert cobj._powu((0.0,0.0),2) == (0.0,0.0)
-        assert cobj._powu((0.0,1.0),2) == (-1.0,0.0)
-        assert cobj._powi((0.0,2.0),0) == (1.0,0.0)
-        assert cobj._powi((0.0,0.0),2) == (0.0,0.0)
-        assert cobj._powi((0.0,1.0),2) == (-1.0,0.0)
-        c = cobj.W_ComplexObject(0.0,1.0)
-        p = cobj.W_ComplexObject(2.0,0.0)
-        r = cobj.pow__Complex_Complex_ANY(self.space,c,p,self.space.wrap(None))
+        def _powu((r1, i1), n):
+            w_res = W_ComplexObject(r1, i1).pow_positive_int(n)
+            return w_res.realval, w_res.imagval
+        assert _powu((0.0,2.0),0) == (1.0,0.0)
+        assert _powu((0.0,0.0),2) == (0.0,0.0)
+        assert _powu((0.0,1.0),2) == (-1.0,0.0)
+
+        def _powi((r1, i1), n):
+            w_res = W_ComplexObject(r1, i1).pow_int(n)
+            return w_res.realval, w_res.imagval
+        assert _powi((0.0,2.0),0) == (1.0,0.0)
+        assert _powi((0.0,0.0),2) == (0.0,0.0)
+        assert _powi((0.0,1.0),2) == (-1.0,0.0)
+        c = W_ComplexObject(0.0,1.0)
+        p = W_ComplexObject(2.0,0.0)
+        r = pow__Complex_Complex_ANY(self.space,c,p,self.space.wrap(None))
         assert r.realval == -1.0
         assert r.imagval == 0.0
 

Modified: pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_strutil.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_strutil.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/objspace/std/test/test_strutil.py	Sat Dec 11 15:10:15 2010
@@ -131,8 +131,6 @@
         assert string_to_bigint('1891234174197319').tolong() == 1891234174197319
 
     def test_string_to_float(self):
-        def string_to_float(x):
-            return interp_string_to_float(self.space, x)
         assert string_to_float('0') == 0.0
         assert string_to_float('1') == 1.0
         assert string_to_float('-1.5') == -1.5
@@ -180,3 +178,4 @@
                     print repr(s)
                     if s.strip(): # empty s raises OperationError directly
                         py.test.raises(ParseStringError, string_to_float, s)
+        py.test.raises(ParseStringError, string_to_float, "")

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/debug.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/debug.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/debug.py	Sat Dec 11 15:10:15 2010
@@ -53,13 +53,11 @@
 
 _log = None       # patched from tests to be an object of class DebugLog
                   # or compatible
-_stderr = sys.stderr   # alternatively, this is patched from tests
-                       # (redirects debug_print(), but not debug_start/stop)
 
 def debug_print(*args):
     for arg in args:
-        print >> _stderr, arg,
-    print >> _stderr
+        print >> sys.stderr, arg,
+    print >> sys.stderr
     if _log is not None:
         _log.debug_print(*args)
 
@@ -87,13 +85,15 @@
     _stop_colors = ""
 
 def debug_start(category):
-    print >> sys.stderr, '%s[%s] {%s%s' % (_start_colors_1, time.clock(),
+    c = int(time.clock() * 100)
+    print >> sys.stderr, '%s[%x] {%s%s' % (_start_colors_1, c,
                                            category, _stop_colors)
     if _log is not None:
         _log.debug_start(category)
 
 def debug_stop(category):
-    print >> sys.stderr, '%s[%s] %s}%s' % (_start_colors_2, time.clock(),
+    c = int(time.clock() * 100)
+    print >> sys.stderr, '%s[%x] %s}%s' % (_start_colors_2, c,
                                            category, _stop_colors)
     if _log is not None:
         _log.debug_stop(category)
@@ -226,31 +226,6 @@
         hop.exception_cannot_occur()
         return hop.inputarg(hop.args_r[0], arg=0)
 
-def make_sure_not_modified(arg):
-    """ Function checking whether annotation of SomeList is never resized
-    and never modified, useful for debugging. Does nothing when run directly
-    """
-    return arg
-
-class Entry(ExtRegistryEntry):
-    _about_ = make_sure_not_modified
-
-    def compute_result_annotation(self, s_arg):
-        from pypy.annotation.model import SomeList
-        assert isinstance(s_arg, SomeList)
-        # the logic behind it is that we try not to propagate
-        # make_sure_not_resized, when list comprehension is not on
-        if self.bookkeeper.annotator.translator.config.translation.list_comprehension_operations:
-            s_arg.listdef.never_mutate()
-        else:
-            from pypy.annotation.annrpython import log
-            log.WARNING('make_sure_not_modified called, but has no effect since list_comprehension is off')
-        return s_arg
-    
-    def specialize_call(self, hop):
-        hop.exception_cannot_occur()
-        return hop.inputarg(hop.args_r[0], arg=0)
-
 
 class IntegerCanBeNegative(Exception):
     pass

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	Sat Dec 11 15:10:15 2010
@@ -156,7 +156,7 @@
 
 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
+    """When JITted, cause an extra operation JIT_DEBUG to appear in
     the graphs.  Should not be left after debugging."""
     keepalive_until_here(string) # otherwise the whole function call is removed
 jit_debug.oopspec = 'jit.debug(string, arg1, arg2, arg3, arg4)'
@@ -260,18 +260,12 @@
 OPTIMIZER_NO_UNROLL = 1
 OPTIMIZER_FULL = 2
 
-DEBUG_OFF = 0
-DEBUG_PROFILE = 1
-DEBUG_STEPS = 2
-DEBUG_DETAILED = 3
-
 PARAMETERS = {'threshold': 1000,
               'trace_eagerness': 200,
               'trace_limit': 10000,
               'inlining': False,
               'optimizer': OPTIMIZER_FULL,
-              #'optimizer': OPTIMIZER_NO_UNROLL,
-              'debug' : DEBUG_STEPS,
+              'loop_longevity': 1000,
               }
 unroll_parameters = unrolling_iterable(PARAMETERS.keys())
 

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/libffi.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/libffi.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/libffi.py	Sat Dec 11 15:10:15 2010
@@ -178,6 +178,9 @@
         # the optimizer will fail to recognize the pattern and won't turn it
         # into a fast CALL.  Note that "arg = arg.next" is optimized away,
         # assuming that archain is completely virtual.
+        if argchain.numargs != len(self.argtypes):
+            raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\
+                (argchain.numargs, len(self.argtypes))
         ll_args = self._prepare()
         i = 0
         arg = argchain.first

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	Sat Dec 11 15:10:15 2010
@@ -92,7 +92,8 @@
         return False
     r_class = rffi.platform.numbertype_to_rclass[tp]
     assert issubclass(r_class, base_int)
-    return r_class.BITS < LONG_BIT
+    return r_class.BITS < LONG_BIT or (
+        r_class.BITS == LONG_BIT and r_class.SIGNED)
 _should_widen_type._annspecialcase_ = 'specialize:memo'
 
 del _bits, _itest, _Ltest
@@ -389,6 +390,11 @@
 r_longlong = build_int('r_longlong', True, 64)
 r_ulonglong = build_int('r_ulonglong', False, 64)
 
+if r_longlong is not r_int:
+    r_int64 = r_longlong
+else:
+    r_int64 = int
+
 
 # float as string  -> sign, beforept, afterpt, exponent
 

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/rdynload.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/rdynload.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/rdynload.py	Sat Dec 11 15:10:15 2010
@@ -14,7 +14,7 @@
 _MINGW = platform.name == "mingw32"
 _WIN32 = _MSVC or _MINGW
 _MAC_OS = platform.name == "darwin"
-_FREEBSD_7 = platform.name == "freebsd7"
+_FREEBSD = platform.name == "freebsd"
 
 if _WIN32:
     from pypy.rlib import rwin32
@@ -27,7 +27,7 @@
 else: 
     pre_include_bits = []
 
-if _FREEBSD_7 or _WIN32:
+if _FREEBSD or _WIN32:
     libraries = []
 else:
     libraries = ['dl']

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/rerased.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/rerased.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/rerased.py	Sat Dec 11 15:10:15 2010
@@ -91,7 +91,7 @@
             return annmodel.SomeInteger()
         assert isinstance(s_type, annmodel.SomePBC)
         assert len(s_type.descriptions) == 1
-        clsdef = s_type.descriptions.keys()[0].getuniqueclassdef()
+        clsdef = s_type.any_description().getuniqueclassdef()
         return annmodel.SomeInstance(clsdef)
 
     def specialize_call(self, hop):
@@ -108,7 +108,7 @@
     def compute_result_annotation(self, s_obj, s_type):
         assert isinstance(s_type, annmodel.SomePBC)
         assert len(s_type.descriptions) == 1
-        clsdef = s_type.descriptions.keys()[0].getuniqueclassdef()
+        clsdef = s_type.any_description().getuniqueclassdef()
         s_item = annmodel.SomeInstance(clsdef)
         return self.bookkeeper.newlist(s_item)
 

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/rmmap.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/rmmap.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/rmmap.py	Sat Dec 11 15:10:15 2010
@@ -67,7 +67,7 @@
     constant_names = ['PAGE_READONLY', 'PAGE_READWRITE', 'PAGE_WRITECOPY',
                       'FILE_MAP_READ', 'FILE_MAP_WRITE', 'FILE_MAP_COPY',
                       'DUPLICATE_SAME_ACCESS', 'MEM_COMMIT', 'MEM_RESERVE',
-                      'MEM_RELEASE', 'PAGE_EXECUTE_READWRITE']
+                      'MEM_RELEASE', 'PAGE_EXECUTE_READWRITE', 'PAGE_NOACCESS']
     for name in constant_names:
         setattr(CConfig, name, rffi_platform.ConstantInteger(name))
 
@@ -100,8 +100,11 @@
                            sandboxsafe=True, threadsafe=False)
     return unsafe, safe
 
-def winexternal(name, args, result):
-    return rffi.llexternal(name, args, result, compilation_info=CConfig._compilation_info_, calling_conv='win')
+def winexternal(name, args, result, **kwargs):
+    return rffi.llexternal(name, args, result,
+                           compilation_info=CConfig._compilation_info_,
+                           calling_conv='win',
+                           **kwargs)
 
 PTR = rffi.CCHARP
 
@@ -189,9 +192,17 @@
     VirtualAlloc = winexternal('VirtualAlloc',
                                [rffi.VOIDP, rffi.SIZE_T, DWORD, DWORD],
                                rffi.VOIDP)
-    VirtualProtect = winexternal('VirtualProtect',
-                                 [rffi.VOIDP, rffi.SIZE_T, DWORD, LPDWORD],
-                                 BOOL)
+    # VirtualProtect is used in llarena and should not release the GIL
+    _VirtualProtect = winexternal('VirtualProtect',
+                                  [rffi.VOIDP, rffi.SIZE_T, DWORD, LPDWORD],
+                                  BOOL,
+                                  _nowrapper=True)
+    def VirtualProtect(addr, size, mode, oldmode_ptr):
+        return _VirtualProtect(addr,
+                               rffi.cast(rffi.SIZE_T, size),
+                               rffi.cast(DWORD, mode),
+                               oldmode_ptr)
+    VirtualProtect._annspecialcase_ = 'specialize:ll'
     VirtualFree = winexternal('VirtualFree',
                               [rffi.VOIDP, rffi.SIZE_T, DWORD], BOOL)
 

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/rsre/rsre_core.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/rsre/rsre_core.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/rsre/rsre_core.py	Sat Dec 11 15:10:15 2010
@@ -1,5 +1,5 @@
 import sys
-from pypy.rlib.debug import check_nonneg, make_sure_not_modified
+from pypy.rlib.debug import check_nonneg
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.rsre import rsre_char
 from pypy.tool.sourcetools import func_with_new_name
@@ -471,7 +471,6 @@
     while True:
         op = ctx.pat(ppos)
         ppos += 1
-        make_sure_not_modified(ctx.pattern)
 
         #jit.jit_debug("sre_match", op, ppos, ptr)
         #

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/rsre/test/test_zjit.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/rsre/test/test_zjit.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/rsre/test/test_zjit.py	Sat Dec 11 15:10:15 2010
@@ -1,6 +1,5 @@
 from pypy.jit.metainterp.test import test_basic
 from pypy.rlib.nonconst import NonConstant
-from pypy.rlib.debug import make_sure_not_modified
 from pypy.rlib.rsre.test.test_match import get_code
 from pypy.rlib.rsre import rsre_core
 from pypy.rpython.lltypesystem import lltype

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/test/test_debug.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/test/test_debug.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/test/test_debug.py	Sat Dec 11 15:10:15 2010
@@ -42,14 +42,14 @@
     py.test.raises(IntegerCanBeNegative, interpret, g, [9])
 
 def test_make_sure_not_resized():
-    from pypy.annotation.listdef import TooLateForChange
+    from pypy.annotation.listdef import ListChangeUnallowed
     def f():
         result = [1,2,3]
         make_sure_not_resized(result)
         result.append(4)
         return len(result)
 
-    py.test.raises(TooLateForChange, interpret, f, [], 
+    py.test.raises(ListChangeUnallowed, interpret, f, [], 
                    list_comprehension_operations=True)
 
 

Modified: pypy/branch/jit-unroll-loops/pypy/rlib/test/test_libffi.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rlib/test/test_libffi.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rlib/test/test_libffi.py	Sat Dec 11 15:10:15 2010
@@ -262,3 +262,24 @@
         #
         res = self.call(get_dummy, [], rffi.LONG)
         assert res == initval+1
+
+    def test_wrong_number_of_arguments(self):
+        from pypy.rpython.llinterp import LLException
+        libfoo = self.get_libfoo() 
+        func = (libfoo, 'sum_xy', [types.sint, types.double], types.sint)
+
+        glob = globals()
+        loc = locals()
+        def my_raises(s):
+            try:
+                exec s in glob, loc
+            except TypeError:
+                pass
+            except LLException, e:
+                if str(e) != "<LLException 'TypeError'>":
+                    raise
+            else:
+                assert False, 'Did not raise'
+
+        my_raises("self.call(func, [38], rffi.LONG)") # one less
+        my_raises("self.call(func, [38, 12.3, 42], rffi.LONG)") # one more

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/extfunc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/extfunc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/extfunc.py	Sat Dec 11 15:10:15 2010
@@ -201,6 +201,11 @@
                 exec py.code.compile("""
                     from pypy.rlib.objectmodel import running_on_llinterp
                     from pypy.rlib.debug import llinterpcall
+                    from pypy.rlib.jit import dont_look_inside
+                    # note: we say 'dont_look_inside' mostly because the
+                    # JIT does not support 'running_on_llinterp', but in
+                    # theory it is probably right to stop jitting anyway.
+                    @dont_look_inside
                     def ll_wrapper(%s):
                         if running_on_llinterp:
                             return llinterpcall(s_result, fakeimpl, %s)

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/ll2ctypes.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/ll2ctypes.py	Sat Dec 11 15:10:15 2010
@@ -409,6 +409,7 @@
     subcls = get_common_subclass(mixin_cls, instance.__class__)
     instance.__class__ = subcls
     instance._storage = ctypes_storage
+    assert ctypes_storage   # null pointer?
 
 class _parentable_mixin(object):
     """Mixin added to _parentable containers when they become ctypes-based.
@@ -442,6 +443,9 @@
                             "not allocated from RPython at all")
         self._storage = None
 
+    def _getid(self):
+        return self._addressof_storage()
+
     def __eq__(self, other):
         if isinstance(other, _llgcopaque):
             addressof_other = other.intval
@@ -1291,7 +1295,7 @@
             def _where_is_errno():
                 return standard_c_lib.__errno_location()
 
-        elif sys.platform in ('darwin', 'freebsd7'):
+        elif sys.platform in ('darwin', 'freebsd7', 'freebsd8', 'freebsd9'):
             standard_c_lib.__error.restype = ctypes.POINTER(ctypes.c_int)
             def _where_is_errno():
                 return standard_c_lib.__error()

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	Sat Dec 11 15:10:15 2010
@@ -26,6 +26,7 @@
         self.objectptrs = {}        # {offset: ptr-to-container}
         self.objectsizes = {}       # {offset: size}
         self.freed = False
+        self.protect_inaccessible = None
         self.reset(zero)
 
     def __repr__(self):
@@ -59,6 +60,8 @@
     def check(self):
         if self.freed:
             raise ArenaError("arena was already freed")
+        if self.protect_inaccessible is not None:
+            raise ArenaError("arena is currently arena_protect()ed")
 
     def _getid(self):
         address, length = self.usagemap.buffer_info()
@@ -127,6 +130,21 @@
     def mark_freed(self):
         self.freed = True    # this method is a hook for tests
 
+    def set_protect(self, inaccessible):
+        if inaccessible:
+            assert self.protect_inaccessible is None
+            saved = []
+            for ptr in self.objectptrs.values():
+                obj = ptr._obj
+                saved.append((obj, obj._protect()))
+            self.protect_inaccessible = saved
+        else:
+            assert self.protect_inaccessible is not None
+            saved = self.protect_inaccessible
+            for obj, storage in saved:
+                obj._unprotect(storage)
+            self.protect_inaccessible = None
+
 class fakearenaaddress(llmemory.fakeaddress):
 
     def __init__(self, arena, offset):
@@ -365,6 +383,16 @@
     """
     return Arena(ptr.arena.nbytes, False).getaddr(0)
 
+def arena_protect(arena_addr, size, inaccessible):
+    """For debugging, set or reset memory protection on an arena.
+    For now, the starting point and size should reference the whole arena.
+    The value of 'inaccessible' is a boolean.
+    """
+    arena_addr = getfakearenaaddress(arena_addr)
+    assert arena_addr.offset == 0
+    assert size == arena_addr.arena.nbytes
+    arena_addr.arena.set_protect(inaccessible)
+
 # ____________________________________________________________
 #
 # Translation support: the functions above turn into the code below.
@@ -475,6 +503,42 @@
     # them immediately.
     clear_large_memory_chunk = llmemory.raw_memclear
 
+if os.name == "posix":
+    from pypy.translator.tool.cbuild import ExternalCompilationInfo
+    _eci = ExternalCompilationInfo(includes=['sys/mman.h'])
+    raw_mprotect = rffi.llexternal('mprotect',
+                                   [llmemory.Address, rffi.SIZE_T, rffi.INT],
+                                   rffi.INT,
+                                   sandboxsafe=True, _nowrapper=True,
+                                   compilation_info=_eci)
+    def llimpl_protect(addr, size, inaccessible):
+        if inaccessible:
+            prot = 0
+        else:
+            from pypy.rlib.rmmap import PROT_READ, PROT_WRITE
+            prot = PROT_READ | PROT_WRITE
+        raw_mprotect(addr, rffi.cast(rffi.SIZE_T, size),
+                     rffi.cast(rffi.INT, prot))
+        # ignore potential errors
+    has_protect = True
+
+elif os.name == 'nt':
+    def llimpl_protect(addr, size, inaccessible):
+        from pypy.rlib.rmmap import VirtualProtect, LPDWORD
+        if inaccessible:
+            from pypy.rlib.rmmap import PAGE_NOACCESS as newprotect
+        else:
+            from pypy.rlib.rmmap import PAGE_READWRITE as newprotect
+        arg = lltype.malloc(LPDWORD.TO, 1, zero=True, flavor='raw')
+        VirtualProtect(rffi.cast(rffi.VOIDP, addr),
+                       size, newprotect, arg)
+        # ignore potential errors
+        lltype.free(arg, flavor='raw')
+    has_protect = True
+
+else:
+    has_protect = False
+
 
 llimpl_malloc = rffi.llexternal('malloc', [lltype.Signed], llmemory.Address,
                                 sandboxsafe=True, _nowrapper=True)
@@ -544,6 +608,21 @@
                   'll_arena.arena_new_view', llimpl=llimpl_arena_new_view,
                   llfakeimpl=arena_new_view, sandboxsafe=True)
 
+def llimpl_arena_protect(addr, size, inaccessible):
+    if has_protect:
+        # do some alignment
+        start = rffi.cast(lltype.Signed, addr)
+        end = start + size
+        start = (start + 4095) & ~ 4095
+        end = end & ~ 4095
+        if end > start:
+            llimpl_protect(rffi.cast(llmemory.Address, start), end-start,
+                           inaccessible)
+register_external(arena_protect, [llmemory.Address, lltype.Signed,
+                                  lltype.Bool], lltype.Void,
+                  'll_arena.arena_protect', llimpl=llimpl_arena_protect,
+                  llfakeimpl=arena_protect, sandboxsafe=True)
+
 def llimpl_getfakearenaaddress(addr):
     return addr
 register_external(getfakearenaaddress, [llmemory.Address], llmemory.Address,

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	Sat Dec 11 15:10:15 2010
@@ -93,8 +93,10 @@
                 return endmarker._as_ptr()
             else:
                 return parent.getitem(index)._as_ptr()
-        elif (isinstance(A, lltype.FixedSizeArray) and
-              array_item_type_match(A.OF, self.TYPE)):
+        elif ((isinstance(A, lltype.FixedSizeArray)
+               or (isinstance(A, lltype.Array) and A._hints.get('nolength',
+                                                                False)))
+              and array_item_type_match(A.OF, self.TYPE)):
             # for array of primitives or pointers
             return lltype.direct_ptradd(firstitemptr, self.repeat)
         else:

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	Sat Dec 11 15:10:15 2010
@@ -1381,6 +1381,15 @@
         self._check()   # no double-frees
         self._storage = None
 
+    def _protect(self):
+        result = self._storage
+        self._free()   # no double-frees or double-protects
+        return result
+
+    def _unprotect(self, saved_storage):
+        assert self._storage is None
+        self._storage = saved_storage
+
     def _was_freed(self):
         if self._storage is None:
             return True

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rbuiltin.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rbuiltin.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rbuiltin.py	Sat Dec 11 15:10:15 2010
@@ -42,7 +42,7 @@
         return hop.genop('cast_pointer', [v_inst],    # v_type implicit in r_result
                          resulttype = hop.r_result.lowleveltype)
 
-    classdef = s_class.descriptions.keys()[0].getuniqueclassdef()
+    classdef = s_class.any_description().getuniqueclassdef()
     return rclass.rtype_new_instance(hop.rtyper, classdef, hop.llops)
 
 def rtype_builtin_hasattr(hop):

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rclass.py	Sat Dec 11 15:10:15 2010
@@ -392,7 +392,7 @@
                 source_classdef = source_desc.getclassdef(None)
                 source_repr = getinstancerepr(self.rtyper, source_classdef)
                 assert len(s_func.descriptions) == 1
-                funcdesc = s_func.descriptions.keys()[0]
+                funcdesc, = s_func.descriptions
                 graph = funcdesc.getuniquegraph()
                 FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
                 destrptr = functionptr(FUNCTYPE, graph.name,

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rdict.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rdict.py	Sat Dec 11 15:10:15 2010
@@ -581,7 +581,7 @@
 def ll_dict_lookup_clean(d, hash):
     # a simplified version of ll_dict_lookup() which assumes that the
     # key is new, and the dictionary doesn't contain deleted entries.
-    # It only find the next free slot for the given hash.
+    # It only finds the next free slot for the given hash.
     entries = d.entries
     mask = len(entries) - 1
     i = hash & mask

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rpbc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rpbc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/rpbc.py	Sat Dec 11 15:10:15 2010
@@ -127,7 +127,7 @@
     def __init__(self, rtyper, s_pbc):
         self.rtyper = rtyper
         self.s_pbc = s_pbc
-        self.callfamily = s_pbc.descriptions.iterkeys().next().getcallfamily()
+        self.callfamily = s_pbc.any_description().getcallfamily()
         concretetable, uniquerows = get_concrete_calltable(self.rtyper,
                                                            self.callfamily)
         assert len(uniquerows) == 1
@@ -166,7 +166,7 @@
         return self, 0
 
     def get_s_signatures(self, shape):
-        funcdesc = self.s_pbc.descriptions.iterkeys().next()
+        funcdesc = self.s_pbc.any_description()
         return funcdesc.get_s_signatures(shape)
 
     def convert_desc(self, funcdesc):
@@ -230,7 +230,7 @@
         bk = self.rtyper.annotator.bookkeeper
         args = bk.build_args(opname, hop.args_s[1:])
         s_pbc = hop.args_s[0]   # possibly more precise than self.s_pbc
-        descs = s_pbc.descriptions.keys()
+        descs = list(s_pbc.descriptions)
         shape, index = description.FunctionDesc.variant_for_call_site(bk, self.callfamily, descs, args)
         row_of_graphs = self.callfamily.calltables[shape][index]
         anygraph = row_of_graphs.itervalues().next()  # pick any witness

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/test/test_llarena.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/test/test_llarena.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/lltypesystem/test/test_llarena.py	Sat Dec 11 15:10:15 2010
@@ -6,6 +6,8 @@
 from pypy.rpython.lltypesystem.llarena import round_up_for_allocation
 from pypy.rpython.lltypesystem.llarena import ArenaError, arena_new_view
 from pypy.rpython.lltypesystem.llarena import arena_shrink_obj
+from pypy.rpython.lltypesystem.llarena import arena_protect, has_protect
+from pypy.translator.c.test import test_genc, test_standalone
 
 def test_arena():
     S = lltype.Struct('S', ('x',lltype.Signed))
@@ -265,8 +267,7 @@
     assert res == 42
 
 def test_compiled():
-    from pypy.translator.c.test.test_genc import compile
-    fn = compile(test_look_inside_object, [])
+    fn = test_genc.compile(test_look_inside_object, [])
     res = fn()
     assert res == 42
 
@@ -282,3 +283,51 @@
     arena_reserve(a, size_gc_header + llmemory.sizeof(S, 10))
     arena_shrink_obj(a, size_gc_header + llmemory.sizeof(S, 5))
     arena_reset(a, size_gc_header + llmemory.sizeof(S, 5), False)
+
+def test_arena_protect():
+    a = arena_malloc(100, False)
+    S = lltype.Struct('S', ('x', lltype.Signed))
+    arena_reserve(a, llmemory.sizeof(S))
+    p = llmemory.cast_adr_to_ptr(a, lltype.Ptr(S))
+    p.x = 123
+    assert p.x == 123
+    arena_protect(a, 100, True)
+    py.test.raises(ArenaError, arena_reserve, a + 48, llmemory.sizeof(S))
+    py.test.raises(RuntimeError, "p.x")
+    py.test.raises(RuntimeError, "p.x = 124")
+    arena_protect(a, 100, False)
+    assert p.x == 123
+    p.x = 125
+    assert p.x == 125
+
+
+class TestStandalone(test_standalone.StandaloneTests):
+    def test_compiled_arena_protect(self):
+        import os
+        from pypy.translator.c.test.test_genc import compile
+        S = lltype.Struct('S', ('x', lltype.Signed))
+        #
+        def fn(argv):
+            testrun = int(argv[1])
+            a = arena_malloc(65536, False)
+            arena_reserve(a, llmemory.sizeof(S))
+            p = llmemory.cast_adr_to_ptr(a + 23432, lltype.Ptr(S))
+            p.x = 123
+            assert p.x == 123
+            arena_protect(a, 65536, True)
+            result = 0
+            if testrun == 1:
+                print p.x       # segfault
+            if testrun == 2:
+                p.x = 124       # segfault
+            arena_protect(a, 65536, False)
+            p.x += 10
+            print p.x
+            return 0
+        #
+        t, cbuilder = self.compile(fn)
+        data = cbuilder.cmdexec('0')
+        assert data == '133\n'
+        if has_protect:
+            cbuilder.cmdexec('1', expect_crash=True)
+            cbuilder.cmdexec('2', expect_crash=True)

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	Sat Dec 11 15:10:15 2010
@@ -5,7 +5,6 @@
 from pypy.rpython.memory.support import get_address_stack, get_address_deque
 from pypy.rpython.memory.support import AddressDict
 from pypy.rpython.lltypesystem.llmemory import NULL, raw_malloc_usage
-from pypy.rlib.rarithmetic import r_uint
 
 TYPEID_MAP = lltype.GcStruct('TYPEID_MAP', ('count', lltype.Signed),
                              ('size', lltype.Signed),
@@ -19,6 +18,7 @@
     malloc_zero_filled = False
     prebuilt_gc_objects_are_static_roots = True
     object_minimal_size = 0
+    gcflag_extra = 0   # or a real GC flag that is always 0 when not collecting
 
     def __init__(self, config, chunk_size=DEFAULT_CHUNK_SIZE,
                  translated_to_c=True):
@@ -36,6 +36,12 @@
         self.finalizer_lock_count = 0
         self.run_finalizers = self.AddressDeque()
 
+    def post_setup(self):
+        # More stuff that needs to be initialized when the GC is already
+        # fully working.  (Only called by gctransform/framework for now.)
+        from pypy.rpython.memory.gc import env
+        self.DEBUG = env.read_from_env('PYPY_GC_DEBUG')
+
     def _teardown(self):
         pass
 
@@ -48,7 +54,8 @@
     # The following flag enables costly consistency checks after each
     # collection.  It is automatically set to True by test_gc.py.  The
     # checking logic is translatable, so the flag can be set to True
-    # here before translation.
+    # here before translation.  At run-time, if PYPY_GC_DEBUG is set,
+    # then it is also set to True.
     DEBUG = False
 
     def set_query_functions(self, is_varsize, has_gcptr_in_varsize,
@@ -410,42 +417,6 @@
     GCClass = getattr(module, classname)
     return GCClass, GCClass.TRANSLATION_PARAMS
 
-def _read_float_and_factor_from_env(varname):
-    import os
-    value = os.environ.get(varname)
-    if value:
-        if len(value) > 1 and value[-1] in 'bB':
-            value = value[:-1]
-        realvalue = value[:-1]
-        if value[-1] in 'kK':
-            factor = 1024
-        elif value[-1] in 'mM':
-            factor = 1024*1024
-        elif value[-1] in 'gG':
-            factor = 1024*1024*1024
-        else:
-            factor = 1
-            realvalue = value
-        try:
-            return (float(realvalue), factor)
-        except ValueError:
-            pass
-    return (0.0, 0)
-
-def read_from_env(varname):
-    value, factor = _read_float_and_factor_from_env(varname)
-    return int(value * factor)
-
-def read_uint_from_env(varname):
-    value, factor = _read_float_and_factor_from_env(varname)
-    return r_uint(value * factor)
-
-def read_float_from_env(varname):
-    value, factor = _read_float_and_factor_from_env(varname)
-    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:

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	Sat Dec 11 15:10:15 2010
@@ -2,7 +2,7 @@
 from pypy.rpython.memory.gc.semispace import SemiSpaceGC
 from pypy.rpython.memory.gc.semispace import GCFLAG_EXTERNAL, GCFLAG_FORWARDED
 from pypy.rpython.memory.gc.semispace import GC_HASH_TAKEN_ADDR
-from pypy.rpython.memory.gc.base import read_from_env
+from pypy.rpython.memory.gc import env
 from pypy.rpython.lltypesystem.llmemory import NULL, raw_malloc_usage
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena
 from pypy.rlib.objectmodel import free_non_gc_object
@@ -93,7 +93,7 @@
         if self.auto_nursery_size:
             newsize = nursery_size_from_env()
             if newsize <= 0:
-                newsize = estimate_best_nursery_size()
+                newsize = env.estimate_best_nursery_size()
             if newsize > 0:
                 self.set_nursery_size(newsize)
 
@@ -633,139 +633,5 @@
 
 # ____________________________________________________________
 
-import os
-
 def nursery_size_from_env():
-    return read_from_env('PYPY_GENERATIONGC_NURSERY')
-
-def best_nursery_size_for_L2cache(L2cache):
-    # Heuristically, the best nursery size to choose is about half
-    # of the L2 cache.  XXX benchmark some more.
-    return L2cache // 2
-
-
-if sys.platform == 'linux2':
-    def estimate_best_nursery_size():
-        """Try to estimate the best nursery size at run-time, depending
-        on the machine we are running on.
-        """
-        debug_start("gc-L2cache")
-        L2cache = sys.maxint
-        try:
-            fd = os.open('/proc/cpuinfo', os.O_RDONLY, 0644)
-            try:
-                data = []
-                while True:
-                    buf = os.read(fd, 4096)
-                    if not buf:
-                        break
-                    data.append(buf)
-            finally:
-                os.close(fd)
-        except OSError:
-            pass
-        else:
-            data = ''.join(data)
-            linepos = 0
-            while True:
-                start = findend(data, '\ncache size', linepos)
-                if start < 0:
-                    break    # done
-                linepos = findend(data, '\n', start)
-                if linepos < 0:
-                    break    # no end-of-line??
-                # *** data[start:linepos] == "   : 2048 KB\n"
-                start = skipspace(data, start)
-                if data[start] != ':':
-                    continue
-                # *** data[start:linepos] == ": 2048 KB\n"
-                start = skipspace(data, start + 1)
-                # *** data[start:linepos] == "2048 KB\n"
-                end = start
-                while '0' <= data[end] <= '9':
-                    end += 1
-                # *** data[start:end] == "2048"
-                if start == end:
-                    continue
-                number = int(data[start:end])
-                # *** data[end:linepos] == " KB\n"
-                end = skipspace(data, end)
-                if data[end] not in ('K', 'k'):    # assume kilobytes for now
-                    continue
-                number = number * 1024
-                # for now we look for the smallest of the L2 caches of the CPUs
-                if number < L2cache:
-                    L2cache = number
-
-        debug_print("L2cache =", L2cache)
-        debug_stop("gc-L2cache")
-
-        if L2cache < sys.maxint:
-            return best_nursery_size_for_L2cache(L2cache)
-        else:
-            # Print a top-level warning even in non-debug builds
-            llop.debug_print(lltype.Void,
-                "Warning: cannot find your CPU L2 cache size in /proc/cpuinfo")
-            return -1
-
-    def findend(data, pattern, pos):
-        pos = data.find(pattern, pos)
-        if pos < 0:
-            return -1
-        return pos + len(pattern)
-
-    def skipspace(data, pos):
-        while data[pos] in (' ', '\t'):
-            pos += 1
-        return pos
-
-elif sys.platform == 'darwin':
-    from pypy.rpython.lltypesystem import rffi
-
-    sysctlbyname = rffi.llexternal('sysctlbyname',
-                                   [rffi.CCHARP, rffi.VOIDP, rffi.SIZE_TP,
-                                    rffi.VOIDP, rffi.SIZE_T],
-                                   rffi.INT,
-                                   sandboxsafe=True)
-
-    def estimate_best_nursery_size():
-        """Try to estimate the best nursery size at run-time, depending
-        on the machine we are running on.
-        """
-        debug_start("gc-L2cache")
-        L2cache = 0
-        l2cache_p = lltype.malloc(rffi.LONGLONGP.TO, 1, flavor='raw')
-        try:
-            len_p = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw')
-            try:
-                size = rffi.sizeof(rffi.LONGLONG)
-                l2cache_p[0] = rffi.cast(rffi.LONGLONG, 0)
-                len_p[0] = rffi.cast(rffi.SIZE_T, size)
-                # XXX a hack for llhelper not being robust-enough
-                result = sysctlbyname("hw.l2cachesize",
-                                      rffi.cast(rffi.VOIDP, l2cache_p),
-                                      len_p,
-                                      lltype.nullptr(rffi.VOIDP.TO), 
-                                      rffi.cast(rffi.SIZE_T, 0))
-                if (rffi.cast(lltype.Signed, result) == 0 and
-                    rffi.cast(lltype.Signed, len_p[0]) == size):
-                    L2cache = rffi.cast(lltype.Signed, l2cache_p[0])
-                    if rffi.cast(rffi.LONGLONG, L2cache) != l2cache_p[0]:
-                        L2cache = 0    # overflow!
-            finally:
-                lltype.free(len_p, flavor='raw')
-        finally:
-            lltype.free(l2cache_p, flavor='raw')
-        debug_print("L2cache =", L2cache)
-        debug_stop("gc-L2cache")
-        if L2cache > 0:
-            return best_nursery_size_for_L2cache(L2cache)
-        else:
-            # Print a top-level warning even in non-debug builds
-            llop.debug_print(lltype.Void,
-                "Warning: cannot find your CPU L2 cache size with sysctl()")
-            return -1
-
-else:
-    def estimate_best_nursery_size():
-        return -1     # XXX implement me for other platforms
+    return env.read_from_env('PYPY_GENERATIONGC_NURSERY')

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	Sat Dec 11 15:10:15 2010
@@ -101,21 +101,24 @@
 
 AddressStack = get_address_stack()
 
-class HeapDumper:
+class HeapDumper(object):
     _alloc_flavor_ = "raw"
     BUFSIZE = 8192     # words
 
     def __init__(self, gc, fd):
         self.gc = gc
+        self.gcflag = gc.gcflag_extra
         self.fd = rffi.cast(rffi.INT, fd)
         self.writebuffer = lltype.malloc(rffi.LONGP.TO, self.BUFSIZE,
                                          flavor='raw')
         self.buf_count = 0
-        self.seen = AddressDict()
+        if self.gcflag == 0:
+            self.seen = AddressDict()
         self.pending = AddressStack()
 
     def delete(self):
-        self.seen.delete()
+        if self.gcflag == 0:
+            self.seen.delete()
         self.pending.delete()
         lltype.free(self.writebuffer, flavor='raw')
         free_non_gc_object(self)
@@ -140,6 +143,8 @@
             self.flush()
     write._always_inline_ = True
 
+    # ----------
+
     def write_marker(self):
         self.write(0)
         self.write(0)
@@ -161,9 +166,15 @@
         self.add(obj)
 
     def add(self, obj):
-        if not self.seen.contains(obj):
-            self.seen.setitem(obj, obj)
-            self.pending.append(obj)
+        if self.gcflag == 0:
+            if not self.seen.contains(obj):
+                self.seen.setitem(obj, obj)
+                self.pending.append(obj)
+        else:
+            hdr = self.gc.header(obj)
+            if (hdr.tid & self.gcflag) == 0:
+                hdr.tid |= self.gcflag
+                self.pending.append(obj)
 
     def add_roots(self):
         self.gc.enumerate_all_roots(_hd_add_root, self)
@@ -177,14 +188,50 @@
         while pending.non_empty():
             self.writeobj(pending.pop())
 
+    # ----------
+    # A simplified copy of the above, to make sure we walk again all the
+    # objects to clear the 'gcflag'.
+
+    def unwriteobj(self, obj):
+        gc = self.gc
+        gc.trace(obj, self._unwriteref, None)
+
+    def _unwriteref(self, pointer, _):
+        obj = pointer.address[0]
+        self.unadd(obj)
+
+    def unadd(self, obj):
+        assert self.gcflag != 0
+        hdr = self.gc.header(obj)
+        if (hdr.tid & self.gcflag) != 0:
+            hdr.tid &= ~self.gcflag
+            self.pending.append(obj)
+
+    def clear_gcflag_again(self):
+        self.gc.enumerate_all_roots(_hd_unadd_root, self)
+        pendingroots = self.pending
+        self.pending = AddressStack()
+        self.unwalk(pendingroots)
+        pendingroots.delete()
+
+    def unwalk(self, pending):
+        while pending.non_empty():
+            self.unwriteobj(pending.pop())
+
 def _hd_add_root(obj, heap_dumper):
     heap_dumper.add(obj)
 
+def _hd_unadd_root(obj, heap_dumper):
+    heap_dumper.unadd(obj)
+
 def dump_rpy_heap(gc, fd):
     heapdumper = HeapDumper(gc, fd)
     heapdumper.add_roots()
     heapdumper.walk(heapdumper.pending)
     heapdumper.flush()
+    if heapdumper.gcflag != 0:
+        heapdumper.clear_gcflag_again()
+        heapdumper.unwalk(heapdumper.pending)
     heapdumper.delete()
     return True
 

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/markcompact.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/markcompact.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/markcompact.py	Sat Dec 11 15:10:15 2010
@@ -1,5 +1,6 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup
-from pypy.rpython.memory.gc.base import MovingGCBase, read_from_env
+from pypy.rpython.memory.gc.base import MovingGCBase
+from pypy.rpython.memory.gc import env
 from pypy.rlib.debug import ll_assert, have_debug_prints
 from pypy.rlib.debug import debug_print, debug_start, debug_stop
 from pypy.rpython.memory.support import get_address_stack, get_address_deque
@@ -110,10 +111,10 @@
         return next
 
     def setup(self):
-        envsize = read_from_env('PYPY_MARKCOMPACTGC_MAX')
+        envsize = env.read_from_env('PYPY_MARKCOMPACTGC_MAX')
         if envsize >= 4096:
             self.space_size = envsize & ~4095
-        mincollect = read_from_env('PYPY_MARKCOMPACTGC_MIN')
+        mincollect = env.read_from_env('PYPY_MARKCOMPACTGC_MIN')
         if mincollect >= 4096:
             self.min_next_collect_after = mincollect
 

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	Sat Dec 11 15:10:15 2010
@@ -3,7 +3,8 @@
 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'.
+                        the L2 cache.  Try values like '1.2MB'.  Small values
+                        (like 1 or 1KB) are useful for debugging.
 
  PYPY_GC_MAJOR_COLLECT  Major collection memory factor.  Default is '1.82',
                         which means trigger a major collection when the
@@ -12,7 +13,7 @@
                         collection.
 
  PYPY_GC_GROWTH         Major collection threshold's max growth rate.
-                        Default is '1.3'.  Useful to collect more often
+                        Default is '1.4'.  Useful to collect more often
                         than normally on sudden memory growth, e.g. when
                         there is a temporary peak in memory usage.
 
@@ -22,10 +23,21 @@
                         crash the program with a fatal error.  Try values
                         like '1.6GB'.
 
+ PYPY_GC_MAX_DELTA      The major collection threshold will never be set
+                        to more than PYPY_GC_MAX_DELTA the amount really
+                        used after a collection.  Defaults to 1/8th of the
+                        total RAM size (which is constrained to be at most
+                        2/3/4GB on 32-bit systems).  Try values like '200MB'.
+
  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.
+
+ PYPY_GC_DEBUG          Enable extra checks around collections that are
+                        too slow for normal use.  Values are 0 (off),
+                        1 (on major collections) or 2 (also on minor
+                        collections).
 """
 # XXX Should find a way to bound the major collection threshold by the
 # XXX total addressable size.  Maybe by keeping some minimarkpage arenas
@@ -36,7 +48,7 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage
 from pypy.rpython.memory.gc.base import GCBase, MovingGCBase
-from pypy.rpython.memory.gc import minimarkpage, base, generation
+from pypy.rpython.memory.gc import minimarkpage, env
 from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask, r_uint
 from pypy.rlib.rarithmetic import LONG_BIT_SHIFT
 from pypy.rlib.debug import ll_assert, debug_print, debug_start, debug_stop
@@ -96,6 +108,7 @@
     needs_write_barrier = True
     prebuilt_gc_objects_are_static_roots = False
     malloc_zero_filled = True    # xxx experiment with False
+    gcflag_extra = GCFLAG_FINALIZATION_ORDERING
 
     # All objects start with a HDR, i.e. with a field 'tid' which contains
     # a word.  This word is divided in two halves: the lower half contains
@@ -154,7 +167,7 @@
         # 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,
+        "growth_rate_max": 1.4,
 
         # 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
@@ -198,6 +211,7 @@
         self.min_heap_size = 0.0
         self.max_heap_size = 0.0
         self.max_heap_size_already_raised = False
+        self.max_delta = float(r_uint(-1))
         #
         self.card_page_indices = card_page_indices
         if self.card_page_indices > 0:
@@ -215,7 +229,8 @@
         self.nursery      = NULL
         self.nursery_free = NULL
         self.nursery_top  = NULL
-        self.debug_always_do_minor_collect = False
+        self.debug_tiny_nursery = -1
+        self.debug_rotating_nurseries = None
         #
         # The ArenaCollection() handles the nonmovable objects allocation.
         if ArenaCollectionClass is None:
@@ -282,53 +297,71 @@
             #
             # 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
+            newsize = env.read_from_env('PYPY_GC_NURSERY')
+            # PYPY_GC_NURSERY=smallvalue means that minor collects occur
+            # very frequently; the extreme case is PYPY_GC_NURSERY=1, which
+            # forces a minor collect for every malloc.  Useful to debug
+            # external factors, like trackgcroot or the handling of the write
+            # barrier.  Implemented by still using 'minsize' for the nursery
+            # size (needed to handle e.g. mallocs of 8249 words) but hacking
+            # at the current nursery position in collect_and_reserve().
             if newsize <= 0:
-                newsize = generation.estimate_best_nursery_size()
+                newsize = env.estimate_best_nursery_size()
                 if newsize <= 0:
                     newsize = defaultsize
-            newsize = max(newsize, minsize)
+            if newsize < minsize:
+                self.debug_tiny_nursery = newsize & ~(WORD-1)
+                newsize = minsize
             #
-            major_coll = base.read_float_from_env('PYPY_GC_MAJOR_COLLECT')
+            major_coll = env.read_float_from_env('PYPY_GC_MAJOR_COLLECT')
             if major_coll > 1.0:
                 self.major_collection_threshold = major_coll
             #
-            growth = base.read_float_from_env('PYPY_GC_GROWTH')
+            growth = env.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')
+            min_heap_size = env.read_uint_from_env('PYPY_GC_MIN')
             if min_heap_size > 0:
                 self.min_heap_size = float(min_heap_size)
             else:
                 # defaults to 8 times the nursery
                 self.min_heap_size = newsize * 8
             #
-            max_heap_size = base.read_uint_from_env('PYPY_GC_MAX')
+            max_heap_size = env.read_uint_from_env('PYPY_GC_MAX')
             if max_heap_size > 0:
                 self.max_heap_size = float(max_heap_size)
             #
+            max_delta = env.read_uint_from_env('PYPY_GC_MAX_DELTA')
+            if max_delta > 0:
+                self.max_delta = float(max_delta)
+            else:
+                self.max_delta = 0.125 * env.get_total_memory()
+            #
             self.minor_collection()    # to empty the nursery
             llarena.arena_free(self.nursery)
             self.nursery_size = newsize
             self.allocate_nursery()
 
 
-    def allocate_nursery(self):
-        debug_start("gc-set-nursery-size")
-        debug_print("nursery size:", self.nursery_size)
+    def _nursery_memory_size(self):
+        extra = self.nonlarge_gcptrs_max + 1
+        return self.nursery_size + extra
+
+    def _alloc_nursery(self):
         # the start of the nursery: we actually allocate a bit more for
         # the nursery than really needed, to simplify pointer arithmetic
         # in malloc_fixedsize_clear().  The few extra pages are never used
         # anyway so it doesn't even count.
-        extra = self.nonlarge_gcptrs_max + 1
-        self.nursery = llarena.arena_malloc(self.nursery_size + extra, 2)
-        if not self.nursery:
+        nursery = llarena.arena_malloc(self._nursery_memory_size(), 2)
+        if not nursery:
             raise MemoryError("cannot allocate nursery")
+        return nursery
+
+    def allocate_nursery(self):
+        debug_start("gc-set-nursery-size")
+        debug_print("nursery size:", self.nursery_size)
+        self.nursery = self._alloc_nursery()
         # the current position in the nursery:
         self.nursery_free = self.nursery
         # the end of the nursery:
@@ -362,6 +395,40 @@
         return bounded
 
 
+    def post_setup(self):
+        # set up extra stuff for PYPY_GC_DEBUG.
+        MovingGCBase.post_setup(self)
+        if self.DEBUG and llarena.has_protect:
+            # gc debug mode: allocate 23 nurseries instead of just 1,
+            # and use them alternatively, while mprotect()ing the unused
+            # ones to detect invalid access.
+            debug_start("gc-debug")
+            self.debug_rotating_nurseries = []
+            for i in range(22):
+                nurs = self._alloc_nursery()
+                llarena.arena_protect(nurs, self._nursery_memory_size(), True)
+                self.debug_rotating_nurseries.append(nurs)
+            debug_print("allocated", len(self.debug_rotating_nurseries),
+                        "extra nurseries")
+            debug_stop("gc-debug")
+
+    def debug_rotate_nursery(self):
+        if self.debug_rotating_nurseries is not None:
+            debug_start("gc-debug")
+            oldnurs = self.nursery
+            llarena.arena_protect(oldnurs, self._nursery_memory_size(), True)
+            self.debug_rotating_nurseries.append(oldnurs)
+            #
+            newnurs = self.debug_rotating_nurseries.pop(0)
+            llarena.arena_protect(newnurs, self._nursery_memory_size(), False)
+            self.nursery = newnurs
+            self.nursery_top = self.nursery + self.nursery_size
+            debug_print("switching from nursery", oldnurs,
+                        "to nursery", self.nursery,
+                        "size", self.nursery_size)
+            debug_stop("gc-debug")
+
+
     def malloc_fixedsize_clear(self, typeid, size, can_collect=True,
                                needs_finalizer=False, contains_weakptr=False):
         ll_assert(can_collect, "!can_collect")
@@ -499,8 +566,9 @@
         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
+        if self.debug_tiny_nursery >= 0:   # for debugging
+            if self.nursery_top - self.nursery_free > self.debug_tiny_nursery:
+                self.nursery_free = self.nursery_top - self.debug_tiny_nursery
         #
         return result
     collect_and_reserve._dont_inline_ = True
@@ -638,8 +706,13 @@
         # means recording that they have a smaller size, so that when
         # moved out of the nursery, they will consume less memory.
         # In particular, an array with GCFLAG_HAS_CARDS is never resized.
+        # Also, a nursery object with GCFLAG_HAS_SHADOW is not resized
+        # either, as this would potentially loose part of the memory in
+        # the already-allocated shadow.
         if not self.is_in_nursery(obj):
             return False
+        if self.header(obj).tid & GCFLAG_HAS_SHADOW:
+            return False
         #
         size_gc_header = self.gcheaderbuilder.size_gc_header
         typeid = self.get_type_id(obj)
@@ -822,7 +895,7 @@
         def remember_young_pointer(addr_struct, newvalue):
             # 'addr_struct' is the address of the object in which we write.
             # 'newvalue' is the address that we are going to write in there.
-            if DEBUG:
+            if DEBUG:   # note: PYPY_GC_DEBUG=1 does not enable this
                 ll_assert(not self.is_in_nursery(addr_struct),
                           "nursery object with GCFLAG_NO_YOUNG_PTRS")
             #
@@ -859,7 +932,7 @@
             # 'addr_array' is the address of the object in which we write,
             # which must have an array part;  'index' is the index of the
             # item that is (or contains) the pointer that we write.
-            if DEBUG:
+            if DEBUG:   # note: PYPY_GC_DEBUG=1 does not enable this
                 ll_assert(not self.is_in_nursery(addr_array),
                           "nursery array with GCFLAG_NO_YOUNG_PTRS")
             objhdr = self.header(addr_array)
@@ -981,13 +1054,14 @@
         # All live nursery objects are out, and the rest dies.  Fill
         # the whole nursery with zero and reset the current nursery pointer.
         llarena.arena_reset(self.nursery, self.nursery_size, 2)
+        self.debug_rotate_nursery()
         self.nursery_free = self.nursery
         #
         debug_print("minor collect, total memory used:",
                     self.get_total_memory_used())
+        if self.DEBUG >= 2:
+            self.debug_check_consistency()     # expensive!
         debug_stop("gc-minor")
-        if 0:  # not we_are_translated():
-            self.debug_check_consistency()     # xxx expensive!
 
 
     def collect_roots_in_nursery(self):
@@ -1205,10 +1279,6 @@
         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
@@ -1218,6 +1288,10 @@
         #
         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()
@@ -1245,9 +1319,12 @@
         #
         # Set the threshold for the next major collection to be when we
         # have allocated 'major_collection_threshold' times more than
+        # we currently have -- but no more than 'max_delta' more than
         # we currently have.
+        total_memory_used = float(self.get_total_memory_used())
         bounded = self.set_major_threshold_from(
-            self.get_total_memory_used() * self.major_collection_threshold,
+            min(total_memory_used * self.major_collection_threshold,
+                total_memory_used + self.max_delta),
             reserving_size)
         #
         # Max heap size: gives an upper bound on the threshold.  If we
@@ -1406,12 +1483,21 @@
                     size = self.get_size(obj)
                     shadowhdr = self._malloc_out_of_nursery(size_gc_header +
                                                             size)
-                    # initialize to an invalid tid *without* GCFLAG_VISITED,
-                    # so that if the object dies before the next minor
-                    # collection, the shadow will stay around but be collected
-                    # by the next major collection.
+                    # Initialize the shadow enough to be considered a
+                    # valid gc object.  If the original object stays
+                    # alive at the next minor collection, it will anyway
+                    # be copied over the shadow and overwrite the
+                    # following fields.  But if the object dies, then
+                    # the shadow will stay around and only be freed at
+                    # the next major collection, at which point we want
+                    # it to look valid (but ready to be freed).
                     shadow = shadowhdr + size_gc_header
-                    self.header(shadow).tid = 0
+                    self.header(shadow).tid = self.header(obj).tid
+                    typeid = self.get_type_id(obj)
+                    if self.is_varsize(typeid):
+                        lenofs = self.varsize_offset_to_length(typeid)
+                        (shadow + lenofs).signed[0] = (obj + lenofs).signed[0]
+                    #
                     self.header(obj).tid |= GCFLAG_HAS_SHADOW
                     self.young_objects_shadows.setitem(obj, shadow)
                 #

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	Sat Dec 11 15:10:15 2010
@@ -42,6 +42,7 @@
     inline_simple_malloc_varsize = True
     malloc_zero_filled = True
     first_unused_gcflag = first_gcflag << 5
+    gcflag_extra = GCFLAG_FINALIZATION_ORDERING
 
     HDR = lltype.Struct('header', ('tid', lltype.Signed))   # XXX or rffi.INT?
     typeid_is_in_field = 'tid'
@@ -266,10 +267,10 @@
         if self.run_finalizers.non_empty():
             self.update_run_finalizers()
         scan = self.scan_copied(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)
+        if self.objects_with_weakrefs.non_empty():
+            self.invalidate_weakrefs()
         self.update_objects_with_id()
         self.finished_full_collect()
         self.debug_check_consistency()

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/test/test_direct.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/test/test_direct.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gc/test/test_direct.py	Sat Dec 11 15:10:15 2010
@@ -60,7 +60,7 @@
         pass
 
 
-class DirectGCTest(object):
+class BaseDirectGCTest(object):
     GC_PARAMS = {}
 
     def setup_method(self, meth):
@@ -106,6 +106,9 @@
         addr = self.gc.malloc(self.get_type_id(TYPE), n, zero=True)
         return llmemory.cast_adr_to_ptr(addr, lltype.Ptr(TYPE))
 
+
+class DirectGCTest(BaseDirectGCTest):
+
     def test_simple(self):
         p = self.malloc(S)
         p.x = 5
@@ -339,6 +342,15 @@
             self.gc.collect()
             assert hash == self.gc.identityhash(self.stackroots[-1])
             self.stackroots.pop()
+        # (7) the same, but the objects are dying young
+        for i in range(10):
+            self.gc.collect()
+            p = self.malloc(VAR, i)
+            self.stackroots.append(p)
+            hash1 = self.gc.identityhash(p)
+            hash2 = self.gc.identityhash(p)
+            assert hash1 == hash2
+            self.stackroots.pop()
 
     def test_memory_alignment(self):
         A1 = lltype.GcArray(lltype.Char)

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/asmgcroot.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/asmgcroot.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/asmgcroot.py	Sat Dec 11 15:10:15 2010
@@ -139,12 +139,13 @@
         self._shape_decompressor = ShapeDecompressor()
         if hasattr(gctransformer.translator, '_jit2gc'):
             jit2gc = gctransformer.translator._jit2gc
-            self._extra_gcmapstart = jit2gc['gcmapstart']
-            self._extra_gcmapend   = jit2gc['gcmapend']
+            self._extra_gcmapstart  = jit2gc['gcmapstart']
+            self._extra_gcmapend    = jit2gc['gcmapend']
+            self._extra_mark_sorted = jit2gc['gcmarksorted']
         else:
-            returns_null = lambda: llmemory.NULL
-            self._extra_gcmapstart = returns_null
-            self._extra_gcmapend   = returns_null
+            self._extra_gcmapstart  = lambda: llmemory.NULL
+            self._extra_gcmapend    = lambda: llmemory.NULL
+            self._extra_mark_sorted = lambda: True
 
     def need_thread_support(self, gctransformer, getfn):
         # Threads supported "out of the box" by the rest of the code.
@@ -295,13 +296,25 @@
             # we have a non-empty JIT-produced table to look in
             item = search_in_gcmap2(gcmapstart2, gcmapend2, retaddr)
             if item:
-                self._shape_decompressor.setaddr(item.address[1])
+                self._shape_decompressor.setaddr(item)
                 return
             # maybe the JIT-produced table is not sorted?
+            was_already_sorted = self._extra_mark_sorted()
+            if not was_already_sorted:
+                sort_gcmap(gcmapstart2, gcmapend2)
+                item = search_in_gcmap2(gcmapstart2, gcmapend2, retaddr)
+                if item:
+                    self._shape_decompressor.setaddr(item)
+                    return
+            # there is a rare risk that the array contains *two* entries
+            # with the same key, one of which is dead (null value), and we
+            # found the dead one above.  Solve this case by replacing all
+            # dead keys with nulls, sorting again, and then trying again.
+            replace_dead_entries_with_nulls(gcmapstart2, gcmapend2)
             sort_gcmap(gcmapstart2, gcmapend2)
             item = search_in_gcmap2(gcmapstart2, gcmapend2, retaddr)
             if item:
-                self._shape_decompressor.setaddr(item.address[1])
+                self._shape_decompressor.setaddr(item)
                 return
         # the item may have been not found because the main array was
         # not sorted.  Sort it and try again.
@@ -357,7 +370,8 @@
     The interval from the start address (included) to the end address
     (excluded) is assumed to be a sorted arrays of pairs (addr1, addr2).
     This searches for the item with a given addr1 and returns its
-    address.
+    address.  If not found exactly, it tries to return the address
+    of the item left of addr1 (i.e. such that result.address[0] < addr1).
     """
     count = (end - start) // arrayitemsize
     while count > 1:
@@ -386,7 +400,7 @@
     # (item.signed[1] is an address in this case, not a signed at all!)
     item = binary_search(gcmapstart, gcmapend, retaddr)
     if item.address[0] == retaddr:
-        return item     # found
+        return item.address[1]     # found
     else:
         return llmemory.NULL    # failed
 
@@ -397,6 +411,15 @@
           rffi.cast(rffi.SIZE_T, arrayitemsize),
           llhelper(QSORT_CALLBACK_PTR, _compare_gcmap_entries))
 
+def replace_dead_entries_with_nulls(start, end):
+    # replace the dead entries (null value) with a null key.
+    count = (end - start) // arrayitemsize - 1
+    while count >= 0:
+        item = start + count * arrayitemsize
+        if item.address[1] == llmemory.NULL:
+            item.address[0] = llmemory.NULL
+        count -= 1
+
 if sys.platform == 'win32':
     def win32_follow_gcmap_jmp(start, end):
         # The initial gcmap table contains addresses to a JMP

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/boehm.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/boehm.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/boehm.py	Sat Dec 11 15:10:15 2010
@@ -120,10 +120,11 @@
             fptr = self.annotate_finalizer(d['ll_finalizer'], [llmemory.Address], lltype.Void)
         elif destrptr:
             EXC_INSTANCE_TYPE = self.translator.rtyper.exceptiondata.lltype_of_exception_value
+            typename = TYPE.__name__
             def ll_finalizer(addr):
                 exc_instance = llop.gc_fetch_exception(EXC_INSTANCE_TYPE)
                 v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
-                ll_call_destructor(destrptr, v)
+                ll_call_destructor(destrptr, v, typename)
                 llop.gc_restore_exception(lltype.Void, exc_instance)
             fptr = self.annotate_finalizer(ll_finalizer, [llmemory.Address], lltype.Void)
         else:

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	Sat Dec 11 15:10:15 2010
@@ -189,6 +189,7 @@
             # run-time initialization code
             root_walker.setup_root_walker()
             gcdata.gc.setup()
+            gcdata.gc.post_setup()
 
         def frameworkgc__teardown():
             # run-time teardown code for tests!
@@ -1204,9 +1205,10 @@
 
         assert not type_contains_pyobjs(TYPE), "not implemented"
         if destrptr:
+            typename = TYPE.__name__
             def ll_finalizer(addr):
                 v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
-                ll_call_destructor(destrptr, v)
+                ll_call_destructor(destrptr, v, typename)
             fptr = self.transformer.annotate_finalizer(ll_finalizer,
                                                        [llmemory.Address],
                                                        lltype.Void)

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/refcounting.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/refcounting.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/refcounting.py	Sat Dec 11 15:10:15 2010
@@ -227,7 +227,7 @@
         # refcount is at zero, temporarily bump it to 1:
         gcheader.refcount = 1
         destr_v = cast_pointer(DESTR_ARG, v)
-        ll_call_destructor(destrptr, destr_v)
+        ll_call_destructor(destrptr, destr_v, %r)
         refcount = gcheader.refcount - 1
         gcheader.refcount = refcount
         if refcount == 0:
@@ -239,7 +239,7 @@
     pop_alive(exc_instance)
     # XXX layering of exceptiontransform versus gcpolicy
 
-""" % (body, TYPE._gckind)
+""" % (TYPE.__name__, body, TYPE._gckind)
         else:
             call_del = None
             body = '\n'.join(_static_deallocator_body_for_type('v', TYPE))

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/support.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/support.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/memory/gctransform/support.py	Sat Dec 11 15:10:15 2010
@@ -98,11 +98,15 @@
         hop.exception_cannot_occur()
         return hop.inputconst(hop.r_result.lowleveltype, hop.s_result.const)
 
-def ll_call_destructor(destrptr, destr_v):
+def ll_call_destructor(destrptr, destr_v, typename):
     try:
         destrptr(destr_v)
-    except:
+    except Exception, e:
         try:
-            os.write(2, "a destructor raised an exception, ignoring it\n")
+            os.write(2, "a destructor of type ")
+            os.write(2, typename)
+            os.write(2, " raised an exception ")
+            os.write(2, str(e))
+            os.write(2, " ignoring it\n")
         except:
             pass

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	Sat Dec 11 15:10:15 2010
@@ -304,7 +304,7 @@
         a = A()
         class B(object):
             def __del__(self):
-                # when __del__ is called, the weakref should have been cleared
+                # when __del__ is called, the weakref to c should be dead
                 if self.ref() is None:
                     a.count += 10  # ok
                 else:
@@ -333,8 +333,10 @@
         a = A()
         class B(object):
             def __del__(self):
-                # when __del__ is called, the weakref should have been cleared
-                if self.ref() is None:
+                # when __del__ is called, the weakref to myself is still valid
+                # in RPython (at least with most GCs; this test might be
+                # skipped for specific GCs)
+                if self.ref() is self:
                     a.count += 10  # ok
                 else:
                     a.count = 666  # not ok
@@ -352,6 +354,29 @@
         res = self.interpret(f, [])
         assert res == 11
 
+    def test_weakref_bug_1(self):
+        import weakref
+        class A(object):
+            pass
+        class B(object):
+            def __del__(self):
+                self.wref().x += 1
+        def g(a):
+            b = B()
+            b.wref = weakref.ref(a)
+            # the only way to reach this weakref is via B, which is an
+            # object with finalizer (but the weakref itself points to
+            # a, which does not go away but will move during the next
+            # gc.collect)
+        def f():
+            a = A()
+            a.x = 10
+            g(a)
+            llop.gc__collect(lltype.Void)
+            return a.x
+        res = self.interpret(f, [])
+        assert res == 11
+
     def test_id(self):
         class A(object):
             pass
@@ -709,6 +734,9 @@
 class TestMarkSweepGC(GCTest):
     from pypy.rpython.memory.gc.marksweep import MarkSweepGC as GCClass
 
+    def test_weakref_to_object_with_finalizer_ordering(self):
+        py.test.skip("Does not work")
+
 class TestSemiSpaceGC(GCTest, snippet.SemiSpaceGCTests):
     from pypy.rpython.memory.gc.semispace import SemiSpaceGC as GCClass
     GC_CAN_MOVE = True
@@ -731,9 +759,6 @@
     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/module/ll_os.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/module/ll_os.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/module/ll_os.py	Sat Dec 11 15:10:15 2010
@@ -730,6 +730,22 @@
         return extdef([traits.str, int, int], int, traits.ll_os_name('open'),
                       llimpl=os_open_llimpl, oofakeimpl=os_open_oofakeimpl)
 
+    @registering_if(os, 'getloadavg')
+    def register_os_getloadavg(self):
+        AP = rffi.CArrayPtr(lltype.Float)
+        c_getloadavg = self.llexternal('getloadavg', [AP, rffi.INT], rffi.INT)
+
+        def getloadavg_llimpl():
+            load = lltype.malloc(AP.TO, 3, flavor='raw')
+            r = c_getloadavg(load, 3)
+            result_tuple = load[0], load[1], load[2]
+            lltype.free(load, flavor='raw')
+            if r != 3:
+                raise OSError
+            return result_tuple
+        return extdef([], (float, float, float),
+                      "ll_os.ll_getloadavg", llimpl=getloadavg_llimpl)
+
 # ------------------------------- os.read -------------------------------
 
     @registering(os.read)
@@ -887,6 +903,18 @@
                       llimpl=fdatasync_llimpl,
                       export_name="ll_os.ll_os_fdatasync")
 
+    @registering_if(os, 'fchdir')
+    def register_os_fchdir(self):
+        os_fchdir = self.llexternal('fchdir', [rffi.INT], rffi.INT)
+
+        def fchdir_llimpl(fd):
+            res = rffi.cast(rffi.LONG, os_fchdir(rffi.cast(rffi.INT, fd)))
+            if res < 0:
+                raise OSError(rposix.get_errno(), "fchdir failed")
+        return extdef([int], s_None,
+                      llimpl=fchdir_llimpl,
+                      export_name="ll_os.ll_os_fchdir")
+
     @registering_str_unicode(os.access)
     def register_os_access(self, traits):
         os_access = self.llexternal(traits.posix_function_name('access'),
@@ -1386,6 +1414,25 @@
         return extdef([], (int, int), "ll_os.ll_os_openpty",
                       llimpl=openpty_llimpl)
 
+    @registering_if(os, 'forkpty')
+    def register_os_forkpty(self):
+        os_forkpty = self.llexternal(
+            'forkpty',
+            [rffi.INTP, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP],
+            rffi.PID_T,
+            compilation_info=ExternalCompilationInfo(libraries=['util']))
+        def forkpty_llimpl():
+            master_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+            childpid = os_forkpty(master_p, None, None, None)
+            master_fd = master_p[0]
+            lltype.free(master_p, flavor='raw')
+            if childpid == -1:
+                raise OSError(rposix.get_errno(), "os_forkpty failed")
+            return (rffi.cast(lltype.Signed, childpid),
+                    rffi.cast(lltype.Signed, master_fd))
+
+        return extdef([], (int, int), "ll_os.ll_os_forkpty",
+                      llimpl=forkpty_llimpl)
 
     @registering(os._exit)
     def register_os__exit(self):

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/module/ll_time.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/module/ll_time.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/module/ll_time.py	Sat Dec 11 15:10:15 2010
@@ -41,7 +41,7 @@
         RUSAGE = platform.Struct('struct rusage', [('ru_utime', TIMEVAL),
                                                    ('ru_stime', TIMEVAL)])
 
-if sys.platform == 'freebsd7':
+if "freebsd" in sys.platform:
     libraries = ['compat']
 else:
     libraries = []

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/ootypesystem/rpbc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/ootypesystem/rpbc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/ootypesystem/rpbc.py	Sat Dec 11 15:10:15 2010
@@ -49,7 +49,7 @@
         return hop.genop('runtimenew', [v_class], resulttype=resulttype)
 
     def getlowleveltype(self):
-        classdescs = self.s_pbc.descriptions.keys()
+        classdescs = list(self.s_pbc.descriptions)
         # if any of the classdefs get the lowleveltype ootype.Class,
         # we can only pick ootype.Class for us too.  Otherwise META.
         for classdesc in classdescs:
@@ -70,7 +70,7 @@
 class MethodImplementations(object):
 
     def __init__(self, rtyper, methdescs):
-        samplemdesc = methdescs.iterkeys().next()
+        samplemdesc = iter(methdescs).next()
         concretetable, uniquerows = get_concrete_calltable(rtyper,
                                              samplemdesc.funcdesc.getcallfamily())
         self.row_mapping = {}
@@ -117,7 +117,7 @@
     concretetable = None # set by _setup_repr_final
 
     def _setup_repr_final(self):
-        sampledesc = self.s_pbc.descriptions.iterkeys().next()
+        sampledesc = self.s_pbc.any_description()
         self.concretetable, _ = get_concrete_calltable(self.rtyper,
                                              sampledesc.funcdesc.getcallfamily())
 

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/rlist.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/rlist.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/rlist.py	Sat Dec 11 15:10:15 2010
@@ -9,7 +9,7 @@
 from pypy.rpython import robject
 from pypy.rlib.objectmodel import malloc_zero_filled
 from pypy.rlib.debug import ll_assert
-from pypy.rlib.rarithmetic import ovfcheck, widen
+from pypy.rlib.rarithmetic import ovfcheck, widen, r_uint, intmask
 from pypy.rpython.annlowlevel import ADTInterface
 from pypy.rlib import rgc
 
@@ -241,17 +241,22 @@
 class __extend__(pairtype(AbstractBaseListRepr, IntegerRepr)):
 
     def rtype_getitem((r_lst, r_int), hop, checkidx=False):
+        v_lst, v_index = hop.inputargs(r_lst, Signed)
         if checkidx:
-            spec = dum_checkidx
+            hop.exception_is_here()
         else:
-            spec = dum_nocheck
-        v_func = hop.inputconst(Void, spec)
-        v_lst, v_index = hop.inputargs(r_lst, Signed)
+            hop.exception_cannot_occur()
         if hop.args_s[0].listdef.listitem.mutated or checkidx:
             if hop.args_s[1].nonneg:
                 llfn = ll_getitem_nonneg
             else:
                 llfn = ll_getitem
+            if checkidx:
+                spec = dum_checkidx
+            else:
+                spec = dum_nocheck
+            c_func_marker = hop.inputconst(Void, spec)
+            v_res = hop.gendirectcall(llfn, c_func_marker, v_lst, v_index)
         else:
             # this is the 'foldable' version, which is not used when
             # we check for IndexError
@@ -259,11 +264,7 @@
                 llfn = ll_getitem_foldable_nonneg
             else:
                 llfn = ll_getitem_foldable
-        if checkidx:
-            hop.exception_is_here()
-        else:
-            hop.exception_cannot_occur()
-        v_res = hop.gendirectcall(llfn, v_func, v_lst, v_index)
+            v_res = hop.gendirectcall(llfn, v_lst, v_index)
         return r_lst.recast(hop.llops, v_res)
 
     rtype_getitem_key = rtype_getitem
@@ -538,12 +539,14 @@
             dest.ll_setitem_fast(dest_start + i, item)
             i += 1
 ll_arraycopy._annenforceargs_ = [None, None, int, int, int]
+# no oopspec -- the function is inlined by the JIT
 
 def ll_copy(RESLIST, l):
     length = l.ll_length()
     new_lst = RESLIST.ll_newlist(length)
     ll_arraycopy(l, new_lst, 0, 0, length)
     return new_lst
+# no oopspec -- the function is inlined by the JIT
 
 def ll_len(l):
     return l.ll_length()
@@ -551,6 +554,7 @@
 def ll_list_is_true(l):
     # check if a list is True, allowing for None
     return bool(l) and l.ll_length() != 0
+# no oopspec -- the function is inlined by the JIT
 
 def ll_len_foldable(l):
     return l.ll_length()
@@ -558,6 +562,7 @@
 
 def ll_list_is_true_foldable(l):
     return bool(l) and ll_len_foldable(l) != 0
+# no oopspec -- the function is inlined by the JIT
 
 def ll_append(l, newitem):
     length = l.ll_length()
@@ -588,6 +593,7 @@
     ll_arraycopy(l1, l, 0, 0, len1)
     ll_arraycopy(l2, l, 0, len1, len2)
     return l
+# no oopspec -- the function is inlined by the JIT
 
 def ll_insert_nonneg(l, index, newitem):
     length = l.ll_length()
@@ -674,60 +680,72 @@
         l.ll_setitem_fast(length_1_i, tmp)
         i += 1
         length_1_i -= 1
+ll_reverse.oopspec = 'list.reverse(l)'
 
 def ll_getitem_nonneg(func, l, index):
     ll_assert(index >= 0, "unexpectedly negative list getitem index")
     if func is dum_checkidx:
         if index >= l.ll_length():
             raise IndexError
-    else:
-        ll_assert(index < l.ll_length(), "list getitem index out of bound")
     return l.ll_getitem_fast(index)
-ll_getitem_nonneg.oopspec = 'list.getitem(l, index)'
+ll_getitem_nonneg._always_inline_ = True
+# no oopspec -- the function is inlined by the JIT
 
 def ll_getitem(func, l, index):
-    length = l.ll_length()
-    if index < 0:
-        index += length
     if func is dum_checkidx:
-        if index < 0 or index >= length:
-            raise IndexError
+        length = l.ll_length()    # common case: 0 <= index < length
+        if r_uint(index) >= r_uint(length):
+            # Failed, so either (-length <= index < 0), or we have to raise
+            # IndexError.  First add 'length' to get the final index, then
+            # check that we now have (0 <= index < length).
+            index = r_uint(index) + r_uint(length)
+            if index >= r_uint(length):
+                raise IndexError
+            index = intmask(index)
     else:
-        ll_assert(index >= 0, "negative list getitem index out of bound")
-        ll_assert(index < length, "list getitem index out of bound")
+        # We don't want checking, but still want to support index < 0.
+        # Only call ll_length() if needed.
+        if index < 0:
+            index += l.ll_length()
+            ll_assert(index >= 0, "negative list getitem index out of bound")
     return l.ll_getitem_fast(index)
-ll_getitem.oopspec = 'list.getitem(l, index)'
+# no oopspec -- the function is inlined by the JIT
 
-def ll_getitem_foldable_nonneg(func, l, index):
-    return ll_getitem_nonneg(func, l, index)
+def ll_getitem_foldable_nonneg(l, index):
+    ll_assert(index >= 0, "unexpectedly negative list getitem index")
+    return l.ll_getitem_fast(index)
 ll_getitem_foldable_nonneg.oopspec = 'list.getitem_foldable(l, index)'
 
-def ll_getitem_foldable(func, l, index):
-    return ll_getitem(func, l, index)
-ll_getitem_foldable.oopspec = 'list.getitem_foldable(l, index)'
+def ll_getitem_foldable(l, index):
+    if index < 0:
+        index += l.ll_length()
+    return ll_getitem_foldable_nonneg(l, index)
+ll_getitem_foldable._always_inline_ = True
+# no oopspec -- the function is inlined by the JIT
 
 def ll_setitem_nonneg(func, l, index, newitem):
     ll_assert(index >= 0, "unexpectedly negative list setitem index")
     if func is dum_checkidx:
         if index >= l.ll_length():
             raise IndexError
-    else:
-        ll_assert(index < l.ll_length(), "list setitem index out of bound")
     l.ll_setitem_fast(index, newitem)
-ll_setitem_nonneg.oopspec = 'list.setitem(l, index, newitem)'
+ll_setitem_nonneg._always_inline_ = True
+# no oopspec -- the function is inlined by the JIT
 
 def ll_setitem(func, l, index, newitem):
-    length = l.ll_length()
-    if index < 0:
-        index += length
     if func is dum_checkidx:
-        if index < 0 or index >= length:
-            raise IndexError
+        length = l.ll_length()
+        if r_uint(index) >= r_uint(length):   # see comments in ll_getitem().
+            index = r_uint(index) + r_uint(length)
+            if index >= r_uint(length):
+                raise IndexError
+            index = intmask(index)
     else:
-        ll_assert(index >= 0, "negative list setitem index out of bound")
-        ll_assert(index < length, "list setitem index out of bound")
+        if index < 0:
+            index += l.ll_length()
+            ll_assert(index >= 0, "negative list setitem index out of bound")
     l.ll_setitem_fast(index, newitem)
-ll_setitem.oopspec = 'list.setitem(l, index, newitem)'
+# no oopspec -- the function is inlined by the JIT
 
 def ll_delitem_nonneg(func, l, index):
     ll_assert(index >= 0, "unexpectedly negative list delitem index")
@@ -751,19 +769,20 @@
     l._ll_resize_le(newlength)
 ll_delitem_nonneg.oopspec = 'list.delitem(l, index)'
 
-def ll_delitem(func, l, i):
-    length = l.ll_length()
-    if i < 0:
-        i += length
+def ll_delitem(func, l, index):
     if func is dum_checkidx:
-        if i < 0 or i >= length:
-            raise IndexError
+        length = l.ll_length()
+        if r_uint(index) >= r_uint(length):   # see comments in ll_getitem().
+            index = r_uint(index) + r_uint(length)
+            if index >= r_uint(length):
+                raise IndexError
+            index = intmask(index)
     else:
-        ll_assert(i >= 0, "negative list delitem index out of bound")
-        ll_assert(i < length, "list delitem index out of bound")
-    ll_delitem_nonneg(dum_nocheck, l, i)
-ll_delitem.oopspec = 'list.delitem(l, i)'
-
+        if index < 0:
+            index += l.ll_length()
+            ll_assert(index >= 0, "negative list delitem index out of bound")
+    ll_delitem_nonneg(dum_nocheck, l, index)
+# no oopspec -- the function is inlined by the JIT
 
 def ll_extend(l1, l2):
     len1 = l1.ll_length()
@@ -799,6 +818,7 @@
         lst.ll_setitem_fast(j, c)
         i += 1
         j += 1
+# not inlined by the JIT -- contains a loop
 
 def ll_extend_with_str_slice_startstop(lst, s, getstrlen, getstritem,
                                        start, stop):
@@ -824,6 +844,7 @@
         lst.ll_setitem_fast(j, c)
         i += 1
         j += 1
+# not inlined by the JIT -- contains a loop
 
 def ll_extend_with_str_slice_minusone(lst, s, getstrlen, getstritem):
     len1 = lst.ll_length()
@@ -843,6 +864,7 @@
         lst.ll_setitem_fast(j, c)
         i += 1
         j += 1
+# not inlined by the JIT -- contains a loop
 
 def ll_extend_with_char_count(lst, char, count):
     if count <= 0:
@@ -859,6 +881,7 @@
     while j < newlength:
         lst.ll_setitem_fast(j, char)
         j += 1
+# not inlined by the JIT -- contains a loop
 
 def ll_listslice_startonly(RESLIST, l1, start):
     len1 = l1.ll_length()
@@ -869,6 +892,7 @@
     ll_arraycopy(l1, l, start, 0, newlength)
     return l
 ll_listslice_startonly._annenforceargs_ = (None, None, int)
+# no oopspec -- the function is inlined by the JIT
 
 def ll_listslice_startstop(RESLIST, l1, start, stop):
     length = l1.ll_length()
@@ -881,6 +905,7 @@
     l = RESLIST.ll_newlist(newlength)
     ll_arraycopy(l1, l, start, 0, newlength)
     return l
+# no oopspec -- the function is inlined by the JIT
 
 def ll_listslice_minusone(RESLIST, l1):
     newlength = l1.ll_length() - 1
@@ -888,6 +913,7 @@
     l = RESLIST.ll_newlist(newlength)
     ll_arraycopy(l1, l, 0, 0, newlength)
     return l
+# no oopspec -- the function is inlined by the JIT
 
 def ll_listdelslice_startonly(l, start):
     ll_assert(start >= 0, "del l[start:] with unexpectedly negative start")
@@ -958,6 +984,7 @@
                 return False
         j += 1
     return True
+# not inlined by the JIT -- contains a loop
 
 def ll_listcontains(lst, obj, eqfn):
     lng = lst.ll_length()
@@ -971,6 +998,7 @@
                 return True
         j += 1
     return False
+# not inlined by the JIT -- contains a loop
 
 def ll_listindex(lst, obj, eqfn):
     lng = lst.ll_length()
@@ -984,6 +1012,7 @@
                 return j
         j += 1
     raise ValueError # can't say 'list.index(x): x not in list'
+# not inlined by the JIT -- contains a loop
 
 def ll_listremove(lst, obj, eqfn):
     index = ll_listindex(lst, obj, eqfn) # raises ValueError if obj not in lst
@@ -1030,3 +1059,4 @@
             i += 1
         j += length
     return res
+# not inlined by the JIT -- contains a loop

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/rpbc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/rpbc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/rpbc.py	Sat Dec 11 15:10:15 2010
@@ -15,11 +15,10 @@
 
 from pypy.rpython import callparse
 
-
 def small_cand(rtyper, s_pbc):
     if 1 < len(s_pbc.descriptions) < rtyper.getconfig().translation.withsmallfuncsets and \
            hasattr(rtyper.type_system.rpbc, 'SmallFunctionSetPBCRepr'):
-        callfamily = s_pbc.descriptions.iterkeys().next().getcallfamily()
+        callfamily = s_pbc.any_description().getcallfamily()
         concretetable, uniquerows = get_concrete_calltable(rtyper, callfamily)
         if len(uniquerows) == 1 and (not s_pbc.subset_of or small_cand(rtyper, s_pbc.subset_of)):
             return True
@@ -31,7 +30,7 @@
             return none_frozen_pbc_repr 
         kind = self.getKind()
         if issubclass(kind, description.FunctionDesc):
-            sample = self.descriptions.keys()[0]
+            sample = self.any_description()
             callfamily = sample.querycallfamily()
             if callfamily and callfamily.total_calltable_size > 0:
                 if sample.overridden:
@@ -181,7 +180,7 @@
     def __init__(self, rtyper, s_pbc):
         self.rtyper = rtyper
         self.s_pbc = s_pbc
-        self.callfamily = s_pbc.descriptions.iterkeys().next().getcallfamily()
+        self.callfamily = s_pbc.any_description().getcallfamily()
         if len(s_pbc.descriptions) == 1 and not s_pbc.can_be_None:
             # a single function
             self.lowleveltype = Void
@@ -207,7 +206,7 @@
         return self, 0
 
     def get_s_signatures(self, shape):
-        funcdesc = self.s_pbc.descriptions.iterkeys().next()
+        funcdesc = self.s_pbc.any_description()
         return funcdesc.get_s_signatures(shape)
 
 ##    def function_signatures(self):
@@ -322,7 +321,7 @@
         bk = self.rtyper.annotator.bookkeeper
         args = bk.build_args(opname, hop.args_s[1:])
         s_pbc = hop.args_s[0]   # possibly more precise than self.s_pbc
-        descs = s_pbc.descriptions.keys()
+        descs = list(s_pbc.descriptions)
         shape, index = description.FunctionDesc.variant_for_call_site(bk, self.callfamily, descs, args)
         row_of_graphs = self.callfamily.calltables[shape][index]
         anygraph = row_of_graphs.itervalues().next()  # pick any witness
@@ -368,7 +367,7 @@
     return robject.pyobj_repr
 
 def getFrozenPBCRepr(rtyper, s_pbc):
-    descs = s_pbc.descriptions.keys()
+    descs = list(s_pbc.descriptions)
     assert len(descs) >= 1
     if len(descs) == 1 and not s_pbc.can_be_None:
         return SingleFrozenPBCRepr(descs[0])
@@ -530,7 +529,7 @@
 
     def __init__(self, rtyper, s_pbc):
         self.rtyper = rtyper
-        self.funcdesc = s_pbc.descriptions.keys()[0].funcdesc
+        self.funcdesc = s_pbc.any_description().funcdesc
 
         # a hack to force the underlying function to show up in call_families
         # (generally not needed, as normalizecalls() should ensure this,
@@ -662,7 +661,7 @@
         and the ClassRepr of the class which stores this attribute in
         its vtable.
         """
-        classdescs = self.s_pbc.descriptions.keys()
+        classdescs = list(self.s_pbc.descriptions)
         access = classdescs[0].queryattrfamily(attrname)
         for classdesc in classdescs[1:]:
             access1 = classdesc.queryattrfamily(attrname)
@@ -819,7 +818,7 @@
         if s_pbc.isNone():
             raise TyperError("unsupported: variable of type "
                              "bound-method-object or None")
-        mdescs = s_pbc.descriptions.keys()
+        mdescs = list(s_pbc.descriptions)
         methodname = mdescs[0].name
         classdef = mdescs[0].selfclassdef
         flags    = mdescs[0].flags

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rclass.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rclass.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rclass.py	Sat Dec 11 15:10:15 2010
@@ -917,6 +917,7 @@
         assert destrptr is not None
     
     def test_del_inheritance(self):
+        from pypy.rlib import rgc
         class State:
             pass
         s = State()
@@ -937,6 +938,7 @@
             A()
             B()
             C()
+            rgc.collect()
             return s.a_dels * 10 + s.b_dels
         res = f()
         assert res == 42
@@ -1067,6 +1069,7 @@
         assert meth.finalizer
 
     def test_del_inheritance(self):
+        from pypy.rlib import rgc
         class State:
             pass
         s = State()
@@ -1087,6 +1090,7 @@
             A()
             B()
             C()
+            rgc.collect()
             return s.a_dels * 10 + s.b_dels
         res = f()
         assert res == 42

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rint.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rint.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rint.py	Sat Dec 11 15:10:15 2010
@@ -4,14 +4,9 @@
 from pypy.annotation import model as annmodel
 from pypy.rpython.test import snippet
 from pypy.rlib.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong
-from pypy.rlib.rarithmetic import ovfcheck
+from pypy.rlib.rarithmetic import ovfcheck, r_int64
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
 
-if r_longlong is not r_int:
-    int64 = r_longlong
-else:
-    int64 = int
-
 
 class TestSnippet(object):
 
@@ -110,10 +105,10 @@
         def f(i):
             return str(i)
 
-        res = self.interpret(f, [int64(0)])
+        res = self.interpret(f, [r_int64(0)])
         assert self.ll_to_string(res) == '0'
 
-        res = self.interpret(f, [int64(413974738222117)])
+        res = self.interpret(f, [r_int64(413974738222117)])
         assert self.ll_to_string(res) == '413974738222117'
 
     def test_unsigned(self):
@@ -135,7 +130,7 @@
         f._annspecialcase_ = "specialize:argtype(0)"
         def g(n):
             if n > 0:
-                return f(int64(0))
+                return f(r_int64(0))
             else:
                 return f(0)
         res = self.interpret(g, [0])
@@ -147,7 +142,7 @@
     def test_downcast_int(self):
         def f(i):
             return int(i)
-        res = self.interpret(f, [int64(0)])
+        res = self.interpret(f, [r_int64(0)])
         assert res == 0
 
     def test_isinstance_vs_int_types(self):
@@ -157,7 +152,7 @@
                     return [None]
                 if isinstance(x, str):
                     return x
-                if isinstance(x, int64):
+                if isinstance(x, r_int64):
                     return int(x)
                 return "XXX"
             wrap._annspecialcase_ = 'specialize:argtype(0)'
@@ -165,7 +160,7 @@
         space = FakeSpace()
         def wrap(x):
             return space.wrap(x)
-        res = self.interpret(wrap, [int64(0)])
+        res = self.interpret(wrap, [r_int64(0)])
         assert res == 0
 
     def test_truediv(self):
@@ -178,25 +173,25 @@
     def test_float_conversion(self):
         def f(ii):
             return float(ii)
-        res = self.interpret(f, [int64(100000000)])
+        res = self.interpret(f, [r_int64(100000000)])
         assert type(res) is float
         assert res == 100000000.
-        res = self.interpret(f, [int64(1234567890123456789)])
+        res = self.interpret(f, [r_int64(1234567890123456789)])
         assert type(res) is float
         assert self.float_eq(res, 1.2345678901234568e+18)
 
     def test_float_conversion_implicit(self):
         def f(ii):
             return 1.0 + ii
-        res = self.interpret(f, [int64(100000000)])
+        res = self.interpret(f, [r_int64(100000000)])
         assert type(res) is float
         assert res == 100000001.
-        res = self.interpret(f, [int64(1234567890123456789)])
+        res = self.interpret(f, [r_int64(1234567890123456789)])
         assert type(res) is float
         assert self.float_eq(res, 1.2345678901234568e+18)
 
     def test_rarithmetic(self):
-        inttypes = [int, r_uint, int64, r_ulonglong]
+        inttypes = [int, r_uint, r_int64, r_ulonglong]
         for inttype in inttypes:
             c = inttype()
             def f():
@@ -231,16 +226,16 @@
             res = self.interpret(f, [int(-1<<(r_int.BITS-1))])
             assert res == 0
 
-            res = self.interpret(f, [int64(-1)])
+            res = self.interpret(f, [r_int64(-1)])
             assert res == 1
-            res = self.interpret(f, [int64(-1)<<(r_longlong.BITS-1)])
+            res = self.interpret(f, [r_int64(-1)<<(r_longlong.BITS-1)])
             assert res == 0
 
     div_mod_iteration_count = 1000
     def test_div_mod(self):
         import random
 
-        for inttype in (int, int64):
+        for inttype in (int, r_int64):
 
             def d(x, y):
                 return x/y
@@ -303,7 +298,7 @@
             except ZeroDivisionError:
                 return 84
 
-        for inttype in (int, int64):
+        for inttype in (int, r_int64):
 
             args = [( 5, 2), (-5, 2), ( 5,-2), (-5,-2),
                     ( 6, 2), (-6, 2), ( 6,-2), (-6,-2),

Modified: pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rlist.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rlist.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/rpython/test/test_rlist.py	Sat Dec 11 15:10:15 2010
@@ -12,6 +12,7 @@
 from pypy.rpython.rint import signed_repr
 from pypy.objspace.flow.model import Constant, Variable
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
+from pypy.rlib.debug import ll_assert
 
 # undo the specialization parameter
 for n1 in 'get set del'.split():
@@ -1076,7 +1077,13 @@
 
         res = self.interpret(f, [0])
         assert res == 1
-        py.test.raises(AssertionError, self.interpret, f, [1])
+        if self.type_system == 'lltype':
+            # on lltype we always get an AssertionError
+            py.test.raises(AssertionError, self.interpret, f, [1])
+        else:
+            # on ootype we happen to get through the ll_asserts and to
+            # hit the IndexError from ootype.py
+            self.interpret_raises(IndexError, f, [1])
 
         def f(x):
             l = [1]
@@ -1121,12 +1128,13 @@
 
         res = self.interpret(f, [0])
         assert res == 1
-        try:
-            self.interpret_raises(IndexError, f, [1])
-        except (AssertionError,), e:
-            pass
+        if self.type_system == 'lltype':
+            # on lltype we always get an AssertionError
+            py.test.raises(AssertionError, self.interpret, f, [1])
         else:
-            assert False
+            # on ootype we happen to get through the ll_asserts and to
+            # hit the IndexError from ootype.py
+            self.interpret_raises(IndexError, f, [1])
 
         def f(x):
             l = [1]
@@ -1163,12 +1171,13 @@
 
         res = self.interpret(f, [0])
         assert res == 1
-        try:
-            self.interpret_raises(IndexError, f, [1])
-        except (AssertionError,), e:
-            pass
+        if self.type_system == 'lltype':
+            # on lltype we always get an AssertionError
+            py.test.raises(AssertionError, self.interpret, f, [1])
         else:
-            assert False
+            # on ootype we happen to get through the ll_asserts and to
+            # hit the IndexError from ootype.py
+            self.interpret_raises(IndexError, f, [1])
 
     def test_charlist_extension_1(self):
         def f(n):
@@ -1327,8 +1336,32 @@
         res = self.interpret(f, [2])
         assert res == True
 
+    def test_immutable_list_out_of_instance(self):
+        from pypy.translator.simplify import get_funcobj
+        for immutable_fields in (["a", "b"], ["a", "b", "y[*]"]):
+            class A(object):
+                _immutable_fields_ = immutable_fields
+            class B(A):
+                pass
+            def f(i):
+                b = B()
+                lst = [i]
+                lst[0] += 1
+                b.y = lst
+                ll_assert(b.y is lst, "copying when reading out the attr?")
+                return b.y[0]
+            res = self.interpret(f, [10])
+            assert res == 11
+            t, rtyper, graph = self.gengraph(f, [int])
+            block = graph.startblock
+            op = block.operations[-1]
+            assert op.opname == 'direct_call'
+            func = get_funcobj(op.args[0].value)._callable
+            assert ('foldable' in func.func_name) == \
+                   ("y[*]" in immutable_fields)
 
 class TestLLtype(BaseTestRlist, LLRtypeMixin):
+    type_system = 'lltype'
     rlist = ll_rlist
 
     def test_memoryerror(self):
@@ -1420,14 +1453,16 @@
             lst2 = [i]
             lst2.append(42)    # mutated list
             return lst1[i] + lst2[i]
-        _, _, graph = self.gengraph(f, [int])
+        from pypy.annotation import model as annmodel
+        _, _, graph = self.gengraph(f, [annmodel.SomeInteger(nonneg=True)])
         block = graph.startblock
         lst1_getitem_op = block.operations[-3]     # XXX graph fishing
         lst2_getitem_op = block.operations[-2]
         func1 = lst1_getitem_op.args[0].value._obj._callable
         func2 = lst2_getitem_op.args[0].value._obj._callable
         assert func1.oopspec == 'list.getitem_foldable(l, index)'
-        assert func2.oopspec == 'list.getitem(l, index)'
+        assert not hasattr(func2, 'oopspec')
 
 class TestOOtype(BaseTestRlist, OORtypeMixin):
     rlist = oo_rlist
+    type_system = 'ootype'

Modified: pypy/branch/jit-unroll-loops/pypy/tool/ansi_print.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/tool/ansi_print.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/tool/ansi_print.py	Sat Dec 11 15:10:15 2010
@@ -16,6 +16,7 @@
         'WARNING': ((31,), False),
         'event': ((1,), True),
         'ERROR': ((1, 31), False),
+        'Error': ((1, 31), False),
         'info': ((35,), False),
         'stub': ((34,), False),
     }

Modified: pypy/branch/jit-unroll-loops/pypy/tool/error.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/tool/error.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/tool/error.py	Sat Dec 11 15:10:15 2010
@@ -120,7 +120,7 @@
         msg.append("      (%s getting at the binding!)" % (
             e.__class__.__name__,))
         return
-    for desc in descs.keys():
+    for desc in list(descs):
         func = desc.pyobj
         if func is None:
             r = repr(desc)

Modified: pypy/branch/jit-unroll-loops/pypy/tool/logparser.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/tool/logparser.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/tool/logparser.py	Sat Dec 11 15:10:15 2010
@@ -12,14 +12,6 @@
 from pypy.tool import progressbar
 
 def parse_log_file(filename, verbose=True):
-    r_start = re.compile(r"\[([0-9a-fA-F]+)\] \{([\w-]+)$")
-    r_stop  = re.compile(r"\[([0-9a-fA-F]+)\] ([\w-]+)\}$")
-    lasttime = 0
-    log = DebugLog()
-    time_decrase = False
-    performance_log = True
-    nested = 0
-    #
     f = open(filename, 'r')
     if f.read(2) == 'BZ':
         f.close()
@@ -30,19 +22,33 @@
     lines = f.readlines()
     f.close()
     #
-    if sys.stdout.isatty():
+    return parse_log(lines, verbose=verbose)
+
+def parse_log(lines, verbose=False):
+    color = "(?:\x1b.*?m)?"
+    r_start = re.compile(color + r"\[([0-9a-fA-F]+)\] \{([\w-]+)" + color + "$")
+    r_stop  = re.compile(color + r"\[([0-9a-fA-F]+)\] ([\w-]+)\}" + color + "$")
+    lasttime = 0
+    log = DebugLog()
+    time_decrase = False
+    performance_log = True
+    nested = 0
+    #
+    if verbose and sys.stdout.isatty():
         progress = progressbar.ProgressBar(color='green')
+        counter = 0
+    else:
+        progress = None
     single_percent = len(lines) / 100
     if verbose:
-        vnext = single_percent
+        vnext = 0
     else:
-        vnext = len(lines)
-    counter = 0
+        vnext = -1
     for i, line in enumerate(lines):
         if i == vnext:
-            counter += 1
-            if sys.stdout.isatty():
+            if progress is not None:
                 progress.render(counter)
+                counter += 1
                 vnext += single_percent
             else:
                 sys.stderr.write('%d%%..' % int(100.0*i/len(lines)))

Modified: pypy/branch/jit-unroll-loops/pypy/tool/release/force-builds.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/tool/release/force-builds.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/tool/release/force-builds.py	Sat Dec 11 15:10:15 2010
@@ -20,11 +20,12 @@
     'own-linux-x86-32',
     'own-linux-x86-64',
 #    'own-macosx-x86-32',
-    'pypy-c-app-level-linux-x86-32',
-    'pypy-c-app-level-linux-x86-64',
+#    'pypy-c-app-level-linux-x86-32',
+#    'pypy-c-app-level-linux-x86-64',
     'pypy-c-stackless-app-level-linux-x86-32',
     'pypy-c-app-level-win-x86-32',
     'pypy-c-jit-linux-x86-32',
+    'pypy-c-jit-linux-x86-64',
 #    'pypy-c-jit-macosx-x86-32',
     'pypy-c-jit-win-x86-32',
 ]

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

Modified: pypy/branch/jit-unroll-loops/pypy/tool/release/package.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/tool/release/package.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/tool/release/package.py	Sat Dec 11 15:10:15 2010
@@ -1,8 +1,12 @@
 #!/usr/bin/env python
 """ A sample script that packages PyPy, provided that it's already built.
-Usage:
+It uses 'pypy/translator/goal/pypy-c' and parts of the rest of the working
+copy.  Usage:
 
-package.py pypydir [name-of-archive] [name-of-pypy-c]
+    package.py root-pypy-dir [name-of-archive] [name-of-pypy-c]
+
+Usually you would do:   package.py ../../.. pypy-VER-PLATFORM.
+The output is found in the directory /tmp/usession-YOURNAME/build/.
 """
 
 import autopath
@@ -32,7 +36,7 @@
 class PyPyCNotFound(Exception):
     pass
 
-def package(basedir, name='pypy-nightly', rename_pypy_c='pypy-c',
+def package(basedir, name='pypy-nightly', rename_pypy_c='pypy',
             copy_to_dir = None, override_pypy_c = None):
     basedir = py.path.local(basedir)
     if sys.platform == 'win32':
@@ -64,13 +68,17 @@
     headers = includedir.listdir('*.h') + includedir.listdir('*.inl')
     for n in headers:
         shutil.copy(str(n), str(pypydir.join('include')))
+    #
+    spdir = pypydir.ensure('site-packages', dir=True)
+    shutil.copy(str(basedir.join('site-packages', 'README')), str(spdir))
+    #
     pypydir.ensure('bin', dir=True)
     archive_pypy_c = pypydir.join('bin', rename_pypy_c)
     shutil.copy(str(pypy_c), str(archive_pypy_c))
     old_dir = os.getcwd()
     try:
         os.chdir(str(builddir))
-        os.system("strip " + str(archive_pypy_c))    # ignore errors
+        os.system("strip -x " + str(archive_pypy_c))    # ignore errors
         if USE_TARFILE_MODULE:
             import tarfile
             tf = tarfile.open(str(builddir.join(name + '.tar.bz2')), 'w:bz2')

Modified: pypy/branch/jit-unroll-loops/pypy/tool/release/test/test_package.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/tool/release/test/test_package.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/tool/release/test/test_package.py	Sat Dec 11 15:10:15 2010
@@ -18,7 +18,7 @@
         prefix = builddir.join(test)
         cpyver = '%d.%d.%d' % CPYTHON_VERSION[:3]
         assert prefix.join('lib-python', cpyver, 'test').check()
-        assert prefix.join('bin', 'pypy-c').check()
+        assert prefix.join('bin', 'pypy').check()
         assert prefix.join('lib_pypy', 'syslog.py').check()
         assert not prefix.join('lib_pypy', 'py').check()
         assert not prefix.join('lib_pypy', 'ctypes_configure').check()

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

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/funcgen.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/funcgen.py	Sat Dec 11 15:10:15 2010
@@ -1,3 +1,4 @@
+import sys
 from pypy.translator.c.support import USESLOTS # set to False if necessary while refactoring
 from pypy.translator.c.support import cdecl
 from pypy.translator.c.support import llvalue_from_constant, gen_assignments
@@ -757,6 +758,16 @@
                 format.append('%s')
                 argv.append('(%s) ? "True" : "False"' % self.expr(arg))
                 continue
+            elif T == SignedLongLong:
+                if sys.platform == 'win32':
+                    format.append('%I64d')
+                else:
+                    format.append('%lld')
+            elif T == UnsignedLongLong:
+                if sys.platform == 'win32':
+                    format.append('%I64u')
+                else:
+                    format.append('%llu')
             else:
                 raise Exception("don't know how to debug_print %r" % (T,))
             argv.append(self.expr(arg))
@@ -765,17 +776,20 @@
             "if (PYPY_HAVE_DEBUG_PRINTS) { fprintf(PYPY_DEBUG_FILE, %s); %s}"
             % (', '.join(argv), free_line))
 
+    def _op_debug(self, opname, arg):
+        if isinstance(arg, Constant):
+            string_literal = c_string_constant(''.join(arg.value.chars))
+            return "%s(%s);" % (opname, string_literal)
+        else:
+            x = "%s(RPyString_AsCharP(%s));\n" % (opname, self.expr(arg))
+            x += "RPyString_FreeCache();"
+            return x
+
     def OP_DEBUG_START(self, op):
-        arg = op.args[0]
-        assert isinstance(arg, Constant)
-        return "PYPY_DEBUG_START(%s);" % (
-            c_string_constant(''.join(arg.value.chars)),)
+        return self._op_debug('PYPY_DEBUG_START', op.args[0])
 
     def OP_DEBUG_STOP(self, op):
-        arg = op.args[0]
-        assert isinstance(arg, Constant)
-        return "PYPY_DEBUG_STOP(%s);" % (
-            c_string_constant(''.join(arg.value.chars)),)
+        return self._op_debug('PYPY_DEBUG_STOP', op.args[0])
 
     def OP_DEBUG_ASSERT(self, op):
         return 'RPyAssert(%s, %s);' % (self.expr(op.args[0]),

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

Modified: pypy/branch/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	Sat Dec 11 15:10:15 2010
@@ -1107,7 +1107,7 @@
     format = 'darwin64'
     function_names_prefix = '_'
 
-    LABEL = ElfFunctionGcRootTracker32.LABEL
+    LABEL = ElfFunctionGcRootTracker64.LABEL
     r_jmptable_item = re.compile(r"\t.(?:long|quad)\t"+LABEL+"(-\"?[A-Za-z0-9$]+\"?)?\s*$")
 
     r_functionstart = re.compile(r"_(\w+):\s*$")
@@ -1406,6 +1406,7 @@
                      'const_data'
                      ]
     r_sectionstart = re.compile(r"\t\.("+'|'.join(OTHERSECTIONS)+").*$")
+    sections_doesnt_end_function = {'cstring': True, 'const': True}
 
     def find_functions(self, iterlines):
         functionlines = []
@@ -1413,20 +1414,20 @@
         in_function = False
         for n, line in enumerate(iterlines):
             if self.r_textstart.match(line):
-                assert not in_text, "unexpected repeated .text start: %d" % n
                 in_text = True
             elif self.r_sectionstart.match(line):
-                if in_function:
+                sectionname = self.r_sectionstart.match(line).group(1)
+                if (in_function and
+                    sectionname not in self.sections_doesnt_end_function):
                     yield in_function, functionlines
                     functionlines = []
+                    in_function = False
                 in_text = False
-                in_function = False
             elif in_text and self.FunctionGcRootTracker.r_functionstart.match(line):
                 yield in_function, functionlines
                 functionlines = []
                 in_function = True
             functionlines.append(line)
-
         if functionlines:
             yield in_function, functionlines
 
@@ -1443,23 +1444,6 @@
     format = "mingw32"
     FunctionGcRootTracker = Mingw32FunctionGcRootTracker
 
-    def find_functions(self, iterlines):
-        functionlines = []
-        in_text = False
-        in_function = False
-        for n, line in enumerate(iterlines):
-            if self.r_textstart.match(line):
-                in_text = True
-            elif self.r_sectionstart.match(line):
-                in_text = False
-            elif in_text and self.FunctionGcRootTracker.r_functionstart.match(line):
-                yield in_function, functionlines
-                functionlines = []
-                in_function = True
-            functionlines.append(line)
-        if functionlines:
-            yield in_function, functionlines
-
 class MsvcAssemblerParser(AssemblerParser):
     format = "msvc"
     FunctionGcRootTracker = MsvcFunctionGcRootTracker

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/src/debug_alloc.h
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/src/debug_alloc.h	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/src/debug_alloc.h	Sat Dec 11 15:10:15 2010
@@ -1,5 +1,5 @@
 /**************************************************************/
- /***  tracking raw mallocs and frees for debugging          ***/
+/***  tracking raw mallocs and frees for debugging          ***/
 
 #ifndef RPY_ASSERT
 
@@ -62,8 +62,8 @@
     count++;
   if (count > 0)
     {
-      fprintf(stderr, "debug_alloc.h: %ld mallocs left", count);
       char *env = getenv("PYPY_ALLOC");
+      fprintf(stderr, "debug_alloc.h: %ld mallocs left", count);
       if (env && *env)
         {
           fprintf(stderr, " (most recent first):\n");

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

Modified: pypy/branch/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	Sat Dec 11 15:10:15 2010
@@ -43,6 +43,10 @@
 #  include "src/asm_gcc_x86.h"
 #endif
 
+#if defined(__GNUC__) && defined(__amd64__)
+#  include "src/asm_gcc_x86_64.h"
+#endif
+
 #if defined(__GNUC__) && defined(__ppc__)
 #  include "src/asm_ppc.h"
 #endif

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/src/mem.h	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/src/mem.h	Sat Dec 11 15:10:15 2010
@@ -233,4 +233,4 @@
 #define OP_GC_GET_RPY_MEMORY_USAGE(x, r) r = -1
 #define OP_GC_GET_RPY_TYPE_INDEX(x, r)   r = -1
 #define OP_GC_IS_RPY_INSTANCE(x, r)      r = 0
-#define OP_GC_DUMP_RPY_HEAP(r)           r = 0
+#define OP_GC_DUMP_RPY_HEAP(fd, r)       r = 0

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_extfunc.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_extfunc.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_extfunc.py	Sat Dec 11 15:10:15 2010
@@ -755,3 +755,31 @@
         for i in range(5):
             res = func(i)
             assert res == os.uname()[i]
+
+if hasattr(os, 'getloadavg'):
+    def test_os_getloadavg():
+        def does_stuff():
+            a, b, c = os.getloadavg()
+            print a, b, c
+            return a + b + c
+        f = compile(does_stuff, [])
+        res = f()
+        assert type(res) is float and res >= 0.0
+
+if hasattr(os, 'fchdir'):
+    def test_os_fchdir():
+        def does_stuff():
+            fd = os.open('/', os.O_RDONLY, 0400)
+            try:
+                os.fchdir(fd)
+                s = os.getcwd()
+            finally:
+                os.close(fd)
+            return s == '/'
+        f = compile(does_stuff, [])
+        localdir = os.getcwd()
+        try:
+            res = f()
+        finally:
+            os.chdir(localdir)
+        assert res == True

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	Sat Dec 11 15:10:15 2010
@@ -1064,14 +1064,16 @@
     def test_get_rpy_type_index(self):
         self.run("get_rpy_type_index")
 
-    filename_dump = str(udir.join('test_dump_rpy_heap'))
+    filename1_dump = str(udir.join('test_dump_rpy_heap.1'))
+    filename2_dump = str(udir.join('test_dump_rpy_heap.2'))
     def define_dump_rpy_heap(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
+        filename1 = self.filename1_dump
+        filename2 = self.filename2_dump
 
         def fn():
             s = lltype.malloc(S)
@@ -1081,20 +1083,31 @@
             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)
+            fd1 = os.open(filename1, os.O_WRONLY | os.O_CREAT, 0666)
+            fd2 = os.open(filename2, os.O_WRONLY | os.O_CREAT, 0666)
+            rgc.dump_rpy_heap(fd1)
+            rgc.dump_rpy_heap(fd2)      # try twice in a row
             keepalive_until_here(s2)
             keepalive_until_here(s)
             keepalive_until_here(a)
-            os.close(fd)
+            os.close(fd1)
+            os.close(fd2)
             return 0
 
         return fn
 
     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) > 64
+        for fn in [self.filename1_dump, self.filename2_dump]:
+            assert os.path.exists(fn)
+            assert os.path.getsize(fn) > 64
+        f = open(self.filename1_dump)
+        data1 = f.read()
+        f.close()
+        f = open(self.filename2_dump)
+        data2 = f.read()
+        f.close()
+        assert data1 == data2
 
     filename_dump_typeids_z = str(udir.join('test_typeids_z'))
     def define_write_typeids_z(self):

Modified: pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_standalone.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/c/test/test_standalone.py	Sat Dec 11 15:10:15 2010
@@ -272,7 +272,7 @@
             x = "got:"
             debug_start  ("mycat")
             if have_debug_prints(): x += "b"
-            debug_print    ("foo", 2, "bar", 3)
+            debug_print    ("foo", r_longlong(2), "bar", 3)
             debug_start      ("cat2")
             if have_debug_prints(): x += "c"
             debug_print        ("baz")
@@ -368,12 +368,27 @@
         assert not err
         assert path.check(file=1)
         data = path.read()
-        assert 'toplevel' in path.read()
-        assert 'mycat' not in path.read()
-        assert 'foo 2 bar 3' not in path.read()
+        assert 'toplevel' in data
+        assert 'mycat' not in data
+        assert 'foo 2 bar 3' not in data
         assert 'cat2' in data
         assert 'baz' in data
         assert 'bok' not in data
+        # check with PYPYLOG=myc,cat2:somefilename   (includes mycat and cat2)
+        path = udir.join('test_debug_xxx_myc_cat2.log')
+        out, err = cbuilder.cmdexec("", err=True,
+                                    env={'PYPYLOG': 'myc,cat2:%s' % path})
+        assert out.strip() == 'got:bcda.'
+        assert not err
+        assert path.check(file=1)
+        data = path.read()
+        assert 'toplevel' in data
+        assert '{mycat' in data
+        assert 'mycat}' in data
+        assert 'foo 2 bar 3' in data
+        assert 'cat2' in data
+        assert 'baz' in data
+        assert 'bok' in data
         #
         # finally, check compiling with logging disabled
         from pypy.config.pypyoption import get_pypy_config
@@ -388,6 +403,20 @@
         assert not err
         assert path.check(file=0)
 
+    def test_debug_print_start_stop_nonconst(self):
+        def entry_point(argv):
+            debug_start(argv[1])
+            debug_print(argv[2])
+            debug_stop(argv[1])
+            return 0
+        t, cbuilder = self.compile(entry_point)
+        out, err = cbuilder.cmdexec("foo bar", err=True, env={'PYPYLOG': ':-'})
+        lines = err.splitlines()
+        assert '{foo' in lines[0]
+        assert 'bar' == lines[1]
+        assert 'foo}' in lines[2]
+
+
     def test_fatal_error(self):
         def g(x):
             if x == 1:

Modified: pypy/branch/jit-unroll-loops/pypy/translator/driver.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/driver.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/driver.py	Sat Dec 11 15:10:15 2010
@@ -11,7 +11,7 @@
 from pypy.annotation import policy as annpolicy
 import optparse
 from pypy.tool.udir import udir
-from pypy.rlib.jit import DEBUG_OFF, DEBUG_DETAILED, DEBUG_PROFILE, DEBUG_STEPS
+from pypy.tool.debug_print import debug_start, debug_print, debug_stop
 from pypy.rlib.entrypoint import secondary_entrypoints
 
 import py
@@ -37,13 +37,6 @@
     'c': 'lltype',
 }
 
-JIT_DEBUG = {
-    'off' : DEBUG_OFF,
-    'profile' : DEBUG_PROFILE,
-    'steps' : DEBUG_STEPS,
-    'detailed' : DEBUG_DETAILED,
-}
-
 def backend_to_typesystem(backend):
     return _BACKEND_TO_TYPESYSTEM.get(backend, 'ootype')
 
@@ -283,6 +276,8 @@
             return
         else:
             self.log.info("%s..." % title)
+        debug_start('translation-task')
+        debug_print('starting', goal)
         self.timer.start_event(goal)
         try:
             instrument = False
@@ -300,11 +295,13 @@
                 assert False, 'we should not get here'
         finally:
             try:
+                debug_stop('translation-task')
                 self.timer.end_event(goal)
             except (KeyboardInterrupt, SystemExit):
                 raise
             except:
                 pass
+        #import gc; gc.dump_rpy_heap('rpyheap-after-%s.dump' % goal)
         return res
 
     def task_annotate(self):
@@ -399,7 +396,6 @@
         #
         from pypy.jit.metainterp.warmspot import apply_jit
         apply_jit(self.translator, policy=self.jitpolicy,
-                  debug_level=JIT_DEBUG[self.config.translation.jit_debug],
                   backend_name=self.config.translation.jit_backend, inline=True)
         #
         self.log.info("the JIT compiler was generated")
@@ -417,7 +413,6 @@
         #
         from pypy.jit.metainterp.warmspot import apply_jit
         apply_jit(self.translator, policy=self.jitpolicy,
-                  debug_level=JIT_DEBUG[self.config.translation.jit_debug],
                   backend_name='cli', inline=True) #XXX
         #
         self.log.info("the JIT compiler was generated")

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	Sat Dec 11 15:10:15 2010
@@ -11,6 +11,7 @@
   -h, --help     show this help message and exit
   -m             library module to be run as a script (terminates option list)
   -W arg         warning control (arg is action:message:category:module:lineno)
+  -E             ignore environment variables (such as PYTHONPATH)
   --version      print the PyPy version
   --info         print translation information about this PyPy executable
 """
@@ -199,7 +200,7 @@
         break      # found!
     return newpath
 
-def setup_initial_paths(executable, nanos):
+def setup_initial_paths(executable, nanos, readenv=True, **extra):
     # a substituted os if we are translated
     global os
     os = nanos
@@ -220,7 +221,7 @@
     sys.executable = os.path.abspath(executable)
 
     newpath = get_library_path(executable)
-    path = os.getenv('PYTHONPATH')
+    path = readenv and os.getenv('PYTHONPATH')
     if path:
         newpath = path.split(os.pathsep) + newpath
     # remove duplicates
@@ -230,7 +231,6 @@
         if dir not in _seen:
             sys.path.append(dir)
             _seen[dir] = True
-    return executable
 
 
 def parse_command_line(argv):
@@ -242,6 +242,7 @@
     run_stdin = False
     warnoptions = []
     unbuffered = False
+    readenv = True
     while i < len(argv):
         arg = argv[i]
         if not arg.startswith('-'):
@@ -253,6 +254,8 @@
             argv[i] = '-c'
             run_command = True
             break
+        elif arg == '-E':
+            readenv = False
         elif arg == '-u':
             unbuffered = True
         elif arg == '-O' or arg == '-OO':
@@ -305,11 +308,13 @@
                      run_stdin,
                      warnoptions,
                      unbuffered,
+                     readenv,
                      cmd=None,
                      **ignored):
     # with PyPy in top of CPython we can only have around 100 
-    # but we need more in the translated PyPy for the compiler package 
-    sys.setrecursionlimit(5000)
+    # but we need more in the translated PyPy for the compiler package
+    if '__pypy__' not in sys.builtin_module_names:
+        sys.setrecursionlimit(5000)
 
     if unbuffered:
         set_unbuffered_io()
@@ -355,7 +360,7 @@
         #     * PYTHONINSPECT is set and stdin is a tty.
         #
         return (go_interactive or
-                (os.getenv('PYTHONINSPECT') and sys.stdin.isatty()))
+            (readenv and os.getenv('PYTHONINSPECT') and sys.stdin.isatty()))
 
     success = True
 
@@ -388,7 +393,7 @@
                 # If stdin is a tty or if "-i" is specified, we print
                 # a banner and run $PYTHONSTARTUP.
                 print_banner()
-                python_startup = os.getenv('PYTHONSTARTUP')
+                python_startup = readenv and os.getenv('PYTHONSTARTUP')
                 if python_startup:
                     try:
                         f = open(python_startup)
@@ -451,7 +456,6 @@
            '"license" for more information.')
 
 def entry_point(executable, argv, nanos):
-    executable = setup_initial_paths(executable, nanos)
     try:
         cmdline = parse_command_line(argv)
     except CommandLineError, e:
@@ -459,8 +463,8 @@
         return 2
     if cmdline is None:
         return 0
-    else:
-        return run_command_line(**cmdline)
+    setup_initial_paths(executable, nanos, **cmdline)
+    return run_command_line(**cmdline)
 
 
 if __name__ == '__main__':
@@ -495,13 +499,13 @@
     sys.pypy_version_info = PYPY_VERSION
     sys.pypy_initial_path = pypy_initial_path
     os = nanos.os_module_for_testing
-    sys.ps1 = '>>>> '
-    sys.ps2 = '.... '
     try:
         sys.exit(int(entry_point(sys.argv[0], sys.argv[1:], os)))
     finally:
-        sys.ps1 = '>>> '     # restore the normal ones, in case
-        sys.ps2 = '... '     # we are dropping to CPython's prompt
+        # restore the normal prompt (which was changed by _pypy_interact), in
+        # case we are dropping to CPython's prompt
+        sys.ps1 = '>>> '
+        sys.ps2 = '... '
         import os; os.environ.update(reset)
         assert old_argv is sys.argv
         assert old_path is sys.path

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	Sat Dec 11 15:10:15 2010
@@ -28,9 +28,14 @@
     w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish))
     w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup))
     w_os = setup_nanos(space)
+    withjit = space.config.objspace.usemodules.pypyjit
 
     def entry_point(argv):
         space.timer.start("Entrypoint")
+        if withjit:
+            from pypy.jit.backend.hlinfo import highleveljitinfo
+            highleveljitinfo.sys_executable = argv[0]
+
         #debug("entry point starting") 
         #for arg in argv: 
         #    debug(" argv -> " + arg)

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	Sat Dec 11 15:10:15 2010
@@ -217,6 +217,38 @@
         finally:
             os.environ['PYTHONSTARTUP'] = old
 
+    def test_ignore_python_startup(self):
+        old = os.environ.get('PYTHONSTARTUP', '')
+        try:
+            os.environ['PYTHONSTARTUP'] = crashing_demo_script
+            child = self.spawn(['-E'])
+            child.expect(re.escape(banner))
+            index = child.expect(['Traceback', '>>> '])
+            assert index == 1      # no traceback
+        finally:
+            os.environ['PYTHONSTARTUP'] = old
+
+    def test_ignore_python_inspect(self):
+        os.environ['PYTHONINSPECT_'] = '1'
+        try:
+            child = self.spawn(['-E', '-c', 'pass'])
+            from pexpect import EOF
+            index = child.expect(['>>> ', EOF])
+            assert index == 1      # no prompt
+        finally:
+            del os.environ['PYTHONINSPECT_']
+
+    def test_ignore_python_path(self):
+        old = os.environ.get('PYTHONPATH', '')
+        try:
+            os.environ['PYTHONPATH'] = 'foobarbaz'
+            child = self.spawn(['-E', '-c', 'import sys; print sys.path'])
+            from pexpect import EOF
+            index = child.expect(['foobarbaz', EOF])
+            assert index == 1      # no foobarbaz
+        finally:
+            os.environ['PYTHONPATH'] = old
+
     def test_unbuffered(self):
         line = 'import os,sys;sys.stdout.write(str(789));os.read(0,1)'
         child = self.spawn(['-u', '-c', line])
@@ -329,6 +361,10 @@
         child = self.spawn(['-mpypy.translator.goal.test2.mymodule'])
         child.expect('mymodule running')
 
+    def test_ps1_only_if_interactive(self):
+        argv = ['-c', 'import sys; print hasattr(sys, "ps1")']
+        child = self.spawn(argv)
+        child.expect('False')
 
 class TestNonInteractive:
 
@@ -534,7 +570,8 @@
             newpath = app_main.get_library_path('/tmp/pypy-c') # stdlib not found
             assert newpath == sys.path
             newpath = app_main.get_library_path(self.fake_exe)
-            assert newpath == self.expected_path
+            # we get at least 'expected_path', and maybe more (e.g.plat-linux2)
+            assert newpath[:len(self.expected_path)] == self.expected_path
         finally:
             sys.path.pop()
 
@@ -547,7 +584,9 @@
             app_main.os = os
             pypy_c = os.path.join(self.trunkdir, 'pypy', 'translator', 'goal', 'pypy-c')
             newpath = app_main.get_library_path(pypy_c)
-            assert len(newpath) == 3
+            # we get at least lib_pypy, lib-python/modified-X.Y.Z,
+            # lib-python/X.Y.Z, and maybe more (e.g. plat-linux2)
+            assert len(newpath) >= 3
             for p in newpath:
                 assert p.startswith(self.trunkdir)
         finally:

Modified: pypy/branch/jit-unroll-loops/pypy/translator/platform/__init__.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/platform/__init__.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/platform/__init__.py	Sat Dec 11 15:10:15 2010
@@ -123,7 +123,9 @@
             errorfile.write(stderr, 'wb')
             stderrlines = stderr.splitlines()
             for line in stderrlines:
-                log.ERROR(line)
+                log.Error(line)
+            # ^^^ don't use ERROR, because it might actually be fine.
+            # Also, ERROR confuses lib-python/conftest.py.
             raise CompilationError(stdout, stderr)
         else:
             for line in stderr.splitlines():
@@ -215,13 +217,13 @@
         host_factory = Darwin_i386
     else:
         host_factory = Darwin_x86_64
-elif sys.platform == 'freebsd7':
-    from pypy.translator.platform.freebsd7 import Freebsd7, Freebsd7_64
+elif "freebsd" in sys.platform:
+    from pypy.translator.platform.freebsd import Freebsd, Freebsd_64
     import platform
     if platform.architecture()[0] == '32bit':
-        host_factory = Freebsd7
+        host_factory = Freebsd
     else:
-        host_factory = Freebsd7_64
+        host_factory = Freebsd_64
 elif os.name == 'nt':
     from pypy.translator.platform.windows import Windows
     host_factory = Windows

Modified: pypy/branch/jit-unroll-loops/pypy/translator/platform/darwin.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/platform/darwin.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/platform/darwin.py	Sat Dec 11 15:10:15 2010
@@ -11,13 +11,17 @@
     shared_only = ()
 
     so_ext = 'so'
-    
+
+    # NOTE: GCC 4.2 will fail at runtime due to subtle issues, possibly
+    # related to GC roots. Using LLVM-GCC or Clang will break the build.
+    default_cc = 'gcc-4.0'
+
     def __init__(self, cc=None):
         if cc is None:
             try:
                 cc = os.environ['CC']
             except KeyError:
-                cc = 'gcc'
+                cc = self.default_cc
         self.cc = cc
 
     def _args_for_shared(self, args):

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

Modified: pypy/branch/jit-unroll-loops/pypy/translator/platform/posix.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/platform/posix.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/platform/posix.py	Sat Dec 11 15:10:15 2010
@@ -104,12 +104,10 @@
         else:
             target_name = exe_name.basename
 
-        cflags = self.cflags
-        if sys.maxint > 2147483647:   # XXX XXX XXX sort this out
-            if shared:
-                cflags = self.cflags + self.shared_only
-            else:
-                cflags = self.cflags + self.standalone_only
+        if shared:
+            cflags = self.cflags + self.shared_only
+        else:
+            cflags = self.cflags + self.standalone_only
 
         m = GnuMakefile(path)
         m.exe_name = exe_name

Modified: pypy/branch/jit-unroll-loops/pypy/translator/sandbox/test/test_sandbox.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/sandbox/test/test_sandbox.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/sandbox/test/test_sandbox.py	Sat Dec 11 15:10:15 2010
@@ -148,6 +148,7 @@
     if sys.platform == 'linux2':  # on Mac, uses another (sandboxsafe) approach
         expect(f, g, "ll_os.ll_os_open", ("/proc/cpuinfo", 0, 420),
                OSError(5232, "xyz"))
+    expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GC_DEBUG",), None)
     g.close()
     tail = f.read()
     f.close()

Modified: pypy/branch/jit-unroll-loops/pypy/translator/tool/cbuild.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/tool/cbuild.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/tool/cbuild.py	Sat Dec 11 15:10:15 2010
@@ -309,6 +309,7 @@
 #define _POSIX_C_SOURCE 200112L
 /* Define on FreeBSD to activate all library features */
 #define __BSD_VISIBLE 1
+#define __XSI_VISIBLE 700
 /* Windows: winsock/winsock2 mess */
 #define WIN32_LEAN_AND_MEAN
 '''

Modified: pypy/branch/jit-unroll-loops/pypy/translator/tool/reftracker.py
==============================================================================
--- pypy/branch/jit-unroll-loops/pypy/translator/tool/reftracker.py	(original)
+++ pypy/branch/jit-unroll-loops/pypy/translator/tool/reftracker.py	Sat Dec 11 15:10:15 2010
@@ -3,7 +3,7 @@
 Usage: call track(obj).
 """
 
-import autopath, sys, os
+import autopath, sys, os, types
 import gc
 from pypy.translator.tool.graphpage import GraphPage, DotGen
 from pypy.tool.uid import uid
@@ -39,7 +39,7 @@
                 if o2 is None:
                     continue
                 addedge(objectlist[i], o2)
-                id2typename[uid(o2)] = type(o2).__name__
+                id2typename[uid(o2)] = self.shortrepr(o2)
                 del o2
             for o2 in self.get_referrers(objectlist[i]):
                 if o2 is None:
@@ -47,7 +47,7 @@
                 if type(o2) is list and o2 and o2[0] is MARKER:
                     continue
                 addedge(o2, objectlist[i])
-                id2typename[uid(o2)] = type(o2).__name__
+                id2typename[uid(o2)] = self.shortrepr(o2)
                 del o2
 
         for ids, label in edges.items():
@@ -82,13 +82,23 @@
         return self.newpage(objectlist)
 
     def formatobject(self, o):
+        header = self.shortrepr(o, compact=False)
+        secondline = repr(o.__class__)
+        return header, secondline, repr(o)
+
+    def shortrepr(self, o, compact=True):
+        t = type(o)
+        if t is types.FrameType:
+            if compact:
+                return 'frame %r' % (o.f_code.co_name,)
+            else:
+                return 'frame %r' % (o.f_code,)
         s = repr(o)
         if len(s) > 50:
-            linktext = s
             s = s[:20] + ' ... ' + s[-20:]
-        else:
-            linktext = ''
-        return type(o).__name__, s, linktext
+        if s.startswith('<') and s.endswith('>'):
+            s = s[1:-1]
+        return s
 
     def edgelabel(self, o1, o2):
         return ''



More information about the Pypy-commit mailing list