[pypy-svn] r76955 - in pypy/branch/fast-forward: . lib-python lib-python/modified-2.5.2 lib-python/modified-2.5.2/ctypes lib-python/modified-2.5.2/test lib_pypy lib_pypy/_ctypes lib_pypy/pypy_test pypy/annotation pypy/annotation/test pypy/bin pypy/config pypy/doc pypy/doc/config pypy/interpreter pypy/interpreter/astcompiler pypy/interpreter/astcompiler/tools pypy/interpreter/test pypy/jit/backend pypy/jit/backend/llgraph pypy/jit/backend/llsupport pypy/jit/backend/llsupport/test pypy/jit/backend/test pypy/jit/backend/x86 pypy/jit/backend/x86/test pypy/jit/backend/x86/tool pypy/jit/codewriter pypy/jit/codewriter/test pypy/jit/metainterp pypy/jit/metainterp/doc pypy/jit/metainterp/test pypy/jit/tl pypy/jit/tool pypy/jit/tool/test pypy/module/__builtin__ pypy/module/__builtin__/test pypy/module/_ast pypy/module/_ast/test pypy/module/_codecs/test pypy/module/_demo pypy/module/_file pypy/module/_file/test pypy/module/_locale pypy/module/_rawffi/test pypy/module/_socket pypy/module/_socket/test pypy/module/_sre pypy/module/_sre/test pypy/module/_stackless pypy/module/array pypy/module/array/benchmark pypy/module/array/test pypy/module/cpyext pypy/module/cpyext/test pypy/module/fcntl/test pypy/module/marshal/test pypy/module/posix pypy/module/posix/test pypy/module/pypyjit pypy/module/pypyjit/test pypy/module/signal pypy/module/test_lib_pypy pypy/module/thread/test pypy/objspace/flow 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 pypy/rpython/memory/gc pypy/rpython/memory/gc/test pypy/rpython/memory/gctransform pypy/rpython/memory/test pypy/rpython/module pypy/rpython/module/test pypy/rpython/ootypesystem pypy/rpython/test pypy/rpython/tool pypy/tool pypy/tool/release pypy/tool/release/test pypy/translator pypy/translator/backendopt/test pypy/translator/c pypy/translator/c/gcc pypy/translator/c/gcc/test pypy/translator/c/gcc/test/elf64 pypy/translator/c/test pypy/translator/goal pypy/translator/goal/test2 pypy/translator/platform pypy/translator/platform/test

benjamin at codespeak.net benjamin at codespeak.net
Thu Sep 9 01:00:24 CEST 2010


Author: benjamin
Date: Thu Sep  9 01:00:13 2010
New Revision: 76955

Added:
   pypy/branch/fast-forward/lib_pypy/array.py
      - copied unchanged from r76954, pypy/trunk/lib_pypy/array.py
   pypy/branch/fast-forward/pypy/doc/config/objspace.usemodules.array.txt   (props changed)
      - copied unchanged from r76954, pypy/trunk/pypy/doc/config/objspace.usemodules.array.txt
   pypy/branch/fast-forward/pypy/jit/backend/x86/arch.py
      - copied unchanged from r76954, pypy/trunk/pypy/jit/backend/x86/arch.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/regloc.py
      - copied unchanged from r76954, pypy/trunk/pypy/jit/backend/x86/regloc.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/rx86.py
      - copied unchanged from r76954, pypy/trunk/pypy/jit/backend/x86/rx86.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regloc.py
      - copied unchanged from r76954, pypy/trunk/pypy/jit/backend/x86/test/test_regloc.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_rx86.py
      - copied unchanged from r76954, pypy/trunk/pypy/jit/backend/x86/test/test_rx86.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
      - copied unchanged from r76954, pypy/trunk/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py
      - copied unchanged from r76954, pypy/trunk/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/tool/instruction_encoding.sh
      - copied unchanged from r76954, pypy/trunk/pypy/jit/backend/x86/tool/instruction_encoding.sh
   pypy/branch/fast-forward/pypy/jit/tool/gen-trace-mode-keywords.py
      - copied unchanged from r76954, pypy/trunk/pypy/jit/tool/gen-trace-mode-keywords.py
   pypy/branch/fast-forward/pypy/jit/tool/pypytrace-mode.el
      - copied unchanged from r76954, pypy/trunk/pypy/jit/tool/pypytrace-mode.el
   pypy/branch/fast-forward/pypy/module/array/   (props changed)
      - copied from r76954, pypy/trunk/pypy/module/array/
   pypy/branch/fast-forward/pypy/module/test_lib_pypy/test_msvcrt.py
      - copied unchanged from r76954, pypy/trunk/pypy/module/test_lib_pypy/test_msvcrt.py
   pypy/branch/fast-forward/pypy/rlib/rsre/   (props changed)
      - copied from r76954, pypy/trunk/pypy/rlib/rsre/
   pypy/branch/fast-forward/pypy/rlib/rsre/__init__.py
      - copied unchanged from r76954, pypy/trunk/pypy/rlib/rsre/__init__.py
   pypy/branch/fast-forward/pypy/rlib/rsre/rsre_char.py
      - copied unchanged from r76954, pypy/trunk/pypy/rlib/rsre/rsre_char.py
   pypy/branch/fast-forward/pypy/rlib/rsre/rsre_core.py
      - copied unchanged from r76954, pypy/trunk/pypy/rlib/rsre/rsre_core.py
   pypy/branch/fast-forward/pypy/rlib/rsre/test/   (props changed)
      - copied from r76954, pypy/trunk/pypy/rlib/rsre/test/
   pypy/branch/fast-forward/pypy/rlib/rsre/test/__init__.py
      - copied unchanged from r76954, pypy/trunk/pypy/rlib/rsre/test/__init__.py
   pypy/branch/fast-forward/pypy/rlib/rsre/test/targetrsre.py
      - copied unchanged from r76954, pypy/trunk/pypy/rlib/rsre/test/targetrsre.py
   pypy/branch/fast-forward/pypy/rlib/rsre/test/test_search.py
      - copied unchanged from r76954, pypy/trunk/pypy/rlib/rsre/test/test_search.py
   pypy/branch/fast-forward/pypy/rlib/rsre/test/test_zinterp.py
      - copied unchanged from r76954, pypy/trunk/pypy/rlib/rsre/test/test_zinterp.py
   pypy/branch/fast-forward/pypy/rlib/test/test_rposix.py
      - copied unchanged from r76954, pypy/trunk/pypy/rlib/test/test_rposix.py
   pypy/branch/fast-forward/pypy/rpython/module/ll_win32file.py
      - copied unchanged from r76954, pypy/trunk/pypy/rpython/module/ll_win32file.py
   pypy/branch/fast-forward/pypy/translator/c/gcc/test/elf64/
      - copied from r76954, pypy/trunk/pypy/translator/c/gcc/test/elf64/
Removed:
   pypy/branch/fast-forward/lib-python/modified-2.5.2/test/test_re.py
   pypy/branch/fast-forward/lib_pypy/_sre.py
   pypy/branch/fast-forward/lib_pypy/greenlet.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/ri386.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/ri386setup.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_ri386.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_ri386_auto_encoding.py
   pypy/branch/fast-forward/pypy/jit/metainterp/doc/
   pypy/branch/fast-forward/pypy/module/_sre/app_sre.py
   pypy/branch/fast-forward/pypy/module/pypyjit/test/test_can_inline.py
   pypy/branch/fast-forward/pypy/module/test_lib_pypy/test_array.py
Modified:
   pypy/branch/fast-forward/   (props changed)
   pypy/branch/fast-forward/lib-python/conftest.py
   pypy/branch/fast-forward/lib-python/modified-2.5.2/ctypes/__init__.py
   pypy/branch/fast-forward/lib-python/modified-2.5.2/site.py
   pypy/branch/fast-forward/lib-python/modified-2.5.2/test/test_array.py
   pypy/branch/fast-forward/lib_pypy/_ctypes/__init__.py
   pypy/branch/fast-forward/lib_pypy/_ctypes/array.py
   pypy/branch/fast-forward/lib_pypy/_ctypes/builtin.py
   pypy/branch/fast-forward/lib_pypy/_ctypes/function.py
   pypy/branch/fast-forward/lib_pypy/_ctypes/primitive.py
   pypy/branch/fast-forward/lib_pypy/datetime.py
   pypy/branch/fast-forward/lib_pypy/msvcrt.py
   pypy/branch/fast-forward/lib_pypy/pypy_test/test_coroutine.py
   pypy/branch/fast-forward/lib_pypy/pypy_test/test_ctypes_support.py
   pypy/branch/fast-forward/lib_pypy/pypy_test/test_datetime.py
   pypy/branch/fast-forward/lib_pypy/stackless.py
   pypy/branch/fast-forward/pypy/annotation/binaryop.py
   pypy/branch/fast-forward/pypy/annotation/bookkeeper.py
   pypy/branch/fast-forward/pypy/annotation/builtin.py
   pypy/branch/fast-forward/pypy/annotation/classdef.py
   pypy/branch/fast-forward/pypy/annotation/model.py
   pypy/branch/fast-forward/pypy/annotation/specialize.py
   pypy/branch/fast-forward/pypy/annotation/test/test_annrpython.py
   pypy/branch/fast-forward/pypy/bin/py.py
   pypy/branch/fast-forward/pypy/config/pypyoption.py
   pypy/branch/fast-forward/pypy/config/translationoption.py
   pypy/branch/fast-forward/pypy/doc/faq.txt
   pypy/branch/fast-forward/pypy/interpreter/argument.py
   pypy/branch/fast-forward/pypy/interpreter/astcompiler/assemble.py
   pypy/branch/fast-forward/pypy/interpreter/astcompiler/ast.py
   pypy/branch/fast-forward/pypy/interpreter/astcompiler/codegen.py
   pypy/branch/fast-forward/pypy/interpreter/astcompiler/consts.py
   pypy/branch/fast-forward/pypy/interpreter/astcompiler/symtable.py
   pypy/branch/fast-forward/pypy/interpreter/astcompiler/tools/asdl_py.py
   pypy/branch/fast-forward/pypy/interpreter/baseobjspace.py
   pypy/branch/fast-forward/pypy/interpreter/error.py
   pypy/branch/fast-forward/pypy/interpreter/gateway.py
   pypy/branch/fast-forward/pypy/interpreter/generator.py
   pypy/branch/fast-forward/pypy/interpreter/pycode.py
   pypy/branch/fast-forward/pypy/interpreter/pyframe.py
   pypy/branch/fast-forward/pypy/interpreter/pyopcode.py
   pypy/branch/fast-forward/pypy/interpreter/test/test_code.py
   pypy/branch/fast-forward/pypy/interpreter/test/test_compiler.py
   pypy/branch/fast-forward/pypy/interpreter/test/test_gateway.py
   pypy/branch/fast-forward/pypy/interpreter/test/test_generator.py
   pypy/branch/fast-forward/pypy/interpreter/test/test_zpy.py
   pypy/branch/fast-forward/pypy/jit/backend/detect_cpu.py
   pypy/branch/fast-forward/pypy/jit/backend/llgraph/llimpl.py
   pypy/branch/fast-forward/pypy/jit/backend/llsupport/descr.py
   pypy/branch/fast-forward/pypy/jit/backend/llsupport/gc.py
   pypy/branch/fast-forward/pypy/jit/backend/llsupport/regalloc.py
   pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_descr.py
   pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_gc.py
   pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_regalloc.py
   pypy/branch/fast-forward/pypy/jit/backend/test/runner_test.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/assembler.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/codebuf.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/jump.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/regalloc.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/runner.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/conftest.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_assembler.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_basic.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_gc_integration.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_jump.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_recompilation.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regalloc.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regalloc2.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_runner.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_symbolic_x86.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_zll_random.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_zrpy_gc.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_ztranslation.py
   pypy/branch/fast-forward/pypy/jit/backend/x86/tool/viewcode.py
   pypy/branch/fast-forward/pypy/jit/codewriter/assembler.py
   pypy/branch/fast-forward/pypy/jit/codewriter/jitcode.py
   pypy/branch/fast-forward/pypy/jit/codewriter/jtransform.py
   pypy/branch/fast-forward/pypy/jit/codewriter/test/test_flatten.py
   pypy/branch/fast-forward/pypy/jit/metainterp/blackhole.py
   pypy/branch/fast-forward/pypy/jit/metainterp/executor.py
   pypy/branch/fast-forward/pypy/jit/metainterp/history.py
   pypy/branch/fast-forward/pypy/jit/metainterp/jitdriver.py
   pypy/branch/fast-forward/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/fast-forward/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/fast-forward/pypy/jit/metainterp/resoperation.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_basic.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_executor.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_immutable.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_jitdriver.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_loop.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_loop_spec.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_recursive.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_virtualizable.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_warmspot.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_warmstate.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_ztranslation.py
   pypy/branch/fast-forward/pypy/jit/metainterp/warmspot.py
   pypy/branch/fast-forward/pypy/jit/metainterp/warmstate.py
   pypy/branch/fast-forward/pypy/jit/tl/pypyjit.py
   pypy/branch/fast-forward/pypy/jit/tl/pypyjit_demo.py
   pypy/branch/fast-forward/pypy/jit/tool/test/test_traceviewer.py
   pypy/branch/fast-forward/pypy/jit/tool/traceviewer.py
   pypy/branch/fast-forward/pypy/module/__builtin__/compiling.py
   pypy/branch/fast-forward/pypy/module/__builtin__/functional.py
   pypy/branch/fast-forward/pypy/module/__builtin__/interp_classobj.py
   pypy/branch/fast-forward/pypy/module/__builtin__/test/test_buffer.py
   pypy/branch/fast-forward/pypy/module/__builtin__/test/test_classobj.py
   pypy/branch/fast-forward/pypy/module/_ast/__init__.py
   pypy/branch/fast-forward/pypy/module/_ast/test/test_ast.py
   pypy/branch/fast-forward/pypy/module/_codecs/test/test_codecs.py
   pypy/branch/fast-forward/pypy/module/_demo/demo.py
   pypy/branch/fast-forward/pypy/module/_file/interp_file.py
   pypy/branch/fast-forward/pypy/module/_file/test/test_file.py
   pypy/branch/fast-forward/pypy/module/_file/test/test_file_extra.py
   pypy/branch/fast-forward/pypy/module/_locale/__init__.py
   pypy/branch/fast-forward/pypy/module/_rawffi/test/test__rawffi.py
   pypy/branch/fast-forward/pypy/module/_socket/interp_socket.py
   pypy/branch/fast-forward/pypy/module/_socket/test/test_sock_app.py
   pypy/branch/fast-forward/pypy/module/_sre/__init__.py
   pypy/branch/fast-forward/pypy/module/_sre/interp_sre.py
   pypy/branch/fast-forward/pypy/module/_sre/test/test_app_sre.py
   pypy/branch/fast-forward/pypy/module/_stackless/interp_coroutine.py
   pypy/branch/fast-forward/pypy/module/array/benchmark/   (props changed)
   pypy/branch/fast-forward/pypy/module/array/test/   (props changed)
   pypy/branch/fast-forward/pypy/module/cpyext/api.py
   pypy/branch/fast-forward/pypy/module/cpyext/methodobject.py
   pypy/branch/fast-forward/pypy/module/cpyext/stubs.py
   pypy/branch/fast-forward/pypy/module/cpyext/test/test_unicodeobject.py
   pypy/branch/fast-forward/pypy/module/cpyext/unicodeobject.py
   pypy/branch/fast-forward/pypy/module/fcntl/test/test_fcntl.py
   pypy/branch/fast-forward/pypy/module/marshal/test/test_marshalimpl.py
   pypy/branch/fast-forward/pypy/module/posix/interp_posix.py
   pypy/branch/fast-forward/pypy/module/posix/test/test_posix2.py
   pypy/branch/fast-forward/pypy/module/pypyjit/interp_jit.py
   pypy/branch/fast-forward/pypy/module/pypyjit/policy.py
   pypy/branch/fast-forward/pypy/module/pypyjit/test/test_pypy_c.py
   pypy/branch/fast-forward/pypy/module/signal/interp_signal.py
   pypy/branch/fast-forward/pypy/module/thread/test/test_gil.py
   pypy/branch/fast-forward/pypy/objspace/flow/specialcase.py
   pypy/branch/fast-forward/pypy/objspace/std/callmethod.py
   pypy/branch/fast-forward/pypy/objspace/std/intobject.py
   pypy/branch/fast-forward/pypy/objspace/std/itertype.py
   pypy/branch/fast-forward/pypy/objspace/std/model.py
   pypy/branch/fast-forward/pypy/objspace/std/objspace.py
   pypy/branch/fast-forward/pypy/objspace/std/test/test_callmethod.py
   pypy/branch/fast-forward/pypy/objspace/std/tupleobject.py
   pypy/branch/fast-forward/pypy/rlib/debug.py
   pypy/branch/fast-forward/pypy/rlib/jit.py
   pypy/branch/fast-forward/pypy/rlib/objectmodel.py
   pypy/branch/fast-forward/pypy/rlib/rarithmetic.py
   pypy/branch/fast-forward/pypy/rlib/rlocale.py
   pypy/branch/fast-forward/pypy/rlib/rmmap.py
   pypy/branch/fast-forward/pypy/rlib/rposix.py
   pypy/branch/fast-forward/pypy/rlib/rsha.py
   pypy/branch/fast-forward/pypy/rlib/rsocket.py
   pypy/branch/fast-forward/pypy/rlib/rweakref.py
   pypy/branch/fast-forward/pypy/rlib/rwin32.py
   pypy/branch/fast-forward/pypy/rlib/rzipfile.py
   pypy/branch/fast-forward/pypy/rlib/streamio.py
   pypy/branch/fast-forward/pypy/rlib/test/test_jit.py
   pypy/branch/fast-forward/pypy/rlib/test/test_objectmodel.py
   pypy/branch/fast-forward/pypy/rpython/extfunc.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/ll2ctypes.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/llgroup.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/llmemory.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/lloperation.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/lltype.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/opimpl.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/rffi.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/rstr.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_llgroup.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_lloperation.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_lltype.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_rffi.py
   pypy/branch/fast-forward/pypy/rpython/memory/gc/base.py
   pypy/branch/fast-forward/pypy/rpython/memory/gc/generation.py
   pypy/branch/fast-forward/pypy/rpython/memory/gc/markcompact.py
   pypy/branch/fast-forward/pypy/rpython/memory/gc/test/test_direct.py
   pypy/branch/fast-forward/pypy/rpython/memory/gctransform/asmgcroot.py
   pypy/branch/fast-forward/pypy/rpython/memory/gctypelayout.py
   pypy/branch/fast-forward/pypy/rpython/memory/gcwrapper.py
   pypy/branch/fast-forward/pypy/rpython/memory/test/test_gc.py
   pypy/branch/fast-forward/pypy/rpython/memory/test/test_gctypelayout.py
   pypy/branch/fast-forward/pypy/rpython/memory/test/test_transformed_gc.py
   pypy/branch/fast-forward/pypy/rpython/module/ll_os.py
   pypy/branch/fast-forward/pypy/rpython/module/ll_os_stat.py
   pypy/branch/fast-forward/pypy/rpython/module/ll_time.py
   pypy/branch/fast-forward/pypy/rpython/module/test/test_ll_os_stat.py
   pypy/branch/fast-forward/pypy/rpython/ootypesystem/ootype.py
   pypy/branch/fast-forward/pypy/rpython/ootypesystem/rclass.py
   pypy/branch/fast-forward/pypy/rpython/rbuiltin.py
   pypy/branch/fast-forward/pypy/rpython/rclass.py
   pypy/branch/fast-forward/pypy/rpython/rstr.py
   pypy/branch/fast-forward/pypy/rpython/test/test_extfunc.py
   pypy/branch/fast-forward/pypy/rpython/test/test_rclass.py
   pypy/branch/fast-forward/pypy/rpython/test/test_rint.py
   pypy/branch/fast-forward/pypy/rpython/tool/rfficache.py
   pypy/branch/fast-forward/pypy/tool/release/package.py
   pypy/branch/fast-forward/pypy/tool/release/test/test_package.py
   pypy/branch/fast-forward/pypy/tool/runsubprocess.py
   pypy/branch/fast-forward/pypy/translator/backendopt/test/test_constfold.py
   pypy/branch/fast-forward/pypy/translator/c/database.py
   pypy/branch/fast-forward/pypy/translator/c/gc.py
   pypy/branch/fast-forward/pypy/translator/c/gcc/instruction.py
   pypy/branch/fast-forward/pypy/translator/c/gcc/test/conftest.py
   pypy/branch/fast-forward/pypy/translator/c/gcc/test/test_trackgcroot.py
   pypy/branch/fast-forward/pypy/translator/c/gcc/trackgcroot.py
   pypy/branch/fast-forward/pypy/translator/c/genc.py
   pypy/branch/fast-forward/pypy/translator/c/node.py
   pypy/branch/fast-forward/pypy/translator/c/test/test_newgc.py
   pypy/branch/fast-forward/pypy/translator/c/test/test_standalone.py
   pypy/branch/fast-forward/pypy/translator/exceptiontransform.py
   pypy/branch/fast-forward/pypy/translator/goal/app_main.py
   pypy/branch/fast-forward/pypy/translator/goal/test2/test_app_main.py
   pypy/branch/fast-forward/pypy/translator/goal/translate.py
   pypy/branch/fast-forward/pypy/translator/platform/__init__.py
   pypy/branch/fast-forward/pypy/translator/platform/darwin.py
   pypy/branch/fast-forward/pypy/translator/platform/freebsd7.py
   pypy/branch/fast-forward/pypy/translator/platform/linux.py
   pypy/branch/fast-forward/pypy/translator/platform/maemo.py
   pypy/branch/fast-forward/pypy/translator/platform/posix.py
   pypy/branch/fast-forward/pypy/translator/platform/test/test_platform.py
   pypy/branch/fast-forward/pypy/translator/platform/windows.py
Log:
merge from trunk

Modified: pypy/branch/fast-forward/lib-python/conftest.py
==============================================================================
--- pypy/branch/fast-forward/lib-python/conftest.py	(original)
+++ pypy/branch/fast-forward/lib-python/conftest.py	Thu Sep  9 01:00:13 2010
@@ -137,7 +137,7 @@
     RegrTest('test_ast.py', core=True),
     RegrTest('test_anydbm.py'),
     RegrTest('test_applesingle.py', skip=True),
-    RegrTest('test_array.py', core=True, usemodules='struct'),
+    RegrTest('test_array.py', core=True, usemodules='struct array'),
     RegrTest('test_ascii_formatd.py'),
     RegrTest('test_asynchat.py', usemodules='thread'),
     RegrTest('test_asyncore.py'),
@@ -514,11 +514,7 @@
     RegrTest('test_coding.py'),
     RegrTest('test_complex_args.py'),
     RegrTest('test_contextlib.py', usemodules="thread"),
-    # we skip test ctypes, since we adapted it massively in order
-    # to test what we want to support. There are real failures,
-    # but it's about missing features that we don't want to support
-    # now
-    RegrTest('test_ctypes.py', skip="we have a replacement"),
+    RegrTest('test_ctypes.py', usemodules="_rawffi"),
     RegrTest('test_defaultdict.py'),
     RegrTest('test_email_renamed.py'),
     RegrTest('test_exception_variations.py'),

Modified: pypy/branch/fast-forward/lib-python/modified-2.5.2/ctypes/__init__.py
==============================================================================
--- pypy/branch/fast-forward/lib-python/modified-2.5.2/ctypes/__init__.py	(original)
+++ pypy/branch/fast-forward/lib-python/modified-2.5.2/ctypes/__init__.py	Thu Sep  9 01:00:13 2010
@@ -471,7 +471,7 @@
 
 # functions
 
-from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
+from _ctypes import _memmove_addr, _memset_addr, _cast_addr
 
 ## void *memmove(void *, const void *, size_t);
 memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
@@ -490,24 +490,34 @@
 def cast(obj, typ):
     return _cast(obj, obj, typ)
 
-_string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
+try:
+    from _ctypes import _string_at_addr
+except ImportError:
+    from _ctypes import _string_at
+else:
+    _string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
+
 def string_at(ptr, size=-1):
     """string_at(addr[, size]) -> string
 
     Return the string at addr."""
     return _string_at(ptr, size)
 
+def wstring_at(ptr, size=-1):
+    """wstring_at(addr[, size]) -> string
+
+    Return the string at addr."""
+    return _wstring_at(ptr, size)
+
 try:
     from _ctypes import _wstring_at_addr
 except ImportError:
-    pass
+    try:
+        from _ctypes import _wstring_at
+    except ImportError:
+        del wstring_at
 else:
     _wstring_at = CFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr)
-    def wstring_at(ptr, size=-1):
-        """wstring_at(addr[, size]) -> string
-
-        Return the string at addr."""
-        return _wstring_at(ptr, size)
 
 
 if _os.name in ("nt", "ce"): # COM stuff

Modified: pypy/branch/fast-forward/lib-python/modified-2.5.2/site.py
==============================================================================
--- pypy/branch/fast-forward/lib-python/modified-2.5.2/site.py	(original)
+++ pypy/branch/fast-forward/lib-python/modified-2.5.2/site.py	Thu Sep  9 01:00:13 2010
@@ -175,7 +175,7 @@
 
 def addsitepackages(known_paths):
     """Add site-packages to sys.path, in a PyPy-specific way."""
-    if hasattr(sys, 'pypy_version_info'):
+    if hasattr(sys, 'pypy_version_info') and hasattr(sys, 'prefix'):
         from distutils.sysconfig import get_python_lib
         sitedir = get_python_lib(standard_lib=False)
         if os.path.isdir(sitedir):

Modified: pypy/branch/fast-forward/lib-python/modified-2.5.2/test/test_array.py
==============================================================================
--- pypy/branch/fast-forward/lib-python/modified-2.5.2/test/test_array.py	(original)
+++ pypy/branch/fast-forward/lib-python/modified-2.5.2/test/test_array.py	Thu Sep  9 01:00:13 2010
@@ -269,9 +269,11 @@
         )
 
         b = array.array(self.badtypecode())
-        self.assertRaises(TypeError, a.__add__, b)
+        #self.assertRaises(TypeError, a.__add__, b)
+        #self.assertRaises(TypeError, a.__add__, "bad")
+        self.assertRaises(TypeError, lambda i, j: i + j, a, b)
+        self.assertRaises(TypeError, lambda i, j: i + j, a, "bad")
 
-        self.assertRaises(TypeError, a.__add__, "bad")
 
     def test_iadd(self):
         a = array.array(self.typecode, self.example[::-1])
@@ -284,9 +286,12 @@
         )
 
         b = array.array(self.badtypecode())
-        self.assertRaises(TypeError, a.__add__, b)
-
-        self.assertRaises(TypeError, a.__iadd__, "bad")
+        #self.assertRaises(TypeError, a.__add__, b)
+        #self.assertRaises(TypeError, a.__iadd__, "bad")
+        def f(i, j):
+            i += j
+        self.assertRaises(TypeError, f, a, b)
+        self.assertRaises(TypeError, f, a, "bad")
 
     def test_mul(self):
         a = 5*array.array(self.typecode, self.example)
@@ -313,7 +318,8 @@
             array.array(self.typecode)
         )
 
-        self.assertRaises(TypeError, a.__mul__, "bad")
+        #self.assertRaises(TypeError, a.__mul__, "bad")
+        self.assertRaises(TypeError, lambda i, j: i * j, a, "bad")
 
     def test_imul(self):
         a = array.array(self.typecode, self.example)
@@ -342,7 +348,10 @@
         a *= -1
         self.assertEqual(a, array.array(self.typecode))
 
-        self.assertRaises(TypeError, a.__imul__, "bad")
+        #self.assertRaises(TypeError, a.__imul__, "bad")
+        def f(i, j):
+            i *= j
+        self.assertRaises(TypeError, f, a, "bad")        
 
     def test_getitem(self):
         a = array.array(self.typecode, self.example)

Modified: pypy/branch/fast-forward/lib_pypy/_ctypes/__init__.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/_ctypes/__init__.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/_ctypes/__init__.py	Thu Sep  9 01:00:13 2010
@@ -7,8 +7,8 @@
 from _ctypes.dll import dlopen
 from _ctypes.structure import Structure
 from _ctypes.array import Array
-from _ctypes.builtin import _memmove_addr, _string_at_addr, _memset_addr,\
-     set_conversion_mode, _wstring_at_addr
+from _ctypes.builtin import _memmove_addr, _string_at, _memset_addr,\
+     set_conversion_mode, _wstring_at
 from _ctypes.union import Union
 
 import os as _os

Modified: pypy/branch/fast-forward/lib_pypy/_ctypes/array.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/_ctypes/array.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/_ctypes/array.py	Thu Sep  9 01:00:13 2010
@@ -4,7 +4,6 @@
 from _ctypes.basics import _CData, cdata_from_address, _CDataMeta, sizeof
 from _ctypes.basics import keepalive_key, store_reference, ensure_objects
 from _ctypes.basics import CArgObject
-from _ctypes.builtin import _string_at_addr, _wstring_at_addr
 
 def _create_unicode(buffer, maxlength):
     res = []
@@ -76,7 +75,7 @@
 
     def _CData_output(self, resarray, base=None, index=-1):
         # this seems to be a string if we're array of char, surprise!
-        from ctypes import c_char, c_wchar, c_char_p, c_wchar_p
+        from ctypes import c_char, c_wchar
         if self._type_ is c_char:
             return _rawffi.charp2string(resarray.buffer, self._length_)
         if self._type_ is c_wchar:

Modified: pypy/branch/fast-forward/lib_pypy/_ctypes/builtin.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/_ctypes/builtin.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/_ctypes/builtin.py	Thu Sep  9 01:00:13 2010
@@ -8,10 +8,10 @@
 _memmove_addr = _rawffi.get_libc().getaddressindll('memmove')
 _memset_addr = _rawffi.get_libc().getaddressindll('memset')
 
-def _string_at_addr(addr, lgt):
+def _string_at(addr, lgt):
     # address here can be almost anything
     import ctypes
-    arg = ctypes.c_char_p._CData_value(addr)
+    arg = ctypes.c_void_p._CData_value(addr)
     return _rawffi.charp2rawstring(arg, lgt)
 
 def set_conversion_mode(encoding, errors):
@@ -20,9 +20,9 @@
     ConvMode.encoding = encoding
     return old_cm
 
-def _wstring_at_addr(addr, lgt):
+def _wstring_at(addr, lgt):
     import ctypes
-    arg = ctypes.c_wchar_p._CData_value(addr)
+    arg = ctypes.c_void_p._CData_value(addr)
     # XXX purely applevel
     if lgt == -1:
         lgt = sys.maxint

Modified: pypy/branch/fast-forward/lib_pypy/_ctypes/function.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/_ctypes/function.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/_ctypes/function.py	Thu Sep  9 01:00:13 2010
@@ -60,7 +60,6 @@
         return self._restype_
     def _setrestype(self, restype):
         self._ptr = None
-        from ctypes import c_char_p
         if restype is int:
             from ctypes import c_int
             restype = c_int
@@ -214,9 +213,7 @@
 
     @staticmethod
     def _guess_argtypes(args):
-        from _ctypes import _CData
         from ctypes import c_char_p, c_wchar_p, c_void_p, c_int
-        from ctypes import Array, Structure
         res = []
         for arg in args:
             if hasattr(arg, '_as_parameter_'):

Modified: pypy/branch/fast-forward/lib_pypy/_ctypes/primitive.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/_ctypes/primitive.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/_ctypes/primitive.py	Thu Sep  9 01:00:13 2010
@@ -57,7 +57,6 @@
 pyobj_container = GlobalPyobjContainer()
 
 def generic_xxx_p_from_param(cls, value):
-    from _ctypes import Array, _Pointer
     if value is None:
         return cls(None)
     if isinstance(value, basestring):
@@ -86,6 +85,8 @@
         return value
     if isinstance(value, _Pointer):
         return cls.from_address(value._buffer.buffer)
+    if isinstance(value, (int, long)):
+        return cls(value)
 
 FROM_PARAM_BY_TYPE = {
     'z': from_param_char_p,
@@ -117,8 +118,6 @@
         result._ffiarray = ffiarray
         if tp == 'z':
             # c_char_p
-            from _ctypes import Array, _Pointer
-
             def _getvalue(self):
                 addr = self._buffer[0]
                 if addr == 0:
@@ -141,13 +140,13 @@
             result.value = property(_getvalue, _setvalue)
         elif tp == 'Z':
             # c_wchar_p
-            from _ctypes import Array, _Pointer, _wstring_at_addr
+            from _ctypes import _wstring_at
             def _getvalue(self):
                 addr = self._buffer[0]
                 if addr == 0:
                     return None
                 else:
-                    return _wstring_at_addr(addr, -1)
+                    return _wstring_at(addr, -1)
 
             def _setvalue(self, value):
                 if isinstance(value, basestring):
@@ -216,14 +215,14 @@
             SysAllocStringLen = windll.oleaut32.SysAllocStringLen
             SysStringLen = windll.oleaut32.SysStringLen
             SysFreeString = windll.oleaut32.SysFreeString
-            from _ctypes import _wstring_at_addr
+            from _ctypes import _wstring_at
             def _getvalue(self):
                 addr = self._buffer[0]
                 if addr == 0:
                     return None
                 else:
                     size = SysStringLen(addr)
-                    return _wstring_at_addr(addr, size)
+                    return _wstring_at(addr, size)
 
             def _setvalue(self, value):
                 if isinstance(value, basestring):
@@ -254,18 +253,21 @@
     from_address = cdata_from_address
 
     def from_param(self, value):
+        if isinstance(value, self):
+            return value
+        
         from_param_f = FROM_PARAM_BY_TYPE.get(self._type_)
         if from_param_f:
             res = from_param_f(self, value)
             if res is not None:
                 return res
-            
-        if isinstance(value, self):
-            return value
-        try:
-            return self(value)
-        except (TypeError, ValueError):
-            return super(SimpleType, self).from_param(value)
+        else:
+            try:
+                return self(value)
+            except (TypeError, ValueError):
+                pass
+
+        return super(SimpleType, self).from_param(value)
 
     def _CData_output(self, resbuffer, base=None, index=-1):
         output = super(SimpleType, self)._CData_output(resbuffer, base, index)

Modified: pypy/branch/fast-forward/lib_pypy/datetime.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/datetime.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/datetime.py	Thu Sep  9 01:00:13 2010
@@ -1412,7 +1412,7 @@
 
     def utcfromtimestamp(cls, t):
         "Construct a UTC datetime from a POSIX timestamp (like time.time())."
-        if 1 - (t % 1.0) < 0.000001:
+        if 1 - (t % 1.0) < 0.0000005:
             t = float(int(t)) + 1
         if t < 0:
             t -= 1

Modified: pypy/branch/fast-forward/lib_pypy/msvcrt.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/msvcrt.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/msvcrt.py	Thu Sep  9 01:00:13 2010
@@ -5,9 +5,12 @@
 """
 
 # XXX incomplete: implemented only functions needed by subprocess.py
+# PAC: 2010/08 added MS locking for Whoosh
 
 import ctypes
 from ctypes_support import standard_c_lib as _c
+from ctypes_support import get_errno
+import errno
 
 try:
     open_osfhandle = _c._open_osfhandle
@@ -25,4 +28,17 @@
 setmode.argtypes = [ctypes.c_int, ctypes.c_int]
 setmode.restype = ctypes.c_int
 
+LK_UNLCK, LK_LOCK, LK_NBLCK, LK_RLCK, LK_NBRLCK = range(5)
+
+_locking = _c._locking
+_locking.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int]
+_locking.restype = ctypes.c_int
+
+def locking(fd, mode, nbytes):
+    '''lock or unlock a number of bytes in a file.'''
+    rv = _locking(fd, mode, nbytes)
+    if rv != 0:
+        e = get_errno()
+        raise IOError(e, errno.errorcode[e])
+
 del ctypes

Modified: pypy/branch/fast-forward/lib_pypy/pypy_test/test_coroutine.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/pypy_test/test_coroutine.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/pypy_test/test_coroutine.py	Thu Sep  9 01:00:13 2010
@@ -2,7 +2,7 @@
 from py.test import skip, raises
 
 try:
-    from ..stackless import coroutine
+    from ..stackless import coroutine, CoroutineExit
 except ImportError, e:
     skip('cannot import stackless: %s' % (e,))
 

Modified: pypy/branch/fast-forward/lib_pypy/pypy_test/test_ctypes_support.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/pypy_test/test_ctypes_support.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/pypy_test/test_ctypes_support.py	Thu Sep  9 01:00:13 2010
@@ -20,3 +20,14 @@
     assert get_errno() != 0
     set_errno(0)
     assert get_errno() == 0
+
+def test_argument_conversion_and_checks():
+    import ctypes
+    libc = ctypes.cdll.LoadLibrary("libc.so.6")
+    libc.strlen.argtypes = ctypes.c_char_p,
+    libc.strlen.restype = ctypes.c_size_t
+    assert libc.strlen("eggs") == 4
+    
+    # Should raise ArgumentError, not segfault
+    py.test.raises(ctypes.ArgumentError, libc.strlen, False)
+

Modified: pypy/branch/fast-forward/lib_pypy/pypy_test/test_datetime.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/pypy_test/test_datetime.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/pypy_test/test_datetime.py	Thu Sep  9 01:00:13 2010
@@ -15,4 +15,18 @@
     expected = datetime.datetime(*(time.strptime(string, format)[0:6]))
     got = datetime.datetime.strptime(string, format)
     assert expected == got
+
+def test_datetime_rounding():
+    b = 0.0000001
+    a = 0.9999994
+
+    assert datetime.datetime.utcfromtimestamp(a).microsecond == 999999
+    assert datetime.datetime.utcfromtimestamp(a).second == 0
+    a += b
+    assert datetime.datetime.utcfromtimestamp(a).microsecond == 999999
+    assert datetime.datetime.utcfromtimestamp(a).second == 0
+    a += b
+    assert datetime.datetime.utcfromtimestamp(a).microsecond == 0
+    assert datetime.datetime.utcfromtimestamp(a).second == 1
+
     

Modified: pypy/branch/fast-forward/lib_pypy/stackless.py
==============================================================================
--- pypy/branch/fast-forward/lib_pypy/stackless.py	(original)
+++ pypy/branch/fast-forward/lib_pypy/stackless.py	Thu Sep  9 01:00:13 2010
@@ -14,9 +14,13 @@
 import traceback
 import sys
 try:
+    # If _stackless can be imported then TaskletExit and CoroutineExit are 
+    # automatically added to the builtins.
     from _stackless import coroutine, greenlet
 except ImportError: # we are running from CPython
-    from greenlet import greenlet
+    from greenlet import greenlet, GreenletExit
+    TaskletExit = CoroutineExit = GreenletExit
+    del GreenletExit
     try:
         from functools import partial
     except ImportError: # we are not running python 2.5

Modified: pypy/branch/fast-forward/pypy/annotation/binaryop.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/binaryop.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/binaryop.py	Thu Sep  9 01:00:13 2010
@@ -924,10 +924,10 @@
 
 class __extend__(pairtype(SomeAddress, SomeAddress)):
     def union((s_addr1, s_addr2)):
-        return SomeAddress(is_null=s_addr1.is_null and s_addr2.is_null)
+        return SomeAddress()
 
     def sub((s_addr1, s_addr2)):
-        if s_addr1.is_null and s_addr2.is_null:
+        if s_addr1.is_null_address() and s_addr2.is_null_address():
             return getbookkeeper().immutablevalue(0)
         return SomeInteger()
 
@@ -953,10 +953,10 @@
 
 class __extend__(pairtype(SomeAddress, SomeInteger)):
     def add((s_addr, s_int)):
-        return SomeAddress(is_null=False)
+        return SomeAddress()
 
     def sub((s_addr, s_int)):
-        return SomeAddress(is_null=False)
+        return SomeAddress()
 
 class __extend__(pairtype(SomeAddress, SomeImpossibleValue)):
     # need to override this specifically to hide the 'raise UnionError'

Modified: pypy/branch/fast-forward/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/bookkeeper.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/bookkeeper.py	Thu Sep  9 01:00:13 2010
@@ -338,8 +338,12 @@
             result = SomeBool()
         elif tp is int:
             result = SomeInteger(nonneg = x>=0)
-        elif tp is long and 0 <= x <= (sys.maxint * 2 + 1):
-            result = SomeInteger(unsigned = True)
+        elif tp is long:
+            if -sys.maxint-1 <= x <= sys.maxint:
+                x = int(x)
+                result = SomeInteger(nonneg = x>=0)
+            else:
+                raise Exception("seeing a prebuilt long (value %s)" % hex(x))
         elif issubclass(tp, str): # py.lib uses annotated str subclasses
             if len(x) == 1:
                 result = SomeChar()
@@ -431,7 +435,7 @@
         elif isinstance(x, lltype._ptr):
             result = SomePtr(lltype.typeOf(x))
         elif isinstance(x, llmemory.fakeaddress):
-            result = SomeAddress(is_null=not x)
+            result = SomeAddress()
         elif isinstance(x, ootype._static_meth):
             result = SomeOOStaticMeth(ootype.typeOf(x))
         elif isinstance(x, ootype._class):

Modified: pypy/branch/fast-forward/pypy/annotation/builtin.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/builtin.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/builtin.py	Thu Sep  9 01:00:13 2010
@@ -92,6 +92,8 @@
     return s_obj.is_true()
 
 def builtin_int(s_obj, s_base=None):
+    if isinstance(s_obj, SomeInteger):
+        assert not s_obj.unsigned, "instead of int(r_uint(x)), use intmask(r_uint(x))"
     assert (s_base is None or isinstance(s_base, SomeInteger)
             and s_obj.knowntype == str), "only int(v|string) or int(string,int) expected"
     if s_base is not None:
@@ -694,18 +696,14 @@
 
 def raw_free(s_addr):
     assert isinstance(s_addr, SomeAddress)
-    assert not s_addr.is_null
 
 def raw_memclear(s_addr, s_int):
     assert isinstance(s_addr, SomeAddress)
-    assert not s_addr.is_null
     assert isinstance(s_int, SomeInteger)
 
 def raw_memcopy(s_addr1, s_addr2, s_int):
     assert isinstance(s_addr1, SomeAddress)
-    assert not s_addr1.is_null
     assert isinstance(s_addr2, SomeAddress)
-    assert not s_addr2.is_null
     assert isinstance(s_int, SomeInteger) #XXX add noneg...?
 
 BUILTIN_ANALYZERS[llmemory.raw_malloc] = raw_malloc

Modified: pypy/branch/fast-forward/pypy/annotation/classdef.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/classdef.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/classdef.py	Thu Sep  9 01:00:13 2010
@@ -276,6 +276,8 @@
         # create the Attribute and do the generalization asked for
         newattr = Attribute(attr, self.bookkeeper)
         if s_value:
+            if newattr.name == 'intval' and getattr(s_value, 'unsigned', False):
+                import pdb; pdb.set_trace()
             newattr.s_value = s_value
 
         # keep all subattributes' values

Modified: pypy/branch/fast-forward/pypy/annotation/model.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/model.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/model.py	Thu Sep  9 01:00:13 2010
@@ -501,12 +501,13 @@
 
 class SomeAddress(SomeObject):
     immutable = True
-    def __init__(self, is_null=False):
-        self.is_null = is_null
 
     def can_be_none(self):
         return False
 
+    def is_null_address(self):
+        return self.is_immutable_constant() and not self.const
+
 # The following class is used to annotate the intermediate value that
 # appears in expressions of the form:
 # addr.signed[offset] and addr.signed[offset] = value

Modified: pypy/branch/fast-forward/pypy/annotation/specialize.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/specialize.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/specialize.py	Thu Sep  9 01:00:13 2010
@@ -354,6 +354,12 @@
 
 def specialize_argtype(funcdesc, args_s, *argindices):
     key = tuple([args_s[i].knowntype for i in argindices])
+    for cls in key:
+        try:
+            assert '_must_specialize_' not in cls.classdesc.pyobj.__dict__, (
+                "%s has the tag _must_specialize_" % (cls,))
+        except AttributeError:
+            pass
     return maybe_star_args(funcdesc, key, args_s)
 
 def specialize_arglistitemtype(funcdesc, args_s, i):

Modified: pypy/branch/fast-forward/pypy/annotation/test/test_annrpython.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/test/test_annrpython.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/test/test_annrpython.py	Thu Sep  9 01:00:13 2010
@@ -767,7 +767,6 @@
         assert s.classdef is a.bookkeeper.getuniqueclassdef(IndexError)  # KeyError ignored because l is a list
 
     def test_overrides(self):
-        import sys
         excs = []
         def record_exc(e):
             """NOT_RPYTHON"""
@@ -869,8 +868,27 @@
         def f():
             return large_constant
         a = self.RPythonAnnotator()
+        py.test.raises(Exception, a.build_types, f, [])
+        # if you want to get a r_uint, you have to be explicit about it
+
+    def test_prebuilt_long_that_is_not_too_long(self):
+        small_constant = 12L
+        def f():
+            return small_constant
+        a = self.RPythonAnnotator()
         s = a.build_types(f, [])
-        assert s.knowntype == r_uint
+        assert s.const == 12
+        assert s.nonneg
+        assert not s.unsigned
+        #
+        small_constant = -23L
+        def f():
+            return small_constant
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [])
+        assert s.const == -23
+        assert not s.nonneg
+        assert not s.unsigned
 
     def test_pbc_getattr(self):
         class C:
@@ -1386,7 +1404,6 @@
         assert isinstance(a.binding(ev), annmodel.SomeInstance) and a.binding(ev).classdef == a.bookkeeper.getuniqueclassdef(Exception)
 
     def test_sys_attrs(self):
-        import sys
         def f():
             return sys.argv[0]
         a = self.RPythonAnnotator()

Modified: pypy/branch/fast-forward/pypy/bin/py.py
==============================================================================
--- pypy/branch/fast-forward/pypy/bin/py.py	(original)
+++ pypy/branch/fast-forward/pypy/bin/py.py	Thu Sep  9 01:00:13 2010
@@ -76,6 +76,8 @@
     config.objspace.suggest(allworkingmodules=False)
     if config.objspace.allworkingmodules:
         pypyoption.enable_allworkingmodules(config)
+    if config.objspace.usemodules.thread:
+        config.translation.thread = True
 
     # create the object space
 

Modified: pypy/branch/fast-forward/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/fast-forward/pypy/config/pypyoption.py	(original)
+++ pypy/branch/fast-forward/pypy/config/pypyoption.py	Thu Sep  9 01:00:13 2010
@@ -30,7 +30,7 @@
       "rctime" , "select", "zipimport", "_lsprof",
      "crypt", "signal", "_rawffi", "termios", "zlib",
      "struct", "md5", "sha", "bz2", "_minimal_curses", "cStringIO",
-     "thread", "itertools", "pyexpat", "_ssl", "cpyext"]
+     "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array"]
 ))
 
 working_oo_modules = default_modules.copy()

Modified: pypy/branch/fast-forward/pypy/config/translationoption.py
==============================================================================
--- pypy/branch/fast-forward/pypy/config/translationoption.py	(original)
+++ pypy/branch/fast-forward/pypy/config/translationoption.py	Thu Sep  9 01:00:13 2010
@@ -342,6 +342,9 @@
     'jit':  'hybrid      extraopts     jit',
     }
 
+def final_check_config(config):
+    pass
+
 def set_opt_level(config, level):
     """Apply optimization suggestions on the 'config'.
     The optimizations depend on the selected level and possibly on the backend.

Modified: pypy/branch/fast-forward/pypy/doc/faq.txt
==============================================================================
--- pypy/branch/fast-forward/pypy/doc/faq.txt	(original)
+++ pypy/branch/fast-forward/pypy/doc/faq.txt	Thu Sep  9 01:00:13 2010
@@ -47,8 +47,8 @@
 
 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 not been released yet, although it should be a major
-point of the next pypy release.
+change) on trunk. It has been a part of 1.3 release, but support is still
+in alpha phase.
 
 .. _`extension modules`: cpython_differences.html#extension-modules
 .. _`cpython_differences`: cpython_differences.html
@@ -373,7 +373,7 @@
 --------------------------------------------
 
 No.  PyPy always runs your code in its own interpreter, which is a
-full and compliant Python 2.4 interpreter.  RPython_ is only the
+full and compliant Python 2.5 interpreter.  RPython_ is only the
 language in which parts of PyPy itself are written and extension
 modules for it.  The answer to whether something needs to be written as
 an extension module, apart from the "gluing to external libraries" reason, will

Modified: pypy/branch/fast-forward/pypy/interpreter/argument.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/argument.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/argument.py	Thu Sep  9 01:00:13 2010
@@ -52,11 +52,15 @@
                 self.argnames, self.varargname, self.kwargname)
 
     def __eq__(self, other):
+        if not isinstance(other, Signature):
+            return NotImplemented
         return (self.argnames == other.argnames and
                 self.varargname == other.varargname and
                 self.kwargname == other.kwargname)
 
     def __ne__(self, other):
+        if not isinstance(other, Signature):
+            return NotImplemented
         return not self == other
 
 

Modified: pypy/branch/fast-forward/pypy/interpreter/astcompiler/assemble.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/astcompiler/assemble.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/astcompiler/assemble.py	Thu Sep  9 01:00:13 2010
@@ -614,22 +614,22 @@
     return (oparg % 256) + 2 * (oparg / 256)
 
 def _compute_CALL_FUNCTION(arg):
-    return _num_args(arg)
+    return -_num_args(arg)
 
 def _compute_CALL_FUNCTION_VAR(arg):
-    return _num_args(arg) - 1
+    return -_num_args(arg) - 1
 
 def _compute_CALL_FUNCTION_KW(arg):
-    return _num_args(arg) - 1
+    return -_num_args(arg) - 1
 
 def _compute_CALL_FUNCTION_VAR_KW(arg):
-    return _num_args(arg) - 2
+    return -_num_args(arg) - 2
 
 def _compute_CALL_LIKELY_BUILTIN(arg):
     return -(arg & 0xFF) + 1
 
 def _compute_CALL_METHOD(arg):
-    return -arg - 1
+    return -_num_args(arg) - 1
 
 
 _stack_effect_computers = {}

Modified: pypy/branch/fast-forward/pypy/interpreter/astcompiler/ast.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/astcompiler/ast.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/astcompiler/ast.py	Thu Sep  9 01:00:13 2010
@@ -230,6 +230,7 @@
         visitor.visit_FunctionDef(self)
 
     def mutate_over(self, visitor):
+        self.args = self.args.mutate_over(visitor)
         if self.body:
             visitor._mutate_sequence(self.body)
         if self.decorator_list:
@@ -798,6 +799,8 @@
     def mutate_over(self, visitor):
         if self.body:
             visitor._mutate_sequence(self.body)
+        if self.handlers:
+            visitor._mutate_sequence(self.handlers)
         if self.orelse:
             visitor._mutate_sequence(self.orelse)
         return visitor.visit_TryExcept(self)
@@ -941,6 +944,8 @@
         visitor.visit_Import(self)
 
     def mutate_over(self, visitor):
+        if self.names:
+            visitor._mutate_sequence(self.names)
         return visitor.visit_Import(self)
 
     def sync_app_attrs(self, space):
@@ -979,6 +984,8 @@
         visitor.visit_ImportFrom(self)
 
     def mutate_over(self, visitor):
+        if self.names:
+            visitor._mutate_sequence(self.names)
         return visitor.visit_ImportFrom(self)
 
     def sync_app_attrs(self, space):
@@ -1296,6 +1303,7 @@
         visitor.visit_Lambda(self)
 
     def mutate_over(self, visitor):
+        self.args = self.args.mutate_over(visitor)
         self.body = self.body.mutate_over(visitor)
         return visitor.visit_Lambda(self)
 
@@ -1450,6 +1458,8 @@
 
     def mutate_over(self, visitor):
         self.elt = self.elt.mutate_over(visitor)
+        if self.generators:
+            visitor._mutate_sequence(self.generators)
         return visitor.visit_ListComp(self)
 
     def sync_app_attrs(self, space):
@@ -1570,6 +1580,8 @@
 
     def mutate_over(self, visitor):
         self.elt = self.elt.mutate_over(visitor)
+        if self.generators:
+            visitor._mutate_sequence(self.generators)
         return visitor.visit_GeneratorExp(self)
 
     def sync_app_attrs(self, space):
@@ -1695,6 +1707,8 @@
         self.func = self.func.mutate_over(visitor)
         if self.args:
             visitor._mutate_sequence(self.args)
+        if self.keywords:
+            visitor._mutate_sequence(self.keywords)
         if self.starargs:
             self.starargs = self.starargs.mutate_over(visitor)
         if self.kwargs:
@@ -2426,6 +2440,13 @@
         self.w_ifs = None
         self.initialization_state = 7
 
+    def mutate_over(self, visitor):
+        self.target = self.target.mutate_over(visitor)
+        self.iter = self.iter.mutate_over(visitor)
+        if self.ifs:
+            visitor._mutate_sequence(self.ifs)
+        return visitor.visit_comprehension(self)
+
     def walkabout(self, visitor):
         visitor.visit_comprehension(self)
 
@@ -2460,6 +2481,15 @@
         self.col_offset = col_offset
         self.initialization_state = 31
 
+    def mutate_over(self, visitor):
+        if self.type:
+            self.type = self.type.mutate_over(visitor)
+        if self.name:
+            self.name = self.name.mutate_over(visitor)
+        if self.body:
+            visitor._mutate_sequence(self.body)
+        return visitor.visit_excepthandler(self)
+
     def walkabout(self, visitor):
         visitor.visit_excepthandler(self)
 
@@ -2499,6 +2529,13 @@
         self.w_defaults = None
         self.initialization_state = 15
 
+    def mutate_over(self, visitor):
+        if self.args:
+            visitor._mutate_sequence(self.args)
+        if self.defaults:
+            visitor._mutate_sequence(self.defaults)
+        return visitor.visit_arguments(self)
+
     def walkabout(self, visitor):
         visitor.visit_arguments(self)
 
@@ -2540,6 +2577,10 @@
         self.value = value
         self.initialization_state = 3
 
+    def mutate_over(self, visitor):
+        self.value = self.value.mutate_over(visitor)
+        return visitor.visit_keyword(self)
+
     def walkabout(self, visitor):
         visitor.visit_keyword(self)
 
@@ -2559,6 +2600,9 @@
         self.asname = asname
         self.initialization_state = 3
 
+    def mutate_over(self, visitor):
+        return visitor.visit_alias(self)
+
     def walkabout(self, visitor):
         visitor.visit_alias(self)
 

Modified: pypy/branch/fast-forward/pypy/interpreter/astcompiler/codegen.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/astcompiler/codegen.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/astcompiler/codegen.py	Thu Sep  9 01:00:13 2010
@@ -298,9 +298,11 @@
         # Load decorators first, but apply them after the function is created.
         if func.decorator_list:
             self.visit_sequence(func.decorator_list)
-        if func.args.defaults:
-            self.visit_sequence(func.args.defaults)
-            num_defaults = len(func.args.defaults)
+        args = func.args
+        assert isinstance(args, ast.arguments)
+        if args.defaults:
+            self.visit_sequence(args.defaults)
+            num_defaults = len(args.defaults)
         else:
             num_defaults = 0
         code = self.sub_scope(FunctionCodeGenerator, func.name, func,
@@ -314,9 +316,11 @@
 
     def visit_Lambda(self, lam):
         self.update_position(lam.lineno)
-        if lam.args.defaults:
-            self.visit_sequence(lam.args.defaults)
-            default_count = len(lam.args.defaults)
+        args = lam.args
+        assert isinstance(args, ast.arguments)
+        if args.defaults:
+            self.visit_sequence(args.defaults)
+            default_count = len(args.defaults)
         else:
             default_count = 0
         code = self.sub_scope(LambdaCodeGenerator, "<lambda>", lam, lam.lineno)
@@ -980,9 +984,12 @@
         elif call_type == 3:
             op = ops.CALL_FUNCTION_VAR_KW
         self.emit_op_arg(op, arg)
+    
+    def _call_has_no_star_args(self, call):
+        return not call.starargs and not call.kwargs
 
     def _call_has_simple_args(self, call):
-        return not call.starargs and not call.kwargs and not call.keywords
+        return self._call_has_no_star_args(call) and not call.keywords
 
     def _optimize_builtin_call(self, call):
         if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \
@@ -1008,7 +1015,7 @@
 
     def _optimize_method_call(self, call):
         if not self.space.config.objspace.opcodes.CALL_METHOD or \
-                not self._call_has_simple_args(call) or \
+                not self._call_has_no_star_args(call) or \
                 not isinstance(call.func, ast.Attribute):
             return False
         attr_lookup = call.func
@@ -1020,7 +1027,12 @@
             arg_count = len(call.args)
         else:
             arg_count = 0
-        self.emit_op_arg(ops.CALL_METHOD, arg_count)
+        if call.keywords:
+            self.visit_sequence(call.keywords)
+            kwarg_count = len(call.keywords)
+        else:
+            kwarg_count = 0
+        self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count)
         return True
 
     def _listcomp_generator(self, gens, gen_index, elt):
@@ -1284,9 +1296,11 @@
         else:
             self.add_const(self.space.w_None)
             start = 0
-        if func.args.args:
-            self._handle_nested_args(func.args.args)
-            self.argcount = len(func.args.args)
+        args = func.args
+        assert isinstance(args, ast.arguments)
+        if args.args:
+            self._handle_nested_args(args.args)
+            self.argcount = len(args.args)
         for i in range(start, len(func.body)):
             func.body[i].walkabout(self)
 
@@ -1295,9 +1309,11 @@
 
     def _compile(self, lam):
         assert isinstance(lam, ast.Lambda)
-        if lam.args.args:
-            self._handle_nested_args(lam.args.args)
-            self.argcount = len(lam.args.args)
+        args = lam.args
+        assert isinstance(args, ast.arguments)
+        if args.args:
+            self._handle_nested_args(args.args)
+            self.argcount = len(args.args)
         # Prevent a string from being the first constant and thus a docstring.
         self.add_const(self.space.w_None)
         lam.body.walkabout(self)

Modified: pypy/branch/fast-forward/pypy/interpreter/astcompiler/consts.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/astcompiler/consts.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/astcompiler/consts.py	Thu Sep  9 01:00:13 2010
@@ -9,7 +9,6 @@
 CO_NESTED = 0x0010
 CO_GENERATOR = 0x0020
 CO_NOFREE = 0x0040
-CO_CONTAINSLOOP = 0x0080
 CO_CONTAINSGLOBALS = 0x0800
 CO_GENERATOR_ALLOWED = 0x1000
 CO_FUTURE_DIVISION = 0x2000
@@ -20,4 +19,4 @@
 
 PyCF_SOURCE_IS_UTF8 = 0x0100
 PyCF_DONT_IMPLY_DEDENT = 0x0200
-PyCF_AST_ONLY = 0x0400
+PyCF_ONLY_AST = 0x0400

Modified: pypy/branch/fast-forward/pypy/interpreter/astcompiler/symtable.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/astcompiler/symtable.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/astcompiler/symtable.py	Thu Sep  9 01:00:13 2010
@@ -353,8 +353,10 @@
     def visit_FunctionDef(self, func):
         self.note_symbol(func.name, SYM_ASSIGNED)
         # Function defaults and decorators happen in the outer scope.
-        if func.args.defaults:
-            self.visit_sequence(func.args.defaults)
+        args = func.args
+        assert isinstance(args, ast.arguments)
+        if args.defaults:
+            self.visit_sequence(args.defaults)
         if func.decorator_list:
             self.visit_sequence(func.decorator_list)
         new_scope = FunctionScope(func.name, func.lineno, func.col_offset)
@@ -422,8 +424,10 @@
             self.note_symbol(name, SYM_GLOBAL)
 
     def visit_Lambda(self, lamb):
-        if lamb.args.defaults:
-            self.visit_sequence(lamb.args.defaults)
+        args = lamb.args
+        assert isinstance(args, ast.arguments)
+        if args.defaults:
+            self.visit_sequence(args.defaults)
         new_scope = FunctionScope("lambda", lamb.lineno, lamb.col_offset)
         self.push_scope(new_scope, lamb)
         lamb.args.walkabout(self)

Modified: pypy/branch/fast-forward/pypy/interpreter/astcompiler/tools/asdl_py.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/astcompiler/tools/asdl_py.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/astcompiler/tools/asdl_py.py	Thu Sep  9 01:00:13 2010
@@ -100,6 +100,7 @@
         self.emit("")
         self.make_constructor(product.fields, product)
         self.emit("")
+        self.make_mutate_over(product, name)
         self.emit("def walkabout(self, visitor):", 1)
         self.emit("visitor.visit_%s(self)" % (name,), 2)
         self.emit("")
@@ -183,6 +184,26 @@
         have_everything = self.data.required_masks[node] | \
             self.data.optional_masks[node]
         self.emit("self.initialization_state = %i" % (have_everything,), 2)
+    
+    def make_mutate_over(self, cons, name):
+        self.emit("def mutate_over(self, visitor):", 1)
+        for field in cons.fields:
+            if (field.type.value not in asdl.builtin_types and
+                field.type.value not in self.data.simple_types):
+                if field.opt or field.seq:
+                    level = 3
+                    self.emit("if self.%s:" % (field.name,), 2)
+                else:
+                    level = 2
+                if field.seq:
+                    sub = (field.name,)
+                    self.emit("visitor._mutate_sequence(self.%s)" % sub, level)
+                else:
+                    sub = (field.name, field.name)
+                    self.emit("self.%s = self.%s.mutate_over(visitor)" % sub,
+                              level)
+        self.emit("return visitor.visit_%s(self)" % (name,), 2)
+        self.emit("")
 
     def visitConstructor(self, cons, base, extra_attributes):
         self.emit("class %s(%s):" % (cons.name, base))
@@ -199,24 +220,7 @@
         self.emit("def walkabout(self, visitor):", 1)
         self.emit("visitor.visit_%s(self)" % (cons.name,), 2)
         self.emit("")
-        self.emit("def mutate_over(self, visitor):", 1)
-        for field in cons.fields:
-            if field.type.value not in asdl.builtin_types and \
-                    field.type.value not in self.data.prod_simple:
-                if field.opt or field.seq:
-                    level = 3
-                    self.emit("if self.%s:" % (field.name,), 2)
-                else:
-                    level = 2
-                if field.seq:
-                    sub = (field.name,)
-                    self.emit("visitor._mutate_sequence(self.%s)" % sub, level)
-                else:
-                    sub = (field.name, field.name)
-                    self.emit("self.%s = self.%s.mutate_over(visitor)" % sub,
-                              level)
-        self.emit("return visitor.visit_%s(self)" % (cons.name,), 2)
-        self.emit("")
+        self.make_mutate_over(cons, cons.name)
         self.make_var_syncer(cons.fields + self.data.cons_attributes[cons],
                              cons, cons.name)
 

Modified: pypy/branch/fast-forward/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/baseobjspace.py	Thu Sep  9 01:00:13 2010
@@ -288,6 +288,7 @@
                 self.timer.stop("startup " + modname)
 
     def finish(self):
+        self.wait_for_thread_shutdown()
         w_exitfunc = self.sys.getdictvalue(self, 'exitfunc')
         if w_exitfunc is not None:
             self.call_function(w_exitfunc)
@@ -305,6 +306,23 @@
             for s in self.FrameClass._space_op_types:
                 print s
 
+    def wait_for_thread_shutdown(self):
+        """Wait until threading._shutdown() completes, provided the threading
+        module was imported in the first place.  The shutdown routine will
+        wait until all non-daemon 'threading' threads have completed."""
+        if not self.config.translation.thread:
+            return
+
+        w_modules = self.sys.get('modules')
+        w_mod = self.finditem_str(w_modules, 'threading')
+        if w_mod is None:
+            return
+
+        try:
+            self.call_method(w_mod, "_shutdown")
+        except OperationError, e:
+            e.write_unraisable(self, "threading._shutdown()")
+
     def reportbytecodecounts(self):
         os.write(2, "Starting bytecode report.\n")
         fd = os.open('bytecode.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644)
@@ -1098,17 +1116,6 @@
                                  self.wrap('argument must be a unicode'))
         return self.unicode_w(w_obj)
 
-    def path_w(self, w_obj):
-        """ Like str_w, but if the object is unicode, encode it using
-        filesystemencoding
-        """
-        filesystemencoding = self.sys.filesystemencoding
-        if (filesystemencoding and
-            self.is_true(self.isinstance(w_obj, self.w_unicode))):
-            w_obj = self.call_method(w_obj, "encode",
-                                     self.wrap(filesystemencoding))
-        return self.str_w(w_obj)
-
     def bool_w(self, w_obj):
         # Unwraps a bool, also accepting an int for compatibility.
         # This is here mostly just for gateway.int_unwrapping_space_method().

Modified: pypy/branch/fast-forward/pypy/interpreter/error.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/error.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/error.py	Thu Sep  9 01:00:13 2010
@@ -344,7 +344,7 @@
 else:
     _WINDOWS = True
 
-    def wrap_windowserror(space, e, filename=None):
+    def wrap_windowserror(space, e, w_filename=None):
         from pypy.rlib import rwin32
 
         winerror = e.winerror
@@ -353,19 +353,19 @@
         except ValueError:
             msg = 'Windows Error %d' % winerror
         exc = space.w_WindowsError
-        if filename is not None:
+        if w_filename is not None:
             w_error = space.call_function(exc, space.wrap(winerror),
-                                          space.wrap(msg), space.wrap(filename))
+                                          space.wrap(msg), w_filename)
         else:
             w_error = space.call_function(exc, space.wrap(winerror),
                                           space.wrap(msg))
         return OperationError(exc, w_error)
 
-def wrap_oserror(space, e, filename=None, exception_name='w_OSError'): 
+def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError'): 
     assert isinstance(e, OSError)
 
     if _WINDOWS and isinstance(e, WindowsError):
-        return wrap_windowserror(space, e, filename)
+        return wrap_windowserror(space, e, w_filename)
 
     errno = e.errno
     try:
@@ -373,10 +373,21 @@
     except ValueError:
         msg = 'error %d' % errno
     exc = getattr(space, exception_name)
-    if filename is not None:
+    if w_filename is not None:
         w_error = space.call_function(exc, space.wrap(errno),
-                                      space.wrap(msg), space.wrap(filename))
+                                      space.wrap(msg), w_filename)
     else:
-        w_error = space.call_function(exc, space.wrap(errno), space.wrap(msg))
+        w_error = space.call_function(exc, space.wrap(errno),
+                                      space.wrap(msg))
     return OperationError(exc, w_error)
+wrap_oserror2._annspecialcase_ = 'specialize:arg(3)'
+
+def wrap_oserror(space, e, filename=None, exception_name='w_OSError'):
+    if filename is not None:
+        return wrap_oserror2(space, e, space.wrap(filename),
+                             exception_name=exception_name)
+    else:
+        return wrap_oserror2(space, e, None,
+                             exception_name=exception_name)
 wrap_oserror._annspecialcase_ = 'specialize:arg(3)'
+

Modified: pypy/branch/fast-forward/pypy/interpreter/gateway.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/gateway.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/gateway.py	Thu Sep  9 01:00:13 2010
@@ -137,9 +137,6 @@
     def visit_c_nonnegint(self, el, app_sig):
         self.checked_space_method(el, app_sig)
 
-    def visit_path(self, el, app_sig):
-        self.checked_space_method(el, app_sig)
-
     def visit__Wrappable(self, el, app_sig):
         name = el.__name__
         argname = self.orig_arg()
@@ -241,9 +238,6 @@
     def visit_bufferstr(self, typ):
         self.run_args.append("space.bufferstr_w(%s)" % (self.scopenext(),))
 
-    def visit_path(self, typ):
-        self.run_args.append("space.path_w(%s)" % (self.scopenext(),))
-
     def visit_nonnegint(self, typ):
         self.run_args.append("space.nonnegint_w(%s)" % (self.scopenext(),))
 
@@ -371,9 +365,6 @@
     def visit_bufferstr(self, typ):
         self.unwrap.append("space.bufferstr_w(%s)" % (self.nextarg(),))
 
-    def visit_path(self, typ):
-        self.unwrap.append("space.path_w(%s)" % (self.nextarg(),))
-
     def visit_nonnegint(self, typ):
         self.unwrap.append("space.nonnegint_w(%s)" % (self.nextarg(),))
 

Modified: pypy/branch/fast-forward/pypy/interpreter/generator.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/generator.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/generator.py	Thu Sep  9 01:00:13 2010
@@ -1,7 +1,6 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.gateway import NoneNotWrapped
-from pypy.rlib.rarithmetic import intmask
 from pypy.rlib import jit
 from pypy.interpreter.pyopcode import LoopBlock
 
@@ -37,13 +36,17 @@
 return next yielded value or raise StopIteration."""
         return self.send_ex(w_arg)
 
-    def send_ex(self, w_arg, exc=False):
+    def send_ex(self, w_arg, operr=None):
         space = self.space
         if self.running:
             raise OperationError(space.w_ValueError,
                                  space.wrap('generator already executing'))
         if self.frame.frame_finished_execution:
-            raise OperationError(space.w_StopIteration, space.w_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:
+                operr = OperationError(space.w_StopIteration, space.w_None)
+            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)
@@ -57,7 +60,7 @@
         self.running = True
         try:
             try:
-                w_result = self.frame.execute_generator_frame(w_arg, exc)
+                w_result = self.frame.execute_generator_frame(w_arg, operr)
             except OperationError:
                 # errors finish a frame
                 self.frame.frame_finished_execution = True
@@ -89,12 +92,7 @@
        
         operr = OperationError(w_type, w_val, tb)
         operr.normalize_exception(space)
-        
-        ec = space.getexecutioncontext()
-        next_instr = self.frame.handle_operation_error(ec, operr)
-        self.frame.last_instr = intmask(next_instr - 1)
-
-        return self.send_ex(space.w_None, True)
+        return self.send_ex(space.w_None, operr)
              
     def descr_next(self):
         """next() -> the next value, or raise StopIteration"""

Modified: pypy/branch/fast-forward/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/pycode.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/pycode.py	Thu Sep  9 01:00:13 2010
@@ -4,7 +4,7 @@
 The bytecode interpreter itself is implemented by the PyFrame class.
 """
 
-import dis, imp, struct, types, new
+import dis, imp, struct, types, new, sys
 
 from pypy.interpreter import eval
 from pypy.interpreter.argument import Signature
@@ -13,7 +13,7 @@
 from pypy.interpreter.baseobjspace import ObjSpace, W_Root
 from pypy.interpreter.astcompiler.consts import (CO_OPTIMIZED,
     CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED,
-    CO_GENERATOR, CO_CONTAINSLOOP, CO_CONTAINSGLOBALS)
+    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 import jit
@@ -118,7 +118,8 @@
         self._compute_flatcall()
 
     def _freeze_(self):
-        if self.magic == cpython_magic:
+        if (self.magic == cpython_magic and
+            '__pypy__' not in sys.builtin_module_names):
             raise Exception("CPython host codes should not be rendered")
         return False
 
@@ -133,9 +134,7 @@
             while opcode == opcodedesc.EXTENDED_ARG.index:
                 opcode = ord(co_code[next_instr])
                 next_instr += 3
-            if opcode == opcodedesc.JUMP_ABSOLUTE.index:
-                self.co_flags |= CO_CONTAINSLOOP
-            elif opcode == opcodedesc.LOAD_GLOBAL.index:
+            if opcode == opcodedesc.LOAD_GLOBAL.index:
                 self.co_flags |= CO_CONTAINSGLOBALS
             elif opcode == opcodedesc.LOAD_NAME.index:
                 self.co_flags |= CO_CONTAINSGLOBALS

Modified: pypy/branch/fast-forward/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/pyframe.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/pyframe.py	Thu Sep  9 01:00:13 2010
@@ -10,6 +10,7 @@
 from pypy.rlib.objectmodel import we_are_translated, instantiate
 from pypy.rlib.jit import hint
 from pypy.rlib.debug import make_sure_not_resized
+from pypy.rlib.rarithmetic import intmask
 from pypy.rlib import jit, rstack
 from pypy.tool import stdlib_opcode
 from pypy.tool.stdlib_opcode import host_bytecode_spec
@@ -126,8 +127,12 @@
         else:
             return self.execute_frame()
 
-    def execute_generator_frame(self, w_inputvalue, ex=False):
-        if self.last_instr != -1 and not ex:
+    def execute_generator_frame(self, w_inputvalue, operr=None):
+        if operr is not None:
+            ec = self.space.getexecutioncontext()
+            next_instr = self.handle_operation_error(ec, operr)
+            self.last_instr = intmask(next_instr - 1)
+        elif self.last_instr != -1:
             self.pushvalue(w_inputvalue)
         return self.execute_frame()
 

Modified: pypy/branch/fast-forward/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/pyopcode.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/pyopcode.py	Thu Sep  9 01:00:13 2010
@@ -211,10 +211,6 @@
                     next_instr = block.handle(self, unroller)
                     return next_instr    # now inside a 'finally' block
 
-            if opcode == self.opcodedesc.YIELD_VALUE.index:
-                #self.last_instr = intmask(next_instr - 1) XXX clean up!
-                raise Yield
-
             if opcode == self.opcodedesc.END_FINALLY.index:
                 unroller = self.end_finally()
                 if isinstance(unroller, SuspendedUnroller):
@@ -239,7 +235,7 @@
                     if not opdesc.is_enabled(space):
                         continue
                     if opdesc.methodname in (
-                        'EXTENDED_ARG', 'RETURN_VALUE', 'YIELD_VALUE',
+                        'EXTENDED_ARG', 'RETURN_VALUE',
                         'END_FINALLY', 'JUMP_ABSOLUTE'):
                         continue   # opcodes implemented above
 
@@ -810,6 +806,9 @@
                                   self.space.str_w(w_name))
         self.pushvalue(w_obj)
 
+    def YIELD_VALUE(self, oparg, next_instr):
+        raise Yield
+
     def jump_absolute(self, jumpto, next_instr, ec):
         return jumpto
 
@@ -1031,23 +1030,9 @@
             self.dropvalues(nargs)
         self.pushvalue(w_result)
 
-    def LOOKUP_METHOD(self, nameindex, next_instr):
-        # overridden by faster version in the standard object space.
-        space = self.space
-        w_obj = self.popvalue()
-        w_name = self.getname_w(nameindex)
-        w_value = space.getattr(w_obj, w_name)
-        self.pushvalue(w_value)
-
-    def CALL_METHOD(self, nargs, next_instr):
-        # overridden by faster version in the standard object space.
-        # 'nargs' is the argument count excluding the implicit 'self'
-        w_callable = self.peekvalue(nargs)
-        try:
-            w_result = self.space.call_valuestack(w_callable, nargs, self)
-        finally:
-            self.dropvalues(nargs + 1)
-        self.pushvalue(w_result)
+    # overridden by faster version in the standard object space.
+    LOOKUP_METHOD = LOAD_ATTR
+    CALL_METHOD = CALL_FUNCTION
 
     def MISSING_OPCODE(self, oparg, next_instr):
         ofs = self.last_instr

Modified: pypy/branch/fast-forward/pypy/interpreter/test/test_code.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/test/test_code.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/test/test_code.py	Thu Sep  9 01:00:13 2010
@@ -184,8 +184,6 @@
         # CO_NESTED
         assert f(4).func_code.co_flags & 0x10
         assert f.func_code.co_flags & 0x10 == 0
-        # check for CO_CONTAINSLOOP
-        assert not f.func_code.co_flags & 0x0080
         # check for CO_CONTAINSGLOBALS
         assert not f.func_code.co_flags & 0x0800
 
@@ -198,9 +196,6 @@
             return [l for l in [1, 2, 3, 4]]
 """
 
-        # check for CO_CONTAINSLOOP
-        assert f.func_code.co_flags & 0x0080
-        assert g.func_code.co_flags & 0x0080
         # check for CO_CONTAINSGLOBALS
         assert f.func_code.co_flags & 0x0800
         assert not g.func_code.co_flags & 0x0800

Modified: pypy/branch/fast-forward/pypy/interpreter/test/test_compiler.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/test/test_compiler.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/test/test_compiler.py	Thu Sep  9 01:00:13 2010
@@ -4,6 +4,7 @@
 from pypy.interpreter.pycode import PyCode
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.argument import Arguments
+from pypy.conftest import gettestobjspace
 
 class BaseTestCompiler:
     def setup_method(self, method):
@@ -852,6 +853,47 @@
             sys.stdout = save_stdout
         output = s.getvalue()
         assert "STOP_CODE" not in output
+    
+    def test_optimize_list_comp(self):
+        source = """def _f(a):
+            return [x for x in a if None]
+        """
+        exec source
+        code = _f.func_code
+        
+        import StringIO, sys, dis
+        s = StringIO.StringIO()
+        out = sys.stdout
+        sys.stdout = s
+        try:
+            dis.dis(code)
+        finally:
+            sys.stdout = out
+        output = s.getvalue()
+        assert "LOAD_GLOBAL" not in output
+
+class AppTestCallMethod(object):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{'objspace.opcodes.CALL_METHOD': True})
+        
+    def test_call_method_kwargs(self):
+        source = """def _f(a):
+            return a.f(a=a)
+        """
+        exec source
+        code = _f.func_code
+        
+        import StringIO, sys, dis
+        s = StringIO.StringIO()
+        out = sys.stdout
+        sys.stdout = s
+        try:
+            dis.dis(code)
+        finally:
+            sys.stdout = out
+        output = s.getvalue()
+        assert "CALL_METHOD" in output
+            
 
 class AppTestExceptions:
     def test_indentation_error(self):

Modified: pypy/branch/fast-forward/pypy/interpreter/test/test_gateway.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/test/test_gateway.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/test/test_gateway.py	Thu Sep  9 01:00:13 2010
@@ -454,16 +454,6 @@
         assert len(l) == 1
         assert space.eq_w(l[0], w("foo"))
 
-    def test_interp2app_unwrap_spec_path(self, monkeypatch):
-        space = self.space
-        def g(space, p):
-            return p
-
-        app_g = gateway.interp2app(g, unwrap_spec=[gateway.ObjSpace, 'path'])
-        w_app_g = space.wrap(app_g)
-        monkeypatch.setattr(space.sys, "filesystemencoding", "utf-8")
-        w_res = space.call_function(w_app_g, space.wrap(u"ą"))
-
     def test_interp2app_classmethod(self):
         space = self.space
         w = space.wrap

Modified: pypy/branch/fast-forward/pypy/interpreter/test/test_generator.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/test/test_generator.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/test/test_generator.py	Thu Sep  9 01:00:13 2010
@@ -126,6 +126,25 @@
         raises(ValueError, g.throw, ValueError)
         assert g.gi_frame is None
 
+    def test_throw_bug(self):
+        def f():
+            try:
+                x.throw(IndexError)     # => "generator already executing"
+            except ValueError:
+                yield 1
+        x = f()
+        res = list(x)
+        assert res == [1]
+
+    def test_throw_on_finished_generator(self):
+        def f():
+            yield 1
+        g = f()
+        res = g.next()
+        assert res == 1
+        raises(StopIteration, g.next)
+        raises(NameError, g.throw, NameError)
+
     def test_close(self):
         def f():
             yield 1

Modified: pypy/branch/fast-forward/pypy/interpreter/test/test_zpy.py
==============================================================================
--- pypy/branch/fast-forward/pypy/interpreter/test/test_zpy.py	(original)
+++ pypy/branch/fast-forward/pypy/interpreter/test/test_zpy.py	Thu Sep  9 01:00:13 2010
@@ -3,27 +3,28 @@
 import py
 import sys
 import pypy
+import subprocess
 
 pypypath = py.path.local(pypy.__file__).dirpath("bin", "py.py")
 
-def cmdexec(s):
-    if sys.platform == 'win32':
-        s = '"%s"' % s     # double double quotes
-    return py.process.cmdexec(s)
+def run(*args):
+    argslist = map(str, args)
+    popen = subprocess.Popen(argslist, stdout=subprocess.PIPE)
+    stdout, stderr = popen.communicate()
+    return stdout
 
 
 def test_executable():
     """Ensures sys.executable points to the py.py script"""
     # TODO : watch out for spaces/special chars in pypypath
-    output = cmdexec( '''"%s" "%s" -c "import sys;print sys.executable" ''' %
-                      (sys.executable, pypypath) )
+    output = run(sys.executable, pypypath,
+                 "-c", "import sys;print sys.executable")
     assert output.splitlines()[-1] == pypypath
 
 def test_special_names():
     """Test the __name__ and __file__ special global names"""
     cmd = "print __name__; print '__file__' in globals()"
-    output = cmdexec( '''"%s" "%s" -c "%s" ''' %
-                                 (sys.executable, pypypath, cmd) )
+    output = run(sys.executable, pypypath, '-c', cmd)
     assert output.splitlines()[-2] == '__main__'
     assert output.splitlines()[-1] == 'False'
 
@@ -32,26 +33,25 @@
     tmpfile.write("print __name__; print __file__\n")
     tmpfile.close()
 
-    output = cmdexec( '''"%s" "%s" "%s" ''' %
-                                 (sys.executable, pypypath, tmpfilepath) )
+    output = run(sys.executable, pypypath, tmpfilepath)
     assert output.splitlines()[-2] == '__main__'
     assert output.splitlines()[-1] == str(tmpfilepath)
 
 def test_argv_command():
     """Some tests on argv"""
     # test 1 : no arguments
-    output = cmdexec( '''"%s" "%s" -c "import sys;print sys.argv" ''' %
-                                 (sys.executable, pypypath) )
+    output = run(sys.executable, pypypath,
+                 "-c", "import sys;print sys.argv")
     assert output.splitlines()[-1] == str(['-c'])
 
     # test 2 : some arguments after
-    output = cmdexec( '''"%s" "%s" -c "import sys;print sys.argv" hello''' %
-                                 (sys.executable, pypypath) )
+    output = run(sys.executable, pypypath,
+                 "-c", "import sys;print sys.argv", "hello")
     assert output.splitlines()[-1] == str(['-c','hello'])
     
     # test 3 : additionnal pypy parameters
-    output = cmdexec( '''"%s" "%s" -O -c "import sys;print sys.argv" hello''' %
-                                 (sys.executable, pypypath) )
+    output = run(sys.executable, pypypath,
+                 "-O", "-c", "import sys;print sys.argv", "hello")
     assert output.splitlines()[-1] == str(['-c','hello'])
 
 SCRIPT_1 = """
@@ -65,18 +65,15 @@
     tmpfile.close()
 
     # test 1 : no arguments
-    output = cmdexec( '''"%s" "%s" "%s" ''' %
-                                 (sys.executable, pypypath, tmpfilepath) )
+    output = run(sys.executable, pypypath, tmpfilepath)
     assert output.splitlines()[-1] == str([tmpfilepath])
     
     # test 2 : some arguments after
-    output = cmdexec( '''"%s" "%s" "%s" hello''' %
-                                 (sys.executable, pypypath, tmpfilepath) )
+    output = run(sys.executable, pypypath, tmpfilepath, "hello")
     assert output.splitlines()[-1] == str([tmpfilepath,'hello'])
     
     # test 3 : additionnal pypy parameters
-    output = cmdexec( '''"%s" "%s" -O "%s" hello''' %
-                                 (sys.executable, pypypath, tmpfilepath) )
+    output = run(sys.executable, pypypath, "-O", tmpfilepath, "hello")
     assert output.splitlines()[-1] == str([tmpfilepath,'hello'])
     
 
@@ -98,11 +95,7 @@
     tmpfile.write(TB_NORMALIZATION_CHK)
     tmpfile.close()
 
-    e = None
-    try:
-        output = cmdexec( '''"%s" "%s" "%s" ''' %
-                                     (sys.executable, pypypath, tmpfilepath) )
-    except py.process.cmdexec.Error, e:
-        pass
-    assert e," expected failure"
-    assert e.err.splitlines()[-1] == 'KeyError: <normalized>'
+    popen = subprocess.Popen([sys.executable, str(pypypath), tmpfilepath],
+                             stderr=subprocess.PIPE)
+    _, stderr = popen.communicate()
+    assert stderr.endswith('KeyError: <normalized>\n')

Modified: pypy/branch/fast-forward/pypy/jit/backend/detect_cpu.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/detect_cpu.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/detect_cpu.py	Thu Sep  9 01:00:13 2010
@@ -56,6 +56,8 @@
         return "pypy.jit.backend.x86.runner", "CPU"
     elif backend_name == 'x86-without-sse2':
         return "pypy.jit.backend.x86.runner", "CPU386_NO_SSE2"
+    elif backend_name == 'x86_64':
+        return "pypy.jit.backend.x86.runner", "CPU_X86_64"
     elif backend_name == 'cli':
         return "pypy.jit.backend.cli.runner", "CliCPU"
     elif backend_name == 'llvm':

Modified: pypy/branch/fast-forward/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/llgraph/llimpl.py	Thu Sep  9 01:00:13 2010
@@ -123,6 +123,9 @@
     'setarrayitem_gc' : (('ref', 'int', 'intorptr'), None),
     'getarrayitem_gc' : (('ref', 'int'), 'intorptr'),
     'getarrayitem_gc_pure' : (('ref', 'int'), 'intorptr'),
+    'setarrayitem_raw' : (('ref', 'int', 'intorptr'), None),
+    'getarrayitem_raw' : (('ref', 'int'), 'intorptr'),
+    'getarrayitem_raw_pure' : (('ref', 'int'), 'intorptr'),
     'arraylen_gc'     : (('ref',), 'int'),
     'call'            : (('ref', 'varargs'), 'intorptr'),
     'call_assembler'  : (('ref', 'varargs'), 'intorptr'),
@@ -689,6 +692,18 @@
 
     op_getarrayitem_gc_pure = op_getarrayitem_gc
 
+    def op_getarrayitem_raw(self, arraydescr, array, index):
+        if arraydescr.typeinfo == REF:
+            raise NotImplementedError("getarrayitem_raw -> gcref")
+        elif arraydescr.typeinfo == INT:
+            return do_getarrayitem_raw_int(array, index)
+        elif arraydescr.typeinfo == FLOAT:
+            return do_getarrayitem_raw_float(array, index)
+        else:
+            raise NotImplementedError
+
+    op_getarrayitem_raw_pure = op_getarrayitem_raw
+
     def op_getfield_gc(self, fielddescr, struct):
         if fielddescr.typeinfo == REF:
             return do_getfield_gc_ptr(struct, fielddescr.ofs)
@@ -734,6 +749,16 @@
         else:
             raise NotImplementedError
 
+    def op_setarrayitem_raw(self, arraydescr, array, index, newvalue):
+        if arraydescr.typeinfo == REF:
+            raise NotImplementedError("setarrayitem_raw <- gcref")
+        elif arraydescr.typeinfo == INT:
+            do_setarrayitem_raw_int(array, index, newvalue)
+        elif arraydescr.typeinfo == FLOAT:
+            do_setarrayitem_raw_float(array, index, newvalue)
+        else:
+            raise NotImplementedError
+
     def op_setfield_gc(self, fielddescr, struct, newvalue):
         if fielddescr.typeinfo == REF:
             do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue)

Modified: pypy/branch/fast-forward/pypy/jit/backend/llsupport/descr.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/llsupport/descr.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/llsupport/descr.py	Thu Sep  9 01:00:13 2010
@@ -67,9 +67,11 @@
 
 class BaseFieldDescr(AbstractDescr):
     offset = 0      # help translation
+    name = ''
     _clsname = ''
 
-    def __init__(self, offset):
+    def __init__(self, name, offset):
+        self.name = name
         self.offset = offset
 
     def sort_key(self):
@@ -88,7 +90,7 @@
         return self._is_float_field
 
     def repr_of_descr(self):
-        return '<%s %s>' % (self._clsname, self.offset)
+        return '<%s %s %s>' % (self._clsname, self.name, self.offset)
 
 
 class NonGcPtrFieldDescr(BaseFieldDescr):
@@ -113,7 +115,8 @@
         offset, _ = symbolic.get_field_token(STRUCT, fieldname,
                                              gccache.translate_support_code)
         FIELDTYPE = getattr(STRUCT, fieldname)
-        fielddescr = getFieldDescrClass(FIELDTYPE)(offset)
+        name = '%s.%s' % (STRUCT._name, fieldname)
+        fielddescr = getFieldDescrClass(FIELDTYPE)(name, offset)
         cachedict = cache.setdefault(STRUCT, {})
         cachedict[fieldname] = fielddescr
         return fielddescr
@@ -195,9 +198,13 @@
     try:
         return cache[ARRAY]
     except KeyError:
+        # we only support Arrays that are either GcArrays, or raw no-length
+        # non-gc Arrays.
         if ARRAY._hints.get('nolength', False):
+            assert not isinstance(ARRAY, lltype.GcArray)
             arraydescr = getArrayNoLengthDescrClass(ARRAY)()
         else:
+            assert isinstance(ARRAY, lltype.GcArray)
             arraydescr = getArrayDescrClass(ARRAY)()
         # verify basic assumption that all arrays' basesize and ofslength
         # are equal

Modified: pypy/branch/fast-forward/pypy/jit/backend/llsupport/gc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/llsupport/gc.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/llsupport/gc.py	Thu Sep  9 01:00:13 2010
@@ -251,13 +251,25 @@
         if oldgcmap:
             lltype.free(oldgcmap, flavor='raw')
 
-    def get_basic_shape(self):
-        return [chr(self.LOC_EBP_PLUS  | 4),    # return addr: at   4(%ebp)
-                chr(self.LOC_EBP_MINUS | 4),    # saved %ebx:  at  -4(%ebp)
-                chr(self.LOC_EBP_MINUS | 8),    # saved %esi:  at  -8(%ebp)
-                chr(self.LOC_EBP_MINUS | 12),   # saved %edi:  at -12(%ebp)
-                chr(self.LOC_EBP_PLUS  | 0),    # saved %ebp:  at    (%ebp)
-                chr(0)]
+    def get_basic_shape(self, is_64_bit=False):
+        # XXX: Should this code even really know about stack frame layout of
+        # the JIT?
+        if is_64_bit:
+            return [chr(self.LOC_EBP_PLUS  | 8),
+                    chr(self.LOC_EBP_MINUS | 8),
+                    chr(self.LOC_EBP_MINUS | 16),
+                    chr(self.LOC_EBP_MINUS | 24),
+                    chr(self.LOC_EBP_MINUS | 32),
+                    chr(self.LOC_EBP_MINUS | 40),
+                    chr(self.LOC_EBP_PLUS  | 0),
+                    chr(0)]
+        else:
+            return [chr(self.LOC_EBP_PLUS  | 4),    # return addr: at   4(%ebp)
+                    chr(self.LOC_EBP_MINUS | 4),    # saved %ebx:  at  -4(%ebp)
+                    chr(self.LOC_EBP_MINUS | 8),    # saved %esi:  at  -8(%ebp)
+                    chr(self.LOC_EBP_MINUS | 12),   # saved %edi:  at -12(%ebp)
+                    chr(self.LOC_EBP_PLUS  | 0),    # saved %ebp:  at    (%ebp)
+                    chr(0)]
 
     def _encode_num(self, shape, number):
         assert number >= 0
@@ -276,17 +288,9 @@
             num = self.LOC_EBP_MINUS | (-offset)
         self._encode_num(shape, num)
 
-    def add_ebx(self, shape):
-        shape.append(chr(self.LOC_REG | 4))
-
-    def add_esi(self, shape):
-        shape.append(chr(self.LOC_REG | 8))
-
-    def add_edi(self, shape):
-        shape.append(chr(self.LOC_REG | 12))
-
-    def add_ebp(self, shape):
-        shape.append(chr(self.LOC_REG | 16))
+    def add_callee_save_reg(self, shape, reg_index):
+        assert reg_index > 0
+        shape.append(chr(self.LOC_REG | (reg_index << 2)))
 
     def compress_callshape(self, shape):
         # Similar to compress_callshape() in trackgcroot.py.
@@ -328,7 +332,7 @@
     DEBUG = False    # forced to True by x86/test/test_zrpy_gc.py
 
     def __init__(self, gcdescr, translator, rtyper, llop1=llop):
-        from pypy.rpython.memory.gctypelayout import _check_typeid
+        from pypy.rpython.memory.gctypelayout import check_typeid
         from pypy.rpython.memory.gcheader import GCHeaderBuilder
         from pypy.rpython.memory.gctransform import framework
         GcLLDescription.__init__(self, gcdescr, translator, rtyper)
@@ -351,7 +355,7 @@
         gcrootmap = cls()
         self.gcrootmap = gcrootmap
         self.gcrefs = GcRefList()
-        self.single_gcref_descr = GcPtrFieldDescr(0)
+        self.single_gcref_descr = GcPtrFieldDescr('', 0)
 
         # make a TransformerLayoutBuilder and save it on the translator
         # where it can be fished and reused by the FrameworkGCTransformer
@@ -375,7 +379,7 @@
         def malloc_basic(size, tid):
             type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
             has_finalizer = bool(tid & (1<<llgroup.HALFSHIFT))
-            _check_typeid(type_id)
+            check_typeid(type_id)
             try:
                 res = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
                                                       type_id, size, True,
@@ -395,7 +399,7 @@
         #
         def malloc_array(itemsize, tid, num_elem):
             type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
-            _check_typeid(type_id)
+            check_typeid(type_id)
             try:
                 return llop1.do_malloc_varsize_clear(
                     llmemory.GCREF,
@@ -482,7 +486,7 @@
 
     def init_size_descr(self, S, descr):
         type_id = self.layoutbuilder.get_type_id(S)
-        assert not self.layoutbuilder.is_weakref(type_id)
+        assert not self.layoutbuilder.is_weakref_type(S)
         has_finalizer = bool(self.layoutbuilder.has_finalizer(S))
         flags = int(has_finalizer) << llgroup.HALFSHIFT
         descr.tid = llop.combine_ushort(lltype.Signed, type_id, flags)

Modified: pypy/branch/fast-forward/pypy/jit/backend/llsupport/regalloc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/llsupport/regalloc.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/llsupport/regalloc.py	Thu Sep  9 01:00:13 2010
@@ -22,18 +22,19 @@
     def get(self, box):
         return self.frame_bindings.get(box, None)
 
-    def loc(self, box, size):
+    def loc(self, box):
         res = self.get(box)
         if res is not None:
             return res
-        newloc = self.frame_pos(self.frame_depth, size)
+        newloc = self.frame_pos(self.frame_depth, box.type)
         self.frame_bindings[box] = newloc
-        self.frame_depth += size
+        # Objects returned by frame_pos must support frame_size()
+        self.frame_depth += newloc.frame_size()
         return newloc
 
     # abstract methods that need to be overwritten for specific assemblers
     @staticmethod
-    def frame_pos(loc, size):
+    def frame_pos(loc, type):
         raise NotImplementedError("Purely abstract")
 
 class RegisterManager(object):
@@ -43,7 +44,6 @@
     all_regs              = []
     no_lower_byte_regs    = []
     save_around_call_regs = []
-    reg_width             = 1 # in terms of stack space eaten
     
     def __init__(self, longevity, frame_manager=None, assembler=None):
         self.free_regs = self.all_regs[:]
@@ -148,7 +148,7 @@
         loc = self.reg_bindings[v_to_spill]
         del self.reg_bindings[v_to_spill]
         if self.frame_manager.get(v_to_spill) is None:
-            newloc = self.frame_manager.loc(v_to_spill, self.reg_width)
+            newloc = self.frame_manager.loc(v_to_spill)
             self.assembler.regalloc_mov(loc, newloc)
         return loc
 
@@ -204,7 +204,7 @@
         try:
             return self.reg_bindings[box]
         except KeyError:
-            return self.frame_manager.loc(box, self.reg_width)
+            return self.frame_manager.loc(box)
 
     def return_constant(self, v, forbidden_vars=[], selected_reg=None,
                         imm_fine=True):
@@ -260,7 +260,7 @@
             self.reg_bindings[v] = loc
             self.assembler.regalloc_mov(prev_loc, loc)
         else:
-            loc = self.frame_manager.loc(v, self.reg_width)
+            loc = self.frame_manager.loc(v)
             self.assembler.regalloc_mov(prev_loc, loc)
 
     def force_result_in_reg(self, result_v, v, forbidden_vars=[]):
@@ -280,7 +280,7 @@
             self.free_regs = [reg for reg in self.free_regs if reg is not loc]
             return loc
         if v not in self.reg_bindings:
-            prev_loc = self.frame_manager.loc(v, self.reg_width)
+            prev_loc = self.frame_manager.loc(v)
             loc = self.force_allocate_reg(v, forbidden_vars)
             self.assembler.regalloc_mov(prev_loc, loc)
         assert v in self.reg_bindings
@@ -300,7 +300,7 @@
     def _sync_var(self, v):
         if not self.frame_manager.get(v):
             reg = self.reg_bindings[v]
-            to = self.frame_manager.loc(v, self.reg_width)
+            to = self.frame_manager.loc(v)
             self.assembler.regalloc_mov(reg, to)
         # otherwise it's clean
 

Modified: pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_descr.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_descr.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_descr.py	Thu Sep  9 01:00:13 2010
@@ -53,6 +53,10 @@
         assert descr_y.__class__ is GcPtrFieldDescr
         assert descr_z.__class__ is NonGcPtrFieldDescr
         assert descr_f.__class__ is clsf
+        assert descr_x.name == 'S.x'
+        assert descr_y.name == 'S.y'
+        assert descr_z.name == 'S.z'
+        assert descr_f.name == 'S.f'
         if not tsc:
             assert descr_x.offset < descr_y.offset < descr_z.offset
             assert descr_x.sort_key() < descr_y.sort_key() < descr_z.sort_key()
@@ -228,11 +232,11 @@
     #
     descr2 = get_field_descr(c0, S, 'y')
     o, _ = symbolic.get_field_token(S, 'y', False)
-    assert descr2.repr_of_descr() == '<GcPtrFieldDescr %d>' % o
+    assert descr2.repr_of_descr() == '<GcPtrFieldDescr S.y %d>' % o
     #
     descr2i = get_field_descr(c0, S, 'x')
     o, _ = symbolic.get_field_token(S, 'x', False)
-    assert descr2i.repr_of_descr() == '<CharFieldDescr %d>' % o
+    assert descr2i.repr_of_descr() == '<CharFieldDescr S.x %d>' % o
     #
     descr3 = get_array_descr(c0, lltype.GcArray(lltype.Ptr(S)))
     assert descr3.repr_of_descr() == '<GcPtrArrayDescr>'

Modified: pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_gc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_gc.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_gc.py	Thu Sep  9 01:00:13 2010
@@ -73,16 +73,16 @@
     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_ebx(shape)
+    gcrootmap.add_callee_save_reg(shape, 1)
     assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
                               4])
-    gcrootmap.add_esi(shape)
+    gcrootmap.add_callee_save_reg(shape, 2)
     assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
                               4, 8])
-    gcrootmap.add_edi(shape)
+    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_ebp(shape)
+    gcrootmap.add_callee_save_reg(shape, 4)
     assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
                               4, 8, 12, 16])
     #

Modified: pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_regalloc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_regalloc.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/llsupport/test/test_regalloc.py	Thu Sep  9 01:00:13 2010
@@ -1,5 +1,5 @@
 
-from pypy.jit.metainterp.history import BoxInt, ConstInt, BoxFloat
+from pypy.jit.metainterp.history import BoxInt, ConstInt, BoxFloat, INT, FLOAT
 from pypy.jit.backend.llsupport.regalloc import FrameManager
 from pypy.jit.backend.llsupport.regalloc import RegisterManager as BaseRegMan
 
@@ -26,9 +26,20 @@
     def convert_to_imm(self, v):
         return v
 
+class FakeFramePos(object):
+    def __init__(self, pos, box_type):
+        self.pos = pos
+        self.box_type = box_type
+
+    def frame_size(self):
+        if self.box_type == FLOAT:
+            return 2
+        else:
+            return 1
+
 class TFrameManager(FrameManager):
-    def frame_pos(self, i, size):
-        return i
+    def frame_pos(self, i, box_type):
+        return FakeFramePos(i, box_type)
 
 class MockAsm(object):
     def __init__(self):
@@ -146,8 +157,8 @@
         rm.next_instruction()
         # allocate a stack position
         b0, b1, b2, b3, b4 = boxes
-        sp = fm.loc(b0, 1)
-        assert sp == 0
+        sp = fm.loc(b0)
+        assert sp.pos == 0
         loc = rm.make_sure_var_in_reg(b0)
         assert isinstance(loc, FakeReg)
         rm._check_invariants()
@@ -207,13 +218,13 @@
         asm = MockAsm()
         rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
         rm.next_instruction()
-        fm.loc(b0, 1)
+        fm.loc(b0)
         rm.force_result_in_reg(b1, b0)
         rm._check_invariants()
         loc = rm.loc(b1)
         assert isinstance(loc, FakeReg)
         loc = rm.loc(b0)
-        assert isinstance(loc, int)
+        assert isinstance(loc, FakeFramePos)
         assert len(asm.moves) == 1
 
     def test_return_constant(self):
@@ -304,7 +315,7 @@
 
     def test_different_frame_width(self):
         class XRegisterManager(RegisterManager):
-            reg_width = 2
+            pass
 
         fm = TFrameManager()
         b0 = BoxInt()

Modified: pypy/branch/fast-forward/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/test/runner_test.py	Thu Sep  9 01:00:13 2010
@@ -461,6 +461,25 @@
                                          [funcbox] + args,
                                          'float', descr=calldescr)
             assert abs(res.value - 4.6) < 0.0001
+
+    def test_call_many_arguments(self):
+        # Test calling a function with a large number of arguments (more than
+        # 6, which will force passing some arguments on the stack on 64-bit)
+
+        def func(*args):
+            assert len(args) == 16
+            # Try to sum up args in a way that would probably detect a
+            # transposed argument
+            return sum(arg * (2**i) for i, arg in enumerate(args))
+
+        FUNC = self.FuncType([lltype.Signed]*16, lltype.Signed)
+        FPTR = self.Ptr(FUNC)
+        calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+        func_ptr = llhelper(FPTR, func)
+        args = range(16)
+        funcbox = self.get_funcbox(self.cpu, func_ptr)
+        res = self.execute_operation(rop.CALL, [funcbox] + map(BoxInt, args), 'int', descr=calldescr)
+        assert res.value == func(*args)
         
     def test_call_stack_alignment(self):
         # test stack alignment issues, notably for Mac OS/X.
@@ -638,6 +657,21 @@
         assert r.value == 1
 
     def test_array_basic(self):
+        a_box, A = self.alloc_array_of(rffi.SHORT, 342)
+        arraydescr = self.cpu.arraydescrof(A)
+        assert not arraydescr.is_array_of_pointers()
+        #
+        r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
+                                   'int', descr=arraydescr)
+        assert r.value == 342
+        r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, BoxInt(310),
+                                                         BoxInt(744)],
+                                   'void', descr=arraydescr)
+        assert r is None
+        r = self.execute_operation(rop.GETARRAYITEM_GC, [a_box, BoxInt(310)],
+                                   'int', descr=arraydescr)
+        assert r.value == 744
+
         a_box, A = self.alloc_array_of(lltype.Signed, 342)
         arraydescr = self.cpu.arraydescrof(A)
         assert not arraydescr.is_array_of_pointers()
@@ -751,6 +785,20 @@
                                        'float', descr=arraydescr)
             assert r.value == 4.5
 
+        # For platforms where sizeof(INT) != sizeof(Signed) (ie, x86-64)
+        a_box, A = self.alloc_array_of(rffi.INT, 342)
+        arraydescr = self.cpu.arraydescrof(A)
+        assert not arraydescr.is_array_of_pointers()
+        r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
+                                   'int', descr=arraydescr)
+        assert r.value == 342
+        r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, BoxInt(310),
+                                                         BoxInt(7441)],
+                                   'void', descr=arraydescr)
+        assert r is None
+        r = self.execute_operation(rop.GETARRAYITEM_GC, [a_box, BoxInt(310)],
+                                   'int', descr=arraydescr)
+        assert r.value == 7441
 
     def test_string_basic(self):
         s_box = self.alloc_string("hello\xfe")
@@ -978,6 +1026,8 @@
             else:
                 assert 0
             operations.append(ResOperation(opnum, boxargs, boxres))
+        # Unique-ify inputargs
+        inputargs = list(set(inputargs))
         faildescr = BasicFailDescr(1)
         operations.append(ResOperation(rop.FINISH, [], None,
                                        descr=faildescr))
@@ -1050,9 +1100,11 @@
                                          descr=BasicFailDescr(5))]
                         operations[1].fail_args = []
                         looptoken = LoopToken()
-                        self.cpu.compile_loop(list(testcase), operations,
+                        # Use "set" to unique-ify inputargs
+                        unique_testcase_list = list(set(testcase))
+                        self.cpu.compile_loop(unique_testcase_list, operations,
                                               looptoken)
-                        for i, box in enumerate(testcase):
+                        for i, box in enumerate(unique_testcase_list):
                             self.cpu.set_future_value_float(i, box.value)
                         fail = self.cpu.execute_token(looptoken)
                         if fail.identifier != 5 - (expected_id^expected):
@@ -1695,7 +1747,7 @@
     def test_assembler_call(self):
         called = []
         def assembler_helper(failindex, virtualizable):
-            assert self.cpu.get_latest_value_int(0) == 10
+            assert self.cpu.get_latest_value_int(0) == 97
             called.append(failindex)
             return 4 + 9
 
@@ -1708,33 +1760,41 @@
                 _assembler_helper_ptr)
 
         ops = '''
-        [i0, i1]
-        i2 = int_add(i0, i1)
-        finish(i2)'''
+        [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9]
+        i10 = int_add(i0, i1)
+        i11 = int_add(i10, i2)
+        i12 = int_add(i11, i3)
+        i13 = int_add(i12, i4)
+        i14 = int_add(i13, i5)
+        i15 = int_add(i14, i6)
+        i16 = int_add(i15, i7)
+        i17 = int_add(i16, i8)
+        i18 = int_add(i17, i9)
+        finish(i18)'''
         loop = parse(ops)
         looptoken = LoopToken()
         looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
         self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
-        ARGS = [lltype.Signed, lltype.Signed]
+        ARGS = [lltype.Signed] * 10
         RES = lltype.Signed
         self.cpu.portal_calldescr = self.cpu.calldescrof(
             lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES)
-        self.cpu.set_future_value_int(0, 1)
-        self.cpu.set_future_value_int(1, 2)
+        for i in range(10):
+            self.cpu.set_future_value_int(i, i+1)
         res = self.cpu.execute_token(looptoken)
-        assert self.cpu.get_latest_value_int(0) == 3
+        assert self.cpu.get_latest_value_int(0) == 55
         ops = '''
-        [i4, i5]
-        i6 = int_add(i4, 1)
-        i3 = call_assembler(i6, i5, descr=looptoken)
+        [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9]
+        i10 = int_add(i0, 42)
+        i11 = call_assembler(i10, i1, i2, i3, i4, i5, i6, i7, i8, i9, descr=looptoken)
         guard_not_forced()[]
-        finish(i3)
+        finish(i11)
         '''
         loop = parse(ops, namespace=locals())
         othertoken = LoopToken()
         self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
-        self.cpu.set_future_value_int(0, 4)
-        self.cpu.set_future_value_int(1, 5)
+        for i in range(10):
+            self.cpu.set_future_value_int(i, i+1)
         res = self.cpu.execute_token(othertoken)
         assert self.cpu.get_latest_value_int(0) == 13
         assert called
@@ -1786,6 +1846,31 @@
         assert self.cpu.get_latest_value_float(0) == 13.5
         assert called
 
+    def test_raw_malloced_getarrayitem(self):
+        ARRAY = rffi.CArray(lltype.Signed)
+        descr = self.cpu.arraydescrof(ARRAY)
+        a = lltype.malloc(ARRAY, 10, flavor='raw')
+        a[7] = -4242
+        addr = llmemory.cast_ptr_to_adr(a)
+        abox = BoxInt(heaptracker.adr2int(addr))
+        r1 = self.execute_operation(rop.GETARRAYITEM_RAW, [abox, BoxInt(7)],
+                                    'int', descr=descr)
+        assert r1.getint() == -4242
+        lltype.free(a, flavor='raw')
+
+    def test_raw_malloced_setarrayitem(self):
+        ARRAY = rffi.CArray(lltype.Signed)
+        descr = self.cpu.arraydescrof(ARRAY)
+        a = lltype.malloc(ARRAY, 10, flavor='raw')
+        addr = llmemory.cast_ptr_to_adr(a)
+        abox = BoxInt(heaptracker.adr2int(addr))
+        self.execute_operation(rop.SETARRAYITEM_RAW, [abox, BoxInt(5),
+                                                      BoxInt(12345)],
+                               'void', descr=descr)
+        assert a[5] == 12345
+        lltype.free(a, flavor='raw')
+
+
 class OOtypeBackendTest(BaseBackendTest):
 
     type_system = 'ootype'

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/assembler.py	Thu Sep  9 01:00:13 2010
@@ -1,4 +1,4 @@
-import sys
+import sys, os
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
 from pypy.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT,\
@@ -7,23 +7,35 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.annlowlevel import llhelper
 from pypy.tool.uid import fixid
-from pypy.jit.backend.x86.regalloc import RegAlloc, WORD,\
-     X86RegisterManager, X86XMMRegisterManager, get_ebp_ofs, FRAME_FIXED_SIZE,\
-     FORCE_INDEX_OFS
+from pypy.jit.backend.x86.regalloc import RegAlloc, \
+     X86RegisterManager, X86XMMRegisterManager, get_ebp_ofs
+
+from pypy.jit.backend.x86.arch import FRAME_FIXED_SIZE, FORCE_INDEX_OFS, WORD, IS_X86_32, IS_X86_64
+
+from pypy.jit.backend.x86.regloc import (eax, ecx, edx, ebx,
+                                         esp, ebp, esi, edi,
+                                         xmm0, xmm1, xmm2, xmm3,
+                                         xmm4, xmm5, xmm6, xmm7,
+                                         r8, r9, r10, r11,
+                                         r12, r13, r14, r15,
+                                         X86_64_SCRATCH_REG,
+                                         X86_64_XMM_SCRATCH_REG,
+                                         RegLoc, StackLoc, ConstFloatLoc,
+                                         ImmedLoc, AddressLoc, imm)
+
 from pypy.rlib.objectmodel import we_are_translated, specialize
-from pypy.jit.backend.x86 import codebuf
-from pypy.jit.backend.x86.ri386 import *
-from pypy.jit.metainterp.resoperation import rop
+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.rlib import rgc
-
-# our calling convention - we pass first 6 args in registers
-# and the rest stays on the stack
+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,
 # better safe than sorry
-CALL_ALIGN = 4
+CALL_ALIGN = 16 // WORD
 
 def align_stack_words(words):
     return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1)
@@ -31,16 +43,36 @@
 class MachineCodeBlockWrapper(object):
     MC_DEFAULT_SIZE = 1024*1024
 
-    def __init__(self, bigsize, profile_agent=None):
+    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()
@@ -62,12 +94,25 @@
     def make_new_mc(self):
         new_mc = self._instantiate_mc()
         debug_print('[new machine code block at', new_mc.tell(), ']')
-        self._mc.JMP(rel32(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
@@ -81,24 +126,39 @@
 
 def _new_method(name):
     def method(self, *args):
-        # XXX er.... pretty random number, just to be sure
-        #     not to write half-instruction
-        if self.bytes_free() < 64:
+        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):
+        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
-    mc2 = None
     mc_size = MachineCodeBlockWrapper.MC_DEFAULT_SIZE
     _float_constants = None
     _regalloc = None
+    _output_loop_log = None
 
     def __init__(self, cpu, translate_support_code=False,
                             failargs_limit=1000):
@@ -113,18 +173,26 @@
         self.fail_boxes_ptr = values_array(llmemory.GCREF, failargs_limit)
         self.fail_boxes_float = values_array(lltype.Float, failargs_limit)
         self.fail_ebp = 0
-        self.loc_float_const_neg = None
-        self.loc_float_const_abs = None
+        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.setup_failure_recovery()
+        self._debug = False
+        self.debug_counter_descr = cpu.fielddescrof(DEBUG_COUNTER, 'i')
 
     def leave_jitted_hook(self):
         ptrs = self.fail_boxes_ptr.ar
         llop.gc_assume_young_pointers(lltype.Void,
                                       llmemory.cast_ptr_to_adr(ptrs))
 
-    def make_sure_mc_exists(self):
+    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
@@ -143,11 +211,7 @@
                 ll_new_unicode = gc_ll_descr.get_funcptr_for_newunicode()
                 self.malloc_unicode_func_addr = rffi.cast(lltype.Signed,
                                                           ll_new_unicode)
-            # done
-            # we generate the loop body in 'mc'
-            # 'mc2' is for guard recovery code
-            self.mc = MachineCodeBlockWrapper(self.mc_size, self.cpu.profile_agent)
-            self.mc2 = MachineCodeBlockWrapper(self.mc_size)
+            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:
@@ -157,46 +221,73 @@
                 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 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")
+            for i in range(len(self.loop_run_counters)):
+                name, struct = self.loop_run_counters[i]
+                f.write(str(struct.i) + " " * (8 - len(str(struct.i))) + name + "\n")
+            f.close()
 
     def _build_float_constants(self):
-        # 11 words: 8 words for the data, and up to 3 words for alignment
-        addr = lltype.malloc(rffi.CArray(lltype.Signed), 11, flavor='raw')
+        # 44 bytes: 32 bytes for the data, and up to 12 bytes for alignment
+        addr = lltype.malloc(rffi.CArray(lltype.Char), 44, flavor='raw')
         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
-        addr = rffi.cast(rffi.CArrayPtr(lltype.Signed), float_constants)
-        addr[0] = 0                # \
-        addr[1] = -2147483648      # / for neg
-        addr[2] = 0                #
-        addr[3] = 0                #
-        addr[4] = -1               # \
-        addr[5] = 2147483647       # / for abs
-        addr[6] = 0                #
-        addr[7] = 0                #
-        self.loc_float_const_neg = heap64(float_constants)
-        self.loc_float_const_abs = heap64(float_constants + 16)
+        addr = rffi.cast(rffi.CArrayPtr(lltype.Char), float_constants)
+        qword_padding = '\x00\x00\x00\x00\x00\x00\x00\x00'
+        # 0x8000000000000000
+        neg_const = '\x00\x00\x00\x00\x00\x00\x00\x80'
+        # 0x7FFFFFFFFFFFFFFF
+        abs_const = '\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F'
+        data = neg_const + qword_padding + abs_const + qword_padding
+        for i in range(len(data)):
+            addr[i] = data[i]
+        self.float_const_neg_addr = float_constants
+        self.float_const_abs_addr = float_constants + 16
 
     def _build_malloc_fixedsize_slowpath(self):
-        mc = self.mc2._mc
         # ---------- first helper for the slow path of malloc ----------
-        self.malloc_fixedsize_slowpath1 = mc.tell()
+        self.malloc_fixedsize_slowpath1 = self.mc.tell()
         if self.cpu.supports_floats:          # save the XMM registers in
-            for i in range(8):                # the *caller* frame, from esp+8
-                mc.MOVSD(mem64(esp, 8+8*i), xmm_registers[i])
-        mc.SUB(edx, eax)                      # compute the size we want
-        mc.MOV(mem(esp, 4), edx)              # save it as the new argument
+            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
+        if IS_X86_32:
+            self.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)
+
         addr = self.cpu.gc_ll_descr.get_malloc_fixedsize_slowpath_addr()
-        mc.JMP(rel32(addr))                   # tail call to the real malloc
+        self.mc.JMP(imm(addr))                    # tail call to the real malloc
         # ---------- second helper for the slow path of malloc ----------
-        self.malloc_fixedsize_slowpath2 = mc.tell()
+        self.malloc_fixedsize_slowpath2 = self.mc.tell()
         if self.cpu.supports_floats:          # restore the XMM registers
-            for i in range(8):                # from where they were saved
-                mc.MOVSD(xmm_registers[i], mem64(esp, 8+8*i))
+            for i in range(self.cpu.NUM_REGS):# from where they were saved
+                self.mc.MOVSD_xs(i, (WORD*2)+8*i)
         nursery_free_adr = self.cpu.gc_ll_descr.get_nursery_free_addr()
-        mc.MOV(edx, heap(nursery_free_adr))   # load this in EDX
-        mc.RET()
-        self.mc2.done()
+        self.mc.MOV(edx, heap(nursery_free_adr))   # load this in EDX
+        self.mc.RET()
+        self.mc.done()
 
     def assemble_loop(self, inputargs, operations, looptoken):
         """adds the following attributes to looptoken:
@@ -207,15 +298,18 @@
                _x86_param_depth
                _x86_arglocs
         """
+        if not we_are_translated():
+            # Arguments should be unique
+            assert len(set(inputargs)) == len(inputargs)
+
+        self.setup()
         funcname = self._find_debug_merge_point(operations)
 
-        self.make_sure_mc_exists()
+        
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
+        operations = self._inject_debugging_code(operations)
         arglocs = regalloc.prepare_loop(inputargs, operations, looptoken)
         looptoken._x86_arglocs = arglocs
-        needed_mem = len(arglocs[0]) * 16 + 16
-        if needed_mem >= self.mc.bytes_free():
-            self.mc.make_new_mc()
 
         # profile support
         name = "Loop # %s: %s" % (looptoken.number, funcname)
@@ -230,29 +324,30 @@
         self._patch_stackadjust(adr_stackadjust, frame_depth+param_depth)
         looptoken._x86_frame_depth = frame_depth
         looptoken._x86_param_depth = param_depth
-        # we need to make sure here that we don't overload an mc badly.
-        # a safe estimate is that we need at most 16 bytes per arg
-        needed_mem = len(arglocs[0]) * 16 + 16
-        if needed_mem >= self.mc.bytes_free():
-            self.mc.make_new_mc()
+
         looptoken._x86_direct_bootstrap_code = self.mc.tell()
         self._assemble_bootstrap_direct_call(arglocs, curadr,
                                              frame_depth+param_depth)
         debug_print("Loop #", looptoken.number, "has address",
                     looptoken._x86_loop_code, "to", self.mc.tell())
         self.mc.end_function()
+        self.write_pending_failure_recoveries()
         
-
     def assemble_bridge(self, faildescr, inputargs, operations):
+        if not we_are_translated():
+            # Arguments should be unique
+            assert len(set(inputargs)) == len(inputargs)
+
+        self.setup()
         funcname = self._find_debug_merge_point(operations)
 
-        self.make_sure_mc_exists()
         arglocs = self.rebuild_faillocs_from_descr(
             faildescr._x86_failure_recovery_bytecode)
         if not we_are_translated():
             assert ([loc.assembler() for loc in arglocs] ==
                     [loc.assembler() for loc in faildescr._x86_debug_faillocs])
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
+        operations = self._inject_debugging_code(operations)
         fail_depths = faildescr._x86_current_depths
         regalloc.prepare_bridge(fail_depths, inputargs, arglocs,
                                 operations)
@@ -276,25 +371,81 @@
                     descr_number,
                     "has address", adr_bridge, "to", self.mc.tell())
         self.mc.end_function()
+        self.write_pending_failure_recoveries()
+
+    def write_pending_failure_recoveries(self):
+        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)
+
+        self.pending_guard_tokens = []
+        self.mc.reset_reserved_bytes()
+        self.mc.done()
 
     def _find_debug_merge_point(self, operations):
+
         for op in operations:
             if op.opnum == rop.DEBUG_MERGE_POINT:
-                return op.args[0]._get_str()
-        return ""
+                funcname = op.args[0]._get_str()
+                break
+        else:
+            funcname = "<loop %d>" % len(self.loop_run_counters)
+        # invent the counter, so we don't get too confused
+        if self._debug:
+            struct = lltype.malloc(DEBUG_COUNTER, flavor='raw')
+            struct.i = 0
+            self.loop_run_counters.append((funcname, struct))
+        return funcname
         
     def patch_jump_for_descr(self, faildescr, adr_new_target):
         adr_jump_offset = faildescr._x86_adr_jump_offset
-        mc = codebuf.InMemoryCodeBuilder(adr_jump_offset, adr_jump_offset + 4)
-        mc.write(packimm32(adr_new_target - adr_jump_offset - 4))
+        adr_recovery_stub = faildescr._x86_adr_recovery_stub
+        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.
+        if rx86.fits_in_32bits(offset):
+            mc = codebuf.InMemoryCodeBuilder(adr_jump_offset, adr_jump_offset + 4)
+            mc.writeimm32(offset)
+        else:
+            # "mov r11, addr; jmp r11" is 13 bytes
+            mc = codebuf.InMemoryCodeBuilder(adr_recovery_stub, adr_recovery_stub + 13)
+            mc.MOV_ri(X86_64_SCRATCH_REG.value, adr_new_target)
+            mc.JMP_r(X86_64_SCRATCH_REG.value)
+
         mc.valgrind_invalidated()
         mc.done()
 
+    def _inject_debugging_code(self, operations):
+        if self._debug:
+            # before doing anything, let's increase a counter
+            c_adr = ConstInt(rffi.cast(lltype.Signed,
+                                     self.loop_run_counters[-1][1]))
+            box = BoxInt()
+            box2 = BoxInt()
+            ops = [ResOperation(rop.GETFIELD_RAW, [c_adr],
+                                box, descr=self.debug_counter_descr),
+                   ResOperation(rop.INT_ADD, [box, ConstInt(1)], box2),
+                   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, imm(1))
+            # 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()
-        self.mc2.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
@@ -309,7 +460,7 @@
 
     def _patchable_stackadjust(self):
         # stack adjustment LEA
-        self.mc.LEA(esp, fixedsize_ebp_ofs(0))
+        self.mc.LEA32_rb(esp.value, 0)
         return self.mc.tell() - 4
 
     def _patch_stackadjust(self, adr_lea, reserved_depth):
@@ -318,23 +469,34 @@
         # Compute the correct offset for the instruction LEA ESP, [EBP-4*words].
         # Given that [EBP] is where we saved EBP, i.e. in the last word
         # of our fixed frame, then the 'words' value is:
-        words = (FRAME_FIXED_SIZE - 1) + reserved_depth
+        words = (self.cpu.FRAME_FIXED_SIZE - 1) + reserved_depth
         # align, e.g. for Mac OS X        
         aligned_words = align_stack_words(words+2)-2 # 2 = EIP+EBP
-        mc.write(packimm32(-WORD * aligned_words))
+        mc.writeimm32(-WORD * aligned_words)
         mc.done()
 
     def _call_header(self):
-        self.mc.PUSH(ebp)
-        self.mc.MOV(ebp, esp)
-        self.mc.PUSH(ebx)
-        self.mc.PUSH(esi)
-        self.mc.PUSH(edi)
+        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)
+
+        for i in range(len(self.cpu.CALLEE_SAVE_REGISTERS)-1, -1, -1):
+            self.mc.POP_r(self.cpu.CALLEE_SAVE_REGISTERS[i].value)
+
+        self.mc.POP_r(ebp.value)
+        self.mc.RET()
+
     def _assemble_bootstrap_direct_call(self, arglocs, jmpadr, stackdepth):
+        if IS_X86_64:
+            return self._assemble_bootstrap_direct_call_64(arglocs, jmpadr, 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
@@ -345,23 +507,81 @@
         self._patch_stackadjust(adr_stackadjust, stackdepth)
         for i in range(len(nonfloatlocs)):
             loc = nonfloatlocs[i]
-            if isinstance(loc, REG):
-                self.mc.MOV(loc, mem(ebp, (2 + i) * WORD))
+            if isinstance(loc, RegLoc):
+                assert not loc.is_xmm
+                self.mc.MOV_rb(loc.value, (2 + i) * WORD)
             loc = floatlocs[i]
-            if isinstance(loc, XMMREG):
-                self.mc.MOVSD(loc, mem64(ebp, (1 + i) * 2 * WORD))
+            if isinstance(loc, RegLoc):
+                assert loc.is_xmm
+                self.mc.MOVSD_xb(loc.value, (1 + i) * 2 * WORD)
         tmp = eax
         xmmtmp = xmm0
         for i in range(len(nonfloatlocs)):
             loc = nonfloatlocs[i]
-            if loc is not None and not isinstance(loc, REG):
-                self.mc.MOV(tmp, mem(ebp, (2 + i) * WORD))
+            if loc is not None and not isinstance(loc, RegLoc):
+                self.mc.MOV_rb(tmp.value, (2 + i) * WORD)
                 self.mc.MOV(loc, tmp)
             loc = floatlocs[i]
-            if loc is not None and not isinstance(loc, XMMREG):
-                self.mc.MOVSD(xmmtmp, mem64(ebp, (1 + i) * 2 * WORD))
-                self.mc.MOVSD(loc, xmmtmp)
-        self.mc.JMP(rel32(jmpadr))
+            if loc is not None and not isinstance(loc, RegLoc):
+                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)
+        return adr_stackadjust
+
+    def _assemble_bootstrap_direct_call_64(self, arglocs, jmpadr, stackdepth):
+        # XXX: Very similar to _emit_call_64
+
+        src_locs = []
+        dst_locs = []
+        xmm_src_locs = []
+        xmm_dst_locs = []
+        get_from_stack = []
+
+        # In reverse order for use with pop()
+        unused_gpr = [r9, r8, ecx, edx, esi, edi]
+        unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0]
+
+        nonfloatlocs, floatlocs = arglocs
+        adr_stackadjust = self._call_header()
+        self._patch_stackadjust(adr_stackadjust, stackdepth)
+
+        # The lists are padded with Nones
+        assert len(nonfloatlocs) == len(floatlocs)
+
+        for i in range(len(nonfloatlocs)):
+            loc = nonfloatlocs[i]
+            if loc is not None:
+                if len(unused_gpr) > 0:
+                    src_locs.append(unused_gpr.pop())
+                    dst_locs.append(loc)
+                else:
+                    get_from_stack.append((loc, False))
+
+            floc = floatlocs[i]
+            if floc is not None:
+                if len(unused_xmm) > 0:
+                    xmm_src_locs.append(unused_xmm.pop())
+                    xmm_dst_locs.append(floc)
+                else:
+                    get_from_stack.append((floc, True))
+
+        remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG)
+        remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, X86_64_XMM_SCRATCH_REG)
+
+        for i in range(len(get_from_stack)):
+            loc, is_xmm = get_from_stack[i]
+            if is_xmm:
+                self.mc.MOVSD_xb(X86_64_XMM_SCRATCH_REG.value, (2 + i) * WORD)
+                self.mc.MOVSD(loc, X86_64_XMM_SCRATCH_REG)
+            else:
+                self.mc.MOV_rb(X86_64_SCRATCH_REG.value, (2 + i) * WORD)
+                # XXX: We're assuming that "loc" won't require regloc to
+                # clobber the scratch register
+                self.mc.MOV(loc, X86_64_SCRATCH_REG)
+
+        self.mc.JMP(imm(jmpadr))
+
         return adr_stackadjust
 
     def _assemble_bootstrap_code(self, inputargs, arglocs):
@@ -369,11 +589,12 @@
         adr_stackadjust = self._call_header()
         tmp = X86RegisterManager.all_regs[0]
         xmmtmp = X86XMMRegisterManager.all_regs[0]
+        self.mc._mc.begin_reuse_scratch_register()
         for i in range(len(nonfloatlocs)):
             loc = nonfloatlocs[i]
             if loc is None:
                 continue
-            if isinstance(loc, REG):
+            if isinstance(loc, RegLoc):
                 target = loc
             else:
                 target = tmp
@@ -387,17 +608,20 @@
                 adr = self.fail_boxes_int.get_addr_for_num(i)
                 self.mc.MOV(target, heap(adr))
             if target is not loc:
-                self.mc.MOV(loc, target)
+                assert isinstance(loc, StackLoc)
+                self.mc.MOV_br(loc.value, target.value)
         for i in range(len(floatlocs)):
             loc = floatlocs[i]
             if loc is None:
                 continue
             adr = self.fail_boxes_float.get_addr_for_num(i)
-            if isinstance(loc, REG):
-                self.mc.MOVSD(loc, heap64(adr))
+            if isinstance(loc, RegLoc):
+                self.mc.MOVSD(loc, heap(adr))
             else:
-                self.mc.MOVSD(xmmtmp, heap64(adr))
-                self.mc.MOVSD(loc, xmmtmp)
+                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
 
     def dump(self, text):
@@ -410,27 +634,10 @@
         finally:
             Box._extended_display = _prev
 
-    def _start_block(self):
-        # Return a 'mc' that can be used to write an "atomic" block,
-        # i.e. one that will not contain any JMP.
-        mc = self.mc._mc
-        if not we_are_translated():
-            self._block_started_mc = (self.mc, mc.tell())
-            self.mc = "block started"
-        return mc
-
-    def _stop_block(self):
-        if not we_are_translated():
-            assert self.mc == "block started"
-            self.mc, orgpos = self._block_started_mc
-            assert 0 <= self.mc._mc.tell() - orgpos <= 58, (
-                "too many bytes in _start_block/_stop_block pair")
-            del self._block_started_mc
-
     # ------------------------------------------------------------
 
     def mov(self, from_loc, to_loc):
-        if isinstance(from_loc, XMMREG) or isinstance(to_loc, XMMREG):
+        if (isinstance(from_loc, RegLoc) and from_loc.is_xmm) or (isinstance(to_loc, RegLoc) and to_loc.is_xmm):
             self.mc.MOVSD(to_loc, from_loc)
         else:
             self.mc.MOV(to_loc, from_loc)
@@ -438,24 +645,24 @@
     regalloc_mov = mov # legacy interface
 
     def regalloc_push(self, loc):
-        if isinstance(loc, XMMREG):
-            self.mc.SUB(esp, imm(2*WORD))
-            self.mc.MOVSD(mem64(esp, 0), loc)
-        elif isinstance(loc, MODRM64):
+        if isinstance(loc, RegLoc) and loc.is_xmm:
+            self.mc.SUB_ri(esp.value, 2*WORD)
+            self.mc.MOVSD_sx(0, loc.value)
+        elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8:
             # XXX evil trick
-            self.mc.PUSH(mem(ebp, get_ebp_ofs(loc.position)))
-            self.mc.PUSH(mem(ebp, get_ebp_ofs(loc.position + 1)))
+            self.mc.PUSH_b(get_ebp_ofs(loc.position))
+            self.mc.PUSH_b(get_ebp_ofs(loc.position + 1))
         else:
             self.mc.PUSH(loc)
 
     def regalloc_pop(self, loc):
-        if isinstance(loc, XMMREG):
-            self.mc.MOVSD(loc, mem64(esp, 0))
-            self.mc.ADD(esp, imm(2*WORD))
-        elif isinstance(loc, MODRM64):
+        if isinstance(loc, RegLoc) and loc.is_xmm:
+            self.mc.MOVSD_xs(loc.value, 0)
+            self.mc.ADD_ri(esp.value, 2*WORD)
+        elif WORD == 4 and isinstance(loc, StackLoc) and loc.width == 8:
             # XXX evil trick
-            self.mc.POP(mem(ebp, get_ebp_ofs(loc.position + 1)))
-            self.mc.POP(mem(ebp, get_ebp_ofs(loc.position)))
+            self.mc.POP_b(get_ebp_ofs(loc.position + 1))
+            self.mc.POP_b(get_ebp_ofs(loc.position))
         else:
             self.mc.POP(loc)
 
@@ -472,14 +679,14 @@
         faildescr._x86_current_depths = current_depths
         failargs = guard_op.fail_args
         guard_opnum = guard_op.opnum
-        failaddr = self.implement_guard_recovery(guard_opnum,
-                                                 faildescr, failargs,
-                                                 faillocs)
+        guard_token = self.implement_guard_recovery(guard_opnum,
+                                                    faildescr, failargs,
+                                                    faillocs)
         if op is None:
             dispatch_opnum = guard_opnum
         else:
             dispatch_opnum = op.opnum
-        res = genop_guard_list[dispatch_opnum](self, op, guard_op, failaddr,
+        res = genop_guard_list[dispatch_opnum](self, op, guard_op, guard_token,
                                                arglocs, resloc)
         faildescr._x86_adr_jump_offset = res
 
@@ -506,103 +713,161 @@
             rl = result_loc.lowest8bits()
             if isinstance(op.args[0], Const):
                 self.mc.CMP(arglocs[1], arglocs[0])
-                getattr(self.mc, 'SET' + rev_cond)(rl)
+                self.mc.SET_ir(rx86.Conditions[rev_cond], rl.value)
             else:
                 self.mc.CMP(arglocs[0], arglocs[1])
-                getattr(self.mc, 'SET' + cond)(rl)
-            self.mc.MOVZX(result_loc, rl)
+                self.mc.SET_ir(rx86.Conditions[cond], rl.value)
+            self.mc.MOVZX8_rr(result_loc.value, rl.value)
         return genop_cmp
 
     def _cmpop_float(cond, is_ne=False):
         def genop_cmp(self, op, arglocs, result_loc):
             self.mc.UCOMISD(arglocs[0], arglocs[1])
-            rl = result_loc.lowest8bits()
-            rh = result_loc.higher8bits()
-            getattr(self.mc, 'SET' + cond)(rl)
+            tmp1 = result_loc.lowest8bits()
+            if IS_X86_32:
+                tmp2 = result_loc.higher8bits()
+            elif IS_X86_64:
+                tmp2 = X86_64_SCRATCH_REG.lowest8bits()
+
+            self.mc.SET_ir(rx86.Conditions[cond], tmp1.value)
             if is_ne:
-                self.mc.SETP(rh)
-                self.mc.OR(rl, rh)
+                self.mc.SET_ir(rx86.Conditions['P'], tmp2.value)
+                self.mc.OR8_rr(tmp1.value, tmp2.value)
             else:
-                self.mc.SETNP(rh)
-                self.mc.AND(rl, rh)
-            self.mc.MOVZX(result_loc, rl)
+                self.mc.SET_ir(rx86.Conditions['NP'], tmp2.value)
+                self.mc.AND8_rr(tmp1.value, tmp2.value)
+            self.mc.MOVZX8_rr(result_loc.value, tmp1.value)
         return genop_cmp
 
     def _cmpop_guard(cond, rev_cond, false_cond, false_rev_cond):
-        def genop_cmp_guard(self, op, guard_op, addr, arglocs, result_loc):
+        def genop_cmp_guard(self, op, guard_op, guard_token, arglocs, result_loc):
             guard_opnum = guard_op.opnum
             if isinstance(op.args[0], Const):
                 self.mc.CMP(arglocs[1], arglocs[0])
                 if guard_opnum == rop.GUARD_FALSE:
-                    name = 'J' + rev_cond
-                    return self.implement_guard(addr, getattr(self.mc, name))
+                    return self.implement_guard(guard_token, rev_cond)
                 else:
-                    name = 'J' + false_rev_cond
-                    return self.implement_guard(addr, getattr(self.mc, name))
+                    return self.implement_guard(guard_token, false_rev_cond)
             else:
                 self.mc.CMP(arglocs[0], arglocs[1])
                 if guard_opnum == rop.GUARD_FALSE:
-                    name = 'J' + cond
-                    return self.implement_guard(addr, getattr(self.mc, name))
+                    return self.implement_guard(guard_token, cond)
                 else:
-                    name = 'J' + false_cond
-                    return self.implement_guard(addr, getattr(self.mc, name))
+                    return self.implement_guard(guard_token, false_cond)
         return genop_cmp_guard
 
     def _cmpop_guard_float(cond, false_cond, need_jp):
-        def genop_cmp_guard_float(self, op, guard_op, addr, arglocs,
+        def genop_cmp_guard_float(self, op, guard_op, guard_token, arglocs,
                                   result_loc):
             guard_opnum = guard_op.opnum
             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:
-                mc = self.mc._mc
-                name = 'J' + cond
                 if need_jp:
-                    mc.JP(rel8(6))
-                getattr(mc, name)(rel32(addr))
-                return mc.tell() - 4
+                    self.mc.J_il8(rx86.Conditions['P'], 6)
+                return self.implement_guard(guard_token, cond)
             else:
                 if need_jp:
-                    mc = self.mc._mc
-                    mc.JP(rel8(2))
-                    getattr(mc, 'J' + cond)(rel8(5))
-                    return self.implement_guard(addr, mc.JMP)
-                name = 'J' + false_cond
-                return self.implement_guard(addr, getattr(self.mc, name))
+                    self.mc.J_il8(rx86.Conditions['P'], 2)
+                    self.mc.J_il8(rx86.Conditions[cond], 5)
+                    return self.implement_guard(guard_token)
+                return self.implement_guard(guard_token, false_cond)
         return genop_cmp_guard_float
 
-    @specialize.arg(5)
-    def _emit_call(self, x, arglocs, start=0, tmp=eax, force_mc=False,
-                   mc=None):
-        if not force_mc:
-            mc = self.mc
+    def _emit_call(self, x, arglocs, start=0, tmp=eax):
+        if IS_X86_64:
+            return self._emit_call_64(x, arglocs, start)
+
         p = 0
         n = len(arglocs)
         for i in range(start, n):
             loc = arglocs[i]
-            if isinstance(loc, REG):
-                if isinstance(loc, XMMREG):
-                    mc.MOVSD(mem64(esp, p), loc)
+            if isinstance(loc, RegLoc):
+                if loc.is_xmm:
+                    self.mc.MOVSD_sx(p, loc.value)
                 else:
-                    mc.MOV(mem(esp, p), loc)
+                    self.mc.MOV_sr(p, loc.value)
             p += round_up_to_4(loc.width)
         p = 0
         for i in range(start, n):
             loc = arglocs[i]
-            if not isinstance(loc, REG):
-                if isinstance(loc, MODRM64):
-                    mc.MOVSD(xmm0, loc)
-                    mc.MOVSD(mem64(esp, p), xmm0)
+            if not isinstance(loc, RegLoc):
+                if loc.width == 8:
+                    self.mc.MOVSD(xmm0, loc)
+                    self.mc.MOVSD_sx(p, xmm0.value)
                 else:
-                    mc.MOV(tmp, loc)
-                    mc.MOV(mem(esp, p), tmp)
+                    self.mc.MOV(tmp, loc)
+                    self.mc.MOV_sr(p, tmp.value)
             p += round_up_to_4(loc.width)
         self._regalloc.reserve_param(p//WORD)
-        mc.CALL(x)
+        # x is a location
+        self.mc.CALL(x)
         self.mark_gc_roots()
+
+    def _emit_call_64(self, x, arglocs, start=0):
+        src_locs = []
+        dst_locs = []
+        xmm_src_locs = []
+        xmm_dst_locs = []
+        pass_on_stack = []
+
+        # In reverse order for use with pop()
+        unused_gpr = [r9, r8, ecx, edx, esi, edi]
+        unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0]
+
+        for i in range(start, len(arglocs)):
+            loc = arglocs[i]
+            # XXX: Should be much simplier to tell whether a location is a
+            # float! It's so ugly because we have to "guard" the access to
+            # .type with isinstance, since not all AssemblerLocation classes
+            # are "typed"
+            if ((isinstance(loc, RegLoc) and loc.is_xmm) or
+                (isinstance(loc, StackLoc) and loc.type == FLOAT) or
+                (isinstance(loc, ConstFloatLoc))):
+                if len(unused_xmm) > 0:
+                    xmm_src_locs.append(loc)
+                    xmm_dst_locs.append(unused_xmm.pop())
+                else:
+                    pass_on_stack.append(loc)
+            else:
+                if len(unused_gpr) > 0:
+                    src_locs.append(loc)
+                    dst_locs.append(unused_gpr.pop())
+                else:
+                    pass_on_stack.append(loc)
         
+        # Emit instructions to pass the stack arguments
+        # XXX: Would be nice to let remap_frame_layout take care of this, but
+        # we'd need to create something like StackLoc, but relative to esp,
+        # and I don't know if it's worth it.
+        for i in range(len(pass_on_stack)):
+            loc = pass_on_stack[i]
+            if not isinstance(loc, RegLoc):
+                if isinstance(loc, StackLoc) and loc.type == FLOAT:
+                    self.mc.MOVSD(X86_64_XMM_SCRATCH_REG, loc)
+                    self.mc.MOVSD_sx(i*WORD, X86_64_XMM_SCRATCH_REG.value)
+                else:
+                    self.mc.MOV(X86_64_SCRATCH_REG, loc)
+                    self.mc.MOV_sr(i*WORD, X86_64_SCRATCH_REG.value)
+            else:
+                # It's a register
+                if loc.is_xmm:
+                    self.mc.MOVSD_sx(i*WORD, loc.value)
+                else:
+                    self.mc.MOV_sr(i*WORD, loc.value)
+
+        # Handle register arguments
+        remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG)
+        remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, X86_64_XMM_SCRATCH_REG)
+
+        self._regalloc.reserve_param(len(pass_on_stack))
+        self.mc.CALL(x)
+        self.mark_gc_roots()
+
     def call(self, addr, args, res):
-        self._emit_call(rel32(addr), args)
+        self._emit_call(imm(addr), args)
         assert res is eax
 
     genop_int_neg = _unaryop("NEG")
@@ -613,6 +878,9 @@
     genop_int_and = _binaryop("AND", True)
     genop_int_or  = _binaryop("OR", True)
     genop_int_xor = _binaryop("XOR", True)
+    genop_int_lshift = _binaryop("SHL")
+    genop_int_rshift = _binaryop("SAR")
+    genop_uint_rshift = _binaryop("SHR")
     genop_float_add = _binaryop("ADDSD", True)
     genop_float_sub = _binaryop('SUBSD')
     genop_float_mul = _binaryop('MULSD', True)
@@ -659,26 +927,27 @@
     genop_guard_float_gt = _cmpop_guard_float("A", "BE", False)
     genop_guard_float_ge = _cmpop_guard_float("AE", "B", False)
 
-    def genop_guard_float_ne(self, op, guard_op, addr, arglocs, result_loc):
+    def genop_guard_float_ne(self, op, guard_op, guard_token, arglocs, result_loc):
         guard_opnum = guard_op.opnum
         self.mc.UCOMISD(arglocs[0], arglocs[1])
-        mc = self.mc._mc
+        # 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:
-            mc.JP(rel8(6))
-            mc.JE(rel32(addr))
-            return mc.tell() - 4
-        else:
-            mc.JP(rel8(2))
-            mc.JE(rel8(5))
-            return self.implement_guard(addr, mc.JMP)
+            self.mc.J_il8(rx86.Conditions['P'], 6)
+            return self.implement_guard(guard_token, 'E')
+        else:
+            self.mc.J_il8(rx86.Conditions['P'], 2)
+            self.mc.J_il8(rx86.Conditions['E'], 5)
+            return self.implement_guard(guard_token)
 
     def genop_float_neg(self, op, arglocs, resloc):
         # Following what gcc does: res = x ^ 0x8000000000000000
-        self.mc.XORPD(arglocs[0], self.loc_float_const_neg)
+        self.mc.XORPD(arglocs[0], heap(self.float_const_neg_addr))
 
     def genop_float_abs(self, op, arglocs, resloc):
         # Following what gcc does: res = x & 0x7FFFFFFFFFFFFFFF
-        self.mc.ANDPD(arglocs[0], self.loc_float_const_abs)
+        self.mc.ANDPD(arglocs[0], heap(self.float_const_abs_addr))
 
     def genop_cast_float_to_int(self, op, arglocs, resloc):
         self.mc.CVTTSD2SI(resloc, arglocs[0])
@@ -686,70 +955,56 @@
     def genop_cast_int_to_float(self, op, arglocs, resloc):
         self.mc.CVTSI2SD(resloc, arglocs[0])
 
-    def genop_int_lshift(self, op, arglocs, resloc):
-        loc, loc2 = arglocs
-        if loc2 is ecx:
-            loc2 = cl
-        self.mc.SHL(loc, loc2)
-
-    def genop_int_rshift(self, op, arglocs, resloc):
-        loc, loc2 = arglocs
-        if loc2 is ecx:
-            loc2 = cl
-        self.mc.SAR(loc, loc2)
-
-    def genop_uint_rshift(self, op, arglocs, resloc):
-        loc, loc2 = arglocs
-        if loc2 is ecx:
-            loc2 = cl
-        self.mc.SHR(loc, loc2)
-
-    def genop_guard_int_is_true(self, op, guard_op, addr, arglocs, resloc):
+    def genop_guard_int_is_true(self, op, guard_op, guard_token, arglocs, resloc):
         guard_opnum = guard_op.opnum
-        self.mc.CMP(arglocs[0], imm8(0))
+        self.mc.CMP(arglocs[0], imm(0))
         if guard_opnum == rop.GUARD_TRUE:
-            return self.implement_guard(addr, self.mc.JZ)
+            return self.implement_guard(guard_token, 'Z')
         else:
-            return self.implement_guard(addr, self.mc.JNZ)
+            return self.implement_guard(guard_token, 'NZ')
 
     def genop_int_is_true(self, op, arglocs, resloc):
-        self.mc.CMP(arglocs[0], imm8(0))
+        self.mc.CMP(arglocs[0], imm(0))
         rl = resloc.lowest8bits()
-        self.mc.SETNE(rl)
-        self.mc.MOVZX(resloc, rl)
+        self.mc.SET_ir(rx86.Conditions['NE'], rl.value)
+        self.mc.MOVZX8(resloc, rl)
 
-    def genop_guard_int_is_zero(self, op, guard_op, addr, arglocs, resloc):
+    def genop_guard_int_is_zero(self, op, guard_op, guard_token, arglocs, resloc):
         guard_opnum = guard_op.opnum
-        self.mc.CMP(arglocs[0], imm8(0))
+        self.mc.CMP(arglocs[0], imm(0))
         if guard_opnum == rop.GUARD_TRUE:
-            return self.implement_guard(addr, self.mc.JNZ)
+            return self.implement_guard(guard_token, 'NZ')
         else:
-            return self.implement_guard(addr, self.mc.JZ)
+            return self.implement_guard(guard_token, 'Z')
 
     def genop_int_is_zero(self, op, arglocs, resloc):
-        self.mc.CMP(arglocs[0], imm8(0))
+        self.mc.CMP(arglocs[0], imm(0))
         rl = resloc.lowest8bits()
-        self.mc.SETE(rl)
-        self.mc.MOVZX(resloc, rl)
+        self.mc.SET_ir(rx86.Conditions['E'], rl.value)
+        self.mc.MOVZX8(resloc, rl)
 
     def genop_same_as(self, op, arglocs, resloc):
         self.mov(arglocs[0], resloc)
     #genop_cast_ptr_to_int = genop_same_as
 
     def genop_int_mod(self, op, arglocs, resloc):
-        self.mc.CDQ()
-        self.mc.IDIV(ecx)
+        if IS_X86_32:
+            self.mc.CDQ()
+        elif IS_X86_64:
+            self.mc.CQO()
+
+        self.mc.IDIV_r(ecx.value)
 
     genop_int_floordiv = genop_int_mod
 
     def genop_uint_floordiv(self, op, arglocs, resloc):
-        self.mc.XOR(edx, edx)
-        self.mc.DIV(ecx)
+        self.mc.XOR_rr(edx.value, edx.value)
+        self.mc.DIV_r(ecx.value)
 
     def genop_new_with_vtable(self, op, arglocs, result_loc):
         assert result_loc is eax
         loc_vtable = arglocs[-1]
-        assert isinstance(loc_vtable, IMM32)
+        assert isinstance(loc_vtable, ImmedLoc)
         arglocs = arglocs[:-1]
         self.call(self.malloc_func_addr, arglocs, eax)
         # xxx ignore NULL returns for now
@@ -757,7 +1012,9 @@
 
     def set_vtable(self, loc, loc_vtable):
         if self.cpu.vtable_offset is not None:
-            self.mc.MOV(mem(loc, self.cpu.vtable_offset), loc_vtable)
+            assert isinstance(loc, RegLoc)
+            assert isinstance(loc_vtable, ImmedLoc)
+            self.mc.MOV_mi((loc.value, self.cpu.vtable_offset), loc_vtable.value)
 
     # XXX genop_new is abused for all varsized mallocs with Boehm, for now
     # (instead of genop_new_array, genop_newstr, genop_newunicode)
@@ -779,16 +1036,22 @@
 
     def genop_getfield_gc(self, op, arglocs, resloc):
         base_loc, ofs_loc, size_loc = arglocs
-        assert isinstance(size_loc, IMM32)
+        assert isinstance(size_loc, ImmedLoc)
+        assert isinstance(resloc, RegLoc)
         size = size_loc.value
-        if size == 1:
-            self.mc.MOVZX(resloc, addr8_add(base_loc, ofs_loc))
+
+        source_addr = AddressLoc(base_loc, ofs_loc)
+        if resloc.is_xmm:
+            self.mc.MOVSD(resloc, source_addr)
+        elif size == 1:
+            self.mc.MOVZX8(resloc, source_addr)
         elif size == 2:
-            self.mc.MOVZX(resloc, addr_add(base_loc, ofs_loc))
-        elif size == WORD:
-            self.mc.MOV(resloc, addr_add(base_loc, ofs_loc))
-        elif size == 8:
-            self.mc.MOVSD(resloc, addr64_add(base_loc, ofs_loc))
+            self.mc.MOVZX16(resloc, source_addr)
+        elif size == 4:
+            # MOV32 is zero-extending on 64-bit, so this is okay
+            self.mc.MOV32(resloc, source_addr)
+        elif IS_X86_64 and size == 8:
+            self.mc.MOV(resloc, source_addr)
         else:
             raise NotImplementedError("getfield size = %d" % size)
 
@@ -798,20 +1061,22 @@
 
     def genop_getarrayitem_gc(self, op, arglocs, resloc):
         base_loc, ofs_loc, scale, ofs = arglocs
-        assert isinstance(ofs, IMM32)
-        assert isinstance(scale, IMM32)
+        assert isinstance(ofs, ImmedLoc)
+        assert isinstance(scale, ImmedLoc)
+        src_addr = addr_add(base_loc, ofs_loc, ofs.value, scale.value)
         if op.result.type == FLOAT:
-            self.mc.MOVSD(resloc, addr64_add(base_loc, ofs_loc, ofs.value,
-                                             scale.value))
+            self.mc.MOVSD(resloc, src_addr)
         else:
             if scale.value == 0:
-                self.mc.MOVZX(resloc, addr8_add(base_loc, ofs_loc, ofs.value,
-                                                scale.value))
+                self.mc.MOVZX8(resloc, src_addr)
+            elif scale.value == 1:
+                self.mc.MOVZX16(resloc, src_addr)
             elif scale.value == 2:
-                self.mc.MOV(resloc, addr_add(base_loc, ofs_loc, ofs.value,
-                                             scale.value))
+                self.mc.MOV32(resloc, src_addr)
+            elif IS_X86_64 and scale.value == 3:
+                self.mc.MOV(resloc, src_addr)
             else:
-                print "[asmgen]setarrayitem unsupported size: %d" % scale.value
+                print "[asmgen]getarrayitem unsupported size: %d" % scale.value
                 raise NotImplementedError()
 
     genop_getarrayitem_gc_pure = genop_getarrayitem_gc
@@ -819,34 +1084,39 @@
 
     def genop_discard_setfield_gc(self, op, arglocs):
         base_loc, ofs_loc, size_loc, value_loc = arglocs
-        assert isinstance(size_loc, IMM32)
+        assert isinstance(size_loc, ImmedLoc)
         size = size_loc.value
-        if size == WORD * 2:
-            self.mc.MOVSD(addr64_add(base_loc, ofs_loc), value_loc)
-        elif size == WORD:
-            self.mc.MOV(addr_add(base_loc, ofs_loc), value_loc)
+        dest_addr = AddressLoc(base_loc, ofs_loc)
+        if isinstance(value_loc, RegLoc) and value_loc.is_xmm:
+            self.mc.MOVSD(dest_addr, value_loc)
+        elif IS_X86_64 and size == 8:
+            self.mc.MOV(dest_addr, value_loc)
+        elif size == 4:
+            self.mc.MOV32(dest_addr, value_loc)
         elif size == 2:
-            self.mc.MOV16(addr_add(base_loc, ofs_loc), value_loc)
+            self.mc.MOV16(dest_addr, value_loc)
         elif size == 1:
-            self.mc.MOV(addr8_add(base_loc, ofs_loc), value_loc.lowest8bits())
+            self.mc.MOV8(dest_addr, value_loc.lowest8bits())
         else:
             print "[asmgen]setfield addr size %d" % size
             raise NotImplementedError("Addr size %d" % size)
 
     def genop_discard_setarrayitem_gc(self, op, arglocs):
         base_loc, ofs_loc, value_loc, scale_loc, baseofs = arglocs
-        assert isinstance(baseofs, IMM32)
-        assert isinstance(scale_loc, IMM32)
+        assert isinstance(baseofs, ImmedLoc)
+        assert isinstance(scale_loc, ImmedLoc)
+        dest_addr = AddressLoc(base_loc, ofs_loc, scale_loc.value, baseofs.value)
         if op.args[2].type == FLOAT:
-            self.mc.MOVSD(addr64_add(base_loc, ofs_loc, baseofs.value,
-                                     scale_loc.value), value_loc)
+            self.mc.MOVSD(dest_addr, value_loc)
         else:
-            if scale_loc.value == 2:
-                self.mc.MOV(addr_add(base_loc, ofs_loc, baseofs.value,
-                                     scale_loc.value), value_loc)
+            if IS_X86_64 and scale_loc.value == 3:
+                self.mc.MOV(dest_addr, value_loc)
+            elif scale_loc.value == 2:
+                self.mc.MOV32(dest_addr, value_loc)
+            elif scale_loc.value == 1:
+                self.mc.MOV16(dest_addr, value_loc)
             elif scale_loc.value == 0:
-                self.mc.MOV(addr8_add(base_loc, ofs_loc, baseofs.value,
-                                      scale_loc.value), value_loc.lowest8bits())
+                self.mc.MOV8(dest_addr, value_loc.lowest8bits())
             else:
                 raise NotImplementedError("scale = %d" % scale_loc.value)
 
@@ -855,17 +1125,17 @@
         basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
                                               self.cpu.translate_support_code)
         assert itemsize == 1
-        self.mc.MOV(addr8_add(base_loc, ofs_loc, basesize),
-                    val_loc.lowest8bits())
+        dest_addr = AddressLoc(base_loc, ofs_loc, 0, basesize)
+        self.mc.MOV8(dest_addr, val_loc.lowest8bits())
 
     def genop_discard_unicodesetitem(self, op, arglocs):
         base_loc, ofs_loc, val_loc = arglocs
         basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
                                               self.cpu.translate_support_code)
         if itemsize == 4:
-            self.mc.MOV(addr_add(base_loc, ofs_loc, basesize, 2), val_loc)
+            self.mc.MOV32(AddressLoc(base_loc, ofs_loc, 2, basesize), val_loc)
         elif itemsize == 2:
-            self.mc.MOV16(addr_add(base_loc, ofs_loc, basesize, 1), val_loc)
+            self.mc.MOV16(AddressLoc(base_loc, ofs_loc, 1, basesize), val_loc)
         else:
             assert 0, itemsize
 
@@ -886,7 +1156,7 @@
 
     def genop_arraylen_gc(self, op, arglocs, resloc):
         base_loc, ofs_loc = arglocs
-        assert isinstance(ofs_loc, IMM32)
+        assert isinstance(ofs_loc, ImmedLoc)
         self.mc.MOV(resloc, addr_add_const(base_loc, ofs_loc.value))
 
     def genop_strgetitem(self, op, arglocs, resloc):
@@ -894,83 +1164,83 @@
         basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
                                              self.cpu.translate_support_code)
         assert itemsize == 1
-        self.mc.MOVZX(resloc, addr8_add(base_loc, ofs_loc, basesize))
+        self.mc.MOVZX8(resloc, AddressLoc(base_loc, ofs_loc, 0, basesize))
 
     def genop_unicodegetitem(self, op, arglocs, resloc):
         base_loc, ofs_loc = arglocs
         basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
                                              self.cpu.translate_support_code)
         if itemsize == 4:
-            self.mc.MOV(resloc, addr_add(base_loc, ofs_loc, basesize, 2))
+            self.mc.MOV32(resloc, AddressLoc(base_loc, ofs_loc, 2, basesize))
         elif itemsize == 2:
-            self.mc.MOVZX(resloc, addr_add(base_loc, ofs_loc, basesize, 1))
+            self.mc.MOVZX16(resloc, AddressLoc(base_loc, ofs_loc, 1, basesize))
         else:
             assert 0, itemsize
 
-    def genop_guard_guard_true(self, ign_1, guard_op, addr, locs, ign_2):
+    def genop_guard_guard_true(self, ign_1, guard_op, guard_token, locs, ign_2):
         loc = locs[0]
         self.mc.TEST(loc, loc)
-        return self.implement_guard(addr, self.mc.JZ)
+        return self.implement_guard(guard_token, 'Z')
     genop_guard_guard_nonnull = genop_guard_guard_true
 
-    def genop_guard_guard_no_exception(self, ign_1, guard_op, addr,
+    def genop_guard_guard_no_exception(self, ign_1, guard_op, guard_token,
                                        locs, ign_2):
         self.mc.CMP(heap(self.cpu.pos_exception()), imm(0))
-        return self.implement_guard(addr, self.mc.JNZ)
+        return self.implement_guard(guard_token, 'NZ')
 
-    def genop_guard_guard_exception(self, ign_1, guard_op, addr,
+    def genop_guard_guard_exception(self, ign_1, guard_op, guard_token,
                                     locs, resloc):
         loc = locs[0]
         loc1 = locs[1]
         self.mc.MOV(loc1, heap(self.cpu.pos_exception()))
         self.mc.CMP(loc1, loc)
-        addr = self.implement_guard(addr, self.mc.JNE)
+        addr = self.implement_guard(guard_token, 'NE')
         if resloc is not None:
             self.mc.MOV(resloc, heap(self.cpu.pos_exc_value()))
         self.mc.MOV(heap(self.cpu.pos_exception()), imm(0))
         self.mc.MOV(heap(self.cpu.pos_exc_value()), imm(0))
         return addr
 
-    def _gen_guard_overflow(self, guard_op, addr):
+    def _gen_guard_overflow(self, guard_op, guard_token):
         guard_opnum = guard_op.opnum
         if guard_opnum == rop.GUARD_NO_OVERFLOW:
-            return self.implement_guard(addr, self.mc.JO)
+            return self.implement_guard(guard_token, 'O')
         elif guard_opnum == rop.GUARD_OVERFLOW:
-            return self.implement_guard(addr, self.mc.JNO)
+            return self.implement_guard(guard_token, 'NO')
         else:
             print "int_xxx_ovf followed by", guard_op.getopname()
             raise AssertionError
 
-    def genop_guard_int_add_ovf(self, op, guard_op, addr, arglocs, result_loc):
+    def genop_guard_int_add_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
         self.genop_int_add(op, arglocs, result_loc)
-        return self._gen_guard_overflow(guard_op, addr)
+        return self._gen_guard_overflow(guard_op, guard_token)
 
-    def genop_guard_int_sub_ovf(self, op, guard_op, addr, arglocs, result_loc):
+    def genop_guard_int_sub_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
         self.genop_int_sub(op, arglocs, result_loc)
-        return self._gen_guard_overflow(guard_op, addr)
+        return self._gen_guard_overflow(guard_op, guard_token)
 
-    def genop_guard_int_mul_ovf(self, op, guard_op, addr, arglocs, result_loc):
+    def genop_guard_int_mul_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
         self.genop_int_mul(op, arglocs, result_loc)
-        return self._gen_guard_overflow(guard_op, addr)
+        return self._gen_guard_overflow(guard_op, guard_token)
 
-    def genop_guard_guard_false(self, ign_1, guard_op, addr, locs, ign_2):
+    def genop_guard_guard_false(self, ign_1, guard_op, guard_token, locs, ign_2):
         loc = locs[0]
         self.mc.TEST(loc, loc)
-        return self.implement_guard(addr, self.mc.JNZ)
+        return self.implement_guard(guard_token, 'NZ')
     genop_guard_guard_isnull = genop_guard_guard_false
 
-    def genop_guard_guard_value(self, ign_1, guard_op, addr, locs, ign_2):
+    def genop_guard_guard_value(self, ign_1, guard_op, guard_token, locs, ign_2):
         if guard_op.args[0].type == FLOAT:
             assert guard_op.args[1].type == FLOAT
             self.mc.UCOMISD(locs[0], locs[1])
         else:
             self.mc.CMP(locs[0], locs[1])
-        return self.implement_guard(addr, self.mc.JNE)
+        return self.implement_guard(guard_token, 'NE')
 
-    def _cmp_guard_class(self, mc, locs):
+    def _cmp_guard_class(self, locs):
         offset = self.cpu.vtable_offset
         if offset is not None:
-            mc.CMP(mem(locs[0], offset), locs[1])
+            self.mc.CMP(mem(locs[0], offset), locs[1])
         else:
             # XXX hard-coded assumption: to go from an object to its class
             # we use the following algorithm:
@@ -979,7 +1249,7 @@
             #   - multiply by 4 and use it as an offset in type_info_group
             #   - add 16 bytes, to go past the TYPE_INFO structure
             loc = locs[1]
-            assert isinstance(loc, IMM32)
+            assert isinstance(loc, ImmedLoc)
             classptr = loc.value
             # here, we have to go back from 'classptr' to the value expected
             # from reading the 16 bits in the object header
@@ -987,38 +1257,42 @@
             sizeof_ti = rffi.sizeof(GCData.TYPE_INFO)
             type_info_group = llop.gc_get_type_info_group(llmemory.Address)
             type_info_group = rffi.cast(lltype.Signed, type_info_group)
-            expected_typeid = (classptr - sizeof_ti - type_info_group) >> 2
-            mc.CMP16(mem(locs[0], 0), imm32(expected_typeid))
-
-    def genop_guard_guard_class(self, ign_1, guard_op, addr, locs, ign_2):
-        mc = self._start_block()
-        self._cmp_guard_class(mc, locs)
-        self._stop_block()
-        return self.implement_guard(addr, self.mc.JNE)
+            expected_typeid = classptr - sizeof_ti - type_info_group
+            if IS_X86_32:
+                expected_typeid >>= 2
+                self.mc.CMP16(mem(locs[0], 0), ImmedLoc(expected_typeid))
+            elif IS_X86_64:
+                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)
+        return self.implement_guard(guard_token, 'NE')
 
     def genop_guard_guard_nonnull_class(self, ign_1, guard_op,
-                                        addr, locs, ign_2):
-        mc = self._start_block()
-        mc.CMP(locs[0], imm8(1))
-        mc.JB(rel8_patched_later)
-        jb_location = mc.get_relative_pos()
-        self._cmp_guard_class(mc, locs)
+                                        guard_token, locs, ign_2):
+        self.mc.ensure_bytes_available(256)
+        self.mc.CMP(locs[0], imm(1))
+        # Patched below
+        self.mc.J_il8(rx86.Conditions['B'], 0)
+        jb_location = self.mc.get_relative_pos()
+        self._cmp_guard_class(locs)
         # patch the JB above
-        offset = mc.get_relative_pos() - jb_location
+        offset = self.mc.get_relative_pos() - jb_location
         assert 0 < offset <= 127
-        mc.overwrite(jb_location-1, [chr(offset)])
-        self._stop_block()
+        self.mc.overwrite(jb_location-1, [chr(offset)])
         #
-        return self.implement_guard(addr, self.mc.JNE)
+        return self.implement_guard(guard_token, 'NE')
 
     def implement_guard_recovery(self, guard_opnum, faildescr, failargs,
                                                                fail_locs):
         exc = (guard_opnum == rop.GUARD_EXCEPTION or
                guard_opnum == rop.GUARD_NO_EXCEPTION or
                guard_opnum == rop.GUARD_NOT_FORCED)
-        return self.generate_quick_failure(faildescr, failargs, fail_locs, exc)
+        desc_bytes = self.failure_recovery_description(failargs, fail_locs)
+        return GuardToken(faildescr, failargs, fail_locs, exc, desc_bytes)
 
-    def generate_quick_failure(self, faildescr, failargs, fail_locs, exc):
+    def generate_quick_failure(self, mc, faildescr, failargs, fail_locs, exc, desc_bytes):
         """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
@@ -1026,38 +1300,43 @@
         really handle recovery from this particular failure.
         """
         fail_index = self.cpu.get_fail_descr_number(faildescr)
-        bytes_needed = 20 + 5 * len(failargs)    # conservative estimate
-        if self.mc2.bytes_free() < bytes_needed:
-            self.mc2.make_new_mc()
-        mc = self.mc2._mc
         addr = mc.tell()
         withfloats = False
         for box in failargs:
             if box is not None and box.type == FLOAT:
                 withfloats = True
                 break
-        mc.CALL(rel32(self.failure_recovery_code[exc + 2 * withfloats]))
+        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()
-        self.write_failure_recovery_description(mc, failargs, fail_locs)
+        for byte in desc_bytes:
+            mc.writechr(ord(byte))
         # write the fail_index too
-        mc.write(packimm32(fail_index))
+        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
 
     DESCR_REF       = 0x00
     DESCR_INT       = 0x01
     DESCR_FLOAT     = 0x02
     DESCR_SPECIAL   = 0x03
-    CODE_FROMSTACK  = 4*8
+    # XXX: 4*8 works on i386, should we optimize for that case?
+    CODE_FROMSTACK  = 4*16
     CODE_STOP       = 0 | DESCR_SPECIAL
     CODE_HOLE       = 4 | DESCR_SPECIAL
 
-    def write_failure_recovery_description(self, mc, failargs, locs):
+    def failure_recovery_description(self, failargs, locs):
+        desc_bytes = []
         for i in range(len(failargs)):
             arg = failargs[i]
             if arg is not None:
@@ -1070,24 +1349,30 @@
                 else:
                     raise AssertionError("bogus kind")
                 loc = locs[i]
-                if isinstance(loc, MODRM):
+                if isinstance(loc, StackLoc):
                     n = self.CODE_FROMSTACK//4 + loc.position
                 else:
-                    assert isinstance(loc, REG)
-                    n = loc.op
+                    assert isinstance(loc, RegLoc)
+                    n = loc.value
                 n = kind + 4*n
                 while n > 0x7F:
-                    mc.writechr((n & 0x7F) | 0x80)
+                    desc_bytes.append(chr((n & 0x7F) | 0x80))
                     n >>= 7
             else:
                 n = self.CODE_HOLE
-            mc.writechr(n)
-        mc.writechr(self.CODE_STOP)
+            desc_bytes.append(chr(n))
+        desc_bytes.append(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
+        descr_to_box_type = [REF, INT, FLOAT]
         bytecode = rffi.cast(rffi.UCHARP, bytecode)
         arglocs = []
         while 1:
@@ -1112,7 +1397,7 @@
                     size = 2
                 else:
                     size = 1
-                loc = X86FrameManager.frame_pos(code, size)
+                loc = X86FrameManager.frame_pos(code, descr_to_box_type[kind])
             elif code == self.CODE_STOP:
                 break
             elif code == self.CODE_HOLE:
@@ -1122,16 +1407,16 @@
                 kind = code & 3
                 code >>= 2
                 if kind == self.DESCR_FLOAT:
-                    loc = xmm_registers[code]
+                    loc = regloc.XMMREGLOCS[code]
                 else:
-                    loc = registers[code]
+                    loc = regloc.REGLOCS[code]
             arglocs.append(loc)
         return arglocs[:]
 
     @rgc.no_collect
     def grab_frame_values(self, bytecode, frame_addr, allregisters):
         # no malloc allowed here!!
-        self.fail_ebp = allregisters[16 + ebp.op]
+        self.fail_ebp = allregisters[16 + ebp.value]
         num = 0
         value_hi = 0
         while 1:
@@ -1154,7 +1439,7 @@
                 code = (code - self.CODE_FROMSTACK) >> 2
                 stackloc = frame_addr + get_ebp_ofs(code)
                 value = rffi.cast(rffi.LONGP, stackloc)[0]
-                if kind == self.DESCR_FLOAT:
+                if kind == self.DESCR_FLOAT and WORD == 4:
                     value_hi = value
                     value = rffi.cast(rffi.LONGP, stackloc - 4)[0]
             else:
@@ -1168,8 +1453,11 @@
                     break
                 code >>= 2
                 if kind == self.DESCR_FLOAT:
-                    value = allregisters[2*code]
-                    value_hi = allregisters[2*code + 1]
+                    if WORD == 4:
+                        value = allregisters[2*code]
+                        value_hi = allregisters[2*code + 1]
+                    else:
+                        value = allregisters[code]
                 else:
                     value = allregisters[16 + code]
 
@@ -1180,7 +1468,8 @@
                 tgt = self.fail_boxes_ptr.get_addr_for_num(num)
             elif kind == self.DESCR_FLOAT:
                 tgt = self.fail_boxes_float.get_addr_for_num(num)
-                rffi.cast(rffi.LONGP, tgt)[1] = value_hi
+                if WORD == 4:
+                    rffi.cast(rffi.LONGP, tgt)[1] = value_hi
             else:
                 assert 0, "bogus kind"
             rffi.cast(rffi.LONGP, tgt)[0] = value
@@ -1189,7 +1478,8 @@
         if not we_are_translated():
             assert bytecode[4] == 0xCC
         self.fail_boxes_count = num
-        fail_index = rffi.cast(rffi.LONGP, bytecode)[0]
+        fail_index = rffi.cast(rffi.INTP, bytecode)[0]
+        fail_index = rffi.cast(lltype.Signed, fail_index)
         return fail_index
 
     def setup_failure_recovery(self):
@@ -1200,8 +1490,8 @@
             # original value of the registers, optionally the original
             # value of XMM registers, and finally a reference to the
             # recovery bytecode.  See _build_failure_recovery() for details.
-            stack_at_ebp = registers[ebp.op]
-            bytecode = rffi.cast(rffi.UCHARP, registers[8])
+            stack_at_ebp = registers[ebp.value]
+            bytecode = rffi.cast(rffi.UCHARP, registers[self.cpu.NUM_REGS])
             allregisters = rffi.ptradd(registers, -16)
             return self.grab_frame_values(bytecode, stack_at_ebp, allregisters)
 
@@ -1216,23 +1506,23 @@
                                          self.failure_recovery_func)
         failure_recovery_func = rffi.cast(lltype.Signed,
                                           failure_recovery_func)
-        mc = self.mc2._mc
+        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.PUSH(edi)
-        mc.PUSH(esi)
-        mc.PUSH(ebp)
-        mc.PUSH(esp)  # <-- not really used, but needed to take up the space
-        mc.PUSH(ebx)
-        mc.PUSH(edx)
-        mc.PUSH(ecx)
-        mc.PUSH(eax)
-        mc.MOV(esi, esp)
+
+        # Push all general purpose registers
+        for gpr in range(self.cpu.NUM_REGS-1, -1, -1):
+            mc.PUSH_r(gpr)
+
+        # ebx/rbx is callee-save in both i386 and x86-64
+        mc.MOV_rr(ebx.value, esp.value)
+
         if withfloats:
-            mc.SUB(esp, imm(8*8))
-            for i in range(8):
-                mc.MOVSD(mem64(esp, 8*i), xmm_registers[i])
+            # Push all float registers
+            mc.SUB_ri(esp.value, self.cpu.NUM_REGS*8)
+            for i in range(self.cpu.NUM_REGS):
+                mc.MOVSD_sx(8*i, i)
 
         # we call a provided function that will
         # - call our on_leave_jitted_hook which will mark
@@ -1240,7 +1530,7 @@
         #   avoid unwarranted freeing
         # - optionally save exception depending on the flag
         addr = self.cpu.get_on_leave_jitted_int(save_exception=exc)
-        mc.CALL(rel32(addr))
+        mc.CALL(imm(addr))
 
         # the following call saves all values from the stack and from
         # registers to the right 'fail_boxes_<type>' location.
@@ -1250,50 +1540,58 @@
         # bytecode, pushed just before by the CALL instruction written by
         # generate_quick_failure().  XXX misaligned stack in the call, but
         # it's ok because failure_recovery_func is not calling anything more
-        mc.PUSH(esi)
-        mc.CALL(rel32(failure_recovery_func))
+
+        # XXX
+        if IS_X86_32:
+            mc.PUSH_r(ebx.value)
+        elif IS_X86_64:
+            mc.MOV_rr(edi.value, ebx.value)
+            # XXX: Correct to only align the stack on 64-bit?
+            mc.AND_ri(esp.value, -16)
+        else:
+            raise AssertionError("Shouldn't happen")
+
+        mc.CALL(imm(failure_recovery_func))
         # returns in eax the fail_index
 
         # now we return from the complete frame, which starts from
-        # _assemble_bootstrap_code().  The LEA below throws away most
-        # of the frame, including all the PUSHes that we did just above.
-        mc.LEA(esp, addr_add(ebp, imm(-3 * WORD)))
-        mc.POP(edi)    # [ebp-12]
-        mc.POP(esi)    # [ebp-8]
-        mc.POP(ebx)    # [ebp-4]
-        mc.POP(ebp)    # [ebp]
-        mc.RET()
-        self.mc2.done()
+        # _assemble_bootstrap_code().  The LEA in _call_footer below throws
+        # away most of the frame, including all the PUSHes that we did just
+        # above.
+
+        self._call_footer()
+        self.mc.done()
         self.failure_recovery_code[exc + 2 * withfloats] = recovery_addr
 
     def generate_failure(self, fail_index, locs, exc, locs_are_ref):
-        mc = self.mc
+        self.mc._mc.begin_reuse_scratch_register()
         for i in range(len(locs)):
             loc = locs[i]
-            if isinstance(loc, REG):
-                if loc.width == 8:
+            if isinstance(loc, RegLoc):
+                if loc.is_xmm:
                     adr = self.fail_boxes_float.get_addr_for_num(i)
-                    mc.MOVSD(heap64(adr), loc)
+                    self.mc.MOVSD(heap(adr), loc)
                 else:
                     if locs_are_ref[i]:
                         adr = self.fail_boxes_ptr.get_addr_for_num(i)
                     else:
                         adr = self.fail_boxes_int.get_addr_for_num(i)
-                    mc.MOV(heap(adr), loc)
+                    self.mc.MOV(heap(adr), loc)
         for i in range(len(locs)):
             loc = locs[i]
-            if not isinstance(loc, REG):
-                if loc.width == 8:
-                    mc.MOVSD(xmm0, loc)
+            if not isinstance(loc, RegLoc):
+                if isinstance(loc, StackLoc) and loc.type == FLOAT:
+                    self.mc.MOVSD_xb(xmm0.value, loc.value)
                     adr = self.fail_boxes_float.get_addr_for_num(i)
-                    mc.MOVSD(heap64(adr), xmm0)
+                    self.mc.MOVSD(heap(adr), xmm0)
                 else:
                     if locs_are_ref[i]:
                         adr = self.fail_boxes_ptr.get_addr_for_num(i)
                     else:
                         adr = self.fail_boxes_int.get_addr_for_num(i)
-                    mc.MOV(eax, loc)
-                    mc.MOV(heap(adr), eax)
+                    self.mc.MOV(eax, loc)
+                    self.mc.MOV(heap(adr), eax)
+        self.mc._mc.end_reuse_scratch_register()
 
         # we call a provided function that will
         # - call our on_leave_jitted_hook which will mark
@@ -1301,28 +1599,31 @@
         #   avoid unwarranted freeing
         # - optionally save exception depending on the flag
         addr = self.cpu.get_on_leave_jitted_int(save_exception=exc)
-        mc.CALL(rel32(addr))
+        self.mc.CALL(imm(addr))
+
+        self.mc.MOV_ri(eax.value, fail_index)
+
+        # exit function
+        self._call_footer()
 
-        mc.LEA(esp, addr_add(ebp, imm(-3 * WORD)))
-        mc.MOV(eax, imm(fail_index))
-        mc.POP(edi)    # [ebp-12]
-        mc.POP(esi)    # [ebp-8]
-        mc.POP(ebx)    # [ebp-4]
-        mc.POP(ebp)    # [ebp]
-        mc.RET()
-
-    @specialize.arg(2)
-    def implement_guard(self, addr, emit_jump):
-        emit_jump(rel32(addr))
+    def implement_guard(self, guard_token, condition=None):
+        self.mc.reserve_bytes(guard_token.recovery_stub_size())
+        self.pending_guard_tokens.append(guard_token)
+        # XXX: These jumps are patched later, the self.mc.tell() are just
+        # dummy values
+        if condition:
+            self.mc.J_il(rx86.Conditions[condition], self.mc.tell())
+        else:
+            self.mc.JMP_l(self.mc.tell())
         return self.mc.tell() - 4
 
     def genop_call(self, op, arglocs, resloc):
         sizeloc = arglocs[0]
-        assert isinstance(sizeloc, IMM32)
+        assert isinstance(sizeloc, ImmedLoc)
         size = sizeloc.value
 
         if isinstance(op.args[0], Const):
-            x = rel32(op.args[0].getint())
+            x = imm(op.args[0].getint())
         else:
             x = arglocs[1]
         if x is eax:
@@ -1332,35 +1633,35 @@
         
         self._emit_call(x, arglocs, 2, tmp=tmp)
 
-        if isinstance(resloc, MODRM64):
-            self.mc.FSTP(resloc)
+        if isinstance(resloc, StackLoc) and resloc.width == 8 and IS_X86_32:
+            self.mc.FSTP_b(resloc.value)
         elif size == 1:
-            self.mc.AND(eax, imm(0xff))
+            self.mc.AND_ri(eax.value, 0xff)
         elif size == 2:
-            self.mc.AND(eax, imm(0xffff))
+            self.mc.AND_ri(eax.value, 0xffff)
     
-    def genop_guard_call_may_force(self, op, guard_op, addr,
+    def genop_guard_call_may_force(self, op, guard_op, guard_token,
                                    arglocs, result_loc):
         faildescr = guard_op.descr
         fail_index = self.cpu.get_fail_descr_number(faildescr)
-        self.mc.MOV(mem(ebp, FORCE_INDEX_OFS), imm(fail_index))
+        self.mc.MOV_bi(FORCE_INDEX_OFS, fail_index)
         self.genop_call(op, arglocs, result_loc)
-        self.mc.CMP(mem(ebp, FORCE_INDEX_OFS), imm(0))
-        return self.implement_guard(addr, self.mc.JL)
+        self.mc.CMP_bi(FORCE_INDEX_OFS, 0)
+        return self.implement_guard(guard_token, 'L')
 
-    def genop_guard_call_assembler(self, op, guard_op, addr,
+    def genop_guard_call_assembler(self, op, guard_op, guard_token,
                                    arglocs, result_loc):
         faildescr = guard_op.descr
         fail_index = self.cpu.get_fail_descr_number(faildescr)
-        self.mc.MOV(mem(ebp, FORCE_INDEX_OFS), imm(fail_index))
+        self.mc.MOV_bi(FORCE_INDEX_OFS, fail_index)
         descr = op.descr
         assert isinstance(descr, LoopToken)
         assert len(arglocs) - 2 == len(descr._x86_arglocs[0])
         #
         # Write a call to the direct_bootstrap_code of the target assembler
-        self._emit_call(rel32(descr._x86_direct_bootstrap_code), arglocs, 2,
+        self._emit_call(imm(descr._x86_direct_bootstrap_code), arglocs, 2,
                         tmp=eax)
-        mc = self._start_block()
+        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
@@ -1376,26 +1677,27 @@
                 value = self.cpu.done_with_this_frame_float_v
             else:
                 raise AssertionError(kind)
-        mc.CMP(eax, imm(value))
-        mc.JE(rel8_patched_later)    # goto B if we get 'done_with_this_frame'
-        je_location = mc.get_relative_pos()
+        self.mc.CMP_ri(eax.value, value)
+        # patched later
+        self.mc.J_il8(rx86.Conditions['E'], 0) # goto B if we get 'done_with_this_frame'
+        je_location = self.mc.get_relative_pos()
         #
         # Path A: use assembler_helper_adr
         jd = descr.outermost_jitdriver_sd
         assert jd is not None
         asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr)
-        self._emit_call(rel32(asm_helper_adr), [eax, arglocs[1]], 0,
-                        tmp=ecx, force_mc=True, mc=mc)
-        if isinstance(result_loc, MODRM64):
-            mc.FSTP(result_loc)
+        self._emit_call(imm(asm_helper_adr), [eax, arglocs[1]], 0,
+                        tmp=ecx)
+        if IS_X86_32 and isinstance(result_loc, StackLoc) and result_loc.type == FLOAT:
+            self.mc.FSTP_b(result_loc.value)
         #else: result_loc is already either eax or None, checked below
-        mc.JMP(rel8_patched_later)     # done
-        jmp_location = mc.get_relative_pos()
+        self.mc.JMP_l8(0) # jump to done, patched later
+        jmp_location = self.mc.get_relative_pos()
         #
         # Path B: fast path.  Must load the return value, and reset the token
         offset = jmp_location - je_location
         assert 0 < offset <= 127
-        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:
@@ -1403,8 +1705,8 @@
             fielddescr = jd.vable_token_descr
             assert isinstance(fielddescr, BaseFieldDescr)
             ofs = fielddescr.offset
-            mc.MOV(eax, arglocs[1])
-            mc.MOV(addr_add(eax, imm(ofs)), imm(0))
+            self.mc.MOV(eax, arglocs[1])
+            self.mc.MOV_mi((eax.value, ofs), 0)
             # in the line above, TOKEN_NONE = 0
         #
         if op.result is not None:
@@ -1413,27 +1715,26 @@
             if kind == FLOAT:
                 xmmtmp = X86XMMRegisterManager.all_regs[0]
                 adr = self.fail_boxes_float.get_addr_for_num(0)
-                mc.MOVSD(xmmtmp, heap64(adr))
-                mc.MOVSD(result_loc, xmmtmp)
+                self.mc.MOVSD(xmmtmp, heap(adr))
+                self.mc.MOVSD(result_loc, xmmtmp)
             else:
                 assert result_loc is eax
                 if kind == INT:
                     adr = self.fail_boxes_int.get_addr_for_num(0)
-                    mc.MOV(eax, heap(adr))
+                    self.mc.MOV(eax, heap(adr))
                 elif kind == REF:
                     adr = self.fail_boxes_ptr.get_addr_for_num(0)
-                    mc.XOR(eax, eax)
-                    mc.XCHG(eax, heap(adr))
+                    self.mc.XOR_rr(eax.value, eax.value)
+                    self.mc.XCHG(eax, heap(adr))
                 else:
                     raise AssertionError(kind)
         #
         # Here we join Path A and Path B again
-        offset = mc.get_relative_pos() - jmp_location
+        offset = self.mc.get_relative_pos() - jmp_location
         assert 0 <= offset <= 127
-        mc.overwrite(jmp_location - 1, [chr(offset)])
-        self._stop_block()
-        self.mc.CMP(mem(ebp, FORCE_INDEX_OFS), imm(0))
-        return self.implement_guard(addr, self.mc.JL)
+        self.mc.overwrite(jmp_location - 1, [chr(offset)])
+        self.mc.CMP_bi(FORCE_INDEX_OFS, 0)
+        return self.implement_guard(guard_token, 'L')
 
     def genop_discard_cond_call_gc_wb(self, op, arglocs):
         # use 'mc._mc' directly instead of 'mc', to avoid
@@ -1443,31 +1744,51 @@
             cls = self.cpu.gc_ll_descr.has_write_barrier_class()
             assert cls is not None and isinstance(descr, cls)
         loc_base = arglocs[0]
-        mc = self._start_block()
-        mc.TEST(mem8(loc_base, descr.jit_wb_if_flag_byteofs),
-                imm8(descr.jit_wb_if_flag_singlebyte))
-        mc.JZ(rel8_patched_later)
-        jz_location = mc.get_relative_pos()
+        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
+        jz_location = self.mc.get_relative_pos()
         # the following is supposed to be the slow path, so whenever possible
         # we choose the most compact encoding over the most efficient one.
         for i in range(len(arglocs)-1, -1, -1):
-            mc.PUSH(arglocs[i])
+            loc = arglocs[i]
+            if isinstance(loc, RegLoc):
+                self.mc.PUSH_r(loc.value)
+            else:
+                if IS_X86_64:
+                    self.mc.MOV_ri(X86_64_SCRATCH_REG.value, loc.getint())
+                    self.mc.PUSH_r(X86_64_SCRATCH_REG.value)
+                else:
+                    self.mc.PUSH_i32(loc.getint())
+        
+        if IS_X86_64:
+            # We clobber these registers to pass the arguments, but that's
+            # okay, because consider_cond_call_gc_wb makes sure that any
+            # caller-save registers with values in them are present in arglocs,
+            # so they are saved on the stack above and restored below 
+            self.mc.MOV_rs(edi.value, 0)
+            self.mc.MOV_rs(esi.value, 8)
+
         # misaligned stack in the call, but it's ok because the write barrier
         # is not going to call anything more.  Also, this assumes that the
         # write barrier does not touch the xmm registers.
-        mc.CALL(rel32(descr.get_write_barrier_fn(self.cpu)))
+        self.mc.CALL(imm(descr.get_write_barrier_fn(self.cpu)))
         for i in range(len(arglocs)):
             loc = arglocs[i]
-            assert isinstance(loc, REG)
-            mc.POP(loc)
+            if isinstance(loc, RegLoc):
+                self.mc.POP_r(loc.value)
+            else:
+                self.mc.ADD_ri(esp.value, WORD)   # ignore the pushed constant
         # patch the JZ above
-        offset = mc.get_relative_pos() - jz_location
+        offset = self.mc.get_relative_pos() - jz_location
         assert 0 < offset <= 127
-        mc.overwrite(jz_location-1, [chr(offset)])
-        self._stop_block()
+        self.mc.overwrite(jz_location-1, [chr(offset)])
 
     def genop_force_token(self, op, arglocs, resloc):
-        self.mc.LEA(resloc, mem(ebp, FORCE_INDEX_OFS))
+        # RegAlloc.consider_force_token ensures this:
+        assert isinstance(resloc, RegLoc)
+        self.mc.LEA_rb(resloc.value, FORCE_INDEX_OFS)
 
     def not_implemented_op_discard(self, op, arglocs):
         msg = "not implemented operation: %s" % op.getopname()
@@ -1495,17 +1816,16 @@
         return loop_token._x86_arglocs
 
     def closing_jump(self, loop_token):
-        self.mc.JMP(rel32(loop_token._x86_loop_code))
+        self.mc.JMP(imm(loop_token._x86_loop_code))
 
     def malloc_cond_fixedsize(self, nursery_free_adr, nursery_top_adr,
                               size, tid):
-        # don't use self.mc
-        mc = self._start_block()
-        mc.MOV(eax, heap(nursery_free_adr))
-        mc.LEA(edx, addr_add(eax, imm(size)))
-        mc.CMP(edx, heap(nursery_top_adr))
-        mc.JNA(rel8_patched_later)
-        jmp_adr = mc.get_relative_pos()
+        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))
+        self.mc.J_il8(rx86.Conditions['NA'], 0) # patched later
+        jmp_adr = self.mc.get_relative_pos()
 
         # See comments in _build_malloc_fixedsize_slowpath for the
         # details of the two helper functions that we are calling below.
@@ -1521,17 +1841,16 @@
         # reserve room for the argument to the real malloc and the
         # 8 saved XMM regs
         self._regalloc.reserve_param(1+16)
-        mc.CALL(rel32(slowpath_addr1))
+        self.mc.CALL(imm(slowpath_addr1))
         self.mark_gc_roots()
         slowpath_addr2 = self.malloc_fixedsize_slowpath2
-        mc.CALL(rel32(slowpath_addr2))
+        self.mc.CALL(imm(slowpath_addr2))
 
-        offset = mc.get_relative_pos() - jmp_adr
+        offset = self.mc.get_relative_pos() - jmp_adr
         assert 0 < offset <= 127
-        mc.overwrite(jmp_adr-1, [chr(offset)])
-        mc.MOV(addr_add(eax, imm(0)), imm(tid))
-        mc.MOV(heap(nursery_free_adr), edx)
-        self._stop_block()
+        self.mc.overwrite(jmp_adr-1, [chr(offset)])
+        self.mc.MOV_mi((eax.value, 0), tid)
+        self.mc.MOV(heap(nursery_free_adr), edx)
         
 genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST
 genop_list = [Assembler386.not_implemented_op] * rop._LAST
@@ -1551,32 +1870,20 @@
         num = getattr(rop, opname.upper())
         genop_list[num] = value
 
-def new_addr_add(heap, mem, memsib):
-    def addr_add(reg_or_imm1, reg_or_imm2, offset=0, scale=0):
-        if isinstance(reg_or_imm1, IMM32):
-            if isinstance(reg_or_imm2, IMM32):
-                return heap(reg_or_imm1.value + offset +
-                            (reg_or_imm2.value << scale))
-            else:
-                return memsib(None, reg_or_imm2, scale, reg_or_imm1.value + offset)
-        else:
-            if isinstance(reg_or_imm2, IMM32):
-                return mem(reg_or_imm1, offset + (reg_or_imm2.value << scale))
-            else:
-                return memsib(reg_or_imm1, reg_or_imm2, scale, offset)
-    return addr_add
-
-addr8_add = new_addr_add(heap8, mem8, memSIB8)
-addr_add = new_addr_add(heap, mem, memSIB)
-addr64_add = new_addr_add(heap64, mem64, memSIB64)
-
-def addr_add_const(reg_or_imm1, offset):
-    if isinstance(reg_or_imm1, IMM32):
-        return heap(reg_or_imm1.value + offset)
-    else:
-        return mem(reg_or_imm1, offset)
-
 def round_up_to_4(size):
     if size < 4:
         return 4
     return size
+
+# XXX: ri386 migration shims:
+def addr_add(reg_or_imm1, reg_or_imm2, offset=0, scale=0):
+    return AddressLoc(reg_or_imm1, reg_or_imm2, scale, offset)
+
+def addr_add_const(reg_or_imm1, offset):
+    return AddressLoc(reg_or_imm1, ImmedLoc(0), 0, offset)
+
+def mem(loc, offset):
+    return AddressLoc(loc, ImmedLoc(0), 0, offset)
+
+def heap(addr):
+    return AddressLoc(ImmedLoc(addr), ImmedLoc(0), 0, 0)

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/codebuf.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/codebuf.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/codebuf.py	Thu Sep  9 01:00:13 2010
@@ -2,12 +2,20 @@
 import os, sys
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.jit.backend.x86.ri386 import I386CodeBuilder
+from pypy.jit.backend.x86.rx86 import X86_32_CodeBuilder, X86_64_CodeBuilder
+from pypy.jit.backend.x86.regloc import LocationCodeBuilder
 from pypy.rlib.rmmap import PTR, alloc, free
 from pypy.rlib.debug import make_sure_not_resized
+from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64
+from pypy.rlib.objectmodel import we_are_translated
 
+# XXX: Seems nasty to change the superclass of InMemoryCodeBuilder like this
+if IS_X86_32:
+    codebuilder_cls = X86_32_CodeBuilder
+elif IS_X86_64:
+    codebuilder_cls = X86_64_CodeBuilder
 
-class InMemoryCodeBuilder(I386CodeBuilder):
+class InMemoryCodeBuilder(codebuilder_cls, LocationCodeBuilder):
     _last_dump_start = 0
 
     def __init__(self, start, end):
@@ -31,13 +39,15 @@
     def write(self, listofchars):
         self._pos = self.overwrite(self._pos, listofchars)
 
-    def writechr(self, n):
-        # purely for performance: don't make the one-element list [chr(n)]
+    def writechar(self, char):
         pos = self._pos
         assert pos + 1 <= self._size
-        self._data[pos] = chr(n)
+        self._data[pos] = char
         self._pos = pos + 1
 
+    def writechr(self, n):
+        self.writechar(chr(n))
+
     def get_relative_pos(self):
         return self._pos
 
@@ -50,11 +60,6 @@
         self._pos = pos
         self._last_dump_start = pos
 
-    def execute(self, arg1, arg2):
-        # XXX old testing stuff
-        fnptr = rffi.cast(lltype.Ptr(BINARYFN), self._data)
-        return fnptr(arg1, arg2)
-
     def done(self):
         # normally, no special action is needed here
         if machine_code_dumper.enabled:
@@ -77,9 +82,6 @@
         valgrind.discard_translations(self._data, self._size)
 
 
-BINARYFN = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed)
-
-
 class MachineCodeDumper:
     enabled = True
     log_fd = -1
@@ -107,7 +109,10 @@
                 return False
             # log the executable name
             from pypy.jit.backend.hlinfo import highleveljitinfo
-            os.write(self.log_fd, 'BACKEND i386\n')
+            if IS_X86_32:
+                os.write(self.log_fd, 'BACKEND x86\n')
+            elif IS_X86_64:
+                os.write(self.log_fd, 'BACKEND x86_64\n')
             if highleveljitinfo.sys_executable:
                 os.write(self.log_fd, 'SYS_EXECUTABLE %s\n' % (
                     highleveljitinfo.sys_executable,))
@@ -137,6 +142,12 @@
 
     def __init__(self, map_size):
         data = alloc(map_size)
+        if IS_X86_64 and not we_are_translated():
+            # Hack to make sure that mcs are not within 32-bits of one
+            # another for testing purposes
+            from pypy.rlib.rmmap import hint
+            hint.pos += 0xFFFFFFFF
+            
         self._init(data, map_size)
 
     def __del__(self):

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/jump.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/jump.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/jump.py	Thu Sep  9 01:00:13 2010
@@ -1,23 +1,6 @@
 import sys
 from pypy.tool.pairtype import extendabletype
-from pypy.jit.backend.x86.ri386 import *
-
-class __extend__(OPERAND):
-    __metaclass__ = extendabletype
-    def _getregkey(self):
-        raise AssertionError("should only happen to registers and frame "
-                             "positions")
-
-class __extend__(REG):
-    __metaclass__ = extendabletype
-    def _getregkey(self):
-        return ~self.op
-
-class __extend__(MODRM):
-    __metaclass__ = extendabletype
-    def _getregkey(self):
-        return self.position
-
+from pypy.jit.backend.x86.regloc import ImmedLoc, StackLoc
 
 def remap_frame_layout(assembler, src_locations, dst_locations, tmpreg):
     pending_dests = len(dst_locations)
@@ -27,7 +10,7 @@
         srccount[dst._getregkey()] = 0
     for i in range(len(dst_locations)):
         src = src_locations[i]
-        if isinstance(src, IMM32):
+        if isinstance(src, ImmedLoc):
             continue
         key = src._getregkey()
         if key in srccount:
@@ -46,7 +29,7 @@
                 srccount[key] = -1       # means "it's done"
                 pending_dests -= 1
                 src = src_locations[i]
-                if not isinstance(src, IMM32):
+                if not isinstance(src, ImmedLoc):
                     key = src._getregkey()
                     if key in srccount:
                         srccount[key] -= 1
@@ -80,7 +63,7 @@
             assert pending_dests == 0
 
 def _move(assembler, src, dst, tmpreg):
-    if isinstance(dst, MODRM) and isinstance(src, MODRM):
+    if dst.is_memory_reference() and src.is_memory_reference():
         assembler.regalloc_mov(src, tmpreg)
         src = tmpreg
     assembler.regalloc_mov(src, dst)

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/regalloc.py	Thu Sep  9 01:00:13 2010
@@ -5,7 +5,7 @@
 from pypy.jit.metainterp.history import (Box, Const, ConstInt, ConstPtr,
                                          ResOperation, BoxPtr,
                                          LoopToken, INT, REF, FLOAT)
-from pypy.jit.backend.x86.ri386 import *
+from pypy.jit.backend.x86.regloc import *
 from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib import rgc
@@ -17,16 +17,7 @@
 from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr
 from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\
      TempBox
-
-WORD = 4
-FRAME_FIXED_SIZE = 5     # ebp + ebx + esi + edi + force_index = 5 words
-FORCE_INDEX_OFS = -4*WORD
-
-width_of_type = {
-    INT : 1,
-    REF : 1,
-    FLOAT : 2,
-    }
+from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE, IS_X86_32, IS_X86_64
 
 class X86RegisterManager(RegisterManager):
 
@@ -35,6 +26,12 @@
     no_lower_byte_regs = [esi, edi]
     save_around_call_regs = [eax, edx, ecx]
 
+    REGLOC_TO_GCROOTMAP_REG_INDEX = {
+        ebx: 1,
+        esi: 2,
+        edi: 3,
+    }
+
     def call_result_location(self, v):
         return eax
 
@@ -50,12 +47,26 @@
             print "convert_to_imm: got a %s" % c
             raise AssertionError
 
+class X86_64_RegisterManager(X86RegisterManager):
+    # r11 omitted because it's used as scratch
+    all_regs = [eax, ecx, edx, ebx, esi, edi, r8, r9, r10, r12, r13, r14, r15]
+    no_lower_byte_regs = []
+    save_around_call_regs = [eax, ecx, edx, esi, edi, r8, r9, r10]
+
+    REGLOC_TO_GCROOTMAP_REG_INDEX = {
+        ebx: 1,
+        r12: 2,
+        r13: 3,
+        r14: 4,
+        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
@@ -71,7 +82,8 @@
         n = self.cur_array_free - 1
         arr[n] = floatval
         self.cur_array_free = n
-        return rffi.cast(lltype.Signed, arr) + n * 8
+        self.const_id += 1
+        return (self.const_id, rffi.cast(lltype.Signed, arr) + n * 8)
 
 
 class X86XMMRegisterManager(RegisterManager):
@@ -80,7 +92,6 @@
     all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7]
     # we never need lower byte I hope
     save_around_call_regs = all_regs
-    reg_width = 2
 
     def __init__(self, longevity, frame_manager=None, assembler=None):
         RegisterManager.__init__(self, longevity, frame_manager=frame_manager,
@@ -93,28 +104,36 @@
             self.float_constants = assembler._float_constants
 
     def convert_to_imm(self, c):
-        adr = self.float_constants.record_float(c.getfloat())
-        return heap64(adr)
+        const_id, adr = self.float_constants.record_float(c.getfloat())
+        return ConstFloatLoc(adr, const_id)
         
     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
         # after the call
-        return self.frame_manager.loc(v, 2)
+        return self.frame_manager.loc(v)
 
-class X86FrameManager(FrameManager):
+class X86_64_XMMRegisterManager(X86XMMRegisterManager):
+    # xmm15 reserved for scratch use
+    all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14]
+    save_around_call_regs = all_regs
+
+    def call_result_location(self, v):
+        return xmm0
+
+    def after_call(self, v):
+        # We use RegisterManager's implementation, since X86XMMRegisterManager
+        # places the result on the stack, which we don't need to do when the
+        # calling convention places the result in xmm0
+        return RegisterManager.after_call(self, v)
 
+class X86FrameManager(FrameManager):
     @staticmethod
-    def frame_pos(i, size):
-        if size == 1:
-            res = mem(ebp, get_ebp_ofs(i))
-        elif size == 2:
-            res = mem64(ebp, get_ebp_ofs(i + 1))
-        else:
-            print "Unimplemented size %d" % i
-            raise NotImplementedError("unimplemented size %d" % i)
-        res.position = i
-        return res
+    def frame_pos(i, box_type):
+        if IS_X86_32 and box_type == FLOAT:
+            return StackLoc(i, get_ebp_ofs(i+1), 2, box_type)
+        else:
+            return StackLoc(i, get_ebp_ofs(i), 1, box_type)
 
 class RegAlloc(object):
     exc = False
@@ -135,11 +154,21 @@
         # compute longevity of variables
         longevity = self._compute_vars_longevity(inputargs, operations)
         self.longevity = longevity
-        self.rm = X86RegisterManager(longevity,
-                                     frame_manager = self.fm,
-                                     assembler = self.assembler)
-        self.xrm = X86XMMRegisterManager(longevity, frame_manager = self.fm,
-                                         assembler = self.assembler)
+        # XXX
+        if cpu.WORD == 4:
+            gpr_reg_mgr_cls = X86RegisterManager
+            xmm_reg_mgr_cls = X86XMMRegisterManager
+        elif cpu.WORD == 8:
+            gpr_reg_mgr_cls = X86_64_RegisterManager
+            xmm_reg_mgr_cls = X86_64_XMMRegisterManager
+        else:
+            raise AssertionError("Word size should be 4 or 8")
+            
+        self.rm = gpr_reg_mgr_cls(longevity,
+                                  frame_manager = self.fm,
+                                  assembler = self.assembler)
+        self.xrm = xmm_reg_mgr_cls(longevity, frame_manager = self.fm,
+                                   assembler = self.assembler)
 
     def prepare_loop(self, inputargs, operations, looptoken):
         self._prepare(inputargs, operations)
@@ -184,7 +213,7 @@
             if reg:
                 loc = reg
             else:
-                loc = self.fm.loc(arg, width_of_type[arg.type])
+                loc = self.fm.loc(arg)
             if arg.type == FLOAT:
                 floatlocs[i] = loc
             else:
@@ -252,23 +281,23 @@
             arg = inputargs[i]
             i += 1
             if arg.type == FLOAT:
-                if isinstance(loc, REG):
+                if isinstance(loc, RegLoc):
                     self.xrm.reg_bindings[arg] = loc
                     used[loc] = None
                 else:
                     self.fm.frame_bindings[arg] = loc
             else:
-                if isinstance(loc, REG):
+                if isinstance(loc, RegLoc):
                     self.rm.reg_bindings[arg] = loc
                     used[loc] = None
                 else:
                     self.fm.frame_bindings[arg] = loc
         self.rm.free_regs = []
-        for reg in X86RegisterManager.all_regs:
+        for reg in self.rm.all_regs:
             if reg not in used:
                 self.rm.free_regs.append(reg)
         self.xrm.free_regs = []
-        for reg in X86XMMRegisterManager.all_regs:
+        for reg in self.xrm.all_regs:
             if reg not in used:
                 self.xrm.free_regs.append(reg)
         # note: we need to make a copy of inputargs because possibly_free_vars
@@ -646,7 +675,7 @@
         vable_index = jd.index_of_virtualizable
         if vable_index >= 0:
             self.rm._sync_var(op.args[vable_index])
-            vable = self.fm.loc(op.args[vable_index], 1)
+            vable = self.fm.loc(op.args[vable_index])
         else:
             vable = imm(0)
         self._call(op, [imm(size), vable] +
@@ -655,13 +684,12 @@
         
     def consider_cond_call_gc_wb(self, op):
         assert op.result is None
+        loc_newvalue = self.rm.make_sure_var_in_reg(op.args[1], op.args)
+        # ^^^ we force loc_newvalue in a reg (unless it's a Const),
+        # because it will be needed anyway by the following setfield_gc.
+        # It avoids loading it twice from the memory.
         loc_base = self.rm.make_sure_var_in_reg(op.args[0], op.args,
                                                 imm_fine=False)
-        loc_newvalue = self.rm.make_sure_var_in_reg(op.args[1], op.args,
-                                                    imm_fine=False)
-        # ^^^ we also force loc_newvalue in a reg, because it will be needed
-        # anyway by the following setfield_gc.  It avoids loading it twice
-        # from the memory.
         arglocs = [loc_base, loc_newvalue]
         # add eax, ecx and edx as extra "arguments" to ensure they are
         # saved and restored.  Fish in self.rm to know which of these
@@ -670,7 +698,7 @@
         # function, a GC write barrier, is known not to touch them.
         # See remember_young_pointer() in rpython/memory/gc/generation.py.
         for v, reg in self.rm.reg_bindings.items():
-            if ((reg is eax or reg is ecx or reg is edx)
+            if (reg in self.rm.save_around_call_regs
                 and self.rm.stays_alive(v)):
                 arglocs.append(reg)
         self.PerformDiscard(op, arglocs)
@@ -679,23 +707,18 @@
     def _fastpath_malloc(self, op, descr):
         assert isinstance(descr, BaseSizeDescr)
         gc_ll_descr = self.assembler.cpu.gc_ll_descr
-        tmp0 = TempBox()
         self.rm.force_allocate_reg(op.result, selected_reg=eax)
-        self.rm.force_allocate_reg(tmp0, selected_reg=edx)
-        # XXX about the next 10 lines: why not just say
-        #      force_allocate_reg(tmp1, selected_reg=ecx)?????
-        for v, reg in self.rm.reg_bindings.items():
-            if reg is ecx:
-                to_sync = v
-                break
-        else:
-            to_sync = None
-        if to_sync is not None:
-            self.rm._sync_var(to_sync)
-            del self.rm.reg_bindings[to_sync]
-            self.rm.free_regs.append(ecx)
-        # we need to do it here, so edx is not in reg_bindings
-        self.rm.possibly_free_var(tmp0)
+        # We need to force-allocate each of save_around_call_regs now.
+        # The alternative would be to save and restore them around the
+        # actual call to malloc(), in the rare case where we need to do
+        # it; however, mark_gc_roots() would need to be adapted to know
+        # where the variables end up being saved.  Messy.
+        for reg in self.rm.save_around_call_regs:
+            if reg is not eax:
+                tmp_box = TempBox()
+                self.rm.force_allocate_reg(tmp_box, selected_reg=reg)
+                self.rm.possibly_free_var(tmp_box)
+
         self.assembler.malloc_cond_fixedsize(
             gc_ll_descr.get_nursery_free_addr(),
             gc_ll_descr.get_nursery_top_addr(),
@@ -809,7 +832,7 @@
 
     def consider_setfield_gc(self, op):
         ofs_loc, size_loc, ptr = self._unpack_fielddescr(op.descr)
-        assert isinstance(size_loc, IMM32)
+        assert isinstance(size_loc, ImmedLoc)
         if size_loc.value == 1:
             need_lower_byte = True
         else:
@@ -947,24 +970,17 @@
         pass
 
     def get_mark_gc_roots(self, gcrootmap):
-        shape = gcrootmap.get_basic_shape()
+        shape = gcrootmap.get_basic_shape(IS_X86_64)
         for v, val in self.fm.frame_bindings.items():
             if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)):
-                assert isinstance(val, MODRM)
+                assert isinstance(val, StackLoc)
                 gcrootmap.add_ebp_offset(shape, get_ebp_ofs(val.position))
         for v, reg in self.rm.reg_bindings.items():
             if reg is eax:
                 continue      # ok to ignore this one
             if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)):
-                if reg is ebx:
-                    gcrootmap.add_ebx(shape)
-                elif reg is esi:
-                    gcrootmap.add_esi(shape)
-                elif reg is edi:
-                    gcrootmap.add_edi(shape)
-                else:
-                    print "[get_mark_gc_roots] bogus register", reg
-                    assert False
+                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)
 
     def consider_force_token(self, op):

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/runner.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/runner.py	Thu Sep  9 01:00:13 2010
@@ -4,11 +4,13 @@
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.jit.metainterp import history, compile
 from pypy.jit.backend.x86.assembler import Assembler386
-from pypy.jit.backend.x86.regalloc import FORCE_INDEX_OFS
+from pypy.jit.backend.x86.arch import FORCE_INDEX_OFS
 from pypy.jit.backend.x86.profagent import ProfileAgent
 from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU
+from pypy.jit.backend.x86 import regloc
+import sys
 
-class CPU386(AbstractLLCPU):
+class AbstractX86CPU(AbstractLLCPU):
     debug = True
     supports_floats = True
 
@@ -44,6 +46,7 @@
         self.profile_agent.startup()
 
     def finish_once(self):
+        self.assembler.finish_once()
         self.profile_agent.shutdown()
 
     def compile_loop(self, inputargs, operations, looptoken):
@@ -131,10 +134,28 @@
         assert fail_index == fail_index_2
         return faildescr
 
+class CPU386(AbstractX86CPU):
+    WORD = 4
+    NUM_REGS = 8
+    CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.esi, regloc.edi]
+    FRAME_FIXED_SIZE = len(CALLEE_SAVE_REGISTERS) + 2
+
+    def __init__(self, *args, **kwargs):
+        assert sys.maxint == (2**31 - 1)
+        super(CPU386, self).__init__(*args, **kwargs)
 
 class CPU386_NO_SSE2(CPU386):
     supports_floats = False
 
+class CPU_X86_64(AbstractX86CPU):
+    WORD = 8
+    NUM_REGS = 16
+    CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.r12, regloc.r13, regloc.r14, regloc.r15]
+    FRAME_FIXED_SIZE = len(CALLEE_SAVE_REGISTERS) + 2
+
+    def __init__(self, *args, **kwargs):
+        assert sys.maxint == (2**63 - 1)
+        super(CPU_X86_64, self).__init__(*args, **kwargs)
 
 CPU = CPU386
 

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/conftest.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/conftest.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/conftest.py	Thu Sep  9 01:00:13 2010
@@ -3,6 +3,5 @@
 
 cpu = detect_cpu.autodetect()
 def pytest_runtest_setup(item):
-    if cpu != 'x86':
-        py.test.skip("x86 directory skipped: cpu is %r" % (cpu,))
-    
+    if cpu not in ('x86', 'x86_64'):
+        py.test.skip("x86/x86_64 tests skipped: cpu is %r" % (cpu,))

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_assembler.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_assembler.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_assembler.py	Thu Sep  9 01:00:13 2010
@@ -1,14 +1,22 @@
-from pypy.jit.backend.x86.ri386 import *
+from pypy.jit.backend.x86.regloc import *
 from pypy.jit.backend.x86.assembler import Assembler386, MachineCodeBlockWrapper
 from pypy.jit.backend.x86.regalloc import X86FrameManager, get_ebp_ofs
-from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat
+from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, INT, REF, FLOAT
 from pypy.rlib.rarithmetic import intmask
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+from pypy.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64
+from pypy.jit.backend.detect_cpu import getcpuclass 
+from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86_64_RegisterManager, X86XMMRegisterManager, X86_64_XMMRegisterManager
 
+ACTUAL_CPU = getcpuclass()
 
 class FakeCPU:
     rtyper = None
     supports_floats = True
+    NUM_REGS = ACTUAL_CPU.NUM_REGS
+
+    def fielddescrof(self, STRUCT, name):
+        return 42
 
 class FakeMC:
     def __init__(self, base_address=0):
@@ -25,7 +33,14 @@
         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 test_write_failure_recovery_description():
     assembler = Assembler386(FakeCPU())
@@ -33,12 +48,12 @@
     failargs = [BoxInt(), BoxPtr(), BoxFloat()] * 3
     failargs.insert(6, None)
     failargs.insert(7, None)
-    locs = [X86FrameManager.frame_pos(0, 1),
-            X86FrameManager.frame_pos(1, 1),
-            X86FrameManager.frame_pos(10, 2),
-            X86FrameManager.frame_pos(100, 1),
-            X86FrameManager.frame_pos(101, 1),
-            X86FrameManager.frame_pos(110, 2),
+    locs = [X86FrameManager.frame_pos(0, INT),
+            X86FrameManager.frame_pos(1, REF),
+            X86FrameManager.frame_pos(10, FLOAT),
+            X86FrameManager.frame_pos(100, INT),
+            X86FrameManager.frame_pos(101, REF),
+            X86FrameManager.frame_pos(110, FLOAT),
             None,
             None,
             ebx,
@@ -46,17 +61,17 @@
             xmm2]
     assert len(failargs) == len(locs)
     assembler.write_failure_recovery_description(mc, failargs, locs)
-    nums = [Assembler386.DESCR_INT   + 4*(8+0),
-            Assembler386.DESCR_REF   + 4*(8+1),
-            Assembler386.DESCR_FLOAT + 4*(8+10),
-            Assembler386.DESCR_INT   + 4*(8+100),
-            Assembler386.DESCR_REF   + 4*(8+101),
-            Assembler386.DESCR_FLOAT + 4*(8+110),
+    nums = [Assembler386.DESCR_INT   + 4*(16+0),
+            Assembler386.DESCR_REF   + 4*(16+1),
+            Assembler386.DESCR_FLOAT + 4*(16+10),
+            Assembler386.DESCR_INT   + 4*(16+100),
+            Assembler386.DESCR_REF   + 4*(16+101),
+            Assembler386.DESCR_FLOAT + 4*(16+110),
             Assembler386.CODE_HOLE,
             Assembler386.CODE_HOLE,
-            Assembler386.DESCR_INT   + 4*ebx.op,
-            Assembler386.DESCR_REF   + 4*esi.op,
-            Assembler386.DESCR_FLOAT + 4*xmm2.op]
+            Assembler386.DESCR_INT   + 4*ebx.value,
+            Assembler386.DESCR_REF   + 4*esi.value,
+            Assembler386.DESCR_FLOAT + 4*xmm2.value]
     double_byte_nums = []
     for num in nums[3:6]:
         double_byte_nums.append((num & 0x7F) | 0x80)
@@ -94,6 +109,9 @@
         return lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))
 
     def get_random_float():
+        # Returns <float>, <low word>, <high word>
+        # NB: on 64-bit, <low word> will be the entire float and <high word>
+        # will be random garbage from malloc!
         assert withfloats
         value = random.random() - 0.5
         # make sure it fits into 64 bits
@@ -101,9 +119,16 @@
         rffi.cast(rffi.DOUBLEP, tmp)[0] = value
         return rffi.cast(rffi.DOUBLEP, tmp)[0], tmp[0], tmp[1]
 
+    if IS_X86_32:
+        main_registers = X86RegisterManager.all_regs
+        xmm_registers = X86XMMRegisterManager.all_regs
+    elif IS_X86_64:
+        main_registers = X86_64_RegisterManager.all_regs
+        xmm_registers = X86_64_XMMRegisterManager.all_regs
+
     # memory locations: 26 integers, 26 pointers, 26 floats
     # main registers: half of them as signed and the other half as ptrs
-    # xmm registers: all floats, from xmm0 to xmm7
+    # xmm registers: all floats, from xmm0 to xmm(7|15)
     # holes: 8
     locations = []
     baseloc = 4
@@ -117,18 +142,17 @@
     content = ([('int', locations.pop()) for _ in range(26)] +
                [('ptr', locations.pop()) for _ in range(26)] +
                [(['int', 'ptr'][random.randrange(0, 2)], reg)
-                         for reg in [eax, ecx, edx, ebx, esi, edi]])
+                         for reg in main_registers])
     if withfloats:
         content += ([('float', locations.pop()) for _ in range(26)] +
-                    [('float', reg) for reg in [xmm0, xmm1, xmm2, xmm3,
-                                                xmm4, xmm5, xmm6, xmm7]])
+                    [('float', reg) for reg in xmm_registers])
     for i in range(8):
         content.append(('hole', None))
     random.shuffle(content)
 
     # prepare the expected target arrays, the descr_bytecode,
     # the 'registers' and the 'stack' arrays according to 'content'
-    xmmregisters = lltype.malloc(rffi.LONGP.TO, 16+9, flavor='raw')
+    xmmregisters = lltype.malloc(rffi.LONGP.TO, 16+ACTUAL_CPU.NUM_REGS+1, flavor='raw')
     registers = rffi.ptradd(xmmregisters, 16)
     stacklen = baseloc + 10
     stack = lltype.malloc(rffi.LONGP.TO, stacklen, flavor='raw')
@@ -140,8 +164,8 @@
         assert loc >= 0
         ofs = get_ebp_ofs(loc)
         assert ofs < 0
-        assert (ofs % 4) == 0
-        stack[stacklen + ofs//4] = value
+        assert (ofs % WORD) == 0
+        stack[stacklen + ofs//WORD] = value
 
     descr_bytecode = []
     for i, (kind, loc) in enumerate(content):
@@ -152,12 +176,18 @@
                 value, lo, hi = get_random_float()
                 expected_floats[i] = value
                 kind = Assembler386.DESCR_FLOAT
-                if isinstance(loc, REG):
-                    xmmregisters[2*loc.op] = lo
-                    xmmregisters[2*loc.op+1] = hi
+                if isinstance(loc, RegLoc):
+                    if WORD == 4:
+                        xmmregisters[2*loc.value] = lo
+                        xmmregisters[2*loc.value+1] = hi
+                    elif WORD == 8:
+                        xmmregisters[loc.value] = lo
                 else:
-                    write_in_stack(loc, hi)
-                    write_in_stack(loc+1, lo)
+                    if WORD == 4:
+                        write_in_stack(loc, hi)
+                        write_in_stack(loc+1, lo)
+                    elif WORD == 8:
+                        write_in_stack(loc, lo)
             else:
                 if kind == 'int':
                     value = get_random_int()
@@ -170,15 +200,15 @@
                     value = rffi.cast(rffi.LONG, value)
                 else:
                     assert 0, kind
-                if isinstance(loc, REG):
-                    registers[loc.op] = value
+                if isinstance(loc, RegLoc):
+                    registers[loc.value] = value
                 else:
                     write_in_stack(loc, value)
 
-            if isinstance(loc, REG):
-                num = kind + 4*loc.op
+            if isinstance(loc, RegLoc):
+                num = kind + 4*loc.value
             else:
-                num = kind + 4*(8+loc)
+                num = kind + Assembler386.CODE_FROMSTACK + (4*loc)
             while num >= 0x80:
                 descr_bytecode.append((num & 0x7F) | 0x80)
                 num >>= 7
@@ -195,8 +225,8 @@
     for i in range(len(descr_bytecode)):
         assert 0 <= descr_bytecode[i] <= 255
         descr_bytes[i] = rffi.cast(rffi.UCHAR, descr_bytecode[i])
-    registers[8] = rffi.cast(rffi.LONG, descr_bytes)
-    registers[ebp.op] = rffi.cast(rffi.LONG, stack) + 4*stacklen
+    registers[ACTUAL_CPU.NUM_REGS] = rffi.cast(rffi.LONG, descr_bytes)
+    registers[ebp.value] = rffi.cast(rffi.LONG, stack) + WORD*stacklen
 
     # run!
     assembler = Assembler386(FakeCPU())
@@ -237,7 +267,8 @@
 
 def test_mc_wrapper_profile_agent():
     agent = FakeProfileAgent()
-    mc = FakeMCWrapper(100, agent)
+    assembler = FakeAssembler()
+    mc = FakeMCWrapper(assembler, 100, agent)
     mc.start_function("abc")
     mc.writechr("x")
     mc.writechr("x")

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_basic.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_basic.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_basic.py	Thu Sep  9 01:00:13 2010
@@ -1,5 +1,5 @@
 import py
-from pypy.jit.backend.x86.runner import CPU386
+from pypy.jit.backend.detect_cpu import getcpuclass
 from pypy.jit.metainterp.warmspot import ll_meta_interp
 from pypy.jit.metainterp.test import test_basic
 from pypy.jit.codewriter.policy import StopAtXPolicy
@@ -7,7 +7,7 @@
 
 class Jit386Mixin(test_basic.LLJitMixin):
     type_system = 'lltype'
-    CPUClass = CPU386
+    CPUClass = getcpuclass()
 
     def check_jumps(self, maxcount):
         pass

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_gc_integration.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_gc_integration.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_gc_integration.py	Thu Sep  9 01:00:13 2010
@@ -9,13 +9,13 @@
 from pypy.jit.codewriter import heaptracker
 from pypy.jit.backend.llsupport.descr import GcCache
 from pypy.jit.backend.llsupport.gc import GcLLDescription
-from pypy.jit.backend.x86.runner import CPU
-from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, FRAME_FIXED_SIZE
+from pypy.jit.backend.detect_cpu import getcpuclass
+from pypy.jit.backend.x86.regalloc import RegAlloc
+from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE
 from pypy.jit.metainterp.test.oparser import parse
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rpython.lltypesystem import rclass, rstr
-from pypy.jit.backend.x86.ri386 import *
 from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcRefList, GcPtrFieldDescr
 
 from pypy.jit.backend.x86.test.test_regalloc import MockAssembler
@@ -23,17 +23,16 @@
 from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86FrameManager,\
      X86XMMRegisterManager
 
+CPU = getcpuclass()
+
 class MockGcRootMap(object):
-    def get_basic_shape(self):
+    def get_basic_shape(self, is_64_bit):
         return ['shape']
     def add_ebp_offset(self, shape, offset):
         shape.append(offset)
-    def add_ebx(self, shape):
-        shape.append('ebx')
-    def add_esi(self, shape):
-        shape.append('esi')
-    def add_edi(self, shape):
-        shape.append('edi')
+    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):
         assert shape[0] == 'shape'
         return ['compressed'] + shape[1:]
@@ -51,7 +50,7 @@
     def initialize(self):
         self.gcrefs = GcRefList()
         self.gcrefs.initialize()
-        self.single_gcref_descr = GcPtrFieldDescr(0)
+        self.single_gcref_descr = GcPtrFieldDescr('', 0)
         
     rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func
 
@@ -84,7 +83,7 @@
         mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap)
         assert mark[0] == 'compressed'
         base = -WORD * FRAME_FIXED_SIZE
-        expected = ['ebx', 'esi', 'edi', base, base-4, base-8]
+        expected = ['ebx', 'esi', 'edi', base, base-WORD, base-WORD*2]
         assert dict.fromkeys(mark[1:]) == dict.fromkeys(expected)
 
 class TestRegallocGcIntegration(BaseTestRegalloc):
@@ -175,7 +174,7 @@
         self.addrs[1] = self.addrs[0] + 64
         # 64 bytes
         def malloc_slowpath(size):
-            assert size == 8
+            assert size == WORD*2
             nadr = rffi.cast(lltype.Signed, self.nursery)
             self.addrs[0] = nadr + size
             return nadr
@@ -199,7 +198,7 @@
         return rffi.cast(lltype.Signed, self.addrs)
 
     def get_nursery_top_addr(self):
-        return rffi.cast(lltype.Signed, self.addrs) + 4
+        return rffi.cast(lltype.Signed, self.addrs) + WORD
 
     def get_malloc_fixedsize_slowpath_addr(self):
         fptr = llhelper(lltype.Ptr(self.MALLOC_SLOWPATH), self.malloc_slowpath)
@@ -213,7 +212,7 @@
 
     def setup_method(self, method):
         cpu = CPU(None, None)
-        cpu.vtable_offset = 4
+        cpu.vtable_offset = WORD
         cpu.gc_ll_descr = GCDescrFastpathMalloc()
 
         NODE = lltype.Struct('node', ('tid', lltype.Signed),
@@ -249,7 +248,7 @@
         assert gc_ll_descr.nursery[0] == self.nodedescr.tid
         assert gc_ll_descr.nursery[1] == 42
         nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        assert gc_ll_descr.addrs[0] == nurs_adr + 8
+        assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*2)
 
     def test_malloc_slowpath(self):
         ops = '''
@@ -269,7 +268,7 @@
         # this should call slow path once
         gc_ll_descr = self.cpu.gc_ll_descr
         nadr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        assert gc_ll_descr.addrs[0] == nadr + 8
+        assert gc_ll_descr.addrs[0] == nadr + (WORD*2)
 
     def test_new_with_vtable(self):
         ops = '''
@@ -284,4 +283,4 @@
         assert gc_ll_descr.nursery[0] == self.descrsize.tid
         assert gc_ll_descr.nursery[1] == self.vtable_int
         nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        assert gc_ll_descr.addrs[0] == nurs_adr + 12
+        assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*3)

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_jump.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_jump.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_jump.py	Thu Sep  9 01:00:13 2010
@@ -1,6 +1,7 @@
-from pypy.jit.backend.x86.ri386 import *
+from pypy.jit.backend.x86.regloc import *
 from pypy.jit.backend.x86.regalloc import X86FrameManager
 from pypy.jit.backend.x86.jump import remap_frame_layout
+from pypy.jit.metainterp.history import INT
 
 frame_pos = X86FrameManager.frame_pos
 
@@ -25,7 +26,7 @@
                 continue
             assert len(op1) == len(op2)
             for x, y in zip(op1, op2):
-                if isinstance(x, MODRM) and isinstance(y, MODRM):
+                if isinstance(x, StackLoc) and isinstance(y, MODRM):
                     assert x.byte == y.byte
                     assert x.extradata == y.extradata
                 else:
@@ -41,9 +42,9 @@
     remap_frame_layout(assembler, [eax, ebx, ecx, edx, esi, edi],
                                   [eax, ebx, ecx, edx, esi, edi], '?')
     assert assembler.ops == []
-    s8 = frame_pos(1, 1)
-    s12 = frame_pos(31, 1)
-    s20 = frame_pos(6, 1)
+    s8 = frame_pos(1, INT)
+    s12 = frame_pos(31, INT)
+    s20 = frame_pos(6, INT)
     remap_frame_layout(assembler, [eax, ebx, ecx, s20, s8, edx, s12, esi, edi],
                                   [eax, ebx, ecx, s20, s8, edx, s12, esi, edi],
                                   '?')
@@ -58,10 +59,10 @@
 
 def test_simple_framelocs():
     assembler = MockAssembler()
-    s8 = frame_pos(0, 1)
-    s12 = frame_pos(13, 1)
-    s20 = frame_pos(20, 1)
-    s24 = frame_pos(221, 1)
+    s8 = frame_pos(0, INT)
+    s12 = frame_pos(13, INT)
+    s20 = frame_pos(20, INT)
+    s24 = frame_pos(221, INT)
     remap_frame_layout(assembler, [s8, eax, s12], [s20, s24, edi], edx)
     assert assembler.ops == [('mov', s8, edx),
                              ('mov', edx, s20),
@@ -70,10 +71,10 @@
 
 def test_reordering():
     assembler = MockAssembler()
-    s8 = frame_pos(8, 1)
-    s12 = frame_pos(12, 1)
-    s20 = frame_pos(19, 1)
-    s24 = frame_pos(1, 1)
+    s8 = frame_pos(8, INT)
+    s12 = frame_pos(12, INT)
+    s20 = frame_pos(19, INT)
+    s24 = frame_pos(1, INT)
     remap_frame_layout(assembler, [eax, s8, s20, ebx],
                                   [s8, ebx, eax, edi], '?')
     assert assembler.got([('mov', ebx, edi),
@@ -83,10 +84,10 @@
 
 def test_cycle():
     assembler = MockAssembler()
-    s8 = frame_pos(8, 1)
-    s12 = frame_pos(12, 1)
-    s20 = frame_pos(19, 1)
-    s24 = frame_pos(1, 1)
+    s8 = frame_pos(8, INT)
+    s12 = frame_pos(12, INT)
+    s20 = frame_pos(19, INT)
+    s24 = frame_pos(1, INT)
     remap_frame_layout(assembler, [eax, s8, s20, ebx],
                                   [s8, ebx, eax, s20], '?')
     assert assembler.got([('push', s8),
@@ -97,12 +98,12 @@
 
 def test_cycle_2():
     assembler = MockAssembler()
-    s8 = frame_pos(8, 1)
-    s12 = frame_pos(12, 1)
-    s20 = frame_pos(19, 1)
-    s24 = frame_pos(1, 1)
-    s2 = frame_pos(2, 1)
-    s3 = frame_pos(3, 1)
+    s8 = frame_pos(8, INT)
+    s12 = frame_pos(12, INT)
+    s20 = frame_pos(19, INT)
+    s24 = frame_pos(1, INT)
+    s2 = frame_pos(2, INT)
+    s3 = frame_pos(3, INT)
     remap_frame_layout(assembler,
                        [eax, s8, edi, s20, eax, s20, s24, esi, s2, s3],
                        [s8, s20, edi, eax, edx, s24, ebx, s12, s3, s2],
@@ -127,14 +128,14 @@
     remap_frame_layout(assembler, [c3], [eax], '?')
     assert assembler.ops == [('mov', c3, eax)]
     assembler = MockAssembler()
-    s12 = frame_pos(12, 1)
+    s12 = frame_pos(12, INT)
     remap_frame_layout(assembler, [c3], [s12], '?')
     assert assembler.ops == [('mov', c3, s12)]
 
 def test_constants_and_cycle():
     assembler = MockAssembler()
     c3 = imm(3)
-    s12 = frame_pos(13, 1)
+    s12 = frame_pos(13, INT)
     remap_frame_layout(assembler, [ebx, c3,  s12],
                                   [s12, eax, ebx], edi)
     assert assembler.ops == [('mov', c3, eax),

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_recompilation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_recompilation.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_recompilation.py	Thu Sep  9 01:00:13 2010
@@ -1,6 +1,5 @@
-
-from pypy.jit.backend.x86.runner import CPU
 from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc
+from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64
 
 class TestRecompilation(BaseTestRegalloc):
     def test_compile_bridge_not_deeper(self):
@@ -51,7 +50,9 @@
         descr = loop.operations[2].descr
         new = descr._x86_bridge_frame_depth
         assert descr._x86_bridge_param_depth == 0        
-        assert new > previous
+        # XXX: Maybe add enough ops to force stack on 64-bit as well?
+        if IS_X86_32:
+            assert new > previous
         self.cpu.set_future_value_int(0, 0)
         fail = self.run(loop)
         assert fail.identifier == 2
@@ -111,7 +112,9 @@
         guard_op = loop.operations[5]
         loop_frame_depth = loop.token._x86_frame_depth
         assert loop.token._x86_param_depth == 0
-        assert guard_op.descr._x86_bridge_frame_depth > loop_frame_depth
+        # XXX: Maybe add enough ops to force stack on 64-bit as well?
+        if IS_X86_32:
+            assert guard_op.descr._x86_bridge_frame_depth > loop_frame_depth
         assert guard_op.descr._x86_bridge_param_depth == 0
         self.cpu.set_future_value_int(0, 0)
         self.cpu.set_future_value_int(1, 0)

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regalloc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regalloc.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regalloc.py	Thu Sep  9 01:00:13 2010
@@ -7,15 +7,17 @@
      BoxPtr, ConstPtr, LoopToken, BasicFailDescr
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.backend.llsupport.descr import GcCache
-from pypy.jit.backend.x86.runner import CPU
-from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, X86RegisterManager,\
+from pypy.jit.backend.detect_cpu import getcpuclass
+from pypy.jit.backend.x86.regalloc import RegAlloc, X86RegisterManager,\
      FloatConstants
+from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64
 from pypy.jit.metainterp.test.oparser import parse
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rpython.lltypesystem import rclass, rstr
-from pypy.jit.backend.x86.ri386 import *
+from pypy.jit.backend.x86.rx86 import *
 
+CPU = getcpuclass()
 class MockGcDescr(GcCache):
     def get_funcptr_for_new(self):
         return 123
@@ -92,13 +94,20 @@
     def f2(x, y):
         return x*y
 
+    def f10(*args):
+        assert len(args) == 10
+        return sum(args)
+
     F1PTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))
     F2PTR = lltype.Ptr(lltype.FuncType([lltype.Signed]*2, lltype.Signed))
+    F10PTR = lltype.Ptr(lltype.FuncType([lltype.Signed]*10, lltype.Signed))
     f1ptr = llhelper(F1PTR, f1)
     f2ptr = llhelper(F2PTR, f2)
+    f10ptr = llhelper(F10PTR, f10)
 
     f1_calldescr = cpu.calldescrof(F1PTR.TO, F1PTR.TO.ARGS, F1PTR.TO.RESULT)
     f2_calldescr = cpu.calldescrof(F2PTR.TO, F2PTR.TO.ARGS, F2PTR.TO.RESULT)
+    f10_calldescr = cpu.calldescrof(F10PTR.TO, F10PTR.TO.ARGS, F10PTR.TO.RESULT)
 
     namespace = locals().copy()
     type_system = 'lltype'
@@ -541,6 +550,12 @@
         assert self.getints(9) == [0, 1, 1, 1, 1, 1, 1, 1, 1]
 
 class TestRegAllocCallAndStackDepth(BaseTestRegalloc):
+    def expected_param_depth(self, num_args):
+        # Assumes the arguments are all non-float
+        if IS_X86_32:
+            return num_args
+        elif IS_X86_64:
+            return max(num_args - 6, 0)
 
     def test_one_call(self):
         ops = '''
@@ -550,7 +565,7 @@
         '''
         loop = self.interpret(ops, [4, 7, 9, 9 ,9, 9, 9, 9, 9, 9, 9])
         assert self.getints(11) == [5, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9]
-        assert loop.token._x86_param_depth == 1
+        assert loop.token._x86_param_depth == self.expected_param_depth(1)
 
     def test_two_calls(self):
         ops = '''
@@ -561,8 +576,21 @@
         '''
         loop = self.interpret(ops, [4, 7, 9, 9 ,9, 9, 9, 9, 9, 9, 9])
         assert self.getints(11) == [5*7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9]
-        assert loop.token._x86_param_depth == 2
-        
+        assert loop.token._x86_param_depth == self.expected_param_depth(2)
+
+    def test_call_many_arguments(self):
+        # NB: The first and last arguments in the call are constants. This
+        # is primarily for x86-64, to ensure that loading a constant to an
+        # argument register or to the stack works correctly
+        ops = '''
+        [i0, i1, i2, i3, i4, i5, i6, i7]
+        i8 = call(ConstClass(f10ptr), 1, i0, i1, i2, i3, i4, i5, i6, i7, 10, descr=f10_calldescr)
+        finish(i8)
+        '''
+        loop = self.interpret(ops, [2, 3, 4, 5, 6, 7, 8, 9])
+        assert self.getint(0) == 55
+        assert loop.token._x86_param_depth == self.expected_param_depth(10)
+
     def test_bridge_calls_1(self):
         ops = '''
         [i0, i1]
@@ -579,7 +607,7 @@
         '''
         bridge = self.attach_bridge(ops, loop, -2)
 
-        assert loop.operations[-2].descr._x86_bridge_param_depth == 2
+        assert loop.operations[-2].descr._x86_bridge_param_depth == self.expected_param_depth(2)
 
         self.cpu.set_future_value_int(0, 4)
         self.cpu.set_future_value_int(1, 7)        
@@ -602,7 +630,7 @@
         '''
         bridge = self.attach_bridge(ops, loop, -2)
 
-        assert loop.operations[-2].descr._x86_bridge_param_depth == 2        
+        assert loop.operations[-2].descr._x86_bridge_param_depth == self.expected_param_depth(2)
 
         self.cpu.set_future_value_int(0, 4)
         self.cpu.set_future_value_int(1, 7)        

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regalloc2.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regalloc2.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_regalloc2.py	Thu Sep  9 01:00:13 2010
@@ -2,7 +2,9 @@
 from pypy.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\
      BoxPtr, ConstPtr, BasicFailDescr, LoopToken
 from pypy.jit.metainterp.resoperation import rop
-from pypy.jit.backend.x86.runner import CPU
+from pypy.jit.backend.detect_cpu import getcpuclass
+from pypy.jit.backend.x86.arch import WORD
+CPU = getcpuclass()
 
 def test_bug_rshift():
     v1 = BoxInt()
@@ -281,5 +283,8 @@
     assert cpu.get_latest_value_int(16) == -57344
     assert cpu.get_latest_value_int(17) == 1
     assert cpu.get_latest_value_int(18) == -1
-    assert cpu.get_latest_value_int(19) == -2147483648
+    if WORD == 4:
+        assert cpu.get_latest_value_int(19) == -2147483648
+    elif WORD == 8:
+        assert cpu.get_latest_value_int(19) == 19327352832
     assert cpu.get_latest_value_int(20) == -49

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_runner.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_runner.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_runner.py	Thu Sep  9 01:00:13 2010
@@ -1,16 +1,22 @@
 import py
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr, rclass
+from pypy.rpython.annlowlevel import llhelper
 from pypy.jit.metainterp.history import ResOperation, LoopToken
-from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr,
-                                         Box, BasicFailDescr)
-from pypy.jit.backend.x86.runner import CPU
-from pypy.jit.backend.x86.regalloc import WORD
+from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstFloat,
+                                         ConstPtr, Box, BoxFloat, BasicFailDescr)
+from pypy.jit.backend.detect_cpu import getcpuclass
+from pypy.jit.backend.x86.arch import WORD
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp.executor import execute
 from pypy.jit.backend.test.runner_test import LLtypeBackendTest
+from pypy.jit.metainterp.test.oparser import parse
+from pypy.tool.udir import udir
 import ctypes
 import sys
+import os
+
+CPU = getcpuclass()
 
 class FakeStats(object):
     pass
@@ -56,7 +62,7 @@
         assert u.chars[3] == u'd'
 
     @staticmethod
-    def _resbuf(res, item_tp=ctypes.c_int):
+    def _resbuf(res, item_tp=ctypes.c_long):
         return ctypes.cast(res.value._obj.intval, ctypes.POINTER(item_tp))
 
     def test_allocations(self):
@@ -71,8 +77,11 @@
             return ctypes.cast(buf, ctypes.c_void_p).value
         func = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)(f)
         addr = ctypes.cast(func, ctypes.c_void_p).value
+        # ctypes produces an unsigned value. We need it to be signed for, eg,
+        # relative addressing to work properly.
+        addr = rffi.cast(lltype.Signed, addr)
         
-        self.cpu.assembler.make_sure_mc_exists()
+        self.cpu.assembler.setup()
         self.cpu.assembler.malloc_func_addr = addr
         ofs = symbolic.get_field_token(rstr.STR, 'chars', False)[0]
 
@@ -184,6 +193,7 @@
 
     def test_getfield_setfield(self):
         TP = lltype.GcStruct('x', ('s', lltype.Signed),
+                             ('i', rffi.INT),
                              ('f', lltype.Float),
                              ('u', rffi.USHORT),
                              ('c1', lltype.Char),
@@ -192,6 +202,7 @@
         res = self.execute_operation(rop.NEW, [],
                                      'ref', self.cpu.sizeof(TP))
         ofs_s = self.cpu.fielddescrof(TP, 's')
+        ofs_i = self.cpu.fielddescrof(TP, 'i')
         #ofs_f = self.cpu.fielddescrof(TP, 'f')
         ofs_u = self.cpu.fielddescrof(TP, 'u')
         ofsc1 = self.cpu.fielddescrof(TP, 'c1')
@@ -209,6 +220,11 @@
                                ofs_s)
         s = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofs_s)
         assert s.value == 3
+
+        self.execute_operation(rop.SETFIELD_GC, [res, BoxInt(1234)], 'void', ofs_i)
+        i = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofs_i)
+        assert i.value == 1234
+        
         #u = self.execute_operation(rop.GETFIELD_GC, [res, ofs_u], 'int')
         #assert u.value == 5
         self.execute_operation(rop.SETFIELD_GC, [res, ConstInt(1)], 'void',
@@ -357,7 +373,9 @@
         self.cpu.compile_bridge(faildescr1, [i1b], bridge)        
         name, address, size = agent.functions[1]
         assert name == "Bridge # 0: bye"
-        assert address == loopaddress + loopsize
+        # Would be exactly ==, but there are some guard failure recovery
+        # stubs in-between
+        assert address >= loopaddress + loopsize
         assert size >= 10 # randomish number
 
         self.cpu.set_future_value_int(0, 2)
@@ -366,6 +384,19 @@
         res = self.cpu.get_latest_value_int(0)
         assert res == 20
 
+    def test_call_with_const_floats(self):
+        def func(f1, f2):
+            return f1 + f2
+
+        FUNC = self.FuncType([lltype.Float, lltype.Float], lltype.Float)
+        FPTR = self.Ptr(FUNC)
+        calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+        func_ptr = llhelper(FPTR, func)
+        funcbox = self.get_funcbox(self.cpu, func_ptr)
+        res = self.execute_operation(rop.CALL, [funcbox, ConstFloat(1.5), ConstFloat(2.5)], 'float', descr=calldescr)
+        assert res.value == 4.0
+
+
 class TestX86OverflowMC(TestX86):
 
     def setup_method(self, meth):
@@ -383,10 +414,100 @@
         ops.append(ResOperation(rop.FINISH, [v], None,
                                 descr=BasicFailDescr()))
         looptoken = LoopToken()
-        self.cpu.assembler.make_sure_mc_exists()
+        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].fail_args = [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
+
+
+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
+
+    def test_debugger_on(self):
+        loop = """
+        [i0]
+        debug_merge_point('xyz')
+        i1 = int_add(i0, 1)
+        i2 = int_ge(i1, 10)
+        guard_false(i2) []
+        jump(i1)
+        """
+        ops = parse(loop)
+        self.cpu.assembler.set_debug(True)
+        self.cpu.compile_loop(ops.inputargs, ops.operations, ops.token)
+        self.cpu.set_future_value_int(0, 0)
+        self.cpu.execute_token(ops.token)
+        # check debugging info
+        name, struct = self.cpu.assembler.loop_run_counters[0]
+        assert name == 'xyz'
+        assert struct.i == 10
+        self.cpu.finish_once()
+        lines = py.path.local(self.logfile + ".count").readlines()
+        assert lines[0] == '10      xyz\n'

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_symbolic_x86.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_symbolic_x86.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_symbolic_x86.py	Thu Sep  9 01:00:13 2010
@@ -1,6 +1,7 @@
 import py
 from pypy.jit.backend.llsupport.symbolic import *
 from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.jit.backend.x86.arch import WORD
 
 # This test file is here and not in llsupport/test/ because it checks
 # that we get correct numbers for a 32-bit machine.
@@ -19,32 +20,32 @@
     ofs_z, size_z = get_field_token(S, 'z', False)
     # ofs_x might be 0 or not, depending on how we count the headers
     # but the rest should be as expected for a 386 machine
-    assert size_x == size_y == size_z == 4
+    assert size_x == size_y == size_z == WORD
     assert ofs_x >= 0
-    assert ofs_y == ofs_x + 4
-    assert ofs_z == ofs_x + 8
+    assert ofs_y == ofs_x + WORD
+    assert ofs_z == ofs_x + (WORD*2)
 
 def test_struct_size():
     ofs_z, size_z = get_field_token(S, 'z', False)
     totalsize = get_size(S, False)
-    assert totalsize == ofs_z + 4
+    assert totalsize == ofs_z + WORD
 
 def test_primitive_size():
-    assert get_size(lltype.Signed, False) == 4
+    assert get_size(lltype.Signed, False) == WORD
     assert get_size(lltype.Char, False) == 1
-    assert get_size(lltype.Ptr(S), False) == 4
+    assert get_size(lltype.Ptr(S), False) == WORD
 
 def test_array_token():
     A = lltype.GcArray(lltype.Char)
     basesize, itemsize, ofs_length = get_array_token(A, False)
-    assert basesize >= 4    # at least the 'length', maybe some gc headers
+    assert basesize >= WORD    # at least the 'length', maybe some gc headers
     assert itemsize == 1
-    assert ofs_length == basesize - 4
+    assert ofs_length == basesize - WORD
     A = lltype.GcArray(lltype.Signed)
     basesize, itemsize, ofs_length = get_array_token(A, False)
-    assert basesize >= 4    # at least the 'length', maybe some gc headers
-    assert itemsize == 4
-    assert ofs_length == basesize - 4
+    assert basesize >= WORD    # at least the 'length', maybe some gc headers
+    assert itemsize == WORD
+    assert ofs_length == basesize - WORD
 
 def test_varsized_struct_size():
     S1 = lltype.GcStruct('S1', ('parent', S),
@@ -54,9 +55,9 @@
     ofs_extra, size_extra = get_field_token(S1, 'extra', False)
     basesize, itemsize, ofs_length = get_array_token(S1, False)
     assert size_parent == ofs_extra
-    assert size_extra == 4
-    assert ofs_length == ofs_extra + 4
-    assert basesize == ofs_length + 4
+    assert size_extra == WORD
+    assert ofs_length == ofs_extra + WORD
+    assert basesize == ofs_length + WORD
     assert itemsize == 1
 
 def test_string():

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_zll_random.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_zll_random.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_zll_random.py	Thu Sep  9 01:00:13 2010
@@ -1,9 +1,11 @@
 from pypy.jit.backend.test.test_random import check_random_function, Random
 from pypy.jit.backend.test.test_ll_random import LLtypeOperationBuilder
-from pypy.jit.backend.x86.runner import CPU386
+from pypy.jit.backend.detect_cpu import getcpuclass
+
+CPU = getcpuclass()
 
 def test_stress():
-    cpu = CPU386(None, None)
+    cpu = CPU(None, None)
     r = Random()
     for i in range(1000):
         check_random_function(cpu, LLtypeOperationBuilder, r, i, 1000)

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_zrpy_gc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_zrpy_gc.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_zrpy_gc.py	Thu Sep  9 01:00:13 2010
@@ -17,6 +17,8 @@
 from pypy.jit.backend.llsupport.gc import GcRefList, GcRootMap_asmgcc
 from pypy.jit.backend.llsupport.gc import GcLLDescr_framework
 from pypy.tool.udir import udir
+from pypy.jit.backend.x86.arch import IS_X86_64
+import py.test
 
 class X(object):
     def __init__(self, x=0):

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_ztranslation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_ztranslation.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/test/test_ztranslation.py	Thu Sep  9 01:00:13 2010
@@ -3,13 +3,14 @@
 from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL, unroll_parameters
 from pypy.rlib.jit import PARAMETERS, dont_look_inside
 from pypy.jit.metainterp.jitprof import Profiler
-from pypy.jit.backend.x86.runner import CPU386
+from pypy.jit.backend.detect_cpu import getcpuclass
 from pypy.jit.backend.test.support import CCompiledMixin
 from pypy.jit.codewriter.policy import StopAtXPolicy
 from pypy.translator.translator import TranslationContext
+from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64
 
 class TestTranslationX86(CCompiledMixin):
-    CPUClass = CPU386
+    CPUClass = getcpuclass()
 
     def _check_cbuilder(self, cbuilder):
         # We assume here that we have sse2.  If not, the CPUClass
@@ -74,8 +75,7 @@
         
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'frame'],
                            virtualizables = ['frame'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno: str(codeno))
         class SomewhereElse(object):
             pass
 
@@ -114,7 +114,7 @@
 
 
 class TestTranslationRemoveTypePtrX86(CCompiledMixin):
-    CPUClass = CPU386
+    CPUClass = getcpuclass()
 
     def _get_TranslationContext(self):
         t = TranslationContext()

Modified: pypy/branch/fast-forward/pypy/jit/backend/x86/tool/viewcode.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/backend/x86/tool/viewcode.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/backend/x86/tool/viewcode.py	Thu Sep  9 01:00:13 2010
@@ -31,16 +31,23 @@
 if sys.platform == "win32":
     XXX   # lots more in Psyco
 
-def machine_code_dump(data, originaddr):
-    # the disassembler to use. 'objdump' writes GNU-style instructions.
-    # 'ndisasm' would use Intel syntax, but you need to fix the output parsing.
-    objdump = ('objdump -M intel -b binary -m i386 '
+def machine_code_dump(data, originaddr, backend_name):
+    objdump_backend_option = {
+        'x86': 'i386',
+        'x86_64': 'x86-64',
+        'i386': 'i386',
+    }
+    objdump = ('objdump -M intel,%(backend)s -b binary -m i386 '
                '--adjust-vma=%(origin)d -D %(file)s')
     #
     f = open(tmpfile, 'wb')
     f.write(data)
     f.close()
-    g = os.popen(objdump % {'file': tmpfile, 'origin': originaddr}, 'r')
+    g = os.popen(objdump % {
+        'file': tmpfile,
+        'origin': originaddr,
+        'backend': objdump_backend_option[backend_name],
+    }, 'r')
     result = g.readlines()
     g.close()
     return result[6:]   # drop some objdump cruft
@@ -126,7 +133,7 @@
 
     def disassemble(self):
         if not hasattr(self, 'text'):
-            lines = machine_code_dump(self.data, self.addr)
+            lines = machine_code_dump(self.data, self.addr, self.world.backend_name)
             # instead of adding symbol names in the dumps we could
             # also make the 0xNNNNNNNN addresses be red and show the
             # symbol name when the mouse is over them
@@ -171,10 +178,13 @@
         self.jumps = {}
         self.symbols = {}
         self.logentries = {}
+        self.backend_name = None
 
     def parse(self, f, textonly=True):
         for line in f:
-            if line.startswith('CODE_DUMP '):
+            if line.startswith('BACKEND '):
+                self.backend_name = line.split(' ')[1].strip()
+            elif line.startswith('CODE_DUMP '):
                 pieces = line.split()
                 assert pieces[1].startswith('@')
                 assert pieces[2].startswith('+')

Modified: pypy/branch/fast-forward/pypy/jit/codewriter/assembler.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/codewriter/assembler.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/codewriter/assembler.py	Thu Sep  9 01:00:13 2010
@@ -53,6 +53,7 @@
         self.liveness = {}
         self.startpoints = set()
         self.alllabels = set()
+        self.resulttypes = {}
 
     def emit_reg(self, reg):
         if reg.index >= self.count_regs[reg.kind]:
@@ -165,7 +166,9 @@
                 raise NotImplementedError(x)
         #
         opname = insn[0]
-        assert '>' not in argcodes or argcodes.index('>') == len(argcodes) - 2
+        if '>' in argcodes:
+            assert argcodes.index('>') == len(argcodes) - 2
+            self.resulttypes[len(self.code)] = argcodes[-1]
         key = opname + '/' + ''.join(argcodes)
         num = self.insns.setdefault(key, len(self.insns))
         self.code[startposition] = chr(num)
@@ -212,7 +215,8 @@
                       self.count_regs['float'],
                       liveness=self.liveness,
                       startpoints=self.startpoints,
-                      alllabels=self.alllabels)
+                      alllabels=self.alllabels,
+                      resulttypes=self.resulttypes)
 
     def see_raw_object(self, value):
         if value._obj not in self._seen_raw_objects:

Modified: pypy/branch/fast-forward/pypy/jit/codewriter/jitcode.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/codewriter/jitcode.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/codewriter/jitcode.py	Thu Sep  9 01:00:13 2010
@@ -19,7 +19,8 @@
 
     def setup(self, code='', constants_i=[], constants_r=[], constants_f=[],
               num_regs_i=255, num_regs_r=255, num_regs_f=255,
-              liveness=None, startpoints=None, alllabels=None):
+              liveness=None, startpoints=None, alllabels=None,
+              resulttypes=None):
         self.code = code
         # if the following lists are empty, use a single shared empty list
         self.constants_i = constants_i or self._empty_i
@@ -33,6 +34,7 @@
         self.liveness = make_liveness_cache(liveness)
         self._startpoints = startpoints   # debugging
         self._alllabels = alllabels       # debugging
+        self._resulttypes = resulttypes   # debugging
 
     def get_fnaddr_as_int(self):
         return heaptracker.adr2int(self.fnaddr)

Modified: pypy/branch/fast-forward/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/codewriter/jtransform.py	Thu Sep  9 01:00:13 2010
@@ -511,14 +511,11 @@
                                                 arraydescr)
             return []
         # check for deepfrozen structures that force constant-folding
-        hints = v_inst.concretetype.TO._hints
-        accessor = hints.get("immutable_fields")
-        if accessor and c_fieldname.value in accessor.fields:
+        immut = v_inst.concretetype.TO._immutable_field(c_fieldname.value)
+        if immut:
             pure = '_pure'
-            if accessor.fields[c_fieldname.value] == "[*]":
+            if immut == "[*]":
                 self.immutable_arrays[op.result] = True
-        elif hints.get('immutable'):
-            pure = '_pure'
         else:
             pure = ''
         argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
@@ -829,13 +826,20 @@
                 self.make_three_lists(op.args[2:2+num_green_args]) +
                 self.make_three_lists(op.args[2+num_green_args:]))
         op1 = SpaceOperation('jit_merge_point', args, None)
-        return ops + [op1]
+        op2 = SpaceOperation('-live-', [], None)
+        # ^^^ we need a -live- for the case of do_recursive_call()
+        return ops + [op1, op2]
 
-    def handle_jit_marker__can_enter_jit(self, op, jitdriver):
+    def handle_jit_marker__loop_header(self, op, jitdriver):
         jd = self.callcontrol.jitdriver_sd_from_jitdriver(jitdriver)
         assert jd is not None
         c_index = Constant(jd.index, lltype.Signed)
-        return SpaceOperation('can_enter_jit', [c_index], None)
+        return SpaceOperation('loop_header', [c_index], None)
+
+    # a 'can_enter_jit' in the source graph becomes a 'loop_header'
+    # operation in the transformed graph, as its only purpose in
+    # the transformed graph is to detect loops.
+    handle_jit_marker__can_enter_jit = handle_jit_marker__loop_header
 
     def rewrite_op_debug_assert(self, op):
         log.WARNING("found debug_assert in %r; should have be removed" %

Modified: pypy/branch/fast-forward/pypy/jit/codewriter/test/test_flatten.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/codewriter/test/test_flatten.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/codewriter/test/test_flatten.py	Thu Sep  9 01:00:13 2010
@@ -593,7 +593,8 @@
             -live- %i0, %i1
             int_guard_value %i0
             jit_merge_point $27, I[%i0], R[], F[], I[%i1], R[], F[]
-            can_enter_jit $27
+            -live-
+            loop_header $27
             void_return
         """, transform=True, liveness=True, cc=MyFakeCallControl(), jd=jd)
 

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/blackhole.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/blackhole.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/blackhole.py	Thu Sep  9 01:00:13 2010
@@ -2,7 +2,7 @@
 from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.debug import debug_start, debug_stop
-from pypy.rlib.debug import make_sure_not_resized
+from pypy.rlib.debug import make_sure_not_resized, fatalerror
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.llinterp import LLException
@@ -756,11 +756,15 @@
         assert e
         reraise(e)
 
+    @arguments("r")
+    def bhimpl_debug_fatalerror(msg):
+        llop.debug_fatalerror(lltype.Void, msg)
+
     # ----------
     # the main hints and recursive calls
 
     @arguments("i")
-    def bhimpl_can_enter_jit(jdindex):
+    def bhimpl_loop_header(jdindex):
         pass
 
     @arguments("self", "i", "I", "R", "F", "I", "R", "F")
@@ -1164,7 +1168,7 @@
             # we now proceed to interpret the bytecode in this frame
             self.run()
         #
-        except JitException:
+        except JitException, e:
             raise     # go through
         except Exception, e:
             # if we get an exception, return it to the caller frame
@@ -1266,6 +1270,33 @@
         e = lltype.cast_opaque_ptr(llmemory.GCREF, e)
         raise sd.ExitFrameWithExceptionRef(self.cpu, e)
 
+    def _handle_jitexception_in_portal(self, e):
+        # This case is really rare, but can occur if
+        # convert_and_run_from_pyjitpl() gets called in this situation:
+        #
+        #     [function 1]             <---- top BlackholeInterpreter()
+        #     [recursive portal jit code]
+        #     ...
+        #     [bottom portal jit code]   <---- bottom BlackholeInterpreter()
+        #
+        # and then "function 1" contains a call to "function 2", which
+        # calls "can_enter_jit".  The latter can terminate by raising a
+        # JitException.  In that case, the JitException is not supposed
+        # to fall through the whole chain of BlackholeInterpreters, but
+        # be caught and handled just below the level "recursive portal
+        # jit code".  The present function is called to handle the case
+        # of recursive portal jit codes.
+        for jd in self.builder.metainterp_sd.jitdrivers_sd:
+            if jd.mainjitcode is self.jitcode:
+                break
+        else:
+            assert 0, "portal jitcode not found??"
+        # call the helper in warmspot.py.  It might either raise a
+        # regular exception (which should then be propagated outside
+        # of 'self', not caught inside), or return (the return value
+        # gets stored in nextblackholeinterp).
+        jd.handle_jitexc_from_bh(self.nextblackholeinterp, e)
+
     def _copy_data_from_miframe(self, miframe):
         self.setposition(miframe.jitcode, miframe.pc)
         for i in range(self.jitcode.num_regs_i()):
@@ -1287,9 +1318,31 @@
     while True:
         try:
             current_exc = blackholeinterp._resume_mainloop(current_exc)
-        finally:
-            blackholeinterp.builder.release_interp(blackholeinterp)
+        except JitException, e:
+            blackholeinterp, current_exc = _handle_jitexception(
+                blackholeinterp, e)
+        blackholeinterp.builder.release_interp(blackholeinterp)
+        blackholeinterp = blackholeinterp.nextblackholeinterp
+
+def _handle_jitexception(blackholeinterp, jitexc):
+    # See comments in _handle_jitexception_in_portal().
+    while not blackholeinterp.jitcode.is_portal:
+        blackholeinterp.builder.release_interp(blackholeinterp)
         blackholeinterp = blackholeinterp.nextblackholeinterp
+    if blackholeinterp.nextblackholeinterp is None:
+        blackholeinterp.builder.release_interp(blackholeinterp)
+        raise jitexc     # bottommost entry: go through
+    # We have reached a recursive portal level.
+    try:
+        blackholeinterp._handle_jitexception_in_portal(jitexc)
+    except Exception, e:
+        # It raised a general exception (it should not be a JitException here).
+        lle = get_llexception(blackholeinterp.cpu, e)
+    else:
+        # It set up the nextblackholeinterp to contain the return value.
+        lle = lltype.nullptr(rclass.OBJECTPTR.TO)
+    # We will continue to loop in _run_forever() from the parent level.
+    return blackholeinterp, lle
 
 def resume_in_blackhole(metainterp_sd, jitdriver_sd, resumedescr,
                         all_virtuals=None):

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/executor.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/executor.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/executor.py	Thu Sep  9 01:00:13 2010
@@ -91,7 +91,7 @@
         return BoxInt(cpu.bh_getarrayitem_gc_i(arraydescr, array, index))
 
 def do_getarrayitem_raw(cpu, _, arraybox, indexbox, arraydescr):
-    array = arraybox.getref_base()
+    array = arraybox.getint()
     index = indexbox.getint()
     assert not arraydescr.is_array_of_pointers()
     if arraydescr.is_array_of_floats():
@@ -172,34 +172,36 @@
                   [x1box.getref_base(), x2box.getref_base()], None)
 
 def do_int_add_ovf(cpu, metainterp, box1, box2):
-    assert metainterp is not None
+    # the overflow operations can be called without a metainterp, if an
+    # overflow cannot occur
     a = box1.getint()
     b = box2.getint()
     try:
         z = ovfcheck(a + b)
     except OverflowError:
+        assert metainterp is not None
         metainterp.execute_raised(OverflowError(), constant=True)
         z = 0
     return BoxInt(z)
 
 def do_int_sub_ovf(cpu, metainterp, box1, box2):
-    assert metainterp is not None
     a = box1.getint()
     b = box2.getint()
     try:
         z = ovfcheck(a - b)
     except OverflowError:
+        assert metainterp is not None
         metainterp.execute_raised(OverflowError(), constant=True)
         z = 0
     return BoxInt(z)
 
 def do_int_mul_ovf(cpu, metainterp, box1, box2):
-    assert metainterp is not None
     a = box1.getint()
     b = box2.getint()
     try:
         z = ovfcheck(a * b)
     except OverflowError:
+        assert metainterp is not None
         metainterp.execute_raised(OverflowError(), constant=True)
         z = 0
     return BoxInt(z)

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/history.py	Thu Sep  9 01:00:13 2010
@@ -919,11 +919,12 @@
                 "found %d %r, expected %d" % (found, insn, expected_count))
         return insns
 
-    def check_loops(self, expected=None, **check):
+    def check_loops(self, expected=None, everywhere=False, **check):
         insns = {}
         for loop in self.loops:
-            if getattr(loop, '_ignore_during_counting', False):
-                continue
+            if not everywhere:
+                if getattr(loop, '_ignore_during_counting', False):
+                    continue
             insns = loop.summary(adding_insns=insns)
         if expected is not None:
             insns.pop('debug_merge_point', None)

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/jitdriver.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/jitdriver.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/jitdriver.py	Thu Sep  9 01:00:13 2010
@@ -12,6 +12,7 @@
     #    self.result_type       ... pypy.jit.metainterp.warmspot
     #    self.virtualizable_info... pypy.jit.metainterp.warmspot
     #    self.warmstate         ... pypy.jit.metainterp.warmspot
+    #    self.handle_jitexc_from_bh pypy.jit.metainterp.warmspot
     #    self.index             ... pypy.jit.codewriter.call
     #    self.mainjitcode       ... pypy.jit.codewriter.call
 

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/optimizeopt.py	Thu Sep  9 01:00:13 2010
@@ -1,7 +1,7 @@
 from pypy.jit.metainterp.history import Box, BoxInt, LoopToken, BoxFloat,\
      ConstFloat
 from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop, ResOperation, opboolinvers, opboolreflex
 from pypy.jit.metainterp import jitprof
 from pypy.jit.metainterp.executor import execute_nonspec
 from pypy.jit.metainterp.specnode import SpecNode, NotSpecNode, ConstantSpecNode
@@ -18,6 +18,7 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.jit.metainterp.history import AbstractDescr, make_hashable_int
 
+
 def optimize_loop_1(metainterp_sd, loop):
     """Optimize loop.operations to make it match the input of loop.specnodes
     and to remove internal overheadish operations.  Note that loop.specnodes
@@ -525,7 +526,9 @@
     def propagate_forward(self):
         self.exception_might_have_happened = False
         self.newoperations = []
-        for op in self.loop.operations:
+        self.i = 0
+        while self.i < len(self.loop.operations):
+            op = self.loop.operations[self.i]
             opnum = op.opnum
             for value, func in optimize_ops:
                 if opnum == value:
@@ -533,6 +536,7 @@
                     break
             else:
                 self.optimize_default(op)
+            self.i += 1
         self.loop.operations = self.newoperations
         # accumulate counters
         self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
@@ -587,7 +591,12 @@
                 descr.make_a_counter_per_value(op)
 
     def optimize_default(self, op):
-        if op.is_always_pure():
+        canfold = op.is_always_pure()
+        is_ovf = op.is_ovf()
+        if is_ovf:
+            nextop = self.loop.operations[self.i + 1]
+            canfold = nextop.opnum == rop.GUARD_NO_OVERFLOW
+        if canfold:
             for arg in op.args:
                 if self.get_constant_box(arg) is None:
                     break
@@ -597,6 +606,8 @@
                 resbox = execute_nonspec(self.cpu, None,
                                          op.opnum, argboxes, op.descr)
                 self.make_constant(op.result, resbox.constbox())
+                if is_ovf:
+                    self.i += 1 # skip next operation, it is the unneeded guard
                 return
 
             # did we do the exact same operation already?
@@ -610,6 +621,10 @@
             if oldop is not None and oldop.descr is op.descr:
                 assert oldop.opnum == op.opnum
                 self.make_equal_to(op.result, self.getvalue(oldop.result))
+                if is_ovf:
+                    self.i += 1 # skip next operation, it is the unneeded guard
+                return
+            elif self.find_rewritable_bool(op, args):
                 return
             else:
                 self.pure_operations[args] = op
@@ -617,6 +632,51 @@
         # otherwise, the operation remains
         self.emit_operation(op)
 
+
+    def try_boolinvers(self, op, targs):
+        oldop = self.pure_operations.get(targs, None)
+        if oldop is not None and oldop.descr is op.descr:
+            value = self.getvalue(oldop.result)
+            if value.is_constant():
+                if value.box is CONST_1:
+                    self.make_constant(op.result, CONST_0)
+                    return True
+                elif value.box is CONST_0:
+                    self.make_constant(op.result, CONST_1)
+                    return True
+        return False
+
+    
+    def find_rewritable_bool(self, op, args):
+        try:
+            oldopnum = opboolinvers[op.opnum]
+            targs = [args[0], args[1], ConstInt(oldopnum)]
+            if self.try_boolinvers(op, targs):
+                return True
+        except KeyError:
+            pass
+
+        try:
+            oldopnum = opboolreflex[op.opnum]
+            targs = [args[1], args[0], ConstInt(oldopnum)]
+            oldop = self.pure_operations.get(targs, None)
+            if oldop is not None and oldop.descr is op.descr:
+                self.make_equal_to(op.result, self.getvalue(oldop.result))
+                return True
+        except KeyError:
+            pass
+
+        try:
+            oldopnum = opboolinvers[opboolreflex[op.opnum]]
+            targs = [args[1], args[0], ConstInt(oldopnum)]
+            if self.try_boolinvers(op, targs):
+                return True
+        except KeyError:
+            pass
+
+        return False
+
+        
     def optimize_JUMP(self, op):
         orgop = self.loop.operations[-1]
         exitargs = []
@@ -992,6 +1052,25 @@
             self.make_equal_to(op.result, v1)
         else:
             self.optimize_default(op)
+    
+    def optimize_INT_SUB(self, op):
+        v1 = self.getvalue(op.args[0])
+        v2 = self.getvalue(op.args[1])
+        if v2.is_constant() and v2.box.getint() == 0:
+            self.make_equal_to(op.result, v1)
+        else:
+            return self.optimize_default(op)
+    
+    def optimize_INT_ADD(self, op):
+        v1 = self.getvalue(op.args[0])
+        v2 = self.getvalue(op.args[1])
+        # If one side of the op is 0 the result is the other side.
+        if v1.is_constant() and v1.box.getint() == 0:
+            self.make_equal_to(op.result, v2)
+        elif v2.is_constant() and v2.box.getint() == 0:
+            self.make_equal_to(op.result, v1)
+        else:
+            self.optimize_default(op)
 
 
 optimize_ops = _findall(Optimizer, 'optimize_')

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/pyjitpl.py	Thu Sep  9 01:00:13 2010
@@ -149,16 +149,20 @@
             assert oldbox not in registers[count:]
 
     def make_result_of_lastop(self, resultbox):
-        if resultbox is None:
-            return
+        got_type = resultbox.type
+        if not we_are_translated():
+            typeof = {'i': history.INT,
+                      'r': history.REF,
+                      'f': history.FLOAT}
+            assert typeof[self.jitcode._resulttypes[self.pc]] == got_type
         target_index = ord(self.bytecode[self.pc-1])
-        if resultbox.type == history.INT:
+        if got_type == history.INT:
             self.registers_i[target_index] = resultbox
-        elif resultbox.type == history.REF:
+        elif got_type == history.REF:
             #debug_print(' ->', 
             #            llmemory.cast_ptr_to_adr(resultbox.getref_base()))
             self.registers_r[target_index] = resultbox
-        elif resultbox.type == history.FLOAT:
+        elif got_type == history.FLOAT:
             self.registers_f[target_index] = resultbox
         else:
             raise AssertionError("bad result box type")
@@ -685,11 +689,11 @@
     def _opimpl_recursive_call(self, jdindex, greenboxes, redboxes):
         targetjitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
         allboxes = greenboxes + redboxes
-        portal_code = targetjitdriver_sd.mainjitcode
         warmrunnerstate = targetjitdriver_sd.warmstate
         token = None
         if warmrunnerstate.inlining:
             if warmrunnerstate.can_inline_callable(greenboxes):
+                portal_code = targetjitdriver_sd.mainjitcode
                 return self.metainterp.perform_call(portal_code, allboxes,
                                                     greenkey=greenboxes)
             token = warmrunnerstate.get_assembler_token(greenboxes)
@@ -697,6 +701,10 @@
             # that assembler that we call is still correct
             self.verify_green_args(targetjitdriver_sd, greenboxes)
         #
+        return self.do_recursive_call(targetjitdriver_sd, allboxes, token)
+
+    def do_recursive_call(self, targetjitdriver_sd, allboxes, token=None):
+        portal_code = targetjitdriver_sd.mainjitcode
         k = targetjitdriver_sd.portal_runner_adr
         funcbox = ConstInt(heaptracker.adr2int(k))
         return self.do_residual_call(funcbox, portal_code.calldescr,
@@ -786,13 +794,8 @@
         return clsbox
 
     @arguments("int")
-    def opimpl_can_enter_jit(self, jdindex):
-        if self.metainterp.in_recursion:
-            from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit
-            raise CannotInlineCanEnterJit()
-        assert jdindex == self.metainterp.jitdriver_sd.index, (
-            "found a can_enter_jit that does not match the current jitdriver")
-        self.metainterp.seen_can_enter_jit = True
+    def opimpl_loop_header(self, jdindex):
+        self.metainterp.seen_loop_header_for_jdindex = jdindex
 
     def verify_green_args(self, jitdriver_sd, varargs):
         num_green_args = jitdriver_sd.num_green_args
@@ -806,22 +809,42 @@
         self.verify_green_args(jitdriver_sd, greenboxes)
         # xxx we may disable the following line in some context later
         self.debug_merge_point(jitdriver_sd, greenboxes)
-        if self.metainterp.seen_can_enter_jit:
-            self.metainterp.seen_can_enter_jit = False
-            # Assert that it's impossible to arrive here with in_recursion
-            # set to a non-zero value: seen_can_enter_jit can only be set
-            # to True by opimpl_can_enter_jit, which should be executed
-            # just before opimpl_jit_merge_point (no recursion inbetween).
-            assert not self.metainterp.in_recursion
+        if self.metainterp.seen_loop_header_for_jdindex < 0:
+            return
+        #
+        assert self.metainterp.seen_loop_header_for_jdindex == jdindex, (
+            "found a loop_header for a JitDriver that does not match "
+            "the following jit_merge_point's")
+        self.metainterp.seen_loop_header_for_jdindex = -1
+        #
+        if not self.metainterp.in_recursion:
             assert jitdriver_sd is self.metainterp.jitdriver_sd
             # Set self.pc to point to jit_merge_point instead of just after:
-            # if reached_can_enter_jit() raises SwitchToBlackhole, then the
+            # if reached_loop_header() raises SwitchToBlackhole, then the
             # pc is still at the jit_merge_point, which is a point that is
             # much less expensive to blackhole out of.
             saved_pc = self.pc
             self.pc = orgpc
-            self.metainterp.reached_can_enter_jit(greenboxes, redboxes)
+            self.metainterp.reached_loop_header(greenboxes, redboxes)
             self.pc = saved_pc
+        else:
+            warmrunnerstate = jitdriver_sd.warmstate
+            token = warmrunnerstate.get_assembler_token(greenboxes)
+            # warning! careful here.  We have to return from the current
+            # frame containing the jit_merge_point, and then use
+            # do_recursive_call() to follow the recursive call.  This is
+            # needed because do_recursive_call() will write its result
+            # with make_result_of_lastop(), so the lastop must be right:
+            # it must be the call to 'self', and not the jit_merge_point
+            # itself, which has no result at all.
+            assert len(self.metainterp.framestack) >= 2
+            try:
+                self.metainterp.finishframe(None)
+            except ChangeFrame:
+                pass
+            frame = self.metainterp.framestack[-1]
+            frame.do_recursive_call(jitdriver_sd, greenboxes + redboxes, token)
+            raise ChangeFrame
 
     def debug_merge_point(self, jitdriver_sd, greenkey):
         # debugging: produce a DEBUG_MERGE_POINT operation
@@ -872,6 +895,12 @@
         return exc_value_box
 
     @arguments("box")
+    def opimpl_debug_fatalerror(self, box):
+        from pypy.rpython.lltypesystem import rstr, lloperation
+        msg = box.getref(lltype.Ptr(rstr.STR))
+        lloperation.llop.debug_fatalerror(msg)
+
+    @arguments("box")
     def opimpl_virtual_ref(self, box):
         # Details on the content of metainterp.virtualref_boxes:
         #
@@ -1018,9 +1047,10 @@
         self.metainterp.clear_exception()
         resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes,
                                                             descr=descr)
-        self.make_result_of_lastop(resbox)
-        # ^^^ this is done before handle_possible_exception() because we need
-        # the box to show up in get_list_of_active_boxes()
+        if resbox is not None:
+            self.make_result_of_lastop(resbox)
+            # ^^^ this is done before handle_possible_exception() because we
+            # need the box to show up in get_list_of_active_boxes()
         if exc:
             self.metainterp.handle_possible_exception()
         else:
@@ -1323,7 +1353,8 @@
         self.last_exc_value_box = None
         self.popframe()
         if self.framestack:
-            self.framestack[-1].make_result_of_lastop(resultbox)
+            if resultbox is not None:
+                self.framestack[-1].make_result_of_lastop(resultbox)
             raise ChangeFrame
         else:
             try:
@@ -1552,7 +1583,7 @@
         redkey = original_boxes[num_green_args:]
         self.resumekey = compile.ResumeFromInterpDescr(original_greenkey,
                                                        redkey)
-        self.seen_can_enter_jit = False
+        self.seen_loop_header_for_jdindex = -1
         try:
             self.interpret()
         except GenerateMergePoint, gmp:
@@ -1579,7 +1610,7 @@
         # because we cannot reconstruct the beginning of the proper loop
         self.current_merge_points = [(original_greenkey, -1)]
         self.resumekey = key
-        self.seen_can_enter_jit = False
+        self.seen_loop_header_for_jdindex = -1
         try:
             self.prepare_resume_from_failure(key.guard_opnum)
             self.interpret()
@@ -1609,7 +1640,7 @@
             else:
                 duplicates[box] = None
 
-    def reached_can_enter_jit(self, greenboxes, redboxes):
+    def reached_loop_header(self, greenboxes, redboxes):
         duplicates = {}
         self.remove_consts_and_duplicates(redboxes, len(redboxes),
                                           duplicates)
@@ -1623,7 +1654,7 @@
             live_arg_boxes += self.virtualizable_boxes
             live_arg_boxes.pop()
         assert len(self.virtualref_boxes) == 0, "missing virtual_ref_finish()?"
-        # Called whenever we reach the 'can_enter_jit' hint.
+        # Called whenever we reach the 'loop_header' hint.
         # First, attempt to make a bridge:
         # - if self.resumekey is a ResumeGuardDescr, it starts from a guard
         #   that failed;
@@ -2232,7 +2263,10 @@
         else:
             resultbox = unboundmethod(self, *args)
         #
-        self.make_result_of_lastop(resultbox)
+        if resultbox is not None:
+            self.make_result_of_lastop(resultbox)
+        elif not we_are_translated():
+            assert self._result_argcode in 'v?'
     #
     unboundmethod = getattr(MIFrame, 'opimpl_' + name).im_func
     argtypes = unrolling_iterable(unboundmethod.argtypes)

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/resoperation.py	Thu Sep  9 01:00:13 2010
@@ -274,3 +274,51 @@
 
 setup(__name__ == '__main__')   # print out the table when run directly
 del _oplist
+
+opboolinvers = {
+    rop.INT_EQ: rop.INT_NE,
+    rop.INT_NE: rop.INT_EQ,
+    rop.INT_LT: rop.INT_GE,
+    rop.INT_GE: rop.INT_LT,
+    rop.INT_GT: rop.INT_LE,
+    rop.INT_LE: rop.INT_GT,
+
+    rop.UINT_LT: rop.UINT_GE,
+    rop.UINT_GE: rop.UINT_LT,
+    rop.UINT_GT: rop.UINT_LE,
+    rop.UINT_LE: rop.UINT_GT,
+
+    rop.FLOAT_EQ: rop.FLOAT_NE,
+    rop.FLOAT_NE: rop.FLOAT_EQ,
+    rop.FLOAT_LT: rop.FLOAT_GE,
+    rop.FLOAT_GE: rop.FLOAT_LT,
+    rop.FLOAT_GT: rop.FLOAT_LE,
+    rop.FLOAT_LE: rop.FLOAT_GT,
+
+    rop.PTR_EQ: rop.PTR_NE,
+    rop.PTR_NE: rop.PTR_EQ,
+    }
+
+opboolreflex = {
+    rop.INT_EQ: rop.INT_EQ,
+    rop.INT_NE: rop.INT_NE,
+    rop.INT_LT: rop.INT_GT,
+    rop.INT_GE: rop.INT_LE,
+    rop.INT_GT: rop.INT_LT,
+    rop.INT_LE: rop.INT_GE,
+
+    rop.UINT_LT: rop.UINT_GT,
+    rop.UINT_GE: rop.UINT_LE,
+    rop.UINT_GT: rop.UINT_LT,
+    rop.UINT_LE: rop.UINT_GE,
+
+    rop.FLOAT_EQ: rop.FLOAT_EQ,
+    rop.FLOAT_NE: rop.FLOAT_NE,
+    rop.FLOAT_LT: rop.FLOAT_GT,
+    rop.FLOAT_GE: rop.FLOAT_LE,
+    rop.FLOAT_GT: rop.FLOAT_LT,
+    rop.FLOAT_LE: rop.FLOAT_GE,
+
+    rop.PTR_EQ: rop.PTR_EQ,
+    rop.PTR_NE: rop.PTR_NE,
+    }

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_basic.py	Thu Sep  9 01:00:13 2010
@@ -116,8 +116,9 @@
 
 class JitMixin:
     basic = True
-    def check_loops(self, expected=None, **check):
-        get_stats().check_loops(expected=expected, **check)
+    def check_loops(self, expected=None, everywhere=False, **check):
+        get_stats().check_loops(expected=expected, everywhere=everywhere,
+                                **check)
     def check_loop_count(self, count):
         """NB. This is a hack; use check_tree_loop_count() or
         check_enter_count() for the real thing.

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_executor.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_executor.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_executor.py	Thu Sep  9 01:00:13 2010
@@ -4,14 +4,14 @@
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.jit.metainterp.executor import execute
 from pypy.jit.metainterp.executor import execute_varargs, execute_nonspec
-from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp.resoperation import rop, opboolinvers, opboolreflex, opname
 from pypy.jit.metainterp.history import BoxInt, ConstInt
 from pypy.jit.metainterp.history import BoxPtr, ConstPtr
 from pypy.jit.metainterp.history import BoxFloat, ConstFloat
 from pypy.jit.metainterp.history import AbstractDescr, Box
 from pypy.jit.metainterp import history
 from pypy.jit.backend.model import AbstractCPU
-
+from pypy.rpython.lltypesystem import  llmemory, rffi
 
 class FakeDescr(AbstractDescr):
     pass
@@ -312,3 +312,40 @@
             assert box.getint() == retvalue
         else:
             assert 0, "rettype is %r" % (rettype,)
+
+def make_args_for_op(op, a, b):
+    n=opname[op]
+    if n[0:3] == 'INT' or n[0:4] == 'UINT':
+        arg1 = ConstInt(a)
+        arg2 = ConstInt(b)
+    elif n[0:5] == 'FLOAT':
+        arg1 = ConstFloat(float(a))
+        arg2 = ConstFloat(float(b))
+    elif n[0:3] == 'PTR':
+        arg1 = ConstPtr(rffi.cast(llmemory.GCREF, a))
+        arg2 = ConstPtr(rffi.cast(llmemory.GCREF, b))
+    else:
+        raise NotImplementedError(
+            "Don't know how to make args for " + n)
+    return arg1, arg2
+
+
+def test_opboolinvers():
+    cpu = FakeCPU()
+    for op1, op2 in opboolinvers.items():
+        for a in (1,2,3):
+            for b in (1,2,3):
+                arg1, arg2 = make_args_for_op(op1, a, b)
+                box1 = execute(cpu, None, op1, None, arg1, arg2)
+                box2 = execute(cpu, None, op2, None, arg1, arg2)
+                assert box1.value == (not box2.value)
+
+def test_opboolreflex():
+    cpu = FakeCPU()
+    for op1, op2 in opboolreflex.items():
+        for a in (1,2,3):
+            for b in (1,2,3):
+                arg1, arg2 = make_args_for_op(op1, a, b)
+                box1 = execute(cpu, None, op1, None, arg1, arg2)
+                box2 = execute(cpu, None, op2, None, arg2, arg1)
+                assert box1.value == box2.value

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_immutable.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_immutable.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_immutable.py	Thu Sep  9 01:00:13 2010
@@ -17,6 +17,38 @@
         assert res == 28
         self.check_operations_history(getfield_gc=0, getfield_gc_pure=1, int_add=1)
 
+    def test_fields_subclass(self):
+        class X(object):
+            _immutable_fields_ = ["x"]
+
+            def __init__(self, x):
+                self.x = x
+
+        class Y(X):
+            _immutable_fields_ = ["y"]
+
+            def __init__(self, x, y):
+                X.__init__(self, x)
+                self.y = y
+
+        def f(x, y):
+            X(x)     # force the field 'x' to be on class 'X'
+            z = Y(x, y)
+            return z.x + z.y + 5
+        res = self.interp_operations(f, [23, 11])
+        assert res == 39
+        self.check_operations_history(getfield_gc=0, getfield_gc_pure=2,
+                                      int_add=2)
+
+        def f(x, y):
+            # this time, the field 'x' only shows up on subclass 'Y'
+            z = Y(x, y)
+            return z.x + z.y + 5
+        res = self.interp_operations(f, [23, 11])
+        assert res == 39
+        self.check_operations_history(getfield_gc=0, getfield_gc_pure=2,
+                                      int_add=2)
+
     def test_array(self):
         class X(object):
             _immutable_fields_ = ["y[*]"]

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_jitdriver.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_jitdriver.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_jitdriver.py	Thu Sep  9 01:00:13 2010
@@ -14,7 +14,6 @@
 
     def test_simple(self):
         myjitdriver1 = JitDriver(greens=[], reds=['n', 'm'],
-                                 can_inline = lambda *args: False,
                                  get_printable_location = getloc1)
         myjitdriver2 = JitDriver(greens=['g'], reds=['r'],
                                  get_printable_location = getloc2)
@@ -30,11 +29,14 @@
             while r > 0:
                 myjitdriver2.can_enter_jit(g=g, r=r)
                 myjitdriver2.jit_merge_point(g=g, r=r)
-                r += loop1(r, g) - 1
+                r += loop1(r, g) + (-1)
             return r
         #
         res = self.meta_interp(loop2, [4, 40], repeat=7, inline=True)
         assert res == loop2(4, 40)
+        # we expect only one int_sub, corresponding to the single
+        # compiled instance of loop1()
+        self.check_loops(int_sub=1)
         # the following numbers are not really expectations of the test
         # itself, but just the numbers that we got after looking carefully
         # at the generated machine code
@@ -42,11 +44,10 @@
         self.check_tree_loop_count(4)    # 2 x loop, 2 x enter bridge
         self.check_enter_count(7)
 
-    def test_simple_inline(self):
+    def test_inline(self):
         # this is not an example of reasonable code: loop1() is unrolled
         # 'n/m' times, where n and m are given as red arguments.
         myjitdriver1 = JitDriver(greens=[], reds=['n', 'm'],
-                                 can_inline = lambda *args: True,
                                  get_printable_location = getloc1)
         myjitdriver2 = JitDriver(greens=['g'], reds=['r'],
                                  get_printable_location = getloc2)

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_loop.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_loop.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_loop.py	Thu Sep  9 01:00:13 2010
@@ -9,6 +9,10 @@
 
 class LoopTest(object):
     optimizer = OPTIMIZER_SIMPLE
+    automatic_promotion_result = {
+        'int_add' : 6, 'int_gt' : 1, 'guard_false' : 1, 'jump' : 1, 
+        'guard_value' : 3
+    }
 
     def meta_interp(self, f, args, policy=None):
         return ll_meta_interp(f, args, optimizer=self.optimizer,
@@ -477,9 +481,9 @@
         res = self.meta_interp(main_interpreter_loop, [1])
         assert res == main_interpreter_loop(1)
         self.check_loop_count(1)
-        # XXX maybe later optimize guard_value away
-        self.check_loops({'int_add' : 6, 'int_gt' : 1,
-                          'guard_false' : 1, 'jump' : 1, 'guard_value' : 3})
+        # These loops do different numbers of ops based on which optimizer we
+        # are testing with.
+        self.check_loops(self.automatic_promotion_result)
 
     def test_can_enter_jit_outside_main_loop(self):
         myjitdriver = JitDriver(greens=[], reds=['i', 'j', 'a'])

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_loop_spec.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_loop_spec.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_loop_spec.py	Thu Sep  9 01:00:13 2010
@@ -5,6 +5,10 @@
 
 class LoopSpecTest(test_loop.LoopTest):
     optimizer = OPTIMIZER_FULL
+    automatic_promotion_result = {
+        'int_add' : 3, 'int_gt' : 1, 'guard_false' : 1, 'jump' : 1, 
+        'guard_value' : 1
+    }
 
     # ====> test_loop.py
 

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_optimizeopt.py	Thu Sep  9 01:00:13 2010
@@ -285,6 +285,24 @@
         """
         self.optimize_loop(ops, '', expected)
 
+    def test_constant_propagate_ovf(self):
+        ops = """
+        []
+        i0 = int_add_ovf(2, 3)
+        guard_no_overflow() []
+        i1 = int_is_true(i0)
+        guard_true(i1) []
+        i2 = int_is_zero(i1)
+        guard_false(i2) []
+        guard_value(i0, 5) []
+        jump()
+        """
+        expected = """
+        []
+        jump()
+        """
+        self.optimize_loop(ops, '', expected)
+
     def test_constfold_all(self):
         from pypy.jit.backend.llgraph.llimpl import TYPES     # xxx fish
         from pypy.jit.metainterp.executor import execute_nonspec
@@ -364,6 +382,74 @@
         """
         self.optimize_loop(ops, 'Not', expected)
 
+    def test_constant_boolrewrite_lt(self):
+        ops = """
+        [i0]
+        i1 = int_lt(i0, 0)
+        guard_true(i1) []
+        i2 = int_ge(i0, 0)
+        guard_false(i2) []
+        jump(i0)
+        """
+        expected = """
+        [i0]
+        i1 = int_lt(i0, 0)
+        guard_true(i1) []
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+
+    def test_constant_boolrewrite_gt(self):
+        ops = """
+        [i0]
+        i1 = int_gt(i0, 0)
+        guard_true(i1) []
+        i2 = int_le(i0, 0)
+        guard_false(i2) []
+        jump(i0)
+        """
+        expected = """
+        [i0]
+        i1 = int_gt(i0, 0)
+        guard_true(i1) []
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+
+    def test_constant_boolrewrite_reflex(self):
+        ops = """
+        [i0]
+        i1 = int_gt(i0, 0)
+        guard_true(i1) []
+        i2 = int_lt(0, i0)
+        guard_true(i2) []
+        jump(i0)
+        """
+        expected = """
+        [i0]
+        i1 = int_gt(i0, 0)
+        guard_true(i1) []
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+
+    def test_constant_boolrewrite_reflex_invers(self):
+        ops = """
+        [i0]
+        i1 = int_gt(i0, 0)
+        guard_true(i1) []
+        i2 = int_ge(0, i0)
+        guard_false(i2) []
+        jump(i0)
+        """
+        expected = """
+        [i0]
+        i1 = int_gt(i0, 0)
+        guard_true(i1) []
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+
     def test_remove_consecutive_guard_value_constfold(self):
         ops = """
         []
@@ -411,7 +497,6 @@
         self.optimize_loop(ops, 'Not', expected)
 
     def test_int_is_true_1(self):
-        py.test.skip("XXX implement me")
         ops = """
         [i0]
         i1 = int_is_true(i0)
@@ -806,16 +891,10 @@
         guard_nonnull(p0) []
         i7 = ptr_ne(p0, p1)
         guard_true(i7) []
-        i8 = ptr_eq(p0, p1)
-        guard_false(i8) []
         i9 = ptr_ne(p0, p2)
         guard_true(i9) []
-        i10 = ptr_eq(p0, p2)
-        guard_false(i10) []
         i11 = ptr_ne(p2, p1)
         guard_true(i11) []
-        i12 = ptr_eq(p2, p1)
-        guard_false(i12) []
         jump(p0, p1, p2)
         """
         self.optimize_loop(ops, 'Not, Not, Not', expected2)
@@ -2037,6 +2116,33 @@
         """
         self.optimize_loop(ops, 'Not', expected)
 
+    def test_remove_duplicate_pure_op_ovf(self):
+        ops = """
+        [i1]
+        i3 = int_add_ovf(i1, 1)
+        guard_no_overflow() []
+        i3b = int_is_true(i3)
+        guard_true(i3b) []
+        i4 = int_add_ovf(i1, 1)
+        guard_no_overflow() []
+        i4b = int_is_true(i4)
+        guard_true(i4b) []
+        escape(i3)
+        escape(i4)
+        jump(i1)
+        """
+        expected = """
+        [i1]
+        i3 = int_add_ovf(i1, 1)
+        guard_no_overflow() []
+        i3b = int_is_true(i3)
+        guard_true(i3b) []
+        escape(i3)
+        escape(i3)
+        jump(i1)
+        """
+        self.optimize_loop(ops, "Not", expected)
+
     def test_int_and_or_with_zero(self):
         ops = """
         [i0, i1]
@@ -2051,8 +2157,41 @@
         jump(i1, i0)
         """
         self.optimize_loop(ops, 'Not, Not', expected)
-
-
+    
+    def test_fold_partially_constant_ops(self):
+        ops = """
+        [i0]
+        i1 = int_sub(i0, 0)
+        jump(i1)
+        """
+        expected = """
+        [i0]
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+        
+        ops = """
+        [i0]
+        i1 = int_add(i0, 0)
+        jump(i1)
+        """
+        expected = """
+        [i0]
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+        
+        ops = """
+        [i0]
+        i1 = int_add(0, i0)
+        jump(i1)
+        """
+        expected = """
+        [i0]
+        jump(i0)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+    
     # ----------
 
     def make_fail_descr(self):

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_recursive.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_recursive.py	Thu Sep  9 01:00:13 2010
@@ -2,10 +2,11 @@
 from pypy.rlib.jit import JitDriver, we_are_jitted, OPTIMIZER_SIMPLE, hint
 from pypy.rlib.jit import unroll_safe, dont_look_inside
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.debug import fatalerror
 from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
 from pypy.jit.codewriter.policy import StopAtXPolicy
 from pypy.rpython.annlowlevel import hlstr
-from pypy.jit.metainterp.warmspot import CannotInlineCanEnterJit, get_stats
+from pypy.jit.metainterp.warmspot import get_stats
 
 class RecursiveTests:
 
@@ -98,23 +99,18 @@
                                policy=StopAtXPolicy(opaque))
         assert res == 1
 
-    def get_interpreter(self, codes, always_inline=False):
+    def get_interpreter(self, codes):
         ADD = "0"
         JUMP_BACK = "1"
         CALL = "2"
         EXIT = "3"
 
-        if always_inline:
-            def can_inline(*args):
-                return True
-        else:
-            def can_inline(i, code):
-                code = hlstr(code)
-                return not JUMP_BACK in code
+        def getloc(i, code):
+            return 'code="%s", i=%d' % (code, i)
 
         jitdriver = JitDriver(greens = ['i', 'code'], reds = ['n'],
-                              can_inline = can_inline)
- 
+                              get_printable_location = getloc)
+
         def interpret(codenum, n, i):
             code = codes[codenum]
             while i < len(code):
@@ -162,31 +158,16 @@
 
         assert self.meta_interp(f, [0, 0, 0], optimizer=OPTIMIZER_SIMPLE,
                                 inline=True) == 42
-        self.check_loops(call_may_force = 1, call = 0)
-
-    def test_inline_faulty_can_inline(self):
-        code = "021"
-        subcode = "301"
-        codes = [code, subcode]
-
-        f = self.get_interpreter(codes, always_inline=True)
-
-        try:
-            self.meta_interp(f, [0, 0, 0], optimizer=OPTIMIZER_SIMPLE,
-                             inline=True)
-        except CannotInlineCanEnterJit:
-            pass
-        else:
-            py.test.fail("DID NOT RAISE")
+        # the call is fully inlined, because we jump to subcode[1], thus
+        # skipping completely the JUMP_BACK in subcode[0]
+        self.check_loops(call_may_force = 0, call_assembler = 0, call = 0)
 
     def test_guard_failure_in_inlined_function(self):
         def p(pc, code):
             code = hlstr(code)
             return "%s %d %s" % (code, pc, code[pc])
-        def c(pc, code):
-            return "l" not in hlstr(code)
         myjitdriver = JitDriver(greens=['pc', 'code'], reds=['n'],
-                                get_printable_location=p, can_inline=c)
+                                get_printable_location=p)
         def f(code, n):
             pc = 0
             while pc < len(code):
@@ -219,10 +200,8 @@
         def p(pc, code):
             code = hlstr(code)
             return "%s %d %s" % (code, pc, code[pc])
-        def c(pc, code):
-            return "l" not in hlstr(code)
         myjitdriver = JitDriver(greens=['pc', 'code'], reds=['n', 'flag'],
-                                get_printable_location=p, can_inline=c)
+                                get_printable_location=p)
         def f(code, n):
             pc = 0
             flag = False
@@ -262,10 +241,8 @@
         def p(pc, code):
             code = hlstr(code)
             return "%s %d %s" % (code, pc, code[pc])
-        def c(pc, code):
-            return "l" not in hlstr(code)
         myjitdriver = JitDriver(greens=['pc', 'code'], reds=['n'],
-                                get_printable_location=p, can_inline=c)
+                                get_printable_location=p)
 
         class Exc(Exception):
             pass
@@ -307,10 +284,8 @@
         def p(pc, code):
             code = hlstr(code)
             return "%s %d %s" % (code, pc, code[pc])
-        def c(pc, code):
-            return "l" not in hlstr(code)
         myjitdriver = JitDriver(greens=['pc', 'code'], reds=['n'],
-                                get_printable_location=p, can_inline=c)
+                                get_printable_location=p)
         
         def f(code, n):
             pc = 0
@@ -524,10 +499,8 @@
         def p(pc, code):
             code = hlstr(code)
             return "'%s' at %d: %s" % (code, pc, code[pc])
-        def c(pc, code):
-            return "l" not in hlstr(code)
         myjitdriver = JitDriver(greens=['pc', 'code'], reds=['n'],
-                                get_printable_location=p, can_inline=c)
+                                get_printable_location=p)
         
         def f(code, n):
             pc = 0
@@ -558,6 +531,8 @@
                 result += f('+-cl--', i)
         g(50)
         self.meta_interp(g, [50], backendopt=True)
+        py.test.skip("tracing from start is by now only longer enabled "
+                     "if a trace gets too big")
         self.check_tree_loop_count(3)
         self.check_history(int_add=1)
 
@@ -565,10 +540,8 @@
         def p(pc, code):
             code = hlstr(code)
             return "%s %d %s" % (code, pc, code[pc])
-        def c(pc, code):
-            return "l" not in hlstr(code)
         myjitdriver = JitDriver(greens=['pc', 'code'], reds=['n'],
-                                get_printable_location=p, can_inline=c)
+                                get_printable_location=p)
         
         def f(code, n):
             pc = 0
@@ -607,8 +580,7 @@
 
     def test_directly_call_assembler(self):
         driver = JitDriver(greens = ['codeno'], reds = ['i'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
 
         def portal(codeno):
             i = 0
@@ -624,28 +596,29 @@
 
     def test_recursion_cant_call_assembler_directly(self):
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'j'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
 
         def portal(codeno, j):
             i = 0
-            while i < 1:
-                driver.can_enter_jit(codeno=codeno, i=i, j=j)
+            while 1:
                 driver.jit_merge_point(codeno=codeno, i=i, j=j)
-                i += 1
-                if j == 0:
+                if i == 1:
+                    if j == 0:
+                        return
+                    portal(2, j - 1)
+                elif i == 3:
                     return
-                portal(2, j - 1)
+                i += 1
+                driver.can_enter_jit(codeno=codeno, i=i, j=j)
 
         portal(2, 50)
         self.meta_interp(portal, [2, 20], inline=True)
-        self.check_history(call_assembler=0, call_may_force=1)
-        self.check_enter_count_at_most(1)
+        self.check_loops(call_assembler=0, call_may_force=1,
+                         everywhere=True)
 
     def test_directly_call_assembler_return(self):
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
 
         def portal(codeno):
             i = 0
@@ -668,8 +641,7 @@
                 self.x = x
         
         driver = JitDriver(greens = ['codeno'], reds = ['i'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
 
         def portal(codeno):
             i = 0
@@ -690,8 +662,7 @@
 
     def test_directly_call_assembler_fail_guard(self):
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
 
         def portal(codeno, k):
             i = 0
@@ -722,8 +693,7 @@
         
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'frame'],
                            virtualizables = ['frame'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
 
         def main(codeno):
             frame = Frame()
@@ -761,8 +731,7 @@
         
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'frame'],
                            virtualizables = ['frame'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
 
         @dont_look_inside
         def check_frame(subframe):
@@ -802,7 +771,7 @@
         res = self.meta_interp(main, [0], inline=True)
         assert res == main(0)
 
-    def test_directly_call_assembler_virtualizable_force(self):
+    def test_directly_call_assembler_virtualizable_force1(self):
         class Thing(object):
             def __init__(self, val):
                 self.val = val
@@ -812,8 +781,7 @@
         
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'frame'],
                            virtualizables = ['frame'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
         class SomewhereElse(object):
             pass
 
@@ -830,6 +798,7 @@
             return frame.thing.val
 
         def portal(codeno, frame):
+            print 'ENTER:', codeno, frame.thing.val
             i = 0
             while i < 10:
                 driver.can_enter_jit(frame=frame, codeno=codeno, i=i)
@@ -839,11 +808,15 @@
                     subframe = Frame()
                     subframe.thing = Thing(nextval)
                     nextval = portal(1, subframe)
-                elif frame.thing.val > 40:
-                    change(Thing(13))
-                    nextval = 13
+                elif codeno == 1:
+                    if frame.thing.val > 40:
+                        change(Thing(13))
+                        nextval = 13
+                else:
+                    fatalerror("bad codeno = " + str(codeno))
                 frame.thing = Thing(nextval + 1)
                 i += 1
+            print 'LEAVE:', codeno, frame.thing.val
             return frame.thing.val
 
         res = self.meta_interp(main, [0], inline=True,
@@ -852,8 +825,7 @@
 
     def test_directly_call_assembler_virtualizable_with_array(self):
         myjitdriver = JitDriver(greens = ['codeno'], reds = ['n', 'x', 'frame'],
-                                virtualizables = ['frame'],
-                                can_inline = lambda codeno : False)
+                                virtualizables = ['frame'])
 
         class Frame(object):
             _virtualizable2_ = ['l[*]', 's']
@@ -899,8 +871,7 @@
         
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'frame'],
                            virtualizables = ['frame'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
         class SomewhereElse(object):
             pass
 
@@ -942,17 +913,16 @@
 
     def test_assembler_call_red_args(self):
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
-                           get_printable_location = lambda codeno : str(codeno),
-                           can_inline = lambda codeno : False)
+                           get_printable_location = lambda codeno : str(codeno))
 
         def residual(k):
-            if k > 40:
+            if k > 150:
                 return 0
             return 1
 
         def portal(codeno, k):
             i = 0
-            while i < 10:
+            while i < 15:
                 driver.can_enter_jit(codeno=codeno, i=i, k=k)
                 driver.jit_merge_point(codeno=codeno, i=i, k=k)
                 if codeno == 2:
@@ -969,10 +939,130 @@
         assert res == portal(2, 0)
         self.check_loops(call_assembler=2)
 
-    # There is a test which I fail to write.
-    #   * what happens if we call recursive_call while blackholing
-    #     this seems to be completely corner case and not really happening
-    #     in the wild
+    def test_inline_without_hitting_the_loop(self):
+        driver = JitDriver(greens = ['codeno'], reds = ['i'],
+                           get_printable_location = lambda codeno : str(codeno))
+
+        def portal(codeno):
+            i = 0
+            while True:
+                driver.jit_merge_point(codeno=codeno, i=i)
+                if codeno < 10:
+                    i += portal(20)
+                    codeno += 1
+                elif codeno == 10:
+                    if i > 63:
+                        return i
+                    codeno = 0
+                    driver.can_enter_jit(codeno=codeno, i=i)
+                else:
+                    return 1
+
+        assert portal(0) == 70
+        res = self.meta_interp(portal, [0], inline=True)
+        assert res == 70
+        self.check_loops(call_assembler=0)
+
+    def test_inline_with_hitting_the_loop_sometimes(self):
+        driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
+                           get_printable_location = lambda codeno : str(codeno))
+
+        def portal(codeno, k):
+            if k > 2:
+                return 1
+            i = 0
+            while True:
+                driver.jit_merge_point(codeno=codeno, i=i, k=k)
+                if codeno < 10:
+                    i += portal(codeno + 5, k+1)
+                    codeno += 1
+                elif codeno == 10:
+                    if i > [-1, 2000, 63][k]:
+                        return i
+                    codeno = 0
+                    driver.can_enter_jit(codeno=codeno, i=i, k=k)
+                else:
+                    return 1
+
+        assert portal(0, 1) == 2095
+        res = self.meta_interp(portal, [0, 1], inline=True)
+        assert res == 2095
+        self.check_loops(call_assembler=6, everywhere=True)
+
+    def test_inline_with_hitting_the_loop_sometimes_exc(self):
+        driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
+                           get_printable_location = lambda codeno : str(codeno))
+        class GotValue(Exception):
+            def __init__(self, result):
+                self.result = result
+
+        def portal(codeno, k):
+            if k > 2:
+                raise GotValue(1)
+            i = 0
+            while True:
+                driver.jit_merge_point(codeno=codeno, i=i, k=k)
+                if codeno < 10:
+                    try:
+                        portal(codeno + 5, k+1)
+                    except GotValue, e:
+                        i += e.result
+                    codeno += 1
+                elif codeno == 10:
+                    if i > [-1, 2000, 63][k]:
+                        raise GotValue(i)
+                    codeno = 0
+                    driver.can_enter_jit(codeno=codeno, i=i, k=k)
+                else:
+                    raise GotValue(1)
+
+        def main(codeno, k):
+            try:
+                portal(codeno, k)
+            except GotValue, e:
+                return e.result
+
+        assert main(0, 1) == 2095
+        res = self.meta_interp(main, [0, 1], inline=True)
+        assert res == 2095
+        self.check_loops(call_assembler=6, everywhere=True)
+
+    def test_handle_jitexception_in_portal(self):
+        # a test for _handle_jitexception_in_portal in blackhole.py
+        driver = JitDriver(greens = ['codeno'], reds = ['i', 'str'],
+                           get_printable_location = lambda codeno: str(codeno))
+        def do_can_enter_jit(codeno, i, str):
+            i = (i+1)-1    # some operations
+            driver.can_enter_jit(codeno=codeno, i=i, str=str)
+        def intermediate(codeno, i, str):
+            if i == 9:
+                do_can_enter_jit(codeno, i, str)
+        def portal(codeno, str):
+            i = value.initial
+            while i < 10:
+                intermediate(codeno, i, str)
+                driver.jit_merge_point(codeno=codeno, i=i, str=str)
+                i += 1
+                if codeno == 64 and i == 10:
+                    str = portal(96, str)
+                str += chr(codeno+i)
+            return str
+        class Value:
+            initial = -1
+        value = Value()
+        def main():
+            value.initial = 0
+            return (portal(64, '') +
+                    portal(64, '') +
+                    portal(64, '') +
+                    portal(64, '') +
+                    portal(64, ''))
+        assert main() == 'ABCDEFGHIabcdefghijJ' * 5
+        for tlimit in [95, 90, 102]:
+            print 'tlimit =', tlimit
+            res = self.meta_interp(main, [], inline=True, trace_limit=tlimit)
+            assert ''.join(res.chars) == 'ABCDEFGHIabcdefghijJ' * 5
+
 
 class TestLLtype(RecursiveTests, LLJitMixin):
     pass

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_virtualizable.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_virtualizable.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_virtualizable.py	Thu Sep  9 01:00:13 2010
@@ -1330,11 +1330,9 @@
         def p(pc, code):
             code = hlstr(code)
             return "%s %d %s" % (code, pc, code[pc])
-        def c(pc, code):
-            return "l" not in hlstr(code)
         myjitdriver = JitDriver(greens=['pc', 'code'], reds=['frame'],
                                 virtualizables=["frame"],
-                                get_printable_location=p, can_inline=c)
+                                get_printable_location=p)
         def f(code, frame):
             pc = 0
             while pc < len(code):

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_warmspot.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_warmspot.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_warmspot.py	Thu Sep  9 01:00:13 2010
@@ -272,6 +272,30 @@
         self.check_enter_count_at_most(2)
         self.check_loops(call=0)
 
+    def test_loop_header(self):
+        # artificial test: we enter into the JIT only when can_enter_jit()
+        # is seen, but we close a loop in the JIT much more quickly
+        # because of loop_header().
+        mydriver = JitDriver(reds = ['n', 'm'], greens = [])
+
+        def f(m):
+            n = 0
+            while True:
+                mydriver.jit_merge_point(n=n, m=m)
+                if n > m:
+                    m -= 1
+                    if m < 0:
+                        return n
+                    n = 0
+                    mydriver.can_enter_jit(n=n, m=m)
+                else:
+                    n += 1
+                    mydriver.loop_header()
+        assert f(15) == 1
+        res = self.meta_interp(f, [15], backendopt=True)
+        assert res == 1
+        self.check_loops(int_add=1)   # I get 13 without the loop_header()
+
 
 class TestLLWarmspot(WarmspotTests, LLJitMixin):
     CPUClass = runner.LLtypeCPU

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_warmstate.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_warmstate.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_warmstate.py	Thu Sep  9 01:00:13 2010
@@ -61,12 +61,14 @@
         _green_args_spec = [lltype.Signed, lltype.Float]
     state = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = state._make_jitcell_getter_default()
-    cell1 = get_jitcell(42, 42.5)
+    cell1 = get_jitcell(True, 42, 42.5)
     assert isinstance(cell1, JitCell)
-    cell2 = get_jitcell(42, 42.5)
+    cell2 = get_jitcell(True, 42, 42.5)
     assert cell1 is cell2
-    cell3 = get_jitcell(41, 42.5)
-    cell4 = get_jitcell(42, 0.25)
+    cell3 = get_jitcell(True, 41, 42.5)
+    assert get_jitcell(False, 42, 0.25) is None
+    cell4 = get_jitcell(True, 42, 0.25)
+    assert get_jitcell(False, 42, 0.25) is cell4
     assert cell1 is not cell3 is not cell4 is not cell1
 
 def test_make_jitcell_getter():
@@ -75,8 +77,8 @@
         _get_jitcell_at_ptr = None
     state = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = state.make_jitcell_getter()
-    cell1 = get_jitcell(1.75)
-    cell2 = get_jitcell(1.75)
+    cell1 = get_jitcell(True, 1.75)
+    cell2 = get_jitcell(True, 1.75)
     assert cell1 is cell2
     assert get_jitcell is state.make_jitcell_getter()
 
@@ -103,14 +105,16 @@
     #
     state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
     get_jitcell = state._make_jitcell_getter_custom()
-    cell1 = get_jitcell(5, 42.5)
+    cell1 = get_jitcell(True, 5, 42.5)
     assert isinstance(cell1, JitCell)
     assert cell1.x == 5
     assert cell1.y == 42.5
-    cell2 = get_jitcell(5, 42.5)
+    cell2 = get_jitcell(True, 5, 42.5)
     assert cell2 is cell1
-    cell3 = get_jitcell(41, 42.5)
-    cell4 = get_jitcell(42, 0.25)
+    cell3 = get_jitcell(True, 41, 42.5)
+    assert get_jitcell(False, 42, 0.25) is None
+    cell4 = get_jitcell(True, 42, 0.25)
+    assert get_jitcell(False, 42, 0.25) is cell4
     assert cell1 is not cell3 is not cell4 is not cell1
 
 def test_make_set_future_values():
@@ -153,52 +157,25 @@
     state.attach_unoptimized_bridge_from_interp([ConstInt(5),
                                                  ConstFloat(2.25)],
                                                 "entry loop token")
-    cell1 = get_jitcell(5, 2.25)
+    cell1 = get_jitcell(True, 5, 2.25)
     assert cell1.counter < 0
     assert cell1.entry_loop_token == "entry loop token"
 
 def test_make_jitdriver_callbacks_1():
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed, lltype.Float]
-        _can_inline_ptr = None
         _get_printable_location_ptr = None
         _confirm_enter_jit_ptr = None
     class FakeCell:
         dont_trace_here = False
     state = WarmEnterState(None, FakeJitDriverSD())
-    def jit_getter(*args):
+    def jit_getter(build, *args):
         return FakeCell()
     state.jit_getter = jit_getter
     state.make_jitdriver_callbacks()
-    res = state.can_inline_callable([ConstInt(5), ConstFloat(42.5)])
-    assert res is True
     res = state.get_location_str([ConstInt(5), ConstFloat(42.5)])
     assert res == '(no jitdriver.get_printable_location!)'
 
-def test_make_jitdriver_callbacks_2():
-    def can_inline(x, y):
-        assert x == 5
-        assert y == 42.5
-        return False
-    CAN_INLINE = lltype.Ptr(lltype.FuncType([lltype.Signed, lltype.Float],
-                                            lltype.Bool))
-    class FakeCell:
-        dont_trace_here = False
-    class FakeWarmRunnerDesc:
-        rtyper = None
-    class FakeJitDriverSD:
-        _green_args_spec = [lltype.Signed, lltype.Float]
-        _can_inline_ptr = llhelper(CAN_INLINE, can_inline)
-        _get_printable_location_ptr = None
-        _confirm_enter_jit_ptr = None
-    state = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
-    def jit_getter(*args):
-        return FakeCell()
-    state.jit_getter = jit_getter
-    state.make_jitdriver_callbacks()
-    res = state.can_inline_callable([ConstInt(5), ConstFloat(42.5)])
-    assert res is False
-
 def test_make_jitdriver_callbacks_3():
     def get_location(x, y):
         assert x == 5
@@ -210,7 +187,6 @@
         rtyper = None
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed, lltype.Float]
-        _can_inline_ptr = None
         _get_printable_location_ptr = llhelper(GET_LOCATION, get_location)
         _confirm_enter_jit_ptr = None
         _get_jitcell_at_ptr = None
@@ -231,7 +207,6 @@
         rtyper = None
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed, lltype.Float]
-        _can_inline_ptr = None
         _get_printable_location_ptr = None
         _confirm_enter_jit_ptr = llhelper(ENTER_JIT, confirm_enter_jit)
         _get_jitcell_at_ptr = None

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_ztranslation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_ztranslation.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_ztranslation.py	Thu Sep  9 01:00:13 2010
@@ -37,15 +37,12 @@
             return jitcellcache.entry
         def get_printable_location():
             return '(hello world)'
-        def can_inline():
-            return False
 
         jitdriver = JitDriver(greens = [], reds = ['total', 'frame'],
                               virtualizables = ['frame'],
                               get_jitcell_at=get_jitcell_at,
                               set_jitcell_at=set_jitcell_at,
-                              get_printable_location=get_printable_location,
-                              can_inline=can_inline)
+                              get_printable_location=get_printable_location)
         def f(i):
             for param in unroll_parameters:
                 defl = PARAMETERS[param]
@@ -63,8 +60,7 @@
                 frame.i -= 1
             return total * 10
         #
-        myjitdriver2 = JitDriver(greens = ['g'], reds = ['m', 'x'],
-                                 can_inline = lambda *args: False)
+        myjitdriver2 = JitDriver(greens = ['g'], reds = ['m', 'x'])
         def f2(g, m, x):
             while m > 0:
                 myjitdriver2.can_enter_jit(g=g, m=m, x=x)

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/warmspot.py	Thu Sep  9 01:00:13 2010
@@ -136,9 +136,6 @@
 class ContinueRunningNormallyBase(JitException):
     pass
 
-class CannotInlineCanEnterJit(JitException):
-    pass
-
 # ____________________________________________________________
 
 class WarmRunnerDesc(object):
@@ -402,7 +399,7 @@
         can_inline = state.can_inline_greenargs
         num_green_args = jd.num_green_args
         def maybe_enter_from_start(*args):
-            if can_inline is not None and not can_inline(*args[:num_green_args]):
+            if not can_inline(*args[:num_green_args]):
                 maybe_compile_and_run(*args)
         maybe_enter_from_start._always_inline_ = True
         jd._maybe_enter_from_start_fn = maybe_enter_from_start
@@ -423,8 +420,6 @@
                 s_BaseJitCell_not_None)
             jd._get_jitcell_at_ptr = self._make_hook_graph(jd,
                 annhelper, jd.jitdriver.get_jitcell_at, s_BaseJitCell_or_None)
-            jd._can_inline_ptr = self._make_hook_graph(jd,
-                annhelper, jd.jitdriver.can_inline, annmodel.s_Bool)
             jd._get_printable_location_ptr = self._make_hook_graph(jd,
                 annhelper, jd.jitdriver.get_printable_location, s_Str)
             jd._confirm_enter_jit_ptr = self._make_hook_graph(jd,
@@ -478,7 +473,13 @@
             jitdriver = op.args[1].value
             assert jitdriver in sublists, \
                    "can_enter_jit with no matching jit_merge_point"
-            sublists[jitdriver].append((graph, block, index))
+            origportalgraph = jd._jit_merge_point_pos[0]
+            if graph is not origportalgraph:
+                sublists[jitdriver].append((graph, block, index))
+            else:
+                pass   # a 'can_enter_jit' before the 'jit-merge_point', but
+                       # originally in the same function: we ignore it here
+                       # see e.g. test_jitdriver.test_simple
         for jd in self.jitdrivers_sd:
             sublist = sublists[jd.jitdriver]
             assert len(sublist) > 0, \
@@ -557,6 +558,7 @@
         # Prepare the portal_runner() helper
         #
         from pypy.jit.metainterp.warmstate import specialize_value
+        from pypy.jit.metainterp.warmstate import unspecialize_value
         portal_ptr = self.cpu.ts.functionptr(PORTALFUNC, 'portal',
                                          graph = portalgraph)
         jd._portal_ptr = portal_ptr
@@ -611,6 +613,37 @@
                         value = cast_base_ptr_to_instance(Exception, value)
                         raise Exception, value
 
+        def handle_jitexception(e):
+            # XXX the bulk of this function is a copy-paste from above :-(
+            try:
+                raise e
+            except self.ContinueRunningNormally, e:
+                args = ()
+                for ARGTYPE, attrname, count in portalfunc_ARGS:
+                    x = getattr(e, attrname)[count]
+                    x = specialize_value(ARGTYPE, x)
+                    args = args + (x,)
+                return ll_portal_runner(*args)
+            except self.DoneWithThisFrameVoid:
+                assert result_kind == 'void'
+                return
+            except self.DoneWithThisFrameInt, e:
+                assert result_kind == 'int'
+                return specialize_value(RESULT, e.result)
+            except self.DoneWithThisFrameRef, e:
+                assert result_kind == 'ref'
+                return specialize_value(RESULT, e.result)
+            except self.DoneWithThisFrameFloat, e:
+                assert result_kind == 'float'
+                return specialize_value(RESULT, e.result)
+            except self.ExitFrameWithExceptionRef, e:
+                value = ts.cast_to_baseclass(e.value)
+                if not we_are_translated():
+                    raise LLException(ts.get_typeptr(value), value)
+                else:
+                    value = cast_base_ptr_to_instance(Exception, value)
+                    raise Exception, value
+
         jd._ll_portal_runner = ll_portal_runner # for debugging
         jd.portal_runner_ptr = self.helper_func(jd._PTR_PORTAL_FUNCTYPE,
                                                 ll_portal_runner)
@@ -631,32 +664,8 @@
                     vinfo.reset_vable_token(virtualizable)
                 try:
                     loop_token = fail_descr.handle_fail(self.metainterp_sd, jd)
-                except self.ContinueRunningNormally, e:
-                    args = ()
-                    for ARGTYPE, attrname, count in portalfunc_ARGS:
-                        x = getattr(e, attrname)[count]
-                        x = specialize_value(ARGTYPE, x)
-                        args = args + (x,)
-                    return ll_portal_runner(*args)
-                except self.DoneWithThisFrameVoid:
-                    assert result_kind == 'void'
-                    return
-                except self.DoneWithThisFrameInt, e:
-                    assert result_kind == 'int'
-                    return specialize_value(RESULT, e.result)
-                except self.DoneWithThisFrameRef, e:
-                    assert result_kind == 'ref'
-                    return specialize_value(RESULT, e.result)
-                except self.DoneWithThisFrameFloat, e:
-                    assert result_kind == 'float'
-                    return specialize_value(RESULT, e.result)
-                except self.ExitFrameWithExceptionRef, e:
-                    value = ts.cast_to_baseclass(e.value)
-                    if not we_are_translated():
-                        raise LLException(ts.get_typeptr(value), value)
-                    else:
-                        value = cast_base_ptr_to_instance(Exception, value)
-                        raise Exception, value
+                except JitException, e:
+                    return handle_jitexception(e)
                 fail_descr = self.cpu.execute_token(loop_token)
 
         jd._assembler_call_helper = assembler_call_helper # for debugging
@@ -668,6 +677,21 @@
         if vinfo is not None:
             jd.vable_token_descr = vinfo.vable_token_descr
 
+        def handle_jitexception_from_blackhole(bhcaller, e):
+            result = handle_jitexception(e)
+            #
+            if result_kind != 'void':
+                result = unspecialize_value(result)
+                if result_kind == 'int':
+                    bhcaller._setup_return_value_i(result)
+                elif result_kind == 'ref':
+                    bhcaller._setup_return_value_r(result)
+                elif result_kind == 'float':
+                    bhcaller._setup_return_value_f(result)
+                else:
+                    assert False
+        jd.handle_jitexc_from_bh = handle_jitexception_from_blackhole
+
         # ____________________________________________________________
         # Now mutate origportalgraph to end with a call to portal_runner_ptr
         #
@@ -687,17 +711,6 @@
         origblock.exitswitch = None
         origblock.recloseblock(Link([v_result], origportalgraph.returnblock))
         #
-        # Also kill any can_enter_jit left behind (example: see
-        # test_jitdriver.test_simple, which has a can_enter_jit in
-        # loop1's origportalgraph)
-        can_enter_jits = _find_jit_marker([origportalgraph], 'can_enter_jit')
-        for _, block, i in can_enter_jits:
-            op = block.operations[i]
-            assert op.opname == 'jit_marker'
-            block.operations[i] = SpaceOperation('same_as',
-                                                 [Constant(None, lltype.Void)],
-                                                 op.result)
-        #
         checkgraph(origportalgraph)
 
     def add_finish(self):

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/warmstate.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/warmstate.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/warmstate.py	Thu Sep  9 01:00:13 2010
@@ -30,6 +30,22 @@
     else:
         return lltype.cast_opaque_ptr(TYPE, x)
 
+ at specialize.ll()
+def unspecialize_value(value):
+    """Casts 'value' to a Signed, a GCREF or a Float."""
+    if isinstance(lltype.typeOf(value), lltype.Ptr):
+        if lltype.typeOf(value).TO._gckind == 'gc':
+            return lltype.cast_opaque_ptr(llmemory.GCREF, value)
+        else:
+            adr = llmemory.cast_ptr_to_adr(value)
+            return heaptracker.adr2int(adr)
+    elif isinstance(lltype.typeOf(value), ootype.OOType):
+        return ootype.cast_to_object(value)
+    elif isinstance(value, float):
+        return value
+    else:
+        return intmask(value)
+
 @specialize.arg(0)
 def unwrap(TYPE, box):
     if TYPE is lltype.Void:
@@ -232,7 +248,7 @@
 
             # look for the cell corresponding to the current greenargs
             greenargs = args[:num_green_args]
-            cell = get_jitcell(*greenargs)
+            cell = get_jitcell(True, *greenargs)
 
             if cell.counter >= 0:
                 # update the profiling counter
@@ -324,7 +340,7 @@
         #
         def jit_cell_at_key(greenkey):
             greenargs = unwrap_greenkey(greenkey)
-            return jit_getter(*greenargs)
+            return jit_getter(True, *greenargs)
         self.jit_cell_at_key = jit_cell_at_key
         self.jit_getter = jit_getter
         #
@@ -355,10 +371,12 @@
         #
         jitcell_dict = r_dict(comparekey, hashkey)
         #
-        def get_jitcell(*greenargs):
+        def get_jitcell(build, *greenargs):
             try:
                 cell = jitcell_dict[greenargs]
             except KeyError:
+                if not build:
+                    return None
                 cell = JitCell()
                 jitcell_dict[greenargs] = cell
             return cell
@@ -371,38 +389,41 @@
         set_jitcell_at_ptr = self.jitdriver_sd._set_jitcell_at_ptr
         lltohlhack = {}
         #
-        def get_jitcell(*greenargs):
+        def get_jitcell(build, *greenargs):
             fn = support.maybe_on_top_of_llinterp(rtyper, get_jitcell_at_ptr)
             cellref = fn(*greenargs)
             # <hacks>
             if we_are_translated():
                 BASEJITCELL = lltype.typeOf(cellref)
                 cell = cast_base_ptr_to_instance(JitCell, cellref)
-            elif isinstance(cellref, (BaseJitCell, type(None))):
-                BASEJITCELL = None
-                cell = cellref
             else:
-                BASEJITCELL = lltype.typeOf(cellref)
-                if cellref:
-                    cell = lltohlhack[rtyper.type_system.deref(cellref)]
+                if isinstance(cellref, (BaseJitCell, type(None))):
+                    BASEJITCELL = None
+                    cell = cellref
                 else:
-                    cell = None
-            # </hacks>
+                    BASEJITCELL = lltype.typeOf(cellref)
+                    if cellref:
+                        cell = lltohlhack[rtyper.type_system.deref(cellref)]
+                    else:
+                        cell = None
+            if not build:
+                return cell
             if cell is None:
                 cell = JitCell()
                 # <hacks>
                 if we_are_translated():
                     cellref = cast_object_to_ptr(BASEJITCELL, cell)
-                elif BASEJITCELL is None:
-                    cellref = cell
                 else:
-                    if isinstance(BASEJITCELL, lltype.Ptr):
-                        cellref = lltype.malloc(BASEJITCELL.TO)
-                    elif isinstance(BASEJITCELL, ootype.Instance):
-                        cellref = ootype.new(BASEJITCELL)
+                    if BASEJITCELL is None:
+                        cellref = cell
                     else:
-                        assert False, "no clue"
-                    lltohlhack[rtyper.type_system.deref(cellref)] = cell
+                        if isinstance(BASEJITCELL, lltype.Ptr):
+                            cellref = lltype.malloc(BASEJITCELL.TO)
+                        elif isinstance(BASEJITCELL, ootype.Instance):
+                            cellref = ootype.new(BASEJITCELL)
+                        else:
+                            assert False, "no clue"
+                        lltohlhack[rtyper.type_system.deref(cellref)] = cell
                 # </hacks>
                 fn = support.maybe_on_top_of_llinterp(rtyper,
                                                       set_jitcell_at_ptr)
@@ -468,34 +489,24 @@
         if hasattr(self, 'get_location_str'):
             return
         #
-        can_inline_ptr = self.jitdriver_sd._can_inline_ptr
         unwrap_greenkey = self.make_unwrap_greenkey()
         jit_getter = self.make_jitcell_getter()
-        if can_inline_ptr is None:
-            def can_inline_callable(*greenargs):
-                # XXX shouldn't it be False by default?
-                return True
-        else:
-            rtyper = self.warmrunnerdesc.rtyper
-            #
-            def can_inline_callable(*greenargs):
-                fn = support.maybe_on_top_of_llinterp(rtyper, can_inline_ptr)
-                return fn(*greenargs)
-        def can_inline(*greenargs):
-            cell = jit_getter(*greenargs)
-            if cell.dont_trace_here:
+
+        def can_inline_greenargs(*greenargs):
+            cell = jit_getter(False, *greenargs)
+            if cell is not None and cell.dont_trace_here:
                 return False
-            return can_inline_callable(*greenargs)
-        self.can_inline_greenargs = can_inline
-        def can_inline_greenkey(greenkey):
+            return True
+        def can_inline_callable(greenkey):
             greenargs = unwrap_greenkey(greenkey)
-            return can_inline(*greenargs)
-        self.can_inline_callable = can_inline_greenkey
+            return can_inline_greenargs(*greenargs)
+        self.can_inline_greenargs = can_inline_greenargs
+        self.can_inline_callable = can_inline_callable
 
         def get_assembler_token(greenkey):
             greenargs = unwrap_greenkey(greenkey)
-            cell = jit_getter(*greenargs)
-            if cell.counter >= 0:
+            cell = jit_getter(False, *greenargs)
+            if cell is None or cell.counter >= 0:
                 return None
             return cell.entry_loop_token
         self.get_assembler_token = get_assembler_token

Modified: pypy/branch/fast-forward/pypy/jit/tl/pypyjit.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/tl/pypyjit.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/tl/pypyjit.py	Thu Sep  9 01:00:13 2010
@@ -37,6 +37,7 @@
 set_opt_level(config, level='jit')
 config.objspace.allworkingmodules = False
 config.objspace.usemodules.pypyjit = True
+config.objspace.usemodules.array = True
 config.objspace.usemodules._weakref = False
 config.objspace.usemodules._sre = False
 set_pypy_opt_level(config, level='jit')

Modified: pypy/branch/fast-forward/pypy/jit/tl/pypyjit_demo.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/tl/pypyjit_demo.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/tl/pypyjit_demo.py	Thu Sep  9 01:00:13 2010
@@ -1,38 +1,64 @@
-base = object
+## base = object
 
-class Number(base):
-    __slots__ = ('val', )
-    def __init__(self, val=0):
-        self.val = val
-
-    def __add__(self, other):
-        if not isinstance(other, int):
-            other = other.val
-        return Number(val=self.val + other)
+## class Number(base):
+##     __slots__ = ('val', )
+##     def __init__(self, val=0):
+##         self.val = val
+
+##     def __add__(self, other):
+##         if not isinstance(other, int):
+##             other = other.val
+##         return Number(val=self.val + other)
             
-    def __cmp__(self, other):
-        val = self.val
-        if not isinstance(other, int):
-            other = other.val
-        return cmp(val, other)
-
-    def __nonzero__(self):
-        return bool(self.val)
-
-def g(x, inc=2):
-    return x + inc
-
-def f(n, x, inc):
-    while x < n:
-        x = g(x, inc=1)
-    return x
-
-import time
-#t1 = time.time()
-#f(10000000, Number(), 1)
-#t2 = time.time()
-#print t2 - t1
-t1 = time.time()
-f(10000000, 0, 1)
-t2 = time.time()
-print t2 - t1
+##     def __cmp__(self, other):
+##         val = self.val
+##         if not isinstance(other, int):
+##             other = other.val
+##         return cmp(val, other)
+
+##     def __nonzero__(self):
+##         return bool(self.val)
+
+## def g(x, inc=2):
+##     return x + inc
+
+## def f(n, x, inc):
+##     while x < n:
+##         x = g(x, inc=1)
+##     return x
+
+## import time
+## #t1 = time.time()
+## #f(10000000, Number(), 1)
+## #t2 = time.time()
+## #print t2 - t1
+## t1 = time.time()
+## f(10000000, 0, 1)
+## t2 = time.time()
+## print t2 - t1
+
+try:
+    from array import array
+    def f(img):
+        i=0
+        sa=0
+        while i < img.__len__():
+            sa+=img[i]
+            i+=1
+        return sa
+
+    img=array('h',(1,2,3,4))
+    print f(img)
+except Exception, e:
+    print "Exception: ", type(e)
+    print e
+    
+## def f():
+##     a=7
+##     i=0
+##     while i<4:
+##         if  i<0: break
+##         if  i<0: break
+##         i+=1
+
+## f()

Modified: pypy/branch/fast-forward/pypy/jit/tool/test/test_traceviewer.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/tool/test/test_traceviewer.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/tool/test/test_traceviewer.py	Thu Sep  9 01:00:13 2010
@@ -52,10 +52,10 @@
 
     def test_postparse(self):
         real_loops = [FinalBlock("debug_merge_point('<code object _runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357> #40 POP_TOP')", None)]
-        postprocess(real_loops, real_loops[:])
+        postprocess(real_loops, real_loops[:], {})
         assert real_loops[0].header.startswith("_runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357")
 
     def test_load_actual(self):
         fname = py.path.local(__file__).join('..', 'data.log.bz2')
-        main(str(fname), view=False)
+        main(str(fname), False, view=False)
         # assert did not explode

Modified: pypy/branch/fast-forward/pypy/jit/tool/traceviewer.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/tool/traceviewer.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/tool/traceviewer.py	Thu Sep  9 01:00:13 2010
@@ -1,11 +1,12 @@
 #!/usr/bin/env python
-""" Usage: traceviewer.py loopfile
+""" Usage: traceviewer.py [--use-threshold] loopfile
 """
 
 import optparse
 import sys
 import re
 import math
+import py
 
 import autopath
 from pypy.translator.tool.graphpage import GraphPage
@@ -40,13 +41,13 @@
         self.source = dotgen.generate(target=None)
 
 class Page(GraphPage):
-    def compute(self, graphs):
+    def compute(self, graphs, counts):
         dotgen = DotGen('trace')
         self.loops = graphs
         self.links = {}
         self.cache = {}
         for loop in self.loops:
-            loop.generate(dotgen)
+            loop.generate(dotgen, counts)
             loop.getlinks(self.links)
             self.cache["loop" + str(loop.no)] = loop
         self.source = dotgen.generate(target=None)
@@ -71,9 +72,14 @@
     def getlinks(self, links):
         links[self.linksource] = self.name()
 
-    def generate(self, dotgen):
+    def generate(self, dotgen, counts):
+        val = counts.get(self.key, 0)
+        if val > counts.threshold:
+            fillcolor = get_gradient_color(self.ratio)
+        else:
+            fillcolor = "white"
         dotgen.emit_node(self.name(), label=self.header,
-                         shape='box', fillcolor=get_gradient_color(self.ratio))
+                         shape='box', fillcolor=fillcolor)
 
     def get_content(self):
         return self._content
@@ -113,11 +119,11 @@
         self.target = target
         BasicBlock.__init__(self, content)
 
-    def postprocess(self, loops, memo):
-        postprocess_loop(self.target, loops, memo)
+    def postprocess(self, loops, memo, counts):
+        postprocess_loop(self.target, loops, memo, counts)
 
-    def generate(self, dotgen):
-        BasicBlock.generate(self, dotgen)
+    def generate(self, dotgen, counts):
+        BasicBlock.generate(self, dotgen, counts)
         if self.target is not None:
             dotgen.emit_edge(self.name(), self.target.name())
 
@@ -127,12 +133,12 @@
         self.right = right
         BasicBlock.__init__(self, content)
 
-    def postprocess(self, loops, memo):
-        postprocess_loop(self.left, loops, memo)
-        postprocess_loop(self.right, loops, memo)
+    def postprocess(self, loops, memo, counts):
+        postprocess_loop(self.left, loops, memo, counts)
+        postprocess_loop(self.right, loops, memo, counts)
 
-    def generate(self, dotgen):
-        BasicBlock.generate(self, dotgen)
+    def generate(self, dotgen, counts):
+        BasicBlock.generate(self, dotgen, counts)
         dotgen.emit_edge(self.name(), self.left.name())
         dotgen.emit_edge(self.name(), self.right.name())
 
@@ -176,13 +182,11 @@
     real_loops = []
     counter = 1
     bar = progressbar.ProgressBar(color='blue')
-    single_percent = len(loops) / 100
     allloops = []
-    for i, loop in enumerate(loops):
+    for i, loop in enumerate(loops): 
         if i > MAX_LOOPS:
             return real_loops, allloops
-        if single_percent and i % single_percent == 0:
-            bar.render(i / single_percent)
+        bar.render((i * 100) / len(loops))
         firstline = loop[:loop.find("\n")]
         m = re.match('# Loop (\d+)', firstline)
         if m:
@@ -202,17 +206,19 @@
         counter += loop.count("\n") + 2
     return real_loops, allloops
 
-def postprocess_loop(loop, loops, memo):
+def postprocess_loop(loop, loops, memo, counts):
     if loop in memo:
         return
     memo.add(loop)
     if loop is None:
         return
-    m = re.search("debug_merge_point\('<code object (.*?)> (.*?)'", loop.content)
+    m = re.search("debug_merge_point\('(<code object (.*?)> (.*?))'", loop.content)
     if m is None:
         name = '?'
+        loop.key = '?'
     else:
-        name = m.group(1) + " " + m.group(2)
+        name = m.group(2) + " " + m.group(3)
+        loop.key = m.group(1)
     opsno = loop.content.count("\n")
     lastline = loop.content[loop.content.rfind("\n", 0, len(loop.content) - 2):]
     m = re.search('descr=<Loop(\d+)', lastline)
@@ -221,8 +227,8 @@
         loop.target = loops[int(m.group(1))]
     bcodes = loop.content.count('debug_merge_point')
     loop.linksource = "loop" + str(loop.no)
-    loop.header = "%s loop%d\n%d operations\n%d opcodes" % (name, loop.no, opsno,
-                                                          bcodes)
+    loop.header = ("%s loop%d\nrun %s times\n%d operations\n%d opcodes" %
+                   (name, loop.no, counts.get(loop.key, '?'), opsno, bcodes))
     loop.header += "\n" * (opsno / 100)
     if bcodes == 0:
         loop.ratio = opsno
@@ -230,29 +236,47 @@
         loop.ratio = float(opsno) / bcodes
     content = loop.content
     loop.content = "Logfile at %d\n" % loop.startlineno + content
-    loop.postprocess(loops, memo)
-
-def postprocess(loops, allloops):
+    loop.postprocess(loops, memo, counts)
+    
+def postprocess(loops, allloops, counts):
     for loop in allloops:
         if isinstance(loop, Block):
             loop.left = allloops[loop.left]
             loop.right = allloops[loop.right]
     memo = set()
     for loop in loops:
-        postprocess_loop(loop, loops, memo)
+        postprocess_loop(loop, loops, memo, counts)
+
+class Counts(dict):
+    pass
 
-def main(loopfile, view=True):
+def main(loopfile, options, view=True):
+    countname = py.path.local(loopfile + '.count')
+    if countname.check():
+        counts = [line.rsplit(':', 1) for line in countname.readlines()]
+        counts = Counts([(k, int(v.strip('\n'))) for k, v in counts])
+        l = list(sorted(counts.values()))
+        if len(l) > 20 and options.use_threshold:
+            counts.threshold = l[-20]
+        else:
+            counts.threshold = 0
+        for_print = [(v, k) for k, v in counts.iteritems()]
+        for_print.sort()
+    else:
+        counts = {}
     log = logparser.parse_log_file(loopfile)
     loops = logparser.extract_category(log, "jit-log-opt-")
     real_loops, allloops = splitloops(loops)
-    postprocess(real_loops, allloops)
+    postprocess(real_loops, allloops, counts)
     if view:
-        Page(allloops).display()
+        Page(allloops, counts).display()
 
 if __name__ == '__main__':
     parser = optparse.OptionParser(usage=__doc__)
+    parser.add_option('--use-threshold', dest='use_threshold',
+                      action="store_true")
     options, args = parser.parse_args(sys.argv)
     if len(args) != 2:
         print __doc__
         sys.exit(1)
-    main(args[1])
+    main(args[1], options.use_threshold)

Modified: pypy/branch/fast-forward/pypy/module/__builtin__/compiling.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/__builtin__/compiling.py	(original)
+++ pypy/branch/fast-forward/pypy/module/__builtin__/compiling.py	Thu Sep  9 01:00:13 2010
@@ -38,7 +38,7 @@
         str_ = space.str_w(w_source)
 
     ec = space.getexecutioncontext()
-    if flags & ~(ec.compiler.compiler_flags | consts.PyCF_AST_ONLY |
+    if flags & ~(ec.compiler.compiler_flags | consts.PyCF_ONLY_AST |
                  consts.PyCF_DONT_IMPLY_DEDENT | consts.PyCF_SOURCE_IS_UTF8):
         raise OperationError(space.w_ValueError,
                              space.wrap("compile() unrecognized flags"))
@@ -53,7 +53,7 @@
                                         "or 'eval' or 'single'"))
 
     if ast_node is None:
-        if flags & consts.PyCF_AST_ONLY:
+        if flags & consts.PyCF_ONLY_AST:
             mod = ec.compiler.compile_to_ast(str_, filename, mode, flags)
             return space.wrap(mod)
         else:

Modified: pypy/branch/fast-forward/pypy/module/__builtin__/functional.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/__builtin__/functional.py	(original)
+++ pypy/branch/fast-forward/pypy/module/__builtin__/functional.py	Thu Sep  9 01:00:13 2010
@@ -221,8 +221,7 @@
 
 from pypy.rlib.jit import JitDriver
 mapjitdriver = JitDriver(greens = ['code'],
-                         reds = ['w_func', 'w_iter', 'result_w'],
-                         can_inline = lambda *args: False)
+                         reds = ['w_func', 'w_iter', 'result_w'])
 def map_single_user_function(code, w_func, w_iter):
     result_w = []
     while True:

Modified: pypy/branch/fast-forward/pypy/module/__builtin__/interp_classobj.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/__builtin__/interp_classobj.py	(original)
+++ pypy/branch/fast-forward/pypy/module/__builtin__/interp_classobj.py	Thu Sep  9 01:00:13 2010
@@ -201,7 +201,7 @@
         w_inst = W_InstanceObjectWithDel(space, self)
     else:
         w_inst = W_InstanceObject(space, self)
-    w_init = w_inst.getattr(space, space.wrap('__init__'), False)
+    w_init = w_inst.getattr_from_class(space, space.wrap('__init__'))
     if w_init is not None:
         w_result = space.call_args(w_init, __args__)
         if not space.is_w(w_result, space.w_None):
@@ -337,25 +337,44 @@
                 space.wrap("__class__ must be set to a class"))
         self.w_class = w_class
 
-
-    def getattr(self, space, w_name, exc=True):
-        w_result = space.finditem(self.w_dict, w_name)
-        if w_result is not None:
-            return w_result
+    def getattr_from_class(self, space, w_name):
+        # Look up w_name in the class dict, and call its __get__.
+        # This method ignores the instance dict and the __getattr__.
+        # Returns None if not found.
         w_value = self.w_class.lookup(space, w_name)
         if w_value is None:
-            if exc:
-                raise operationerrfmt(
-                    space.w_AttributeError,
-                    "%s instance has no attribute '%s'",
-                    self.w_class.name, space.str_w(w_name))
-            else:
-                return None
+            return None
         w_descr_get = space.lookup(w_value, '__get__')
         if w_descr_get is None:
             return w_value
         return space.call_function(w_descr_get, w_value, self, self.w_class)
 
+    def getattr(self, space, w_name, exc=True):
+        # Normal getattr rules: look up w_name in the instance dict,
+        # in the class dict, and then via a call to __getatttr__.
+        w_result = space.finditem(self.w_dict, w_name)
+        if w_result is not None:
+            return w_result
+        w_result = self.getattr_from_class(space, w_name)
+        if w_result is not None:
+            return w_result
+        w_meth = self.getattr_from_class(space, space.wrap('__getattr__'))
+        if w_meth is not None:
+            try:
+                return space.call_function(w_meth, w_name)
+            except OperationError, e:
+                if not exc and e.match(space, space.w_AttributeError):
+                    return None     # eat the AttributeError
+                raise
+        # not found at all
+        if exc:
+            raise operationerrfmt(
+                space.w_AttributeError,
+                "%s instance has no attribute '%s'",
+                self.w_class.name, space.str_w(w_name))
+        else:
+            return None
+
     def descr_getattribute(self, space, w_attr):
         name = space.str_w(w_attr)
         if len(name) >= 8 and name[0] == '_':
@@ -363,19 +382,11 @@
                 return self.w_dict
             elif name == "__class__":
                 return self.w_class
-        try:
-            return self.getattr(space, w_attr)
-        except OperationError, e:
-            if not e.match(space, space.w_AttributeError):
-                raise
-            w_meth = self.getattr(space, space.wrap('__getattr__'), False)
-            if w_meth is not None:
-                return space.call_function(w_meth, w_attr)
-            raise
+        return self.getattr(space, w_attr)
 
     def descr_setattr(self, space, w_name, w_value):
         name = unwrap_attr(space, w_name)
-        w_meth = self.getattr(space, space.wrap('__setattr__'), False)
+        w_meth = self.getattr_from_class(space, space.wrap('__setattr__'))
         if name and name[0] == "_":
             if name == '__dict__':
                 self.setdict(space, w_value)
@@ -405,7 +416,7 @@
                 # use setclass to raise the error
                 self.setclass(space, None)
                 return
-        w_meth = self.getattr(space, space.wrap('__delattr__'), False)
+        w_meth = self.getattr_from_class(space, space.wrap('__delattr__'))
         if w_meth is not None:
             space.call_function(w_meth, w_name)
         else:
@@ -658,7 +669,10 @@
     def descr_del(self, space):
         # Note that this is called from executioncontext.UserDelAction
         # via the space.userdel() method.
-        w_func = self.getattr(space, space.wrap('__del__'), False)
+        w_name = space.wrap('__del__')
+        w_func = space.finditem(self.w_dict, w_name)
+        if w_func is None:
+            w_func = self.getattr_from_class(space, w_name)
         if w_func is not None:
             space.call_function(w_func)
 

Modified: pypy/branch/fast-forward/pypy/module/__builtin__/test/test_buffer.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/__builtin__/test/test_buffer.py	(original)
+++ pypy/branch/fast-forward/pypy/module/__builtin__/test/test_buffer.py	Thu Sep  9 01:00:13 2010
@@ -1,8 +1,11 @@
 """Tests some behaviour of the buffer type that is not tested in
 lib-python/2.5.2/test/test_types.py where the stdlib buffer tests live."""
 import autopath
+from pypy.conftest import gettestobjspace
 
 class AppTestBuffer:
+    def setup_class(cls):
+        cls.space = gettestobjspace(usemodules=('array',))
 
     def test_unicode_buffer(self):
         import sys

Modified: pypy/branch/fast-forward/pypy/module/__builtin__/test/test_classobj.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/__builtin__/test/test_classobj.py	(original)
+++ pypy/branch/fast-forward/pypy/module/__builtin__/test/test_classobj.py	Thu Sep  9 01:00:13 2010
@@ -786,6 +786,168 @@
                 return [1, 2]
         assert reversed(X()) == [1, 2]
 
+    def test_special_method_via_getattr(self):
+        class A:
+            def __getattr__(self, attr):
+                print 'A getattr:', attr
+                def callable(*args):
+                    print 'A called:', attr + repr(args)
+                    return attr + repr(args)
+                return callable
+        class B:
+            def __getattr__(self, attr):
+                print 'B getattr:', attr
+                def callable(*args):
+                    print 'B called:', attr, args
+                    self.called = attr, args
+                    if attr == '__coerce__':
+                        return self, args[0]
+                    return 42
+                return callable
+        a = A()
+        a.instancevalue = 42      # does not go via __getattr__('__setattr__')
+        a.__getattr__ = "hi there, ignore me, I'm in a"
+        a.__setattr__ = "hi there, ignore me, I'm in a too"
+        assert a.instancevalue == 42
+        A.classvalue = 123
+        assert a.classvalue == 123
+        assert a.foobar(5) == 'foobar(5,)'
+        assert a.__dict__ == {'instancevalue': 42,
+                              '__getattr__': a.__getattr__,
+                              '__setattr__': a.__setattr__}
+        assert a.__class__ is A
+        # This follows the Python 2.5 rules, more precisely.
+        # It is still valid in Python 2.7 too.
+        assert repr(a) == '__repr__()'
+        assert str(a) == '__str__()'
+        assert unicode(a) == u'__unicode__()'
+        b = B()
+        b.__getattr__ = "hi there, ignore me, I'm in b"
+        b.__setattr__ = "hi there, ignore me, I'm in b too"
+        assert 'called' not in b.__dict__      # and not e.g. ('__init__', ())
+        assert len(b) == 42
+        assert b.called == ('__len__', ())
+        assert a[5] == '__getitem__(5,)'
+        b[6] = 7
+        assert b.called == ('__setitem__', (6, 7))
+        del b[8]
+        assert b.called == ('__delitem__', (8,))
+        #
+        class C:
+            def __getattr__(self, name):
+                if name == '__iter__':
+                    return lambda: iter([3, 33, 333])
+                raise AttributeError
+        assert list(iter(C())) == [3, 33, 333]
+        #
+        class C:
+            def __getattr__(self, name):
+                if name == '__getitem__':
+                    return lambda n: [3, 33, 333][n]
+                raise AttributeError
+        assert list(iter(C())) == [3, 33, 333]
+        #
+        assert a[:6] == '__getslice__(0, 6)'
+        b[3:5] = 7
+        assert b.called == ('__setslice__', (3, 5, 7))
+        del b[:-1000]
+        assert b.called == ('__delslice__', (0, -958))   # adds len(b)...
+        assert a(5) == '__call__(5,)'
+        raises(TypeError, bool, a)     # "should return an int"
+        assert not not b
+        #
+        class C:
+            def __getattr__(self, name):
+                if name == '__nonzero__':
+                    return lambda: False
+                raise AttributeError
+        assert not C()
+        #
+        class C:
+            def __getattr__(self, name):
+                if name == '__len__':
+                    return lambda: 0
+                raise AttributeError
+        assert not C()
+        #
+        #assert cmp(b, 43) == 0    # because __eq__(43) returns 42, so True...
+        # ... I will leave this case as XXX implement me
+        assert hash(b) == 42
+        assert range(100, 200)[b] == 142
+        assert "foo" in b
+        #
+        class C:
+            def __iter__(self):
+                return self
+            def __getattr__(self, name):
+                if name == 'next':
+                    return lambda: 'the next item'
+                raise AttributeError
+        for x in C():
+            assert x == 'the next item'
+            break
+        #
+        # XXX a really corner case: '__del__'
+        #
+        import operator
+        op_by_name = {"neg": operator.neg,
+                      "pos": operator.pos,
+                      "abs": abs,
+                      "invert": operator.invert,
+                      "int": int,
+                      "long": long}
+        for opname, opfunc in op_by_name.items():
+            assert opfunc(b) == 42
+            assert b.called == ("__" + opname + "__", ())
+        assert oct(a) == '__oct__()'
+        assert hex(a) == '__hex__()'
+        #
+        class C:
+            def __getattr__(self, name):
+                return lambda: 5.5
+        raises(TypeError, float, b)
+        assert float(C()) == 5.5
+        #
+        op_by_name = {'eq': operator.eq,
+                      'ne': operator.ne,
+                      'gt': operator.gt,
+                      'lt': operator.lt,
+                      'ge': operator.ge,
+                      'le': operator.le,
+                      'imod': operator.imod,
+                      'iand': operator.iand,
+                      'ipow': operator.ipow,
+                      'itruediv': operator.itruediv,
+                      'ilshift': operator.ilshift,
+                      'ixor': operator.ixor,
+                      'irshift': operator.irshift,
+                      'ifloordiv': operator.ifloordiv,
+                      'idiv': operator.idiv,
+                      'isub': operator.isub,
+                      'imul': operator.imul,
+                      'iadd': operator.iadd,
+                      'ior': operator.ior,
+                      'or': operator.or_,
+                      'and': operator.and_,
+                      'xor': operator.xor,
+                      'lshift': operator.lshift,
+                      'rshift': operator.rshift,
+                      'add': operator.add,
+                      'sub': operator.sub,
+                      'mul': operator.mul,
+                      'div': operator.div,
+                      'mod': operator.mod,
+                      'divmod': divmod,
+                      'floordiv': operator.floordiv,
+                      'truediv': operator.truediv}
+        for opname, opfunc in op_by_name.items():
+            assert opfunc(b, 5) == 42
+            assert b.called == ("__" + opname + "__", (5,))
+        x, y = coerce(b, 5)
+        assert x is b
+        assert y == 5
+
+
 class AppTestOldStyleSharing(AppTestOldstyle):
     def setup_class(cls):
         cls.space = gettestobjspace(**{"objspace.std.withsharingdict": True})

Modified: pypy/branch/fast-forward/pypy/module/_ast/__init__.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_ast/__init__.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_ast/__init__.py	Thu Sep  9 01:00:13 2010
@@ -5,7 +5,7 @@
 class Module(MixedModule):
 
     interpleveldefs = {
-        "PyCF_AST_ONLY" : "space.wrap(%s)" % consts.PyCF_AST_ONLY
+        "PyCF_ONLY_AST" : "space.wrap(%s)" % consts.PyCF_ONLY_AST
         }
     appleveldefs = {}
 

Modified: pypy/branch/fast-forward/pypy/module/_ast/test/test_ast.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_ast/test/test_ast.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_ast/test/test_ast.py	Thu Sep  9 01:00:13 2010
@@ -10,7 +10,7 @@
         cls.w_get_ast = cls.space.appexec([], """():
     def get_ast(source, mode="exec"):
         import _ast as ast
-        mod = compile(source, "<test>", mode, ast.PyCF_AST_ONLY)
+        mod = compile(source, "<test>", mode, ast.PyCF_ONLY_AST)
         assert isinstance(mod, ast.mod)
         return mod
     return get_ast""")

Modified: pypy/branch/fast-forward/pypy/module/_codecs/test/test_codecs.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_codecs/test/test_codecs.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_codecs/test/test_codecs.py	Thu Sep  9 01:00:13 2010
@@ -123,6 +123,10 @@
 
 class AppTestPartialEvaluation:
 
+    def setup_class(cls):
+        space = gettestobjspace(usemodules=('array',))
+        cls.space = space
+
     def test_partial_utf8(self):
         import _codecs
         encoding = 'utf-8'

Modified: pypy/branch/fast-forward/pypy/module/_demo/demo.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_demo/demo.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_demo/demo.py	Thu Sep  9 01:00:13 2010
@@ -4,11 +4,14 @@
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.tool import rffi_platform
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 import sys, math
 
 time_t = rffi_platform.getsimpletype('time_t', '#include <time.h>', rffi.LONG)
 
-time = rffi.llexternal('time', [rffi.VOIDP], time_t, includes=['time.h'])
+eci = ExternalCompilationInfo(includes=['time.h'])
+time = rffi.llexternal('time', [int], time_t,
+                       compilation_info=eci)
 
 def get(space, name):
     w_module = space.getbuiltinmodule('_demo')
@@ -20,10 +23,10 @@
         w_DemoError = get(space, 'DemoError')
         msg = "repetition count must be > 0"
         raise OperationError(w_DemoError, space.wrap(msg))
-    starttime = time(None)
+    starttime = time(0)
     for i in range(repetitions):
         space.call_function(w_callable)
-    endtime = time(None)
+    endtime = time(0)
     return space.wrap(endtime - starttime)
 measuretime.unwrap_spec = [ObjSpace, int, W_Root]
 
@@ -62,11 +65,16 @@
         self.x = space.int_w(w_value)
 
 def mytype_new(space, w_subtype, x):
+    if x == 3:
+        return space.wrap(MySubType(space, x))
     return space.wrap(W_MyType(space, x))
 mytype_new.unwrap_spec = [ObjSpace, W_Root, int]
 
 getset_x = GetSetProperty(W_MyType.fget_x, W_MyType.fset_x, cls=W_MyType)
 
+class MySubType(W_MyType):
+    pass
+
 W_MyType.typedef = TypeDef('MyType',
     __new__ = interp2app(mytype_new),
     x = getset_x,

Modified: pypy/branch/fast-forward/pypy/module/_file/interp_file.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_file/interp_file.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_file/interp_file.py	Thu Sep  9 01:00:13 2010
@@ -4,6 +4,7 @@
 from pypy.rlib.rarithmetic import r_longlong
 from pypy.module._file.interp_stream import W_AbstractStream
 from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror
+from pypy.module.posix.interp_posix import dispatch_filename
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import ObjSpace, W_Root, Arguments
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
@@ -81,11 +82,11 @@
     # file lock.  They don't convert StreamErrors to OperationErrors, too.
 
     def direct___init__(self, w_name, mode='r', buffering=-1):
-        name = self.space.str_w(w_name)
         self.direct_close()
         self.w_name = w_name
         self.check_mode_ok(mode)
-        stream = streamio.open_file_as_stream(name, mode, buffering)
+        stream = dispatch_filename(streamio.open_file_as_stream)(
+            self.space, w_name, mode, buffering)
         fd = stream.try_to_find_file_descriptor()
         self.fdopenstream(stream, fd, mode)
 

Modified: pypy/branch/fast-forward/pypy/module/_file/test/test_file.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_file/test/test_file.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_file/test/test_file.py	Thu Sep  9 01:00:13 2010
@@ -125,6 +125,15 @@
         assert type(res) is str
         f.close()
 
+    def test_unicode_filename(self):
+        import sys
+        try:
+            u'\xe9'.encode(sys.getfilesystemencoding())
+        except UnicodeEncodeError:
+            skip("encoding not good enough")
+        f = self.file(self.temppath + u'\xe9', "w")
+        f.close()
+
     def test_oserror_has_filename(self):
         try:
             f = self.file("file that is clearly not there")

Modified: pypy/branch/fast-forward/pypy/module/_file/test/test_file_extra.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_file/test/test_file_extra.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_file/test/test_file_extra.py	Thu Sep  9 01:00:13 2010
@@ -353,6 +353,10 @@
 
 class AppTestAFewExtra:
 
+    def setup_class(cls):
+        space = gettestobjspace(usemodules=('array',))
+        cls.space = space
+
     def setup_method(self, method):
         fn = str(udir.join('temptestfile'))
         self.w_temptestfile = self.space.wrap(fn)

Modified: pypy/branch/fast-forward/pypy/module/_locale/__init__.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_locale/__init__.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_locale/__init__.py	Thu Sep  9 01:00:13 2010
@@ -1,5 +1,4 @@
 from pypy.interpreter.mixedmodule import MixedModule
-from pypy.module._locale import interp_locale
 from pypy.rlib import rlocale
 import sys
 

Modified: pypy/branch/fast-forward/pypy/module/_rawffi/test/test__rawffi.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_rawffi/test/test__rawffi.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_rawffi/test/test__rawffi.py	Thu Sep  9 01:00:13 2010
@@ -677,7 +677,12 @@
         a = A(1)
         a[0] = -1234
         a.free()
-        
+
+    def test_long_with_fromaddress(self):
+        import _rawffi
+        addr = -1
+        raises(ValueError, _rawffi.Array('u').fromaddress, addr, 100)
+
     def test_passing_raw_pointers(self):
         import _rawffi
         lib = _rawffi.CDLL(self.lib_name)

Modified: pypy/branch/fast-forward/pypy/module/_socket/interp_socket.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_socket/interp_socket.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_socket/interp_socket.py	Thu Sep  9 01:00:13 2010
@@ -74,7 +74,11 @@
         This is like connect(address), but returns an error code (the errno value)
         instead of raising an exception when an error occurs.
         """
-        error = self.connect_ex(self.addr_from_object(space, w_addr))
+        try:
+            addr = self.addr_from_object(space, w_addr)
+        except SocketError, e:
+            raise converted_error(space, e)
+        error = self.connect_ex(addr)
         return space.wrap(error)
     connect_ex_w.unwrap_spec = ['self', ObjSpace, W_Root]
 

Modified: pypy/branch/fast-forward/pypy/module/_socket/test/test_sock_app.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_socket/test/test_sock_app.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_socket/test/test_sock_app.py	Thu Sep  9 01:00:13 2010
@@ -4,7 +4,7 @@
 from pypy.tool.udir import udir
 
 def setup_module(mod):
-    mod.space = gettestobjspace(usemodules=['_socket'])
+    mod.space = gettestobjspace(usemodules=['_socket', 'array'])
     global socket
     import socket
     mod.w_socket = space.appexec([], "(): import _socket as m; return m")
@@ -221,6 +221,21 @@
                         "(_socket, host, port): return _socket.getaddrinfo(host, port)")
     assert space.unwrap(w_l) == info
 
+def test_unknown_addr_as_object():
+    from pypy.rlib import rsocket
+    from pypy.rpython.lltypesystem import lltype, rffi
+    
+    c_addr = lltype.malloc(rsocket._c.sockaddr, flavor='raw')
+    c_addr.c_sa_data[0] = 'c'
+    rffi.setintfield(c_addr, 'c_sa_family', 15)
+    # XXX what size to pass here? for the purpose of this test it has
+    #     to be short enough so we have some data, 1 sounds good enough
+    #     + sizeof USHORT
+    w_obj = rsocket.Address(c_addr, 1 + 2).as_object(space)
+    assert space.is_true(space.isinstance(w_obj, space.w_tuple))
+    assert space.int_w(space.getitem(w_obj, space.wrap(0))) == 15
+    assert space.str_w(space.getitem(w_obj, space.wrap(1))) == 'c'
+
 def test_getnameinfo():
     host = "127.0.0.1"
     port = 25
@@ -339,6 +354,13 @@
         name = s.getpeername() # Will raise socket.error if not connected
         assert name[1] == 80
         s.close()
+    
+    def test_socket_connect_ex(self):
+        import _socket
+        s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM, 0)
+        # Make sure we get an app-level error, not an interp one.
+        raises(_socket.gaierror, s.connect_ex, ("wrong.invalid", 80))
+        s.close()
 
     def test_socket_connect_typeerrors(self):
         tests = [
@@ -433,7 +455,6 @@
         s2 = s.dup()
         assert s.fileno() != s2.fileno()
         assert s.getsockname() == s2.getsockname()
-    
 
     def test_buffer_or_unicode(self):
         # Test that send/sendall/sendto accept a buffer or a unicode as arg

Modified: pypy/branch/fast-forward/pypy/module/_sre/__init__.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_sre/__init__.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_sre/__init__.py	Thu Sep  9 01:00:13 2010
@@ -1,24 +1,14 @@
 from pypy.interpreter.mixedmodule import MixedModule 
 
 class Module(MixedModule):
-    """A pure Python reimplementation of the _sre module from CPython 2.4
-Copyright 2005 Nik Haldimann, licensed under the MIT license
 
-This code is based on material licensed under CNRI's Python 1.6 license and
-copyrighted by: Copyright (c) 1997-2001 by Secret Labs AB
-"""
-    
     appleveldefs = {
-        'compile':        'app_sre.compile',
     }
 
     interpleveldefs = {
         'CODESIZE':       'space.wrap(interp_sre.CODESIZE)',
         'MAGIC':          'space.wrap(interp_sre.MAGIC)',
-        'copyright':      'space.wrap(interp_sre.copyright)',
+        'compile':        'interp_sre.W_SRE_Pattern',
         'getlower':       'interp_sre.w_getlower',
         'getcodesize':    'interp_sre.w_getcodesize',
-        '_State':         'interp_sre.make_state',
-        '_match':         'interp_sre.w_match',
-        '_search':        'interp_sre.w_search',
     }

Modified: pypy/branch/fast-forward/pypy/module/_sre/interp_sre.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_sre/interp_sre.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_sre/interp_sre.py	Thu Sep  9 01:00:13 2010
@@ -1,27 +1,20 @@
+import sys
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.typedef import GetSetProperty, TypeDef
 from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
+from pypy.interpreter.typedef import make_weakref_descr
 from pypy.interpreter.gateway import interp2app, ObjSpace, W_Root
 from pypy.interpreter.error import OperationError
 from pypy.rlib.rarithmetic import intmask
+from pypy.tool.pairtype import extendabletype
 
-# This can be compiled in two ways:
-#
-# * THREE_VERSIONS_OF_CORE=True: you get three copies of the whole
-#   regexp searching and matching code: for strings, for unicode strings,
-#   and for generic buffer objects (like mmap.mmap or array.array).
-#
-# * THREE_VERSIONS_OF_CORE=False: there is only one copy of the code,
-#   at the cost of an indirect method call to fetch each character.
-
-THREE_VERSIONS_OF_CORE = True
 
+# ____________________________________________________________
+#
+# Constants and exposed functions
 
-#### Constants and exposed functions
-
-from pypy.rlib.rsre import rsre
-from pypy.rlib.rsre.rsre_char import MAGIC, CODESIZE, getlower
-copyright = "_sre.py 2.4 Copyright 2005 by Nik Haldimann"
+from pypy.rlib.rsre import rsre_core
+from pypy.rlib.rsre.rsre_char import MAGIC, CODESIZE, getlower, set_unicode_db
 
 def w_getlower(space, char_ord, flags):
     return space.wrap(getlower(char_ord, flags))
@@ -31,166 +24,529 @@
     return space.wrap(CODESIZE)
 
 # use the same version of unicodedb as the standard objspace
-from pypy.objspace.std.unicodeobject import unicodedb
-rsre.set_unicode_db(unicodedb)
+import pypy.objspace.std.unicodeobject
+set_unicode_db(pypy.objspace.std.unicodeobject.unicodedb)
 
-#### State classes
+# ____________________________________________________________
+#
+# Additional methods on the classes XxxMatchContext
+
+class __extend__(rsre_core.AbstractMatchContext):
+    __metaclass__ = extendabletype
+    def _w_slice(self, space, start, end):
+        raise NotImplementedError
+    def _w_string(self, space):
+        raise NotImplementedError
 
-def make_state(space, w_string, start, end, flags):
-    # XXX maybe turn this into a __new__ method of W_State
-    if space.is_true(space.isinstance(w_string, space.w_str)):
-        cls = W_StringState
-    elif space.is_true(space.isinstance(w_string, space.w_unicode)):
-        cls = W_UnicodeState
-    else:
-        cls = W_GenericState
-    return space.wrap(cls(space, w_string, start, end, flags))
-make_state.unwrap_spec = [ObjSpace, W_Root, int, int, int]
-
-
-class W_State(Wrappable):
-    if not THREE_VERSIONS_OF_CORE:
-        rsre.insert_sre_methods(locals(), 'all')
-
-    def __init__(self, space, w_string, start, end, flags):
-        self.space = space
-        self.w_string = w_string
-        length = self.unwrap_object()
-        if start < 0:
-            start = 0
-        if end > length:
-            end = length
-        self.start = start
-        self.pos   = start     # records the original start position
-        self.end   = end
-        self.flags = flags
-        self.reset()
+class __extend__(rsre_core.StrMatchContext):
+    __metaclass__ = extendabletype
+    def _w_slice(self, space, start, end):
+        return space.wrap(self._string[start:end])
+    def _w_string(self, space):
+        return space.wrap(self._string)
+
+class __extend__(rsre_core.UnicodeMatchContext):
+    __metaclass__ = extendabletype
+    def _w_slice(self, space, start, end):
+        return space.wrap(self._unicodestr[start:end])
+    def _w_string(self, space):
+        return space.wrap(self._unicodestr)
+
+def slice_w(space, ctx, start, end, w_default):
+    if 0 <= start <= end:
+        return ctx._w_slice(space, start, end)
+    return w_default
+
+def do_flatten_marks(ctx, num_groups):
+    # Returns a list of RPython-level integers.
+    # Unlike the app-level groups() method, groups are numbered from 0
+    # and the returned list does not start with the whole match range.
+    if num_groups == 0:
+        return None
+    result = [-1] * (2*num_groups)
+    mark = ctx.match_marks
+    while mark is not None:
+        index = mark.gid
+        if result[index] == -1:
+            result[index] = mark.position
+        mark = mark.prev
+    return result
+
+def allgroups_w(space, ctx, fmarks, num_groups, w_default):
+    grps = [slice_w(space, ctx, fmarks[i*2], fmarks[i*2+1], w_default)
+            for i in range(num_groups)]
+    return space.newtuple(grps)
+
+def import_re(space):
+    w_builtin = space.getbuiltinmodule('__builtin__')
+    w_import = space.getattr(w_builtin, space.wrap("__import__"))
+    return space.call_function(w_import, space.wrap("re"))
 
-    def lower(self, char_ord):
-        return getlower(char_ord, self.flags)
+def matchcontext(space, ctx):
+    try:
+        return rsre_core.match_context(ctx)
+    except rsre_core.Error, e:
+        raise OperationError(space.w_RuntimeError, space.wrap(e.msg))
 
-    # methods overridden by subclasses
+def searchcontext(space, ctx):
+    try:
+        return rsre_core.search_context(ctx)
+    except rsre_core.Error, e:
+        raise OperationError(space.w_RuntimeError, space.wrap(e.msg))
 
-    def unwrap_object(self):
-        raise NotImplementedError
+# ____________________________________________________________
+#
+# SRE_Pattern class
 
-    if 'reset' not in locals():
-        def reset(self):
-            raise NotImplementedError
-
-    if 'search' not in locals():
-        def search(self, pattern_codes):
-            raise NotImplementedError
-
-    if 'match' not in locals():
-        def match(self, pattern_codes):
-            raise NotImplementedError
-
-    # Accessors for the typedef
-
-    def w_reset(self):
-        self.reset()
-
-    def create_regs(self, group_count):
-        """ Purely abstract method
-        """
-        raise NotImplementedError
+class W_SRE_Pattern(Wrappable):
 
-    def w_create_regs(self, group_count):
-        """Creates a tuple of index pairs representing matched groups, a format
-        that's convenient for SRE_Match."""
+    def cannot_copy_w(self):
         space = self.space
-        return space.newtuple([
-            space.newtuple([space.wrap(value1),
-                            space.wrap(value2)])
-            for value1, value2 in self.create_regs(group_count)])
-    w_create_regs.unwrap_spec = ['self', int]
+        raise OperationError(space.w_TypeError,
+                             space.wrap("cannot copy this pattern object"))
 
-    def fget_start(space, self):
-        return space.wrap(self.start)
-
-    def fset_start(space, self, w_value):
-        self.start = space.int_w(w_value)
+    def make_ctx(self, w_string, pos=0, endpos=sys.maxint):
+        """Make a StrMatchContext or a UnicodeMatchContext for searching
+        in the given w_string object."""
+        space = self.space
+        if pos < 0: pos = 0
+        if endpos < pos: endpos = pos
+        if space.is_true(space.isinstance(w_string, space.w_unicode)):
+            unicodestr = space.unicode_w(w_string)
+            if pos > len(unicodestr): pos = len(unicodestr)
+            if endpos > len(unicodestr): endpos = len(unicodestr)
+            return rsre_core.UnicodeMatchContext(self.code, unicodestr,
+                                                 pos, endpos, self.flags)
+        else:
+            str = space.bufferstr_w(w_string)
+            if pos > len(str): pos = len(str)
+            if endpos > len(str): endpos = len(str)
+            return rsre_core.StrMatchContext(self.code, str,
+                                             pos, endpos, self.flags)
+
+    def getmatch(self, ctx, found):
+        if found:
+            return W_SRE_Match(self, ctx)
+        else:
+            return self.space.w_None
+
+    def match_w(self, w_string, pos=0, endpos=sys.maxint):
+        ctx = self.make_ctx(w_string, pos, endpos)
+        return self.getmatch(ctx, matchcontext(self.space, ctx))
+    match_w.unwrap_spec = ['self', W_Root, int, int]
+
+    def search_w(self, w_string, pos=0, endpos=sys.maxint):
+        ctx = self.make_ctx(w_string, pos, endpos)
+        return self.getmatch(ctx, searchcontext(self.space, ctx))
+    search_w.unwrap_spec = ['self', W_Root, int, int]
 
-    def fget_string_position(space, self):
-        return space.wrap(self.string_position)
+    def findall_w(self, w_string, pos=0, endpos=sys.maxint):
+        space = self.space
+        matchlist_w = []
+        ctx = self.make_ctx(w_string, pos, endpos)
+        while ctx.match_start <= ctx.end:
+            if not searchcontext(space, ctx):
+                break
+            num_groups = self.num_groups
+            w_emptystr = space.wrap("")
+            if num_groups == 0:
+                w_item = slice_w(space, ctx, ctx.match_start, ctx.match_end,
+                                 w_emptystr)
+            else:
+                fmarks = do_flatten_marks(ctx, num_groups)
+                if num_groups == 1:
+                    w_item = slice_w(space, ctx, fmarks[0], fmarks[1],
+                                     w_emptystr)
+                else:
+                    w_item = allgroups_w(space, ctx, fmarks, num_groups,
+                                         w_emptystr)
+            matchlist_w.append(w_item)
+            no_progress = (ctx.match_start == ctx.match_end)
+            ctx.reset(ctx.match_end + no_progress)
+        return space.newlist(matchlist_w)
+    findall_w.unwrap_spec = ['self', W_Root, int, int]
+
+    def finditer_w(self, w_string, pos=0, endpos=sys.maxint):
+        # this also works as the implementation of the undocumented
+        # scanner() method.
+        ctx = self.make_ctx(w_string, pos, endpos)
+        scanner = W_SRE_Scanner(self, ctx)
+        return self.space.wrap(scanner)
+    finditer_w.unwrap_spec = ['self', W_Root, int, int]
 
-    def fset_string_position(space, self, w_value):
-        self.start = space.int_w(w_value)
+    def split_w(self, w_string, maxsplit=0):
+        space = self.space
+        splitlist = []
+        n = 0
+        last = 0
+        ctx = self.make_ctx(w_string)
+        while not maxsplit or n < maxsplit:
+            if not searchcontext(space, ctx):
+                break
+            if ctx.match_start == ctx.match_end:     # zero-width match
+                if ctx.match_start == ctx.end:       # or end of string
+                    break
+                ctx.reset(ctx.match_end + 1)
+                continue
+            splitlist.append(slice_w(space, ctx, last, ctx.match_start,
+                                     space.w_None))
+            # add groups (if any)
+            fmarks = do_flatten_marks(ctx, self.num_groups)
+            for groupnum in range(self.num_groups):
+                groupstart, groupend = fmarks[groupnum*2], fmarks[groupnum*2+1]
+                splitlist.append(slice_w(space, ctx, groupstart, groupend,
+                                         space.w_None))
+            n += 1
+            last = ctx.match_end
+            ctx.reset(last)
+        splitlist.append(slice_w(space, ctx, last, ctx.end, space.w_None))
+        return space.newlist(splitlist)
+    split_w.unwrap_spec = ['self', W_Root, int]
+
+    def sub_w(self, w_repl, w_string, count=0):
+        w_item, n = self.subx(w_repl, w_string, count)
+        return w_item
+    sub_w.unwrap_spec = ['self', W_Root, W_Root, int]
 
-    def get_char_ord(self, p):
-        raise NotImplementedError
+    def subn_w(self, w_repl, w_string, count=0):
+        w_item, n = self.subx(w_repl, w_string, count)
+        space = self.space
+        return space.newtuple([w_item, space.wrap(n)])
+    subn_w.unwrap_spec = ['self', W_Root, W_Root, int]
 
-getset_start = GetSetProperty(W_State.fget_start, W_State.fset_start, cls=W_State)
-getset_string_position = GetSetProperty(W_State.fget_string_position,
-                                     W_State.fset_string_position, cls=W_State)
-
-W_State.typedef = TypeDef("W_State",
-    string = interp_attrproperty_w("w_string", W_State),
-    start = getset_start,
-    end = interp_attrproperty("end", W_State),
-    string_position = getset_string_position,
-    pos = interp_attrproperty("pos", W_State),
-    lastindex = interp_attrproperty("lastindex", W_State),
-    reset = interp2app(W_State.w_reset),
-    create_regs = interp2app(W_State.w_create_regs),
+    def subx(self, w_ptemplate, w_string, count):
+        space = self.space
+        if space.is_true(space.callable(w_ptemplate)):
+            w_filter = w_ptemplate
+            filter_is_callable = True
+        else:
+            if space.is_true(space.isinstance(w_ptemplate, space.w_unicode)):
+                filter_as_unicode = space.unicode_w(w_ptemplate)
+                literal = u'\\' not in filter_as_unicode
+            else:
+                try:
+                    filter_as_string = space.str_w(w_ptemplate)
+                except OperationError, e:
+                    if e.async(space):
+                        raise
+                    literal = False
+                else:
+                    literal = '\\' not in filter_as_string
+            if literal:
+                w_filter = w_ptemplate
+                filter_is_callable = False
+            else:
+                # not a literal; hand it over to the template compiler
+                w_re = import_re(space)
+                w_filter = space.call_method(w_re, '_subx',
+                                             space.wrap(self), w_ptemplate)
+                filter_is_callable = space.is_true(space.callable(w_filter))
+        #
+        ctx = self.make_ctx(w_string)
+        sublist_w = []
+        n = last_pos = 0
+        while not count or n < count:
+            if not searchcontext(space, ctx):
+                break
+            if last_pos < ctx.match_start:
+                sublist_w.append(slice_w(space, ctx, last_pos,
+                                         ctx.match_start, space.w_None))
+            start = ctx.match_end
+            if start == ctx.match_start:
+                start += 1
+            nextctx = ctx.fresh_copy(start)
+            if not (last_pos == ctx.match_start
+                             == ctx.match_end and n > 0):
+                # the above ignores empty matches on latest position
+                if filter_is_callable:
+                    w_match = self.getmatch(ctx, True)
+                    w_piece = space.call_function(w_filter, w_match)
+                    if not space.is_w(w_piece, space.w_None):
+                        sublist_w.append(w_piece)
+                else:
+                    sublist_w.append(w_filter)
+                last_pos = ctx.match_end
+                n += 1
+            elif last_pos >= ctx.end:
+                break    # empty match at the end: finished
+            ctx = nextctx
+
+        if last_pos < ctx.end:
+            sublist_w.append(slice_w(space, ctx, last_pos, ctx.end,
+                                     space.w_None))
+        if n == 0:
+            # not just an optimization -- see test_sub_unicode
+            return w_string, n
+
+        if space.is_true(space.isinstance(w_string, space.w_unicode)):
+            w_emptystr = space.wrap(u'')
+        else:
+            w_emptystr = space.wrap('')
+        w_item = space.call_method(w_emptystr, 'join',
+                                   space.newlist(sublist_w))
+        return w_item, n
+
+
+def SRE_Pattern__new__(space, w_subtype, w_pattern, flags, w_code,
+              groups=0, w_groupindex=None, w_indexgroup=None):
+    n = space.int_w(space.len(w_code))
+    code = [0] * n
+    for i in range(n):
+        x = space.uint_w(space.getitem(w_code, space.wrap(i)))
+        code[i] = intmask(x)
+    #
+    w_srepat = space.allocate_instance(W_SRE_Pattern, w_subtype)
+    srepat = space.interp_w(W_SRE_Pattern, w_srepat)
+    srepat.space = space
+    srepat.w_pattern = w_pattern      # the original uncompiled pattern
+    srepat.flags = flags
+    srepat.code = code
+    srepat.num_groups = groups
+    srepat.w_groupindex = w_groupindex
+    srepat.w_indexgroup = w_indexgroup
+    return w_srepat
+SRE_Pattern__new__.unwrap_spec = [ObjSpace, W_Root, W_Root, int, W_Root,
+                                  int, W_Root, W_Root]
+
+
+W_SRE_Pattern.typedef = TypeDef(
+    'SRE_Pattern',
+    __new__      = interp2app(SRE_Pattern__new__),
+    __copy__     = interp2app(W_SRE_Pattern.cannot_copy_w),
+    __deepcopy__ = interp2app(W_SRE_Pattern.cannot_copy_w),
+    __weakref__  = make_weakref_descr(W_SRE_Pattern),
+    findall      = interp2app(W_SRE_Pattern.findall_w),
+    finditer     = interp2app(W_SRE_Pattern.finditer_w),
+    match        = interp2app(W_SRE_Pattern.match_w),
+    scanner      = interp2app(W_SRE_Pattern.finditer_w),    # reuse finditer()
+    search       = interp2app(W_SRE_Pattern.search_w),
+    split        = interp2app(W_SRE_Pattern.split_w),
+    sub          = interp2app(W_SRE_Pattern.sub_w),
+    subn         = interp2app(W_SRE_Pattern.subn_w),
+    flags        = interp_attrproperty('flags', W_SRE_Pattern),
+    groupindex   = interp_attrproperty_w('w_groupindex', W_SRE_Pattern),
+    groups       = interp_attrproperty('num_groups', W_SRE_Pattern),
+    pattern      = interp_attrproperty_w('w_pattern', W_SRE_Pattern),
 )
 
+# ____________________________________________________________
+#
+# SRE_Match class
 
-class W_StringState(W_State):
-    if THREE_VERSIONS_OF_CORE:
-        rsre.insert_sre_methods(locals(), 'str')
-
-    def unwrap_object(self):
-        self.string = self.space.str_w(self.w_string)
-        return len(self.string)
-
-    def get_char_ord(self, p):
-        return ord(self.string[p])
+class W_SRE_Match(Wrappable):
+    flatten_cache = None
 
+    def __init__(self, srepat, ctx):
+        self.space = srepat.space
+        self.srepat = srepat
+        self.ctx = ctx
 
-class W_UnicodeState(W_State):
-    if THREE_VERSIONS_OF_CORE:
-        rsre.insert_sre_methods(locals(), 'unicode')
+    def cannot_copy_w(self):
+        space = self.space
+        raise OperationError(space.w_TypeError,
+                             space.wrap("cannot copy this match object"))
 
-    def unwrap_object(self):
-        self.unicode = self.space.unicode_w(self.w_string)
-        return len(self.unicode)
+    def group_w(self, args_w):
+        space = self.space
+        ctx = self.ctx
+        if len(args_w) <= 1:
+            if len(args_w) == 0:
+                start, end = ctx.match_start, ctx.match_end
+            else:
+                start, end = self.do_span(args_w[0])
+            return slice_w(space, ctx, start, end, space.w_None)
+        else:
+            results = [None] * len(args_w)
+            for i in range(len(args_w)):
+                start, end = self.do_span(args_w[i])
+                results[i] = slice_w(space, ctx, start, end, space.w_None)
+            return space.newtuple(results)
+    group_w.unwrap_spec = ['self', 'args_w']
+
+    def groups_w(self, w_default=None):
+        fmarks = self.flatten_marks()
+        num_groups = self.srepat.num_groups
+        return allgroups_w(self.space, self.ctx, fmarks, num_groups, w_default)
 
-    def get_char_ord(self, p):
-        return ord(self.unicode[p])
+    def groupdict_w(self, w_default=None):
+        space = self.space
+        w_dict = space.newdict()
+        w_groupindex = self.srepat.w_groupindex
+        w_iterator = space.iter(w_groupindex)
+        while True:
+            try:
+                w_key = space.next(w_iterator)
+            except OperationError, e:
+                if not e.match(space, space.w_StopIteration):
+                    raise
+                break  # done
+            w_value = space.getitem(w_groupindex, w_key)
+            start, end = self.do_span(w_value)
+            w_grp = slice_w(space, self.ctx, start, end, w_default)
+            space.setitem(w_dict, w_key, w_grp)
+        return w_dict
 
+    def expand_w(self, w_template):
+        space = self.space
+        w_re = import_re(space)
+        return space.call_method(w_re, '_expand', space.wrap(self.srepat),
+                                 space.wrap(self), w_template)
+
+    def start_w(self, w_groupnum=0):
+        return self.space.wrap(self.do_span(w_groupnum)[0])
+
+    def end_w(self, w_groupnum=0):
+        return self.space.wrap(self.do_span(w_groupnum)[1])
+
+    def span_w(self, w_groupnum=0):
+        start, end = self.do_span(w_groupnum)
+        return self.space.newtuple([self.space.wrap(start),
+                                    self.space.wrap(end)])
+
+    def flatten_marks(self):
+        if self.flatten_cache is None:
+            num_groups = self.srepat.num_groups
+            self.flatten_cache = do_flatten_marks(self.ctx, num_groups)
+        return self.flatten_cache
 
-class W_GenericState(W_State):
-    if THREE_VERSIONS_OF_CORE:
-        rsre.insert_sre_methods(locals(), 'generic')
+    def do_span(self, w_arg):
+        space = self.space
+        try:
+            groupnum = space.int_w(w_arg)
+        except OperationError, e:
+            if not e.match(space, space.w_TypeError):
+                raise
+            w_groupnum = space.getitem(self.srepat.w_groupindex, w_arg)
+            groupnum = space.int_w(w_groupnum)
+        if groupnum == 0:
+            return self.ctx.match_start, self.ctx.match_end
+        elif 1 <= groupnum <= self.srepat.num_groups:
+            fmarks = self.flatten_marks()
+            idx = 2*(groupnum-1)
+            assert idx >= 0
+            return fmarks[idx], fmarks[idx+1]
+        else:
+            raise OperationError(space.w_IndexError,
+                                 space.wrap("group index out of range"))
+
+    def _last_index(self):
+        mark = self.ctx.match_marks
+        if mark is not None:
+            return mark.gid // 2 + 1
+        return -1
+
+    def fget_lastgroup(space, self):
+        lastindex = self._last_index()
+        if lastindex < 0:
+            return space.w_None
+        w_result = space.finditem(self.srepat.w_indexgroup,
+                                  space.wrap(lastindex))
+        if w_result is None:
+            return space.w_None
+        return w_result
+
+    def fget_lastindex(space, self):
+        lastindex = self._last_index()
+        if lastindex >= 0:
+            return space.wrap(lastindex)
+        return space.w_None
 
-    def unwrap_object(self):
-        self.buffer = self.space.buffer_w(self.w_string)
-        return self.buffer.getlength()
+    def fget_pos(space, self):
+        return space.wrap(self.ctx.original_pos)
 
-    def get_char_ord(self, p):
-        return ord(self.buffer.getitem(p))
+    def fget_endpos(space, self):
+        return space.wrap(self.ctx.end)
 
+    def fget_regs(space, self):
+        space = self.space
+        fmarks = self.flatten_marks()
+        num_groups = self.srepat.num_groups
+        result_w = [None] * (num_groups + 1)
+        ctx = self.ctx
+        result_w[0] = space.newtuple([space.wrap(ctx.match_start),
+                                      space.wrap(ctx.match_end)])
+        for i in range(num_groups):
+            result_w[i + 1] = space.newtuple([space.wrap(fmarks[i*2]),
+                                              space.wrap(fmarks[i*2+1])])
+        return space.newtuple(result_w)
+
+    def fget_string(space, self):
+        return self.ctx._w_string(space)
+
+
+W_SRE_Match.typedef = TypeDef(
+    'SRE_Match',
+    __copy__     = interp2app(W_SRE_Match.cannot_copy_w),
+    __deepcopy__ = interp2app(W_SRE_Match.cannot_copy_w),
+    group        = interp2app(W_SRE_Match.group_w),
+    groups       = interp2app(W_SRE_Match.groups_w),
+    groupdict    = interp2app(W_SRE_Match.groupdict_w),
+    start        = interp2app(W_SRE_Match.start_w),
+    end          = interp2app(W_SRE_Match.end_w),
+    span         = interp2app(W_SRE_Match.span_w),
+    expand       = interp2app(W_SRE_Match.expand_w),
+    #
+    re           = interp_attrproperty('srepat', W_SRE_Match),
+    string       = GetSetProperty(W_SRE_Match.fget_string),
+    pos          = GetSetProperty(W_SRE_Match.fget_pos),
+    endpos       = GetSetProperty(W_SRE_Match.fget_endpos),
+    lastgroup    = GetSetProperty(W_SRE_Match.fget_lastgroup),
+    lastindex    = GetSetProperty(W_SRE_Match.fget_lastindex),
+    regs         = GetSetProperty(W_SRE_Match.fget_regs),
+)
 
-def w_search(space, w_state, w_pattern_codes):
-    state = space.interp_w(W_State, w_state)
-    pattern_codes = [intmask(space.uint_w(code)) for code
-                                    in space.unpackiterable(w_pattern_codes)]
-    try:
-        res = state.search(pattern_codes)
-    except RuntimeError:
-        raise OperationError(space.w_RuntimeError,
-                             space.wrap("Internal re error"))
-    return space.newbool(res)
-
-def w_match(space, w_state, w_pattern_codes):
-    state = space.interp_w(W_State, w_state)
-    pattern_codes = [intmask(space.uint_w(code)) for code
-                                    in space.unpackiterable(w_pattern_codes)]
-    try:
-        res = state.match(pattern_codes)
-    except RuntimeError:
-        raise OperationError(space.w_RuntimeError,
-                             space.wrap("Internal re error"))
-    return space.newbool(res)
+# ____________________________________________________________
+#
+# SRE_Scanner class
+# This is mostly an internal class in CPython.
+# Our version is also directly iterable, to make finditer() easier.
+
+class W_SRE_Scanner(Wrappable):
+
+    def __init__(self, pattern, ctx):
+        self.space = pattern.space
+        self.srepat = pattern
+        self.ctx = ctx
+        # 'self.ctx' is always a fresh context in which no searching
+        # or matching succeeded so far.
+
+    def iter_w(self):
+        return self.space.wrap(self)
+
+    def next_w(self):
+        if self.ctx.match_start > self.ctx.end:
+            raise OperationError(self.space.w_StopIteration, self.space.w_None)
+        if not searchcontext(self.space, self.ctx):
+            raise OperationError(self.space.w_StopIteration, self.space.w_None)
+        return self.getmatch(True)
+
+    def match_w(self):
+        if self.ctx.match_start > self.ctx.end:
+            return self.space.w_None
+        return self.getmatch(matchcontext(self.space, self.ctx))
+
+    def search_w(self):
+        if self.ctx.match_start > self.ctx.end:
+            return self.space.w_None
+        return self.getmatch(searchcontext(self.space, self.ctx))
+
+    def getmatch(self, found):
+        if found:
+            ctx = self.ctx
+            nextstart = ctx.match_end
+            nextstart += (ctx.match_start == nextstart)
+            self.ctx = ctx.fresh_copy(nextstart)
+            match = W_SRE_Match(self.srepat, ctx)
+            return self.space.wrap(match)
+        else:
+            self.ctx.match_start += 1     # obscure corner case
+            return None
+
+W_SRE_Scanner.typedef = TypeDef(
+    'SRE_Scanner',
+    __iter__ = interp2app(W_SRE_Scanner.iter_w,   unwrap_spec=['self']),
+    next     = interp2app(W_SRE_Scanner.next_w,   unwrap_spec=['self']),
+    match    = interp2app(W_SRE_Scanner.match_w,  unwrap_spec=['self']),
+    search   = interp2app(W_SRE_Scanner.search_w, unwrap_spec=['self']),
+    pattern  = interp_attrproperty('srepat', W_SRE_Scanner),
+)

Modified: pypy/branch/fast-forward/pypy/module/_sre/test/test_app_sre.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_sre/test/test_app_sre.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_sre/test/test_app_sre.py	Thu Sep  9 01:00:13 2010
@@ -33,8 +33,8 @@
         # copy support is disabled by default in _sre.c
         import re
         p = re.compile("b")
-        raises(TypeError, p.__copy__)
-        raises(TypeError, p.__deepcopy__)
+        raises(TypeError, p.__copy__)        # p.__copy__() should raise
+        raises(TypeError, p.__deepcopy__)    # p.__deepcopy__() should raise
 
     def test_creation_attributes(self):
         import re
@@ -85,9 +85,15 @@
         assert ['', 'a', None, 'l', 'u', None, 'lla'] == (
             re.split("b([ua]|(s))", "balbulla"))
 
+    def test_weakref(self):
+        import re, _weakref
+        _weakref.ref(re.compile(r""))
 
-class AppTestSreMatch:
 
+class AppTestSreMatch:
+    def setup_class(cls):
+        cls.space = gettestobjspace(usemodules=('array', ))
+        
     def test_copy(self):
         import re
         # copy support is disabled by default in _sre.c
@@ -200,6 +206,20 @@
             return ret
         assert ("bbbbb", 3) == re.subn("a", call_me, "ababa")
 
+    def test_sub_callable_returns_none(self):
+        import re
+        def call_me(match):
+            return None
+        assert "acd" == re.sub("b", call_me, "abcd")
+
+    def test_sub_callable_suddenly_unicode(self):
+        import re
+        def call_me(match):
+            if match.group() == 'A':
+                return unichr(0x3039)
+            return ''
+        assert (u"bb\u3039b", 2) == re.subn("[aA]", call_me, "babAb")
+
     def test_match_array(self):
         import re, array
         a = array.array('c', 'hello')
@@ -266,6 +286,18 @@
                                     p.match().group(0), p.match().group(0))
         assert None == p.match()
 
+    def test_scanner_match_detail(self):
+        import re
+        p = re.compile("a").scanner("aaXaa")
+        assert "a" == p.match().group(0)
+        assert "a" == p.match().group(0)
+        assert None == p.match()
+        assert "a" == p.match().group(0)
+        assert "a" == p.match().group(0)
+        assert None == p.match()
+        assert None == p.match()
+        assert None == p.match()
+
     def test_scanner_search(self):
         import re
         p = re.compile("\d").scanner("bla23c5a")
@@ -651,69 +683,6 @@
             s.ATCODES["at_uni_non_boundary"], s.OPCODES["success"]]
         s.assert_match(opcodes, ["blaha", u"bl%sja" % UPPER_PI])
 
-    def test_category_digit(self):
-        INDIAN_DIGIT = u"\u0966"
-        opcodes = [s.OPCODES["category"], s.CHCODES["category_digit"]] \
-            + s.encode_literal("b") + [s.OPCODES["success"]]
-        s.assert_match(opcodes, ["1b", "a1b"])
-        s.assert_no_match(opcodes, ["bb", "b1", u"%sb" % INDIAN_DIGIT])
-
-    def test_category_not_digit(self):
-        INDIAN_DIGIT = u"\u0966"
-        opcodes = [s.OPCODES["category"], s.CHCODES["category_not_digit"]] \
-            + s.encode_literal("b") + [s.OPCODES["success"]]
-        s.assert_match(opcodes, ["bb", "1ab", u"%sb" % INDIAN_DIGIT])
-        s.assert_no_match(opcodes, ["1b", "a1b"])
-
-    def test_category_space(self):
-        EM_SPACE = u"\u2001"
-        opcodes = s.encode_literal("b") \
-             + [s.OPCODES["category"], s.CHCODES["category_space"], s.OPCODES["success"]]
-        s.assert_match(opcodes, ["b ", "b\n", "b\t", "b\r", "b\v", "b\f"])
-        s.assert_no_match(opcodes, ["bb", "b1", u"b%s" % EM_SPACE])
-
-    def test_category_not_space(self):
-        EM_SPACE = u"\u2001"
-        opcodes = s.encode_literal("b") \
-             + [s.OPCODES["category"], s.CHCODES["category_not_space"], s.OPCODES["success"]]
-        s.assert_match(opcodes, ["bb", "b1", u"b%s" % EM_SPACE])
-        s.assert_no_match(opcodes, ["b ", "b\n", "b\t", "b\r", "b\v", "b\f"])
-
-    def test_category_word(self):
-        LOWER_PI = u"\u03c0"
-        opcodes = s.encode_literal("b") \
-             + [s.OPCODES["category"], s.CHCODES["category_word"], s.OPCODES["success"]]
-        s.assert_match(opcodes, ["bl", "b4", "b_"])
-        s.assert_no_match(opcodes, ["b ", "b\n", u"b%s" % LOWER_PI])
-
-    def test_category_not_word(self):
-        LOWER_PI = u"\u03c0"
-        opcodes = s.encode_literal("b") \
-             + [s.OPCODES["category"], s.CHCODES["category_not_word"], s.OPCODES["success"]]
-        s.assert_match(opcodes, ["b ", "b\n", u"b%s" % LOWER_PI])
-        s.assert_no_match(opcodes, ["bl", "b4", "b_"])
-
-    def test_category_linebreak(self):
-        LINE_SEP = u"\u2028"
-        opcodes = s.encode_literal("b") \
-             + [s.OPCODES["category"], s.CHCODES["category_linebreak"], s.OPCODES["success"]]
-        s.assert_match(opcodes, ["b\n"])
-        s.assert_no_match(opcodes, ["b ", "bs", "b\r", u"b%s" % LINE_SEP])
-        opcodes = s.encode_literal("b") \
-             + [s.OPCODES["category"], s.CHCODES["category_uni_linebreak"], s.OPCODES["success"]]
-        s.assert_match(opcodes, ["b\n", u"b%s" % LINE_SEP])
-
-    def test_category_not_linebreak(self):
-        LINE_SEP = u"\u2028"
-        opcodes = s.encode_literal("b") \
-             + [s.OPCODES["category"], s.CHCODES["category_not_linebreak"], s.OPCODES["success"]]
-        s.assert_match(opcodes, ["b ", "bs", u"b%s" % LINE_SEP])
-        s.assert_no_match(opcodes, ["b\n"])
-        opcodes = s.encode_literal("b") \
-             + [s.OPCODES["category"], s.CHCODES["category_uni_not_linebreak"], s.OPCODES["success"]]
-        s.assert_match(opcodes, ["b ", "bs"])
-        s.assert_no_match(opcodes, ["b\n", u"b%s" % LINE_SEP, "b\r"])
-
     def test_category_loc_word(self):
         import locale
         try:
@@ -871,10 +840,6 @@
         s.assert_match(opcodes, ["ab", "aaaab", "baabb"])
         s.assert_no_match(opcodes, ["aaa", "", "ac"])
 
-    def test_max_until_error(self):
-        opcodes = [s.OPCODES["max_until"], s.OPCODES["success"]]
-        raises(RuntimeError, s.search, opcodes, "a")
-
     def test_max_until_zero_width_match(self):
         # re.compile won't compile prospective zero-with matches (all of them?),
         # so we can only produce an example by directly constructing bytecodes.
@@ -894,10 +859,6 @@
         s.assert_no_match(opcodes, ["b"])
         assert "aab" == s.search(opcodes, "aabb").group(0)
 
-    def test_min_until_error(self):
-        opcodes = [s.OPCODES["min_until"], s.OPCODES["success"]]
-        raises(RuntimeError, s.search, opcodes, "a")
-
     def test_groupref(self):
         opcodes = [s.OPCODES["mark"], 0, s.OPCODES["any"], s.OPCODES["mark"], 1] \
             + s.encode_literal("a") + [s.OPCODES["groupref"], 0, s.OPCODES["success"]]

Modified: pypy/branch/fast-forward/pypy/module/_stackless/interp_coroutine.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_stackless/interp_coroutine.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_stackless/interp_coroutine.py	Thu Sep  9 01:00:13 2010
@@ -265,10 +265,14 @@
             instr += 1
             oparg = ord(code[instr]) | ord(code[instr + 1]) << 8
             nargs = oparg & 0xff
+            nkwds = (oparg >> 8) & 0xff
             if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']:
-                chain = resume_state_create(chain, 'CALL_METHOD', frame,
-                                            nargs)
-            elif opcode == map['CALL_FUNCTION'] and (oparg >> 8) & 0xff == 0:
+                if nkwds == 0:     # only positional arguments
+                    chain = resume_state_create(chain, 'CALL_METHOD', frame,
+                                                nargs)
+                else:              # includes keyword arguments
+                    chain = resume_state_create(chain, 'CALL_METHOD_KW', frame)
+            elif opcode == map['CALL_FUNCTION'] and nkwds == 0:
                 # Only positional arguments
                 # case1: ("CALL_FUNCTION", f, nargs, returns=w_result)
                 chain = resume_state_create(chain, 'CALL_FUNCTION', frame,

Modified: pypy/branch/fast-forward/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/api.py	Thu Sep  9 01:00:13 2010
@@ -1,5 +1,5 @@
 import ctypes
-import sys
+import sys, os
 import atexit
 
 import py
@@ -62,11 +62,15 @@
 
 VA_LIST_P = rffi.VOIDP # rffi.COpaquePtr('va_list')
 CONST_STRING = lltype.Ptr(lltype.Array(lltype.Char,
-                                       hints={'nolength': True}))
+                                       hints={'nolength': True}),
+                          use_cache=False)
 CONST_WSTRING = lltype.Ptr(lltype.Array(lltype.UniChar,
-                                        hints={'nolength': True}))
+                                        hints={'nolength': True}),
+                           use_cache=False)
 assert CONST_STRING is not rffi.CCHARP
+assert CONST_STRING == rffi.CCHARP
 assert CONST_WSTRING is not rffi.CWCHARP
+assert CONST_WSTRING == rffi.CWCHARP
 
 # FILE* interface
 FILEP = rffi.COpaquePtr('FILE')
@@ -896,6 +900,8 @@
 initfunctype = lltype.Ptr(lltype.FuncType([], lltype.Void))
 @unwrap_spec(ObjSpace, str, str)
 def load_extension_module(space, path, name):
+    if os.sep not in path:
+        path = os.curdir + os.sep + path      # force a '/' in the path
     state = space.fromcache(State)
     state.package_context = name
     try:

Modified: pypy/branch/fast-forward/pypy/module/cpyext/methodobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/methodobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/methodobject.py	Thu Sep  9 01:00:13 2010
@@ -100,7 +100,11 @@
             return generic_cpy_call(space, self.ml.c_ml_meth, w_self, w_arg)
 
     def get_doc(space, self):
-        return space.wrap(rffi.charp2str(self.ml.c_ml_doc))
+        doc = self.ml.c_ml_doc
+        if doc:
+            return space.wrap(rffi.charp2str(doc))
+        else:
+            return space.w_None
 
 
 class W_PyCMethodObject(W_PyCFunctionObject):

Modified: pypy/branch/fast-forward/pypy/module/cpyext/stubs.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/stubs.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/stubs.py	Thu Sep  9 01:00:13 2010
@@ -2874,36 +2874,6 @@
     """
     raise NotImplementedError
 
- at cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP, rffi.INTP], PyObject)
-def PyUnicode_DecodeUTF16(space, s, size, errors, byteorder):
-    """Decode length bytes from a UTF-16 encoded buffer string and return the
-    corresponding Unicode object.  errors (if non-NULL) defines the error
-    handling. It defaults to "strict".
-    
-    If byteorder is non-NULL, the decoder starts decoding using the given byte
-    order:
-    
-    *byteorder == -1: little endian
-    *byteorder == 0:  native order
-    *byteorder == 1:  big endian
-    
-    If *byteorder is zero, and the first two bytes of the input data are a
-    byte order mark (BOM), the decoder switches to this byte order and the BOM is
-    not copied into the resulting Unicode string.  If *byteorder is -1 or
-    1, any byte order mark is copied to the output (where it will result in
-    either a \ufeff or a \ufffe character).
-    
-    After completion, *byteorder is set to the current byte order at the end
-    of input data.
-    
-    If byteorder is NULL, the codec starts in native order mode.
-    
-    Return NULL if an exception was raised by the codec.
-    
-    This function used an int type for size. This might require
-    changes in your code for properly supporting 64-bit systems."""
-    raise NotImplementedError
-
 @cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP, rffi.INTP, Py_ssize_t], PyObject)
 def PyUnicode_DecodeUTF16Stateful(space, s, size, errors, byteorder, consumed):
     """If consumed is NULL, behave like PyUnicode_DecodeUTF16(). If

Modified: pypy/branch/fast-forward/pypy/module/cpyext/test/test_unicodeobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/test/test_unicodeobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/test/test_unicodeobject.py	Thu Sep  9 01:00:13 2010
@@ -172,4 +172,37 @@
         result = api.PyUnicode_AsASCIIString(w_ustr)
         assert result is None
 
+    def test_decode_utf16(self, space, api):
+        def test(encoded, endian, realendian=None):
+            encoded_charp = rffi.str2charp(encoded)
+            strict_charp = rffi.str2charp("strict")
+            if endian is not None:
+                pendian = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+                if endian < 0:
+                    pendian[0] = -1
+                elif endian > 0:
+                    pendian[0] = 1
+                else:
+                    pendian[0] = 0
+            else:
+                pendian = None
 
+            w_ustr = api.PyUnicode_DecodeUTF16(encoded_charp, len(encoded), strict_charp, pendian)
+            assert space.eq_w(space.call_method(w_ustr, 'encode', space.wrap('ascii')),
+                              space.wrap("abcd"))
+
+            rffi.free_charp(encoded_charp)
+            rffi.free_charp(strict_charp)
+            if pendian:
+                if realendian is not None:
+                    assert rffi.cast(rffi.INT, realendian) == pendian[0]
+                lltype.free(pendian, flavor='raw')
+
+        test("\x61\x00\x62\x00\x63\x00\x64\x00", -1)
+
+        test("\x61\x00\x62\x00\x63\x00\x64\x00", None)
+
+        test("\x00\x61\x00\x62\x00\x63\x00\x64", 1)
+
+        test("\xFE\xFF\x00\x61\x00\x62\x00\x63\x00\x64", 0, 1)
+        test("\xFF\xFE\x61\x00\x62\x00\x63\x00\x64\x00", 0, -1)

Modified: pypy/branch/fast-forward/pypy/module/cpyext/unicodeobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/unicodeobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/unicodeobject.py	Thu Sep  9 01:00:13 2010
@@ -9,6 +9,7 @@
 from pypy.module.cpyext.pyobject import PyObject, from_ref, make_typedescr
 from pypy.module.sys.interp_encoding import setdefaultencoding
 from pypy.objspace.std import unicodeobject, unicodetype
+from pypy.rlib import runicode
 import sys
 
 ## See comment in stringobject.py.  PyUnicode_FromUnicode(NULL, size) is not
@@ -307,6 +308,64 @@
         w_errors = space.w_None
     return space.call_method(w_str, 'decode', space.wrap("utf-8"), w_errors)
 
+ at cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP, rffi.INTP], PyObject)
+def PyUnicode_DecodeUTF16(space, s, size, llerrors, pbyteorder):
+    """Decode length bytes from a UTF-16 encoded buffer string and return the
+    corresponding Unicode object.  errors (if non-NULL) defines the error
+    handling. It defaults to "strict".
+    
+    If byteorder is non-NULL, the decoder starts decoding using the given byte
+    order:
+    
+    *byteorder == -1: little endian
+    *byteorder == 0:  native order
+    *byteorder == 1:  big endian
+    
+    If *byteorder is zero, and the first two bytes of the input data are a
+    byte order mark (BOM), the decoder switches to this byte order and the BOM is
+    not copied into the resulting Unicode string.  If *byteorder is -1 or
+    1, any byte order mark is copied to the output (where it will result in
+    either a \ufeff or a \ufffe character).
+    
+    After completion, *byteorder is set to the current byte order at the end
+    of input data.
+    
+    If byteorder is NULL, the codec starts in native order mode.
+    
+    Return NULL if an exception was raised by the codec.
+    
+    This function used an int type for size. This might require
+    changes in your code for properly supporting 64-bit systems."""
+
+    string = rffi.charpsize2str(s, size)
+
+    #FIXME: I don't like these prefixes
+    if pbyteorder is not None: # correct NULL check?
+        llbyteorder = rffi.cast(lltype.Signed, pbyteorder[0]) # compatible with int?
+        if llbyteorder < 0:
+            byteorder = "little"
+        elif llbyteorder > 0:
+            byteorder = "big"
+        else:
+            byteorder = "native"
+    else:
+        byteorder = "native"
+
+    if llerrors:
+        errors = rffi.charp2str(llerrors)
+    else:
+        errors = None
+
+    result, length, byteorder = runicode.str_decode_utf_16_helper(string, size,
+                                           errors,
+                                           True, # final ? false for multiple passes?
+                                           None, # errorhandler
+                                           byteorder)
+    if pbyteorder is not None:
+        pbyteorder[0] = rffi.cast(rffi.INT, byteorder)
+
+    return space.wrap(result)
+
 @cpython_api([PyObject], PyObject)
 def PyUnicode_AsASCIIString(space, w_unicode):
     """Encode a Unicode object using ASCII and return the result as Python string

Modified: pypy/branch/fast-forward/pypy/module/fcntl/test/test_fcntl.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/fcntl/test/test_fcntl.py	(original)
+++ pypy/branch/fast-forward/pypy/module/fcntl/test/test_fcntl.py	Thu Sep  9 01:00:13 2010
@@ -13,7 +13,7 @@
 
 class AppTestFcntl:
     def setup_class(cls):
-        space = gettestobjspace(usemodules=('fcntl',))
+        space = gettestobjspace(usemodules=('fcntl', 'array'))
         cls.space = space
         tmpprefix = str(udir.ensure('test_fcntl', dir=1).join('tmp_'))
         cls.w_tmp = space.wrap(tmpprefix)

Modified: pypy/branch/fast-forward/pypy/module/marshal/test/test_marshalimpl.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/marshal/test/test_marshalimpl.py	(original)
+++ pypy/branch/fast-forward/pypy/module/marshal/test/test_marshalimpl.py	Thu Sep  9 01:00:13 2010
@@ -1,9 +1,13 @@
 from pypy.module.marshal import interp_marshal
 from pypy.interpreter.error import OperationError
+from pypy.conftest import gettestobjspace
 import sys
 
 
 class AppTestMarshalMore:
+    def setup_class(cls):
+        space = gettestobjspace(usemodules=('array',))
+        cls.space = space
 
     def test_long_0(self):
         import marshal

Modified: pypy/branch/fast-forward/pypy/module/posix/interp_posix.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/posix/interp_posix.py	(original)
+++ pypy/branch/fast-forward/pypy/module/posix/interp_posix.py	Thu Sep  9 01:00:13 2010
@@ -1,8 +1,9 @@
 from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped
 from pypy.rlib import rposix, objectmodel
+from pypy.rlib.objectmodel import specialize
 from pypy.rlib.rarithmetic import r_longlong
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.interpreter.error import OperationError, wrap_oserror
+from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2
 from pypy.rpython.module.ll_os import RegisterOs
 from pypy.rpython.module import ll_os_stat
 from pypy.rpython.lltypesystem import rffi, lltype
@@ -12,15 +13,78 @@
 import os, sys
 _WIN = sys.platform == 'win32'
 
-def open(space, fname, flag, mode=0777):
+class FileEncoder:
+    def __init__(self, space, w_obj):
+        self.space = space
+        self.w_obj = w_obj
+
+    def as_bytes(self):
+        from pypy.module.sys.interp_encoding import getfilesystemencoding
+        space = self.space
+        w_bytes = space.call_method(self.w_obj, 'encode',
+                                    getfilesystemencoding(space))
+        return space.str_w(w_bytes)
+
+    def as_unicode(self):
+        return self.space.unicode_w(self.w_obj)
+
+class FileDecoder:
+    def __init__(self, space, w_obj):
+        self.space = space
+        self.w_obj = w_obj
+
+    def as_bytes(self):
+        return self.space.str_w(self.w_obj)
+
+    def as_unicode(self):
+        from pypy.module.sys.interp_encoding import getfilesystemencoding
+        space = self.space
+        w_unicode = space.call_method(self.w_obj, 'decode',
+                                      getfilesystemencoding(space))
+        return space.unicode_w(w_unicode)
+
+ at specialize.memo()
+def dispatch_filename(func, tag=0):
+    def dispatch(space, w_fname, *args):
+        if space.isinstance_w(w_fname, space.w_unicode):
+            fname = FileEncoder(space, w_fname)
+            return func(fname, *args)
+        else:
+            fname = space.str_w(w_fname)
+            return func(fname, *args)
+    return dispatch
+
+ at specialize.memo()
+def dispatch_filename_2(func):
+    def dispatch(space, w_fname1, w_fname2, *args):
+        if space.isinstance_w(w_fname1, space.w_unicode):
+            fname1 = FileEncoder(space, w_fname1)
+            if space.isinstance_w(w_fname2, space.w_unicode):
+                fname2 = FileEncoder(space, w_fname2)
+                return func(fname1, fname2, *args)
+            else:
+                fname2 = FileDecoder(space, w_fname2)
+                return func(fname1, fname2, *args)
+        else:
+            fname1 = FileDecoder(space, w_fname1)
+            if space.isinstance_w(w_fname2, space.w_unicode):
+                fname2 = FileEncoder(space, w_fname2)
+                return func(fname1, fname2, *args)
+            else:
+                fname2 = FileDecoder(space, w_fname2)
+                return func(fname1, fname2, *args)
+    return dispatch
+
+def open(space, w_fname, flag, mode=0777):
     """Open a file (for low level IO).
 Return a file descriptor (a small integer)."""
-    try: 
-        fd = os.open(fname, flag, mode)
+    try:
+        fd = dispatch_filename(rposix.open)(
+            space, w_fname, flag, mode)
     except OSError, e: 
-        raise wrap_oserror(space, e, fname)
+        raise wrap_oserror2(space, e, w_fname)
     return space.wrap(fd)
-open.unwrap_spec = [ObjSpace, 'path', "c_int", "c_int"]
+open.unwrap_spec = [ObjSpace, W_Root, "c_int", "c_int"]
 
 def lseek(space, fd, pos, how):
     """Set the current position of a file descriptor.  Return the new position.
@@ -167,7 +231,7 @@
         return build_stat_result(space, st)
 fstat.unwrap_spec = [ObjSpace, "c_int"]
 
-def stat(space, path):
+def stat(space, w_path):
     """Perform a stat system call on the given path.  Return an object
 with (at least) the following attributes:
     st_mode
@@ -183,22 +247,22 @@
 """
 
     try:
-        st = os.stat(path)
+        st = dispatch_filename(rposix.stat)(space, w_path)
     except OSError, e: 
-        raise wrap_oserror(space, e, path)
+        raise wrap_oserror2(space, e, w_path)
     else: 
         return build_stat_result(space, st)
-stat.unwrap_spec = [ObjSpace, 'path']
+stat.unwrap_spec = [ObjSpace, W_Root]
 
-def lstat(space, path):
+def lstat(space, w_path):
     "Like stat(path), but do no follow symbolic links."
     try:
-        st = os.lstat(path)
+        st = dispatch_filename(rposix.lstat)(space, w_path)
     except OSError, e:
-        raise wrap_oserror(space, e, path)
+        raise wrap_oserror2(space, e, w_path)
     else:
         return build_stat_result(space, st)
-lstat.unwrap_spec = [ObjSpace, 'path']
+lstat.unwrap_spec = [ObjSpace, W_Root]
 
 class StatState(object):
     def __init__(self, space):
@@ -239,7 +303,7 @@
         raise wrap_oserror(space, e) 
 dup2.unwrap_spec = [ObjSpace, "c_int", "c_int"]
 
-def access(space, path, mode):
+def access(space, w_path, mode):
     """
     access(path, mode) -> 1 if granted, 0 otherwise
 
@@ -250,12 +314,12 @@
     existence, or the inclusive-OR of R_OK, W_OK, and X_OK.
     """
     try:
-        ok = os.access(path, mode)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
+        ok = dispatch_filename(rposix.access)(space, w_path, mode)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
     else:
         return space.wrap(ok)
-access.unwrap_spec = [ObjSpace, str, "c_int"]
+access.unwrap_spec = [ObjSpace, W_Root, "c_int"]
 
 
 def times(space):
@@ -286,32 +350,38 @@
         return space.wrap(rc)
 system.unwrap_spec = [ObjSpace, str]
 
-def unlink(space, path):
+def unlink(space, w_path):
     """Remove a file (same as remove(path))."""
     try:
-        os.unlink(path)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-unlink.unwrap_spec = [ObjSpace, 'path']
+        dispatch_filename(rposix.unlink)(space, w_path)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+unlink.unwrap_spec = [ObjSpace, W_Root]
 
-def remove(space, path):
+def remove(space, w_path):
     """Remove a file (same as unlink(path))."""
     try:
-        os.unlink(path)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-remove.unwrap_spec = [ObjSpace, 'path']
+        dispatch_filename(rposix.unlink)(space, w_path)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+remove.unwrap_spec = [ObjSpace, W_Root]
 
-def _getfullpathname(space, path):
+def _getfullpathname(space, w_path):
     """helper for ntpath.abspath """
-    posix = __import__(os.name) # nt specific
     try:
-        fullpath = posix._getfullpathname(path)
+        if space.isinstance_w(w_path, space.w_unicode):
+            path = FileEncoder(space, w_path)
+            fullpath = rposix._getfullpathname(path)
+            w_fullpath = space.wrap(fullpath)
+        else:
+            path = space.str_w(w_path)
+            fullpath = rposix._getfullpathname(path)
+            w_fullpath = space.wrap(fullpath)
     except OSError, e:
-        raise wrap_oserror(space, e, path)
-    else: 
-        return space.wrap(fullpath)
-_getfullpathname.unwrap_spec = [ObjSpace, str]
+        raise wrap_oserror2(space, e, w_path)
+    else:
+        return w_fullpath
+_getfullpathname.unwrap_spec = [ObjSpace, W_Root]
 
 def getcwd(space):
     """Return the current working directory."""
@@ -323,35 +393,46 @@
         return space.wrap(cur)
 getcwd.unwrap_spec = [ObjSpace]
 
-def getcwdu(space):
-    """Return the current working directory as a unicode string."""
-    # XXX ascii encoding for now
-    return space.call_method(getcwd(space), 'decode')
+if sys.platform == 'win32':
+    def getcwdu(space):
+        """Return the current working directory as a unicode string."""
+        try:
+            cur = os.getcwdu()
+        except OSError, e:
+            raise wrap_oserror(space, e)
+        else:
+            return space.wrap(cur)
+else:
+    def getcwdu(space):
+        """Return the current working directory as a unicode string."""
+        filesystemencoding = space.sys.filesystemencoding
+        return space.call_method(getcwd(space), 'decode',
+                                 space.wrap(filesystemencoding))
 getcwdu.unwrap_spec = [ObjSpace]
 
-def chdir(space, path):
+def chdir(space, w_path):
     """Change the current working directory to the specified path."""
     try:
-        os.chdir(path)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-chdir.unwrap_spec = [ObjSpace, str]
+        dispatch_filename(rposix.chdir)(space, w_path)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+chdir.unwrap_spec = [ObjSpace, W_Root]
 
-def mkdir(space, path, mode=0777):
+def mkdir(space, w_path, mode=0777):
     """Create a directory."""
     try:
-        os.mkdir(path, mode)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-mkdir.unwrap_spec = [ObjSpace, str, "c_int"]
+        dispatch_filename(rposix.mkdir)(space, w_path, mode)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+mkdir.unwrap_spec = [ObjSpace, W_Root, "c_int"]
 
-def rmdir(space, path):
+def rmdir(space, w_path):
     """Remove a directory."""
     try:
-        os.rmdir(path)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-rmdir.unwrap_spec = [ObjSpace, str]
+        dispatch_filename(rposix.rmdir)(space, w_path)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+rmdir.unwrap_spec = [ObjSpace, W_Root]
 
 def strerror(space, errno):
     """Translate an error code to a message string."""
@@ -418,7 +499,7 @@
 unsetenv.unwrap_spec = [ObjSpace, str]
 
 
-def listdir(space, dirname):
+def listdir(space, w_dirname):
     """Return a list containing the names of the entries in the directory.
 
 \tpath: path of directory to list
@@ -426,12 +507,18 @@
 The list is in arbitrary order.  It does not include the special
 entries '.' and '..' even if they are present in the directory."""
     try:
-        result = os.listdir(dirname)
+        if space.isinstance_w(w_dirname, space.w_unicode):
+            dirname = FileEncoder(space, w_dirname)
+            result = rposix.listdir(dirname)
+            result_w = [space.wrap(s) for s in result]
+        else:
+            dirname = space.str_w(w_dirname)
+            result = rposix.listdir(dirname)
+            result_w = [space.wrap(s) for s in result]
     except OSError, e:
-        raise wrap_oserror(space, e, dirname)
-    result_w = [space.wrap(s) for s in result]
+        raise wrap_oserror2(space, e, w_dirname)
     return space.newlist(result_w)
-listdir.unwrap_spec = [ObjSpace, str]
+listdir.unwrap_spec = [ObjSpace, W_Root]
 
 def pipe(space):
     "Create a pipe.  Returns (read_end, write_end)."
@@ -442,21 +529,21 @@
     return space.newtuple([space.wrap(fd1), space.wrap(fd2)])
 pipe.unwrap_spec = [ObjSpace]
 
-def chmod(space, path, mode):
+def chmod(space, w_path, mode):
     "Change the access permissions of a file."
-    try: 
-        os.chmod(path, mode)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-chmod.unwrap_spec = [ObjSpace, str, "c_int"]
+    try:
+        dispatch_filename(rposix.chmod)(space, w_path, mode)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+chmod.unwrap_spec = [ObjSpace, W_Root, "c_int"]
 
-def rename(space, old, new):
+def rename(space, w_old, w_new):
     "Rename a file or directory."
-    try: 
-        os.rename(old, new)
-    except OSError, e: 
+    try:
+        dispatch_filename_2(rposix.rename)(space, w_old, w_new)
+    except OSError, e:
         raise wrap_oserror(space, e) 
-rename.unwrap_spec = [ObjSpace, str, str]
+rename.unwrap_spec = [ObjSpace, W_Root, W_Root]
 
 def umask(space, mask):
     "Set the current numeric umask and return the previous umask."
@@ -590,7 +677,7 @@
         raise wrap_oserror(space, e)
 execve.unwrap_spec = [ObjSpace, str, W_Root, W_Root]
 
-def utime(space, path, w_tuple):
+def utime(space, w_path, w_tuple):
     """ utime(path, (atime, mtime))
 utime(path, None)
 
@@ -599,10 +686,10 @@
     """
     if space.is_w(w_tuple, space.w_None):
         try:
-            os.utime(path, None)
+            dispatch_filename(rposix.utime, 1)(space, w_path, None)
             return
         except OSError, e:
-            raise wrap_oserror(space, e, path)
+            raise wrap_oserror2(space, e, w_path)
     try:
         msg = "utime() arg 2 must be a tuple (atime, mtime) or None"
         args_w = space.fixedview(w_tuple)
@@ -610,14 +697,14 @@
             raise OperationError(space.w_TypeError, space.wrap(msg))
         actime = space.float_w(args_w[0])
         modtime = space.float_w(args_w[1])
-        os.utime(path, (actime, modtime))
+        dispatch_filename(rposix.utime, 2)(space, w_path, (actime, modtime))
     except OSError, e:
-        raise wrap_oserror(space, e, path)
+        raise wrap_oserror2(space, e, w_path)
     except OperationError, e:
         if not e.match(space, space.w_TypeError):
             raise
         raise OperationError(space.w_TypeError, space.wrap(msg))
-utime.unwrap_spec = [ObjSpace, str, W_Root]
+utime.unwrap_spec = [ObjSpace, W_Root, W_Root]
 
 def setsid(space):
     """setsid() -> pid

Modified: pypy/branch/fast-forward/pypy/module/posix/test/test_posix2.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/posix/test/test_posix2.py	(original)
+++ pypy/branch/fast-forward/pypy/module/posix/test/test_posix2.py	Thu Sep  9 01:00:13 2010
@@ -32,6 +32,9 @@
     # even when running on top of CPython 2.4.
     os.stat_float_times(True)
 
+    # Initialize sys.filesystemencoding
+    space.call_method(space.getbuiltinmodule('sys'), 'getfilesystemencoding')
+
 def need_sparse_files():
     if sys.platform == 'darwin':
         py.test.skip("no sparse files on default Mac OS X file system")
@@ -322,15 +325,12 @@
     if hasattr(__import__(os.name), "openpty"):
         def test_openpty(self):
             os = self.posix
-            master_fd, slave_fd = self.posix.openpty()
-            try:
-                assert isinstance(master_fd, int)
-                assert isinstance(slave_fd, int)
-                os.write(slave_fd, 'x')
-                assert os.read(master_fd, 1) == 'x'
-            finally:
-                os.close(master_fd)
-                os.close(slave_fd)
+            master_fd, slave_fd = os.openpty()
+            assert isinstance(master_fd, int)
+            assert isinstance(slave_fd, int)
+            os.write(slave_fd, 'x\n')
+            data = os.read(master_fd, 100)
+            assert data.startswith('x')
 
 
     if hasattr(__import__(os.name), "execv"):
@@ -709,6 +709,28 @@
         except OSError:
             pass
 
+class AppTestUnicodeFilename:
+    def setup_class(cls):
+        ufilename = (unicode(udir.join('test_unicode_filename_')) +
+                     u'\u65e5\u672c.txt') # "Japan"
+        try:
+            f = file(ufilename, 'w')
+        except UnicodeEncodeError:
+            py.test.skip("encoding not good enough")
+        f.write("test")
+        f.close()
+        cls.space = space
+        cls.w_filename = space.wrap(ufilename)
+        cls.w_posix = space.appexec([], GET_POSIX)
+
+    def test_open(self):
+        fd = self.posix.open(self.filename, self.posix.O_RDONLY)
+        try:
+            content = self.posix.read(fd, 50)
+        finally:
+            self.posix.close(fd)
+        assert content == "test"
+
 
 class TestPexpect(object):
     # XXX replace with AppExpectTest class as soon as possible

Modified: pypy/branch/fast-forward/pypy/module/pypyjit/interp_jit.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/pypyjit/interp_jit.py	(original)
+++ pypy/branch/fast-forward/pypy/module/pypyjit/interp_jit.py	Thu Sep  9 01:00:13 2010
@@ -9,7 +9,7 @@
 import pypy.interpreter.pyopcode   # for side-effects
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import ObjSpace, Arguments
-from pypy.interpreter.pycode import PyCode, CO_CONTAINSLOOP
+from pypy.interpreter.pycode import PyCode, CO_GENERATOR
 from pypy.interpreter.pyframe import PyFrame
 from pypy.interpreter.pyopcode import ExitFrame
 from opcode import opmap
@@ -24,9 +24,6 @@
 
 JUMP_ABSOLUTE = opmap['JUMP_ABSOLUTE']
 
-def can_inline(next_instr, bytecode):
-    return not bool(bytecode.co_flags & CO_CONTAINSLOOP)
-
 def get_printable_location(next_instr, bytecode):
     from pypy.tool.stdlib_opcode import opcode_method_names
     name = opcode_method_names[ord(bytecode.co_code[next_instr])]
@@ -39,7 +36,8 @@
     bytecode.jit_cells[next_instr] = newcell
 
 def confirm_enter_jit(next_instr, bytecode, frame, ec):
-    return (frame.w_f_trace is None and
+    return (not (bytecode.co_flags & CO_GENERATOR) and
+            frame.w_f_trace is None and
             ec.profilefunc is None and
             ec.w_tracefunc is None)
 
@@ -57,8 +55,7 @@
 ##        blockstack = frame.blockstack
 ##        return (valuestackdepth, blockstack)
 
-pypyjitdriver = PyPyJitDriver(can_inline = can_inline,
-                              get_printable_location = get_printable_location,
+pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location,
                               get_jitcell_at = get_jitcell_at,
                               set_jitcell_at = set_jitcell_at,
                               confirm_enter_jit = confirm_enter_jit)

Modified: pypy/branch/fast-forward/pypy/module/pypyjit/policy.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/pypyjit/policy.py	(original)
+++ pypy/branch/fast-forward/pypy/module/pypyjit/policy.py	Thu Sep  9 01:00:13 2010
@@ -11,7 +11,7 @@
         if '.' in modname:
             modname, _ = modname.split('.', 1)
         if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions',
-                       'imp', 'sys']:
+                       'imp', 'sys', 'array']:
             return True
         return False
 
@@ -32,6 +32,8 @@
             return False
         if mod.startswith('pypy.interpreter.pyparser.'):
             return False
+        if mod == 'pypy.interpreter.generator':
+            return False
         if mod.startswith('pypy.module.'):
             modname = mod[len('pypy.module.'):]
             if not self.look_inside_pypy_module(modname):

Modified: pypy/branch/fast-forward/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/pypyjit/test/test_pypy_c.py	(original)
+++ pypy/branch/fast-forward/pypy/module/pypyjit/test/test_pypy_c.py	Thu Sep  9 01:00:13 2010
@@ -189,7 +189,7 @@
                 return r
         ''', 28,
                    ([5], 120),
-                    ([20], 2432902008176640000L))
+                    ([25], 15511210043330985984000000L))
 
     def test_factorialrec(self):
         self.run_source('''
@@ -200,7 +200,7 @@
                     return 1
         ''', 0,
                    ([5], 120),
-                    ([20], 2432902008176640000L))
+                    ([25], 15511210043330985984000000L))
 
     def test_richards(self):
         self.run_source('''
@@ -615,6 +615,237 @@
             return total
         ''', 170, ([], 4999450000L))
 
+    def test_boolrewrite_invers(self):
+        for a, b, res, ops in (('2000', '2000', 20001000, 51),
+                               ( '500',  '500', 15001500, 81),
+                               ( '300',  '600', 16001700, 83),
+                               (   'a',    'b', 16001700, 89),
+                               (   'a',    'a', 13001700, 85)):
+
+            self.run_source('''
+            def main():
+                sa = 0
+                a = 300
+                b = 600
+                for i in range(1000):
+                    if i < %s: sa += 1
+                    else: sa += 2
+                    if i >= %s: sa += 10000
+                    else: sa += 20000
+                return sa
+            '''%(a, b), ops, ([], res))
+
+    def test_boolrewrite_reflex(self):
+        for a, b, res, ops in (('2000', '2000', 10001000, 51),
+                               ( '500',  '500', 15001500, 81),
+                               ( '300',  '600', 14001700, 83),
+                               (   'a',    'b', 14001700, 89),
+                               (   'a',    'a', 17001700, 85)):
+
+            self.run_source('''
+            def main():
+                sa = 0
+                a = 300
+                b = 600
+                for i in range(1000):
+                    if i < %s: sa += 1
+                    else: sa += 2
+                    if %s > i: sa += 10000
+                    else: sa += 20000
+                return sa
+            '''%(a, b), ops, ([], res))
+
+
+    def test_boolrewrite_correct_invers(self):
+        def opval(i, op, a):
+            if eval('%d %s %d' % (i, op, a)): return 1
+            return 2
+
+        ops = ('<', '>', '<=', '>=', '==', '!=')        
+        for op1 in ops:
+            for op2 in ops:
+                for a,b in ((500, 500), (300, 600)):
+                    res = 0
+                    res += opval(a-1, op1, a) * (a)
+                    res += opval(  a, op1, a) 
+                    res += opval(a+1, op1, a) * (1000 - a - 1)
+                    res += opval(b-1, op2, b) * 10000 * (b)
+                    res += opval(  b, op2, b) * 10000 
+                    res += opval(b+1, op2, b) * 10000 * (1000 - b - 1)
+
+                    self.run_source('''
+                    def main():
+                        sa = 0
+                        for i in range(1000):
+                            if i %s %d: sa += 1
+                            else: sa += 2
+                            if i %s %d: sa += 10000
+                            else: sa += 20000
+                        return sa
+                    '''%(op1, a, op2, b), 83, ([], res))
+
+                    self.run_source('''
+                    def main():
+                        sa = 0
+                        i = 0.0
+                        while i < 250.0:
+                            if i %s %f: sa += 1
+                            else: sa += 2
+                            if i %s %f: sa += 10000
+                            else: sa += 20000
+                            i += 0.25
+                        return sa
+                    '''%(op1, float(a)/4.0, op2, float(b)/4.0), 109, ([], res))
+                    
+
+    def test_boolrewrite_correct_reflex(self):
+        def opval(i, op, a):
+            if eval('%d %s %d' % (i, op, a)): return 1
+            return 2
+
+        ops = ('<', '>', '<=', '>=', '==', '!=')        
+        for op1 in ops:
+            for op2 in ops:
+                for a,b in ((500, 500), (300, 600)):
+                    res = 0
+                    res += opval(a-1, op1, a) * (a)
+                    res += opval(  a, op1, a) 
+                    res += opval(a+1, op1, a) * (1000 - a - 1)
+                    res += opval(b, op2, b-1) * 10000 * (b)
+                    res += opval(b, op2,   b) * 10000
+                    res += opval(b, op2, b+1) * 10000 * (1000 - b - 1)
+
+                    self.run_source('''
+                    def main():
+                        sa = 0
+                        for i in range(1000):
+                            if i %s %d: sa += 1
+                            else: sa += 2
+                            if %d %s i: sa += 10000
+                            else: sa += 20000
+                        return sa
+                    '''%(op1, a, b, op2), 83, ([], res))
+
+                    self.run_source('''
+                    def main():
+                        sa = 0
+                        i = 0.0
+                        while i < 250.0:
+                            if i %s %f: sa += 1
+                            else: sa += 2
+                            if %f %s i: sa += 10000
+                            else: sa += 20000
+                            i += 0.25
+                        return sa
+                    '''%(op1, float(a)/4.0, float(b)/4.0, op2), 109, ([], res))
+
+    def test_boolrewrite_ptr(self):
+        compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b')
+        for e1 in compares:
+            for e2 in compares:
+                a, b, c = 1, 2, 3
+                if eval(e1): res = 752 * 1 
+                else: res = 752 * 2 
+                if eval(e2): res += 752 * 10000 
+                else: res += 752 * 20000 
+                a = b
+                if eval(e1): res += 248 * 1
+                else: res += 248 * 2
+                if eval(e2): res += 248 * 10000
+                else: res += 248 * 20000
+
+
+                if 'c' in e1 or 'c' in e2:
+                    n = 337
+                else:
+                    n = 215
+
+                self.run_source('''
+                class tst:
+                    pass
+                def main():
+                    a = tst()
+                    b = tst()
+                    c = tst()
+                    sa = 0
+                    for i in range(1000):
+                        if %s: sa += 1
+                        else: sa += 2
+                        if %s: sa += 10000
+                        else: sa += 20000
+                        if i > 750: a = b
+                    return sa
+                '''%(e1, e2), n, ([], res))
+
+    def test_array_sum(self):
+        for tc, maxops in zip('bhilBHILfd', (38,) * 6 + (40, 40, 41, 38)):
+            res = 19352859
+            if tc in 'IL':
+                res = long(res)
+            elif tc in 'fd':
+                res = float(res)
+            
+            self.run_source('''
+            from array import array
+
+            def main():
+                img = array("%s", range(127) * 5) * 484
+                l, i = 0, 0
+                while i < 640 * 480:
+                    l += img[i]
+                    i += 1
+                return l
+            ''' % tc, maxops, ([], res))
+
+    def test_array_sum_char(self):
+        self.run_source('''
+            from array import array
+
+            def main():
+                img = array("c", "Hello") * 130 * 480
+                l, i = 0, 0
+                while i < 640 * 480:
+                    l += ord(img[i])
+                    i += 1
+                return l
+            ''', 60, ([], 30720000))
+
+    def test_array_sum_unicode(self):
+        self.run_source('''
+            from array import array
+
+            def main():
+                img = array("u", u"Hello") * 130 * 480
+                l, i = 0, 0
+                while i < 640 * 480:
+                    if img[i] == u"l":
+                        l += 1
+                    i += 1
+                return l
+            ''', 65, ([], 122880))
+
+    def test_array_intimg(self):
+        for tc, maxops in zip('ilILd', (67, 67, 69, 69, 61)):
+            res = 73574560
+            if tc in 'IL':
+                res = long(res)
+            elif tc in 'fd':
+                res = float(res)
+            
+            self.run_source('''
+            from array import array
+
+            def main(tc):
+                img = array(tc, range(3)) * (350 * 480)
+                intimg = array(tc, (0,)) * (640 * 480)
+                l, i = 0, 640
+                while i < 640 * 480:
+                    l = l + img[i]
+                    intimg[i] = (intimg[i-640] + l) 
+                    i += 1
+                return intimg[i - 1]
+            ''', maxops, ([tc], res))
+
 class AppTestJIT(PyPyCJITTests):
     def setup_class(cls):
         if not option.runappdirect:
@@ -637,6 +868,7 @@
         cls.counter = 0
         cls.pypy_c = option.pypy_c
 
+
 def has_info(pypy_c, option):
     g = os.popen('"%s" --info' % pypy_c, 'r')
     lines = g.readlines()

Modified: pypy/branch/fast-forward/pypy/module/signal/interp_signal.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/signal/interp_signal.py	(original)
+++ pypy/branch/fast-forward/pypy/module/signal/interp_signal.py	Thu Sep  9 01:00:13 2010
@@ -7,6 +7,7 @@
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 import py
 from pypy.tool import autopath
+from pypy.rlib import jit
 
 def setup():
     for key, value in cpy_signal.__dict__.items():
@@ -159,10 +160,12 @@
     return space.wrap(SIG_DFL)
 getsignal.unwrap_spec = [ObjSpace, int]
 
+ at jit.dont_look_inside
 def alarm(space, timeout):
     return space.wrap(c_alarm(timeout))
 alarm.unwrap_spec = [ObjSpace, int]
 
+ at jit.dont_look_inside
 def pause(space):
     c_pause()
     return space.w_None
@@ -173,6 +176,7 @@
         raise OperationError(space.w_ValueError,
                              space.wrap("signal number out of range"))
 
+ at jit.dont_look_inside
 def signal(space, signum, w_handler):
     """
     signal(sig, action) -> action

Modified: pypy/branch/fast-forward/pypy/module/thread/test/test_gil.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/thread/test/test_gil.py	(original)
+++ pypy/branch/fast-forward/pypy/module/thread/test/test_gil.py	Thu Sep  9 01:00:13 2010
@@ -1,7 +1,6 @@
 import time
 from pypy.module.thread import gil
 from pypy.module.thread.test import test_ll_thread
-from pypy.rpython.lltypesystem import rffi
 from pypy.module.thread import ll_thread as thread
 from pypy.rlib.objectmodel import we_are_translated
 

Modified: pypy/branch/fast-forward/pypy/objspace/flow/specialcase.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/flow/specialcase.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/flow/specialcase.py	Thu Sep  9 01:00:13 2010
@@ -3,6 +3,7 @@
 from pypy.interpreter.gateway import ApplevelClass
 from pypy.interpreter.error import OperationError
 from pypy.tool.cache import Cache
+from pypy.rlib.rarithmetic import r_uint
 import py
 
 def sc_import(space, fn, args):
@@ -120,6 +121,14 @@
         pass
     return space.do_operation('simple_call', Constant(func), *args_w)
 
+def sc_r_uint(space, r_uint, args):
+    args_w, kwds_w = args.unpack()
+    assert not kwds_w
+    [w_value] = args_w
+    if isinstance(w_value, Constant):
+        return Constant(r_uint(w_value.value))
+    return space.do_operation('simple_call', space.wrap(r_uint), w_value)
+
 def setup(space):
     # fn = pyframe.normalize_exception.get_function(space)
     # this is now routed through the objspace, directly.
@@ -131,3 +140,7 @@
     # if possible
     for fn in OperationName:
         space.specialcases[fn] = sc_operator
+    # special case to constant-fold r_uint(32-bit-constant)
+    # (normally, the 32-bit constant is a long, and is not allowed to
+    # show up in the flow graphs at all)
+    space.specialcases[r_uint] = sc_r_uint

Modified: pypy/branch/fast-forward/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/callmethod.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/callmethod.py	Thu Sep  9 01:00:13 2010
@@ -12,7 +12,7 @@
 
 from pypy.interpreter import function
 from pypy.objspace.descroperation import object_getattribute
-from pypy.rlib import rstack # for resume points
+from pypy.rlib import jit, rstack # for resume points
 
 # This module exports two extra methods for StdObjSpaceFrame implementing
 # the LOOKUP_METHOD and CALL_METHOD opcodes in an efficient way, as well
@@ -56,16 +56,41 @@
     f.pushvalue(w_value)
     f.pushvalue(None)
 
-def CALL_METHOD(f, nargs, *ignored):
-    # 'nargs' is the argument count excluding the implicit 'self'
-    w_self = f.peekvalue(nargs)
-    w_callable = f.peekvalue(nargs + 1)
-    n = nargs + (w_self is not None)
-    try:
-        w_result = f.space.call_valuestack(w_callable, n, f)
-        rstack.resume_point("CALL_METHOD", f, nargs, returns=w_result)
-    finally:
-        f.dropvalues(nargs + 2)
+ at jit.unroll_safe
+def CALL_METHOD(f, oparg, *ignored):
+    # opargs contains the arg, and kwarg count, excluding the implicit 'self'
+    n_args = oparg & 0xff
+    n_kwargs = (oparg >> 8) & 0xff
+    w_self = f.peekvalue(n_args + (2 * n_kwargs))
+    n = n_args + (w_self is not None)
+    
+    if not n_kwargs:
+        w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1)
+        try:
+            w_result = f.space.call_valuestack(w_callable, n, f)
+            rstack.resume_point("CALL_METHOD", f, n_args, returns=w_result)
+        finally:
+            f.dropvalues(n_args + 2)
+    else:
+        keywords = [None] * n_kwargs
+        keywords_w = [None] * n_kwargs
+        while True:
+            n_kwargs -= 1
+            if n_kwargs < 0:
+                break
+            w_value = f.popvalue()
+            w_key = f.popvalue()
+            key = f.space.str_w(w_key)
+            keywords[n_kwargs] = key
+            keywords_w[n_kwargs] = w_value
+    
+        arguments = f.popvalues(n)    # includes w_self if it is not None
+        args = f.argument_factory(arguments, keywords, keywords_w, None, None)
+        if w_self is None:
+            f.popvalue()    # removes w_self, which is None
+        w_callable = f.popvalue()
+        w_result = f.space.call_args(w_callable, args)
+        rstack.resume_point("CALL_METHOD_KW", f, returns=w_result)
     f.pushvalue(w_result)
 
 

Modified: pypy/branch/fast-forward/pypy/objspace/std/intobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/intobject.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/intobject.py	Thu Sep  9 01:00:13 2010
@@ -245,34 +245,36 @@
 def lshift__Int_Int(space, w_int1, w_int2):
     a = w_int1.intval
     b = w_int2.intval
+    if r_uint(b) < LONG_BIT: # 0 <= b < LONG_BIT
+        try:
+            c = ovfcheck_lshift(a, b)
+        except OverflowError:
+            raise FailedToImplementArgs(space.w_OverflowError,
+                                    space.wrap("integer left shift"))
+        return wrapint(space, c)
     if b < 0:
         raise OperationError(space.w_ValueError,
                              space.wrap("negative shift count"))
-    if a == 0 or b == 0:
-        return get_integer(space, w_int1)
-    if b >= LONG_BIT:
+    else: #b >= LONG_BIT
+        if a == 0:
+            return get_integer(space, w_int1)
         raise FailedToImplementArgs(space.w_OverflowError,
                                 space.wrap("integer left shift"))
-    try:
-        c = ovfcheck_lshift(a, b)
-    except OverflowError:
-        raise FailedToImplementArgs(space.w_OverflowError,
-                                space.wrap("integer left shift"))
-    return wrapint(space, c)
 
 def rshift__Int_Int(space, w_int1, w_int2):
     a = w_int1.intval
     b = w_int2.intval
-    if b < 0:
-        raise OperationError(space.w_ValueError,
-                             space.wrap("negative shift count"))
-    if a == 0 or b == 0:
-        return get_integer(space, w_int1)
-    if b >= LONG_BIT:
-        if a < 0:
-            a = -1
-        else:
-            a = 0
+    if r_uint(b) >= LONG_BIT: # not (0 <= b < LONG_BIT)
+        if b < 0:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("negative shift count"))
+        else: # b >= LONG_BIT
+            if a == 0:
+                return get_integer(space, w_int1)
+            if a < 0:
+                a = -1
+            else:
+                a = 0
     else:
         a = a >> b
     return wrapint(space, a)

Modified: pypy/branch/fast-forward/pypy/objspace/std/itertype.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/itertype.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/itertype.py	Thu Sep  9 01:00:13 2010
@@ -1,5 +1,6 @@
 from pypy.interpreter import gateway
 from pypy.objspace.std.stdtypedef import StdTypeDef
+from pypy.interpreter.error import OperationError
 
 # ____________________________________________________________
 
@@ -8,6 +9,11 @@
     XXX to do: remove this __reduce__ method and do
     a registration with copy_reg, instead.
     """
+
+    # cpython does not support pickling iterators but stackless python do
+    #msg = 'Pickling for iterators dissabled as cpython does not support it'
+    #raise OperationError(space.w_TypeError, space.wrap(msg))
+
     from pypy.objspace.std.iterobject import W_AbstractSeqIterObject
     assert isinstance(w_self, W_AbstractSeqIterObject)
     from pypy.interpreter.mixedmodule import MixedModule

Modified: pypy/branch/fast-forward/pypy/objspace/std/model.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/model.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/model.py	Thu Sep  9 01:00:13 2010
@@ -88,6 +88,8 @@
         import pypy.objspace.std.default # register a few catch-all multimethods
 
         import pypy.objspace.std.marshal_impl # install marshal multimethods
+        if config.objspace.usemodules.array:
+            import pypy.module.array
 
         # the set of implementation types
         self.typeorder = {
@@ -140,6 +142,8 @@
 
         # check if we missed implementations
         for implcls in _registered_implementations:
+            if hasattr(implcls, 'register'):
+                implcls.register(self.typeorder)
             assert (implcls in self.typeorder or
                     implcls in self.imported_but_not_registered), (
                 "please add %r in StdTypeModel.typeorder" % (implcls,))

Modified: pypy/branch/fast-forward/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/objspace.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/objspace.py	Thu Sep  9 01:00:13 2010
@@ -405,8 +405,8 @@
     def getattr(self, w_obj, w_name):
         if not self.config.objspace.std.getattributeshortcut:
             return DescrOperation.getattr(self, w_obj, w_name)
-
         # an optional shortcut for performance
+
         w_type = self.type(w_obj)
         w_descr = w_type.getattribute_if_not_from_object()
         if w_descr is not None:

Modified: pypy/branch/fast-forward/pypy/objspace/std/test/test_callmethod.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/test/test_callmethod.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/test/test_callmethod.py	Thu Sep  9 01:00:13 2010
@@ -106,6 +106,15 @@
             else:
                 raise Exception("did not raise?")
         """
+    
+    def test_kwargs(self):
+        exec """if 1:
+            class C(object):
+                def f(self, a):
+                    return a + 2
+            
+            assert C().f(a=3) == 5
+        """
 
 
 class AppTestCallMethodWithGetattributeShortcut(AppTestCallMethod):

Modified: pypy/branch/fast-forward/pypy/objspace/std/tupleobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/tupleobject.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/tupleobject.py	Thu Sep  9 01:00:13 2010
@@ -11,7 +11,7 @@
 
 class W_TupleObject(W_Object):
     from pypy.objspace.std.tupletype import tuple_typedef as typedef
-    _immutable_ = True
+    _immutable_fields_ = ['wrappeditems[*]']
 
     def __init__(w_self, wrappeditems):
         make_sure_not_resized(wrappeditems)

Modified: pypy/branch/fast-forward/pypy/rlib/debug.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/debug.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/debug.py	Thu Sep  9 01:00:13 2010
@@ -255,11 +255,32 @@
 class IntegerCanBeNegative(Exception):
     pass
 
-def _check_nonneg(ann, bk):
-    from pypy.annotation.model import SomeInteger
-    s_nonneg = SomeInteger(nonneg=True)
-    if not s_nonneg.contains(ann):
-        raise IntegerCanBeNegative
+class UnexpectedRUInt(Exception):
+    pass
 
 def check_nonneg(x):
-    check_annotation(x, _check_nonneg)
+    """Give a translation-time error if 'x' is not known to be non-negative.
+    To help debugging, this also gives a translation-time error if 'x' is
+    actually typed as an r_uint (in which case the call to check_nonneg()
+    is a bit strange and probably unexpected).
+    """
+    assert type(x)(-1) < 0     # otherwise, 'x' is a r_uint or similar
+    assert x >= 0
+    return x
+
+class Entry(ExtRegistryEntry):
+    _about_ = check_nonneg
+
+    def compute_result_annotation(self, s_arg):
+        from pypy.annotation.model import SomeInteger
+        if isinstance(s_arg, SomeInteger) and s_arg.unsigned:
+            raise UnexpectedRUInt("check_nonneg() arg is a %s" % (
+                s_arg.knowntype,))
+        s_nonneg = SomeInteger(nonneg=True)
+        if not s_nonneg.contains(s_arg):
+            raise IntegerCanBeNegative
+        return s_arg
+
+    def specialize_call(self, hop):
+        hop.exception_cannot_occur()
+        return hop.inputarg(hop.args_r[0], arg=0)

Modified: pypy/branch/fast-forward/pypy/rlib/jit.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/jit.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/jit.py	Thu Sep  9 01:00:13 2010
@@ -253,8 +253,7 @@
     
     def __init__(self, greens=None, reds=None, virtualizables=None,
                  get_jitcell_at=None, set_jitcell_at=None,
-                 can_inline=None, get_printable_location=None,
-                 confirm_enter_jit=None):
+                 get_printable_location=None, confirm_enter_jit=None):
         if greens is not None:
             self.greens = greens
         if reds is not None:
@@ -270,7 +269,6 @@
         self.get_jitcell_at = get_jitcell_at
         self.set_jitcell_at = set_jitcell_at
         self.get_printable_location = get_printable_location
-        self.can_inline = can_inline
         self.confirm_enter_jit = confirm_enter_jit
 
     def _freeze_(self):
@@ -284,6 +282,10 @@
         # special-cased by ExtRegistryEntry
         assert dict.fromkeys(livevars) == _self._alllivevars
 
+    def loop_header(self):
+        # special-cased by ExtRegistryEntry
+        pass
+
     def _set_param(self, name, value):
         # special-cased by ExtRegistryEntry
         # (internal, must receive a constant 'name')
@@ -323,11 +325,15 @@
         # specifically for them.
         self.jit_merge_point = self.jit_merge_point
         self.can_enter_jit = self.can_enter_jit
+        self.loop_header = self.loop_header
         self._set_param = self._set_param
 
         class Entry(ExtEnterLeaveMarker):
             _about_ = (self.jit_merge_point, self.can_enter_jit)
 
+        class Entry(ExtLoopHeader):
+            _about_ = self.loop_header
+
         class Entry(ExtSetParam):
             _about_ = self._set_param
 
@@ -384,7 +390,6 @@
         self.annotate_hook(driver.get_jitcell_at, driver.greens, **kwds_s)
         self.annotate_hook(driver.set_jitcell_at, driver.greens, [s_jitcell],
                            **kwds_s)
-        self.annotate_hook(driver.can_inline, driver.greens, **kwds_s)
         self.annotate_hook(driver.get_printable_location, driver.greens, **kwds_s)
 
     def annotate_hook(self, func, variables, args_s=[], **kwds_s):
@@ -425,6 +430,23 @@
         return hop.genop('jit_marker', vlist,
                          resulttype=lltype.Void)
 
+class ExtLoopHeader(ExtRegistryEntry):
+    # Replace a call to myjitdriver.loop_header()
+    # with an operation jit_marker('loop_header', myjitdriver).
+
+    def compute_result_annotation(self, **kwds_s):
+        from pypy.annotation import model as annmodel
+        return annmodel.s_None
+
+    def specialize_call(self, hop):
+        from pypy.rpython.lltypesystem import lltype
+        driver = self.instance.im_self
+        hop.exception_cannot_occur()
+        vlist = [hop.inputconst(lltype.Void, 'loop_header'),
+                 hop.inputconst(lltype.Void, driver)]
+        return hop.genop('jit_marker', vlist,
+                         resulttype=lltype.Void)
+
 class ExtSetParam(ExtRegistryEntry):
 
     def compute_result_annotation(self, s_name, s_value):

Modified: pypy/branch/fast-forward/pypy/rlib/objectmodel.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/objectmodel.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/objectmodel.py	Thu Sep  9 01:00:13 2010
@@ -19,32 +19,80 @@
 # def f(...
 #
 
-class _AttachSpecialization(object):
+class _Specialize(object):
+    def memo(self):
+        """ Specialize functions based on argument values. All arguments has
+        to be constant at the compile time. The whole function call is replaced
+        by a call result then.
+        """
+        def decorated_func(func):
+            func._annspecialcase_ = 'specialize:memo'
+            return func
+        return decorated_func
 
-    def __init__(self, tag):
-        self.tag = tag
+    def arg(self, *args):
+        """ Specialize function based on values of given positions of arguments.
+        They must be compile-time constants in order to work.
+
+        There will be a copy of provided function for each combination
+        of given arguments on positions in args (that can lead to
+        exponential behavior!).
+        """
+        def decorated_func(func):
+            func._annspecialcase_ = 'specialize:arg' + self._wrap(args)
+            return func
 
-    def __call__(self, *args):
-        if not args:
-            args = ""
-        else:
-            args = "("+','.join([repr(arg) for arg in args]) +")"
-        specialcase = "specialize:%s%s" % (self.tag, args)
-        
-        def specialize_decorator(func):
-            "NOT_RPYTHON"
-            func._annspecialcase_ = specialcase
+        return decorated_func
+
+    def argtype(self, *args):
+        """ Specialize function based on types of arguments on given positions.
+
+        There will be a copy of provided function for each combination
+        of given arguments on positions in args (that can lead to
+        exponential behavior!).
+        """
+        def decorated_func(func):
+            func._annspecialcase_ = 'specialize:argtype' + self._wrap(args)
             return func
 
-        return specialize_decorator
-        
-class _Specialize(object):
+        return decorated_func
 
-    def __getattr__(self, name):
-        return _AttachSpecialization(name)
+    def ll(self):
+        """ This is version of argtypes that cares about low-level types
+        (so it'll get additional copies for two different types of pointers
+        for example). Same warnings about exponential behavior apply.
+        """
+        def decorated_func(func):
+            func._annspecialcase_ = 'specialize:ll'
+            return func
+
+        return decorated_func
+
+    def ll_and_arg(self, arg):
+        """ XXX what does that do?
+        """
+        def decorated_func(func):
+            func._annspecialcase_ = 'specialize:ll_and_arg(%d)' % arg
+            return func
+
+        return decorated_func
+
+    def _wrap(self, args):
+        return "("+','.join([repr(arg) for arg in args]) +")"
         
 specialize = _Specialize()
 
+def enforceargs(*args):
+    """ Decorate a function with forcing of RPython-level types on arguments.
+    None means no enforcing.
+
+    XXX shouldn't we also add asserts in function body?
+    """
+    def decorator(f):
+        f._annenforceargs_ = args
+        return f
+    return decorator
+
 # ____________________________________________________________
 
 class Symbolic(object):

Modified: pypy/branch/fast-forward/pypy/rlib/rarithmetic.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rarithmetic.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rarithmetic.py	Thu Sep  9 01:00:13 2010
@@ -167,7 +167,7 @@
 def widen(n):
     from pypy.rpython.lltypesystem import lltype
     if _should_widen_type(lltype.typeOf(n)):
-        return int(n)
+        return intmask(n)
     else:
         return n
 widen._annspecialcase_ = 'specialize:argtype(0)'

Modified: pypy/branch/fast-forward/pypy/rlib/rlocale.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rlocale.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rlocale.py	Thu Sep  9 01:00:13 2010
@@ -15,6 +15,12 @@
 HAVE_LANGINFO = sys.platform != 'win32'
 HAVE_LIBINTL  = sys.platform != 'win32'
 
+if HAVE_LIBINTL:
+    try:
+        platform.verify_eci(ExternalCompilationInfo(includes=['libintl.h']))
+    except platform.CompilationError:
+        HAVE_LIBINTL = False
+
 class CConfig:
     includes = ['locale.h', 'limits.h']
 

Modified: pypy/branch/fast-forward/pypy/rlib/rmmap.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rmmap.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rmmap.py	Thu Sep  9 01:00:13 2010
@@ -646,8 +646,14 @@
         hintp = rffi.cast(PTR, hint.pos)
         res = c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
         if res == rffi.cast(PTR, -1):
-            raise MemoryError
-        hint.pos += map_size
+            # some systems (some versions of OS/X?) complain if they
+            # are passed a non-zero address.  Try again.
+            hintp = rffi.cast(PTR, 0)
+            res = c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
+            if res == rffi.cast(PTR, -1):
+                raise MemoryError
+        else:
+            hint.pos += map_size
         return res
     alloc._annenforceargs_ = (int,)
 

Modified: pypy/branch/fast-forward/pypy/rlib/rposix.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rposix.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rposix.py	Thu Sep  9 01:00:13 2010
@@ -3,6 +3,7 @@
 from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rlib.rarithmetic import intmask
+from pypy.rlib.objectmodel import specialize
 
 class CConstantErrno(CConstant):
     # these accessors are used when calling get_errno() or set_errno()
@@ -42,3 +43,102 @@
             os.close(fd)
         except OSError:
             pass
+
+#___________________________________________________________________
+# Wrappers around posix functions, that accept either strings, or
+# instances with a "as_bytes()" method.
+# - pypy.modules.posix.interp_posix passes an object containing a unicode path
+#   which can encode itself with sys.filesystemencoding.
+# - but pypy.rpython.module.ll_os.py on Windows will replace these functions
+#   with other wrappers that directly handle unicode strings.
+ at specialize.argtype(0)
+def open(path, flags, mode):
+    if isinstance(path, str):
+        return os.open(path, flags, mode)
+    else:
+        return os.open(path.as_bytes(), flags, mode)
+
+ at specialize.argtype(0)
+def stat(path):
+    if isinstance(path, str):
+        return os.stat(path)
+    else:
+        return os.stat(path.as_bytes())
+
+ at specialize.argtype(0)
+def lstat(path):
+    if isinstance(path, str):
+        return os.lstat(path)
+    else:
+        return os.lstat(path.as_bytes())
+
+ at specialize.argtype(0)
+def unlink(path):
+    if isinstance(path, str):
+        return os.unlink(path)
+    else:
+        return os.unlink(path.as_bytes())
+
+ at specialize.argtype(0, 1)
+def rename(path1, path2):
+    if isinstance(path1, str):
+        return os.rename(path1, path2)
+    else:
+        return os.rename(path1.as_bytes(), path2.as_bytes())
+
+ at specialize.argtype(0)
+def listdir(dirname):
+    if isinstance(dirname, str):
+        return os.listdir(dirname)
+    else:
+        return os.listdir(dirname.as_bytes())
+
+ at specialize.argtype(0)
+def access(path, mode):
+    if isinstance(path, str):
+        return os.access(path, mode)
+    else:
+        return os.access(path.as_bytes(), mode)
+
+ at specialize.argtype(0)
+def chmod(path, mode):
+    if isinstance(path, str):
+        return os.chmod(path, mode)
+    else:
+        return os.chmod(path.as_bytes(), mode)
+
+ at specialize.argtype(0, 1)
+def utime(path, times):
+    if isinstance(path, str):
+        return os.utime(path, times)
+    else:
+        return os.utime(path.as_bytes(), times)
+
+ at specialize.argtype(0)
+def chdir(path):
+    if isinstance(path, str):
+        return os.chdir(path)
+    else:
+        return os.chdir(path.as_bytes())
+
+ at specialize.argtype(0)
+def mkdir(path, mode=0777):
+    if isinstance(path, str):
+        return os.mkdir(path, mode)
+    else:
+        return os.mkdir(path.as_bytes(), mode)
+
+ at specialize.argtype(0)
+def rmdir(path):
+    if isinstance(path, str):
+        return os.rmdir(path)
+    else:
+        return os.rmdir(path.as_bytes())
+
+if os.name == 'nt':
+    import nt
+    def _getfullpathname(path):
+        if isinstance(path, str):
+            return nt._getfullpathname(path)
+        else:
+            return nt._getfullpathname(path.as_bytes())

Modified: pypy/branch/fast-forward/pypy/rlib/rsha.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rsha.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rsha.py	Thu Sep  9 01:00:13 2010
@@ -88,7 +88,7 @@
     0xCA62C1D6L  # (60 <= t <= 79)
     ]
 
-unroll_f_K = unrolling_iterable(zip(f, K))
+unroll_f_K = unrolling_iterable(zip(f, map(r_uint, K)))
 if UNROLL_ALL:
     unroll_range_20 = unrolling_iterable(range(20))
 

Modified: pypy/branch/fast-forward/pypy/rlib/rsocket.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rsocket.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rsocket.py	Thu Sep  9 01:00:13 2010
@@ -100,8 +100,6 @@
     def lock(self, TYPE=_c.sockaddr):
         """Return self.addr_p, cast as a pointer to TYPE.  Must call unlock()!
         """
-        if not (self.minlen <= self.addrlen <= self.maxlen):
-            raise RSocketError("invalid address")
         return rffi.cast(lltype.Ptr(TYPE), self.addr_p)
     lock._annspecialcase_ = 'specialize:ll'
 

Modified: pypy/branch/fast-forward/pypy/rlib/rweakref.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rweakref.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rweakref.py	Thu Sep  9 01:00:13 2010
@@ -78,7 +78,7 @@
         return self.__class__,
 
     def method_get(self, s_key):
-        assert isinstance(s_key, annmodel.SomeString)
+        assert annmodel.SomeString(can_be_None=True).contains(s_key)
         return annmodel.SomeInstance(self.valueclassdef, can_be_None=True)
 
     def method_set(self, s_key, s_value):

Modified: pypy/branch/fast-forward/pypy/rlib/rwin32.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rwin32.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rwin32.py	Thu Sep  9 01:00:13 2010
@@ -31,6 +31,7 @@
         DWORD = rffi_platform.SimpleType("DWORD", rffi.UINT)
         BOOL = rffi_platform.SimpleType("BOOL", rffi.LONG)
         BYTE = rffi_platform.SimpleType("BYTE", rffi.UCHAR)
+        WCHAR = rffi_platform.SimpleType("WCHAR", rffi.UCHAR)
         INT = rffi_platform.SimpleType("INT", rffi.INT)
         LONG = rffi_platform.SimpleType("LONG", rffi.LONG)
         PLONG = rffi_platform.SimpleType("PLONG", rffi.LONGP)
@@ -38,6 +39,8 @@
         LPCVOID = rffi_platform.SimpleType("LPCVOID", rffi.VOIDP)
         LPSTR = rffi_platform.SimpleType("LPSTR", rffi.CCHARP)
         LPCSTR = rffi_platform.SimpleType("LPCSTR", rffi.CCHARP)
+        LPWSTR = rffi_platform.SimpleType("LPWSTR", rffi.CWCHARP)
+        LPCWSTR = rffi_platform.SimpleType("LPCWSTR", rffi.CWCHARP)
         LPDWORD = rffi_platform.SimpleType("LPDWORD", rffi.INTP)
         SIZE_T = rffi_platform.SimpleType("SIZE_T", rffi.SIZE_T)
         ULONG_PTR = rffi_platform.SimpleType("ULONG_PTR", rffi.ULONG)
@@ -87,6 +90,10 @@
     GetLastError = winexternal('GetLastError', [], DWORD)
     SetLastError = winexternal('SetLastError', [DWORD], lltype.Void)
 
+    # In tests, the first call to GetLastError is always wrong, because error
+    # is hidden by operations in ll2ctypes.  Call it now.
+    GetLastError()
+
     LoadLibrary = winexternal('LoadLibraryA', [rffi.CCHARP], rffi.VOIDP)
     GetProcAddress = winexternal('GetProcAddress',
                                  [rffi.VOIDP, rffi.CCHARP],
@@ -129,13 +136,29 @@
                     }
                     return 0;
                 }''')
-        exename = static_platform.compile(
-            [cfile], ExternalCompilationInfo(),
-            outputfilename = "dosmaperr",
-            standalone=True)
-        output = os.popen(str(exename))
-        errors = dict(map(int, line.split())
-                      for line in output)
+        try:
+            exename = static_platform.compile(
+                [cfile], ExternalCompilationInfo(),
+                outputfilename = "dosmaperr",
+                standalone=True)
+        except WindowsError:
+            # Fallback for the mingw32 compiler
+            errors = {
+                2: 2, 3: 2, 4: 24, 5: 13, 6: 9, 7: 12, 8: 12, 9: 12, 10: 7,
+                11: 8, 15: 2, 16: 13, 17: 18, 18: 2, 19: 13, 20: 13, 21: 13,
+                22: 13, 23: 13, 24: 13, 25: 13, 26: 13, 27: 13, 28: 13,
+                29: 13, 30: 13, 31: 13, 32: 13, 33: 13, 34: 13, 35: 13,
+                36: 13, 53: 2, 65: 13, 67: 2, 80: 17, 82: 13, 83: 13, 89: 11,
+                108: 13, 109: 32, 112: 28, 114: 9, 128: 10, 129: 10, 130: 9,
+                132: 13, 145: 41, 158: 13, 161: 2, 164: 11, 167: 13, 183: 17,
+                188: 8, 189: 8, 190: 8, 191: 8, 192: 8, 193: 8, 194: 8,
+                195: 8, 196: 8, 197: 8, 198: 8, 199: 8, 200: 8, 201: 8,
+                202: 8, 206: 2, 215: 11, 1816: 12,
+                }
+        else:
+            output = os.popen(str(exename))
+            errors = dict(map(int, line.split())
+                          for line in output)
         return errors, errno.EINVAL
 
     # A bit like strerror...

Modified: pypy/branch/fast-forward/pypy/rlib/rzipfile.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rzipfile.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rzipfile.py	Thu Sep  9 01:00:13 2010
@@ -19,12 +19,12 @@
 
 def crc32(s, crc=0):
     result = 0
-    crc = ~r_uint(crc) & 0xffffffffL
+    crc = ~r_uint(crc) & r_uint(0xffffffffL)
     for c in s:
         crc = rcrc_32_tab[(crc ^ r_uint(ord(c))) & 0xffL] ^ (crc >> 8)
         #/* Note:  (crc >> 8) MUST zero fill on left
 
-        result = crc ^ 0xffffffffL
+        result = crc ^ r_uint(0xffffffffL)
     
     return result
 
@@ -194,7 +194,7 @@
             (x.create_version, x.create_system, x.extract_version, x.reserved,
                 x.flag_bits, x.compress_type, t, d,
                 crc, x.compress_size, x.file_size) = centdir[1:12]
-            x.CRC = r_uint(crc) & 0xffffffff
+            x.CRC = r_uint(crc) & r_uint(0xffffffff)
             x.dostime = t
             x.dosdate = d
             x.volume, x.internal_attr, x.external_attr = centdir[15:18]

Modified: pypy/branch/fast-forward/pypy/rlib/streamio.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/streamio.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/streamio.py	Thu Sep  9 01:00:13 2010
@@ -38,7 +38,9 @@
 #
 
 import os, sys
+from pypy.rlib.objectmodel import specialize
 from pypy.rlib.rarithmetic import r_longlong, intmask
+from pypy.rlib import rposix
 
 from os import O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC
 O_BINARY = getattr(os, "O_BINARY", 0)
@@ -71,6 +73,7 @@
     return s.join(string.split(c))
 
 
+ at specialize.argtype(0)
 def open_file_as_stream(path, mode="r", buffering=-1):
     os_flags, universal, reading, writing, basemode, binary = decode_mode(mode)
     stream = open_path_helper(path, os_flags, basemode == "a")
@@ -89,9 +92,10 @@
     return construct_stream_tower(stream, buffering, universal, reading,
                                   writing, binary)
 
+ at specialize.argtype(0)
 def open_path_helper(path, os_flags, append):
     # XXX for now always return DiskFile
-    fd = os.open(path, os_flags, 0666)
+    fd = rposix.open(path, os_flags, 0666)
     if append:
         try:
             os.lseek(fd, 0, 2)

Modified: pypy/branch/fast-forward/pypy/rlib/test/test_jit.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/test/test_jit.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/test/test_jit.py	Thu Sep  9 01:00:13 2010
@@ -59,11 +59,9 @@
 
     def test_annotate_hooks(self):
         
-        def can_inline(m): pass
         def get_printable_location(m): pass
         
         myjitdriver = JitDriver(greens=['m'], reds=['n'],
-                                can_inline=can_inline,
                                 get_printable_location=get_printable_location)
         def fn(n):
             m = 42.5
@@ -81,9 +79,8 @@
                     return [v.concretetype for v in graph.getargs()]
             raise Exception, 'function %r has not been annotated' % func
 
-        can_inline_args = getargs(can_inline)
         get_printable_location_args = getargs(get_printable_location)
-        assert can_inline_args == get_printable_location_args == [lltype.Float]
+        assert get_printable_location_args == [lltype.Float]
 
     def test_annotate_argumenterror(self):
         myjitdriver = JitDriver(greens=['m'], reds=['n'])

Modified: pypy/branch/fast-forward/pypy/rlib/test/test_objectmodel.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/test/test_objectmodel.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/test/test_objectmodel.py	Thu Sep  9 01:00:13 2010
@@ -404,6 +404,13 @@
 
     assert f._annspecialcase_ == 'specialize:arg(1)'
 
+def test_enforceargs_decorator():
+    @enforceargs(int, str, None)
+    def f(a, b, c):
+        pass
+
+    assert f._annenforceargs_ == (int, str, None)
+
 def getgraph(f, argtypes):
     from pypy.translator.translator import TranslationContext, graphof
     from pypy.translator.backendopt.all import backend_optimizations

Modified: pypy/branch/fast-forward/pypy/rpython/extfunc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/extfunc.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/extfunc.py	Thu Sep  9 01:00:13 2010
@@ -52,7 +52,10 @@
                         return super(ExtRegistryEntry, self).__getattr__(attr)
                     raise exc, exc_inst, tb
 
-def registering(func):
+def registering(func, condition=True):
+    if not condition:
+        return lambda method: None
+
     def decorator(method):
         method._registering_func = func
         return method
@@ -63,11 +66,9 @@
         func = getattr(ns, name)
     except AttributeError:
         condition = False
+        func = None
 
-    if condition:
-        return registering(func)
-    else:
-        return lambda method: None
+    return registering(func, condition=condition)
 
 class LazyRegisteringMeta(type):
     def __new__(self, _name, _type, _vars):
@@ -167,8 +168,6 @@
         return signature_args
 
     def compute_result_annotation(self, *args_s):
-        if hasattr(self, 'ann_hook'):
-            self.ann_hook()
         self.normalize_args(*args_s)   # check arguments
         return self.signature_result
 
@@ -235,7 +234,6 @@
 def register_external(function, args, result=None, export_name=None,
                        llimpl=None, ooimpl=None,
                        llfakeimpl=None, oofakeimpl=None,
-                       annotation_hook=None,
                        sandboxsafe=False):
     """
     function: the RPython function that will be rendered as an external function (e.g.: math.floor)
@@ -244,7 +242,6 @@
     export_name: the name of the function as it will be seen by the backends
     llimpl, ooimpl: optional; if provided, these RPython functions are called instead of the target function
     llfakeimpl, oofakeimpl: optional; if provided, they are called by the llinterpreter
-    annotationhook: optional; a callable that is called during annotation, useful for genc hacks
     sandboxsafe: use True if the function performs no I/O (safe for --sandbox)
     """
 
@@ -271,8 +268,6 @@
             lltypefakeimpl = staticmethod(llfakeimpl)
         if oofakeimpl:
             ootypefakeimpl = staticmethod(oofakeimpl)
-        if annotation_hook:
-            ann_hook = staticmethod(annotation_hook)
 
     if export_name:
         FunEntry.__name__ = export_name

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/ll2ctypes.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/ll2ctypes.py	Thu Sep  9 01:00:13 2010
@@ -24,6 +24,7 @@
 from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
 from pypy.rpython import raddress
 from pypy.translator.platform import platform
+from array import array
 
 def uaddressof(obj):
     return fixid(ctypes.addressof(obj))
@@ -756,7 +757,15 @@
     elif T is lltype.Char:
         llobj = chr(cobj)
     elif T is lltype.UniChar:
-        llobj = unichr(cobj)
+        try:
+            llobj = unichr(cobj)
+        except (ValueError, OverflowError):
+            for tc in 'HIL':
+                if array(tc).itemsize == array('u').itemsize:
+                    llobj = array('u', array(tc, (cobj,)).tostring())[0]
+                    break
+            else:
+                raise
     elif T is lltype.Signed:
         llobj = cobj
     elif T is lltype.Bool:

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/llgroup.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/llgroup.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/llgroup.py	Thu Sep  9 01:00:13 2010
@@ -99,6 +99,7 @@
     '&~0xFFFF' or with a direct masking like '&0x10000' (resp. on 64-bit
     platform, with '&~0xFFFFFFFF' or '&0x100000000').
     """
+    __slots__ = ['lowpart', 'rest']
     MASK = (1<<HALFSHIFT)-1     # 0xFFFF or 0xFFFFFFFF
 
     def annotation(self):
@@ -135,6 +136,10 @@
         assert (other & CombinedSymbolic.MASK) == 0
         return CombinedSymbolic(self.lowpart, self.rest - other)
 
+    def __rshift__(self, other):
+        assert other >= HALFSHIFT
+        return self.rest >> other
+
     def __eq__(self, other):
         if (isinstance(other, CombinedSymbolic) and
             self.lowpart is other.lowpart):

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/llmemory.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/llmemory.py	Thu Sep  9 01:00:13 2010
@@ -361,19 +361,27 @@
 
 # ____________________________________________________________
 
+def _sizeof_none(TYPE):
+    assert not TYPE._is_varsize()
+    return ItemOffset(TYPE)
+_sizeof_none._annspecialcase_ = 'specialize:memo'
+
+def _sizeof_int(TYPE, n):
+    "NOT_RPYTHON"
+    if isinstance(TYPE, lltype.Struct):
+        return FieldOffset(TYPE, TYPE._arrayfld) + \
+               itemoffsetof(TYPE._flds[TYPE._arrayfld], n)
+    else:
+        raise Exception("don't know how to take the size of a %r"%TYPE)
+
 def sizeof(TYPE, n=None):
     if n is None:
-        assert not TYPE._is_varsize()
-        return ItemOffset(TYPE)
+        return _sizeof_none(TYPE)
+    elif isinstance(TYPE, lltype.Array):
+        return itemoffsetof(TYPE) + _sizeof_none(TYPE.OF) * n
     else:
-        if isinstance(TYPE, lltype.Array):
-            return itemoffsetof(TYPE, n)
-        elif isinstance(TYPE, lltype.Struct):
-            return FieldOffset(TYPE, TYPE._arrayfld) + \
-                   itemoffsetof(TYPE._flds[TYPE._arrayfld], n)
-        else:
-            raise Exception("don't know how to take the size of a %r"%TYPE)
-sizeof._annspecialcase_ = 'specialize:memo'   # only for n == None
+        return _sizeof_int(TYPE, n)
+sizeof._annspecialcase_ = 'specialize:arg(0)'
 
 def offsetof(TYPE, fldname):
     assert fldname in TYPE._flds
@@ -389,6 +397,7 @@
 # -------------------------------------------------------------
 
 class fakeaddress(object):
+    __slots__ = ['ptr']
     # NOTE: the 'ptr' in the addresses must be normalized.
     # Use cast_ptr_to_adr() instead of directly fakeaddress() if unsure.
     def __init__(self, ptr):
@@ -530,7 +539,6 @@
     pass
 
 NULL = fakeaddress(None)
-NULL.intaddress = 0      # this is to make memory.lladdress more happy
 Address = lltype.Primitive("Address", NULL)
 
 # GCREF is similar to Address but it is GC-aware

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/lloperation.py	Thu Sep  9 01:00:13 2010
@@ -85,16 +85,20 @@
     fold = roproperty(get_fold_impl)
 
     def is_pure(self, args_v):
-        return (self.canfold or                # canfold => pure operation
-                self is llop.debug_assert or   # debug_assert is pure enough
-                                               # reading from immutable
-                (self in (llop.getfield, llop.getarrayitem) and
-                 args_v[0].concretetype.TO._hints.get('immutable')) or
-                (self is llop.getfield and     # reading from immutable_field
-                 'immutable_fields' in args_v[0].concretetype.TO._hints and
-                 args_v[1].value in args_v[0].concretetype.TO
-                                           ._hints['immutable_fields'].fields))
-        # XXX: what about ootype immutable arrays?
+        if self.canfold:                # canfold => pure operation
+            return True
+        if self is llop.debug_assert:   # debug_assert is pure enough
+            return True
+        # reading from immutable (lltype)
+        if self is llop.getfield or self is llop.getarrayitem:
+            field = getattr(args_v[1], 'value', None)
+            return args_v[0].concretetype.TO._immutable_field(field)
+        # reading from immutable (ootype) (xxx what about arrays?)
+        if self is llop.oogetfield:
+            field = getattr(args_v[1], 'value', None)
+            return args_v[0].concretetype._immutable_field(field)
+        # default
+        return False
 
     def __repr__(self):
         return '<LLOp %s>' % (getattr(self, 'opname', '?'),)

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/lltype.py	Thu Sep  9 01:00:13 2010
@@ -37,7 +37,7 @@
         return '<Uninitialized %r>'%(self.TYPE,)
         
 
-def saferecursive(func, defl):
+def saferecursive(func, defl, TLS=TLS):
     def safe(*args):
         try:
             seeing = TLS.seeing
@@ -54,7 +54,7 @@
     return safe
 
 #safe_equal = saferecursive(operator.eq, True)
-def safe_equal(x, y):
+def safe_equal(x, y, TLS=TLS):
     # a specialized version for performance
     try:
         seeing = TLS.seeing_eq
@@ -97,7 +97,7 @@
             raise TypeError
         return value
 
-    def __hash__(self):
+    def __hash__(self, TLS=TLS):
         # cannot use saferecursive() -- see test_lltype.test_hash().
         # NB. the __cached_hash should neither be used nor updated
         # if we enter with hash_level > 0, because the computed
@@ -297,6 +297,15 @@
             n = 1
         return _struct(self, n, initialization='example')
 
+    def _immutable_field(self, field):
+        if 'immutable_fields' in self._hints:
+            try:
+                s = self._hints['immutable_fields'].fields[field]
+                return s or True
+            except KeyError:
+                pass
+        return self._hints.get('immutable', False)
+
 class RttiStruct(Struct):
     _runtime_type_info = None
 
@@ -391,6 +400,9 @@
     def _container_example(self):
         return _array(self, 1, initialization='example')
 
+    def _immutable_field(self, index=None):
+        return self._hints.get('immutable', False)
+
 class GcArray(Array):
     _gckind = 'gc'
     def _inline_is_varsize(self, last):
@@ -401,6 +413,19 @@
     # behaves more or less like a Struct with fields item0, item1, ...
     # but also supports __getitem__(), __setitem__(), __len__().
 
+    _cache = weakref.WeakValueDictionary() # cache the length-1 FixedSizeArrays
+    def __new__(cls, OF, length, **kwds):
+        if length == 1 and not kwds:
+            try:
+                obj = FixedSizeArray._cache[OF]
+            except KeyError:
+                obj = FixedSizeArray._cache[OF] = Struct.__new__(cls)
+            except TypeError:
+                obj = Struct.__new__(cls)
+        else:
+            obj = Struct.__new__(cls)
+        return obj
+
     def __init__(self, OF, length, **kwds):
         fields = [('item%d' % i, OF) for i in range(length)]
         super(FixedSizeArray, self).__init__('array%d' % length, *fields,
@@ -610,11 +635,22 @@
 class Ptr(LowLevelType):
     __name__ = property(lambda self: '%sPtr' % self.TO.__name__)
 
-    def __init__(self, TO):
+    _cache = weakref.WeakValueDictionary()  # cache the Ptrs
+    def __new__(cls, TO, use_cache=True):
         if not isinstance(TO, ContainerType):
             raise TypeError, ("can only point to a Container type, "
                               "not to %s" % (TO,))
-        self.TO = TO
+        if not use_cache:
+            obj = LowLevelType.__new__(cls)
+        else:
+            try:
+                return Ptr._cache[TO]
+            except KeyError:
+                obj = Ptr._cache[TO] = LowLevelType.__new__(cls)
+            except TypeError:
+                obj = LowLevelType.__new__(cls)
+        obj.TO = TO
+        return obj
 
     def _needsgc(self):
         # XXX deprecated interface

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/opimpl.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/opimpl.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/opimpl.py	Thu Sep  9 01:00:13 2010
@@ -150,12 +150,7 @@
     # we can constant-fold this if the innermost structure from which we
     # read the final field is immutable.
     T = lltype.typeOf(innermostcontainer).TO
-    if T._hints.get('immutable'):
-        pass
-    elif ('immutable_fields' in T._hints and
-          offsets[-1] in T._hints['immutable_fields'].fields):
-        pass
-    else:
+    if not T._immutable_field(offsets[-1]):
         raise TypeError("cannot fold getinteriorfield on mutable struct")
     assert not isinstance(ob, lltype._interior_ptr)
     return ob
@@ -197,6 +192,18 @@
     assert isinstance(y, int)
     return intmask(x - y)
 
+def op_int_ge(x, y):
+    # special case for 'AddressOffset >= 0'
+    assert isinstance(x, (int, llmemory.AddressOffset))
+    assert isinstance(y, int)
+    return x >= y
+
+def op_int_lt(x, y):
+    # special case for 'AddressOffset < 0'
+    assert isinstance(x, (int, llmemory.AddressOffset))
+    assert isinstance(y, int)
+    return x < y
+
 def op_int_between(a, b, c):
     assert lltype.typeOf(a) is lltype.Signed
     assert lltype.typeOf(b) is lltype.Signed
@@ -222,6 +229,13 @@
     assert isinstance(y, (int, llmemory.AddressOffset))
     return intmask(x * y)
 
+def op_int_rshift(x, y):
+    if not isinstance(x, int):
+        from pypy.rpython.lltypesystem import llgroup
+        assert isinstance(x, llgroup.CombinedSymbolic)
+    assert isinstance(y, int)
+    return x >> y
+
 def op_int_floordiv(x, y):
     assert isinstance(x, (int, llmemory.AddressOffset))
     assert isinstance(y, (int, llmemory.AddressOffset))
@@ -418,19 +432,15 @@
 def op_getfield(p, name):
     checkptr(p)
     TYPE = lltype.typeOf(p).TO
-    if TYPE._hints.get('immutable'):
-        pass
-    elif ('immutable_fields' in TYPE._hints and
-          name in TYPE._hints['immutable_fields'].fields):
-        pass
-    else:
+    if not TYPE._immutable_field(name):
         raise TypeError("cannot fold getfield on mutable struct")
     return getattr(p, name)
 
 def op_getarrayitem(p, index):
     checkptr(p)
-    if not lltype.typeOf(p).TO._hints.get('immutable'):
-        raise TypeError("cannot fold getfield on mutable array")
+    ARRAY = lltype.typeOf(p).TO
+    if not ARRAY._immutable_field(index):
+        raise TypeError("cannot fold getarrayitem on mutable array")
     return p[index]
 
 def _normalize(x):

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/rffi.py	Thu Sep  9 01:00:13 2010
@@ -176,6 +176,15 @@
                     # XXX leaks if a str2charp() fails with MemoryError
                     # and was not the first in this function
                     freeme = arg
+            elif TARGET == CWCHARP:
+                if arg is None:
+                    arg = lltype.nullptr(CWCHARP.TO)   # None => (wchar_t*)NULL
+                    freeme = arg
+                elif isinstance(arg, unicode):
+                    arg = unicode2wcharp(arg)
+                    # XXX leaks if a unicode2wcharp() fails with MemoryError
+                    # and was not the first in this function
+                    freeme = arg
             elif _isfunctype(TARGET) and not _isllptr(arg):
                 # XXX pass additional arguments
                 if invoke_around_handlers:
@@ -584,9 +593,12 @@
         """ str -> char*
         """
         array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw')
-        for i in range(len(s)):
+        i = len(s)
+        array[i] = lastchar
+        i -= 1
+        while i >= 0:
             array[i] = s[i]
-        array[len(s)] = lastchar
+            i -= 1
         return array
     str2charp._annenforceargs_ = [strtype]
 

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/rstr.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/rstr.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/rstr.py	Thu Sep  9 01:00:13 2010
@@ -2,7 +2,7 @@
 from pypy.tool.pairtype import pairtype
 from pypy.rpython.error import TyperError
 from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated
-from pypy.rlib.objectmodel import _hash_string
+from pypy.rlib.objectmodel import _hash_string, enforceargs
 from pypy.rlib.debug import ll_assert
 from pypy.rlib.jit import purefunction
 from pypy.rpython.robject import PyObjRepr, pyobj_repr
@@ -56,6 +56,7 @@
                 llmemory.itemoffsetof(TP.chars, 0) +
                 llmemory.sizeof(CHAR_TP) * item)
 
+    @enforceargs(None, None, int, int, int)
     def copy_string_contents(src, dst, srcstart, dststart, length):
         assert srcstart >= 0
         assert dststart >= 0
@@ -674,6 +675,7 @@
             res_index += item_len
             i += 1
         return result
+    ll_join_strs._annenforceargs_ = [int, None]
 
     def ll_join_chars(length, chars, RES):
         # no need to optimize this, will be replaced by string builder

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_llgroup.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_llgroup.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_llgroup.py	Thu Sep  9 01:00:13 2010
@@ -105,6 +105,8 @@
             assert p == test.p1b
         assert cslist[0] & ~MASK == 0x45 << HALFSHIFT
         assert cslist[1] & ~MASK == 0x41 << HALFSHIFT
+        assert cslist[0] >> HALFSHIFT == 0x45
+        assert cslist[1] >> (HALFSHIFT+1) == 0x41 >> 1
         #
         return 42
     return f

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_lloperation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_lloperation.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_lloperation.py	Thu Sep  9 01:00:13 2010
@@ -88,7 +88,7 @@
     accessor = rclass.FieldListAccessor()
     S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed),
                          hints={'immutable_fields': accessor})
-    accessor.initialize(S3, ['x'])
+    accessor.initialize(S3, {'x': ''})
     v_s3 = Variable()
     v_s3.concretetype = lltype.Ptr(S3)
     assert not llop.setfield.is_pure([v_s3, Constant('x'), Variable()])
@@ -103,7 +103,7 @@
     accessor = rclass.FieldListAccessor()
     S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed),
                          hints={'immutable_fields': accessor})
-    accessor.initialize(S3, ['x'])
+    accessor.initialize(S3, {'x': ''})
     #
     s1 = lltype.malloc(S1); s1.x = 45
     py.test.raises(TypeError, llop.getfield, lltype.Signed, s1, 'x')

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_lltype.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_lltype.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_lltype.py	Thu Sep  9 01:00:13 2010
@@ -781,6 +781,28 @@
     p = cast_opaque_ptr(llmemory.GCREF, a)
     assert hash1 == identityhash(p)
 
+def test_immutable_hint():
+    S = GcStruct('S', ('x', lltype.Signed))
+    assert S._immutable_field('x') == False
+    #
+    S = GcStruct('S', ('x', lltype.Signed), hints={'immutable': True})
+    assert S._immutable_field('x') == True
+    #
+    class FieldListAccessor(object):
+        def __init__(self, fields):
+            self.fields = fields
+    S = GcStruct('S', ('x', lltype.Signed),
+                 hints={'immutable_fields': FieldListAccessor({'x':''})})
+    assert S._immutable_field('x') == True
+    #
+    class FieldListAccessor(object):
+        def __init__(self, fields):
+            self.fields = fields
+    S = GcStruct('S', ('x', lltype.Signed),
+                 hints={'immutable_fields': FieldListAccessor({'x':'[*]'})})
+    assert S._immutable_field('x') == '[*]'
+
+
 class TestTrackAllocation:
     def setup_method(self, func):
         start_tracking_allocations()

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_rffi.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_rffi.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/test/test_rffi.py	Thu Sep  9 01:00:13 2010
@@ -186,6 +186,11 @@
     
     def test_externvar(self):
         import os
+        if os.name == 'nt':
+            # Windows CRT badly aborts when an invalid fd is used.
+            bad_fd = 0
+        else:
+            bad_fd = 12312312
     
         def f():
             set_errno(12)
@@ -193,7 +198,7 @@
     
         def g():
             try:
-                os.write(12312312, "xxx")
+                os.write(bad_fd, "xxx")
             except OSError:
                 pass
             return get_errno()

Modified: pypy/branch/fast-forward/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/gc/base.py	Thu Sep  9 01:00:13 2010
@@ -86,8 +86,7 @@
         addr -= self.gcheaderbuilder.size_gc_header
         return llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
 
-    def get_size(self, obj):
-        typeid = self.get_type_id(obj)
+    def _get_size_for_typeid(self, obj, typeid):
         size = self.fixed_size(typeid)
         if self.is_varsize(typeid):
             lenaddr = obj + self.varsize_offset_to_length(typeid)
@@ -99,6 +98,9 @@
             # gctypelayout.encode_type_shape()
         return size
 
+    def get_size(self, obj):
+        return self._get_size_for_typeid(obj, self.get_type_id(obj))
+
     def malloc(self, typeid, length=0, zero=False):
         """For testing.  The interface used by the gctransformer is
         the four malloc_[fixed,var]size[_clear]() functions.
@@ -218,7 +220,6 @@
             pending = self._debug_pending
             while pending.non_empty():
                 obj = pending.pop()
-                self.debug_check_object(obj)
                 self.trace(obj, self._debug_callback2, None)
             self._debug_seen.delete()
             self._debug_pending.delete()
@@ -227,6 +228,7 @@
         seen = self._debug_seen
         if not seen.contains(obj):
             seen.add(obj)
+            self.debug_check_object(obj)
             self._debug_pending.append(obj)
     def _debug_callback(self, root):
         obj = root.address[0]
@@ -348,3 +350,23 @@
                         globals(), locals(), [classname])
     GCClass = getattr(module, classname)
     return GCClass, GCClass.TRANSLATION_PARAMS
+
+def read_from_env(varname):
+    import os
+    value = os.environ.get(varname)
+    if value:
+        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 int(float(realvalue) * factor)
+        except ValueError:
+            pass
+    return -1

Modified: pypy/branch/fast-forward/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/gc/generation.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/gc/generation.py	Thu Sep  9 01:00:13 2010
@@ -2,6 +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.lltypesystem.llmemory import NULL, raw_malloc_usage
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena
 from pypy.rpython.memory.support import DEFAULT_CHUNK_SIZE
@@ -625,18 +626,7 @@
 import os
 
 def nursery_size_from_env():
-    value = os.environ.get('PYPY_GENERATIONGC_NURSERY')
-    if value:
-        if value[-1] in 'kK':
-            factor = 1024
-            value = value[:-1]
-        else:
-            factor = 1
-        try:
-            return int(value) * factor
-        except ValueError:
-            pass
-    return -1
+    return read_from_env('PYPY_GENERATIONGC_NURSERY')
 
 def best_nursery_size_for_L2cache(L2cache):
     # Heuristically, the best nursery size to choose is about half

Modified: pypy/branch/fast-forward/pypy/rpython/memory/gc/markcompact.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/gc/markcompact.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/gc/markcompact.py	Thu Sep  9 01:00:13 2010
@@ -1,26 +1,17 @@
-
-import time
-
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup
-from pypy.rpython.memory.gc.base import MovingGCBase
-from pypy.rlib.debug import ll_assert
+from pypy.rpython.memory.gc.base import MovingGCBase, read_from_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 DEFAULT_CHUNK_SIZE
 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 ovfcheck
+from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask
 from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.objectmodel import we_are_translated, running_on_llinterp
 from pypy.rpython.lltypesystem import rffi
 from pypy.rpython.memory.gcheader import GCHeaderBuilder
 
-first_gcflag = 1 << 16
-GCFLAG_MARKBIT = first_gcflag << 0
-GCFLAG_HASHTAKEN = first_gcflag << 1      # someone already asked for the hash
-GCFLAG_HASHFIELD = first_gcflag << 2      # we have an extra hash field
-
-memoryError = MemoryError()
-
 # Mark'n'compact garbage collector
 #
 # main point of this GC is to save as much memory as possible
@@ -33,41 +24,44 @@
 # this gc works more or less like semispace, but has some essential
 # differencies. The main difference is that we have separate phases of
 # marking and assigning pointers, hence order of objects is preserved.
-# This means we can reuse the same space if it did not grow enough.
-# More importantly, in case we need to resize space we can copy it bit by
-# bit, hence avoiding double memory consumption at peak times
+# This means we can reuse the same space, overwriting it as we collect.
 
-# so the algorithm itself is performed in 3 stages (module weakrefs and
-# finalizers)
+# so the algorithm itself is performed in 3 stages (modulo weakrefs and
+# finalizers):
 
 # 1. We mark alive objects
 # 2. We walk all objects and assign forward pointers in the same order,
 #    also updating all references
-# 3. We compact the space by moving. In case we move to the same space,
-#    we use arena_new_view trick, which looks like new space to tests,
-#    but compiles to the same pointer. Also we use raw_memmove in case
-#    objects overlap.
-
-# Exact algorithm for space resizing: we keep allocated more space than needed
-# (2x, can be even more), but it's full of zeroes. After each collection,
-# we bump next_collect_after which is a marker where to start each collection.
-# It should be exponential (but less than 2) from the size occupied by objects
+# 3. We compact the space by moving.  We use 'arena_new_view' trick, which
+#    looks like new space to tests, but compiles to the same pointer.
+#    Also we use raw_memmove in case the object overlaps with its destination.
+
+# After each collection, we bump 'next_collect_after' which is a marker
+# where to start each collection.  It should be exponential (but less
+# than 2) from the size occupied by objects so far.
 
 # field optimization - we don't need forward pointer and flags at the same
-# time. Instead we copy list of tids when we know how many objects are alive
-# and store forward pointer there.
+# time. Instead we copy the TIDs in a list when we know how many objects are
+# alive, and store the forward pointer in the old object header.
 
+first_gcflag_bit = LONG_BIT//2
+first_gcflag = 1 << first_gcflag_bit
+GCFLAG_HASHTAKEN = first_gcflag << 0      # someone already asked for the hash
+GCFLAG_HASHFIELD = first_gcflag << 1      # we have an extra hash field
+# note that only the first 2 bits are preserved during a collection!
+GCFLAG_MARKBIT   = intmask(first_gcflag << (LONG_BIT//2-1))
+assert GCFLAG_MARKBIT < 0     # should be 0x80000000
+
+GCFLAG_SAVED_HASHTAKEN = GCFLAG_HASHTAKEN >> first_gcflag_bit
+GCFLAG_SAVED_HASHFIELD = GCFLAG_HASHFIELD >> first_gcflag_bit
 
-# in case we need to grow space, we use
-# current_space_size * FREE_SPACE_MULTIPLIER / FREE_SPACE_DIVIDER + needed
-FREE_SPACE_MULTIPLIER = 3
-FREE_SPACE_DIVIDER = 2
-FREE_SPACE_ADD = 256
-# XXX adjust
-GC_CLEARANCE = 32*1024
 
 TID_TYPE = llgroup.HALFWORD
 BYTES_PER_TID = rffi.sizeof(TID_TYPE)
+TID_BACKUP = rffi.CArray(TID_TYPE)
+
+def translated_to_c():
+    return we_are_translated() and not running_on_llinterp
 
 
 class MarkCompactGC(MovingGCBase):
@@ -76,38 +70,63 @@
     withhash_flag_is_in_field = 'tid', GCFLAG_HASHFIELD
     # ^^^ all prebuilt objects have GCFLAG_HASHTAKEN, but only some have
     #     GCFLAG_HASHFIELD (and then they are one word longer).
-    TID_BACKUP = lltype.Array(TID_TYPE, hints={'nolength':True})
-    WEAKREF_OFFSETS = lltype.Array(lltype.Signed)
 
+    # The default space size is 1.9375 GB, i.e. almost 2 GB, allocated as
+    # a big mmap.  The process does not actually consume that space until
+    # needed, of course.
+    TRANSLATION_PARAMS = {'space_size': int((1 + 15.0/16)*1024*1024*1024),
+                          'min_next_collect_after': 16*1024*1024}   # 16MB
 
-    TRANSLATION_PARAMS = {'space_size': 8*1024*1024} # XXX adjust
-
-    malloc_zero_filled = True
+    malloc_zero_filled = False
     inline_simple_malloc = True
     inline_simple_malloc_varsize = True
-    first_unused_gcflag = first_gcflag << 3
-    total_collection_time = 0.0
-    total_collection_count = 0
-
-    def __init__(self, config, chunk_size=DEFAULT_CHUNK_SIZE, space_size=4096):
-        import py; py.test.skip("Disabled for now, sorry")
-        self.param_space_size = space_size
+    #total_collection_time = 0.0
+    #total_collection_count = 0
+
+    free = NULL
+    next_collect_after = -1
+
+    def __init__(self, config, chunk_size=DEFAULT_CHUNK_SIZE, space_size=4096,
+                 min_next_collect_after=128):
         MovingGCBase.__init__(self, config, chunk_size)
+        self.space_size = space_size
+        self.min_next_collect_after = min_next_collect_after
 
-    def setup(self):
-        self.space_size = self.param_space_size
-        self.next_collect_after = self.param_space_size/2 # whatever...
+    def next_collection(self, used_space, num_objects_so_far, requested_size):
+        used_space += BYTES_PER_TID * num_objects_so_far
+        ll_assert(used_space <= self.space_size,
+                  "used_space + num_objects_so_far overflow")
+        try:
+            next = (used_space // 3) * 2 + requested_size
+        except OverflowError:
+            next = self.space_size
+        if next < self.min_next_collect_after:
+            next = self.min_next_collect_after
+        if next > self.space_size - used_space:
+            next = self.space_size - used_space
+        # The value we return guarantees that used_space + next <= space_size,
+        # with 'BYTES_PER_TID*num_objects_so_far' included in used_space.
+        # Normally, the value we return should also be at least requested_size
+        # unless we are out of memory.
+        return next
 
-        if self.config.gcconfig.debugprint:
-            self.program_start_time = time.time()
-        self.space = llarena.arena_malloc(self.space_size, True)
-        ll_assert(bool(self.space), "couldn't allocate arena")
+    def setup(self):
+        envsize = read_from_env('PYPY_MARKCOMPACTGC_MAX')
+        if envsize >= 4096:
+            self.space_size = envsize & ~4095
+        mincollect = read_from_env('PYPY_MARKCOMPACTGC_MIN')
+        if mincollect >= 4096:
+            self.min_next_collect_after = mincollect
+
+        #self.program_start_time = time.time()
+        self.space = llarena.arena_malloc(self.space_size, False)
+        if not self.space:
+            raise CannotAllocateGCArena
         self.free = self.space
-        self.top_of_space = self.space + self.next_collect_after
         MovingGCBase.setup(self)
         self.objects_with_finalizers = self.AddressDeque()
-        self.objects_with_weakrefs = self.AddressStack()
-        self.tid_backup = lltype.nullptr(self.TID_BACKUP)
+        self.tid_backup = lltype.nullptr(TID_BACKUP)
+        self.next_collect_after = self.next_collection(0, 0, 0)
 
     def init_gc_object(self, addr, typeid16, flags=0):
         hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
@@ -115,219 +134,204 @@
 
     def init_gc_object_immortal(self, addr, typeid16, flags=0):
         hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
-        flags |= GCFLAG_HASHTAKEN
+        flags |= GCFLAG_HASHTAKEN | GCFLAG_MARKBIT
+        # All prebuilt GC objects have the GCFLAG_MARKBIT always set.
+        # That's convenient to make the GC always think that they
+        # survive the current collection.
         hdr.tid = self.combine(typeid16, flags)
-        # XXX we can store forward_ptr to itself, if we fix C backend
-        # so that get_forwarding_address(obj) returns
-        # obj itself if obj is a prebuilt object
 
-    def malloc_fixedsize_clear(self, typeid16, size, can_collect,
-                               has_finalizer=False, contains_weakptr=False):
-        size_gc_header = self.gcheaderbuilder.size_gc_header
-        totalsize = size_gc_header + size
-        result = self.free
-        if raw_malloc_usage(totalsize) > self.top_of_space - result:
-            result = self.obtain_free_space(totalsize)
+    def _get_memory(self, totalsize):
+        # also counts the space that will be needed during the following
+        # collection to store the TID
+        requested_size = raw_malloc_usage(totalsize) + BYTES_PER_TID
+        self.next_collect_after -= requested_size
+        if self.next_collect_after < 0:
+            result = self.obtain_free_space(requested_size)
+        else:
+            result = self.free
+        self.free += totalsize
         llarena.arena_reserve(result, totalsize)
+        return result
+    _get_memory._always_inline_ = True
+
+    def _get_totalsize_var(self, nonvarsize, itemsize, length):
+        try:
+            varsize = ovfcheck(itemsize * length)
+        except OverflowError:
+            raise MemoryError
+        # Careful to detect overflows.  The following works even if varsize
+        # is almost equal to sys.maxint; morever, self.space_size is known
+        # to be at least 4095 bytes smaller than sys.maxint, so this function
+        # always raises instead of returning an integer >= sys.maxint-4095.
+        if (raw_malloc_usage(varsize) > self.space_size -
+                                        raw_malloc_usage(nonvarsize)):
+            raise MemoryError
+        return llarena.round_up_for_allocation(nonvarsize + varsize)
+    _get_totalsize_var._always_inline_ = True
+
+    def _setup_object(self, result, typeid16, has_finalizer):
+        size_gc_header = self.gcheaderbuilder.size_gc_header
         self.init_gc_object(result, typeid16)
-        self.free += totalsize
         if has_finalizer:
             self.objects_with_finalizers.append(result + size_gc_header)
-        if contains_weakptr:
-            self.objects_with_weakrefs.append(result + size_gc_header)
         return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF)
-    
+    _setup_object._always_inline_ = True
+
+    def malloc_fixedsize(self, typeid16, size, can_collect,
+                         has_finalizer=False, contains_weakptr=False):
+        size_gc_header = self.gcheaderbuilder.size_gc_header
+        totalsize = size_gc_header + size
+        result = self._get_memory(totalsize)
+        return self._setup_object(result, typeid16, has_finalizer)
+
+    def malloc_fixedsize_clear(self, typeid16, size, can_collect,
+                               has_finalizer=False, contains_weakptr=False):
+        size_gc_header = self.gcheaderbuilder.size_gc_header
+        totalsize = size_gc_header + size
+        result = self._get_memory(totalsize)
+        llmemory.raw_memclear(result, totalsize)
+        return self._setup_object(result, typeid16, has_finalizer)
+
     def malloc_varsize_clear(self, typeid16, length, size, itemsize,
                              offset_to_length, can_collect):
         size_gc_header = self.gcheaderbuilder.size_gc_header
         nonvarsize = size_gc_header + size
-        try:
-            varsize = ovfcheck(itemsize * length)
-            totalsize = ovfcheck(nonvarsize + varsize)
-        except OverflowError:
-            raise memoryError
-        result = self.free
-        if raw_malloc_usage(totalsize) > self.top_of_space - result:
-            result = self.obtain_free_space(totalsize)
-        llarena.arena_reserve(result, totalsize)
-        self.init_gc_object(result, typeid16)
+        totalsize = self._get_totalsize_var(nonvarsize, itemsize, length)
+        result = self._get_memory(totalsize)
+        llmemory.raw_memclear(result, totalsize)
         (result + size_gc_header + offset_to_length).signed[0] = length
-        self.free = result + llarena.round_up_for_allocation(totalsize)
-        return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF)
+        return self._setup_object(result, typeid16, False)
 
-    def obtain_free_space(self, totalsize):
-        # a bit of tweaking to maximize the performance and minimize the
-        # amount of code in an inlined version of malloc_fixedsize_clear()
-        if not self.try_obtain_free_space(totalsize):
-            raise memoryError
+    def obtain_free_space(self, requested_size):
+        if self.free == NULL:
+            return self._emergency_initial_block(requested_size)
+        while True:
+            executed_some_finalizers = self.markcompactcollect(requested_size)
+            self.next_collect_after -= requested_size
+            if self.next_collect_after >= 0:
+                break    # ok
+            else:
+                if executed_some_finalizers:
+                    pass   # try again to do a collection
+                else:
+                    raise MemoryError
         return self.free
     obtain_free_space._dont_inline_ = True
 
-    def try_obtain_free_space(self, needed):
-        needed = raw_malloc_usage(needed)
-        while 1:
-            self.markcompactcollect(needed)
-            missing = needed - (self.top_of_space - self.free)
-            if missing < 0:
-                return True
-
-    def new_space_size(self, occupied, needed):
-        res = (occupied * FREE_SPACE_MULTIPLIER /
-               FREE_SPACE_DIVIDER + FREE_SPACE_ADD + needed)
-        # align it to 4096, which is somewhat around page size
-        return ((res/4096) + 1) * 4096
-
-    def double_space_size(self, minimal_size):
-        while self.space_size <= minimal_size:
-            self.space_size *= 2
-        toaddr = llarena.arena_malloc(self.space_size, True)
-        return toaddr
-
-    def compute_alive_objects(self):
-        fromaddr = self.space
-        addraftercollect = self.space
-        num = 1
-        while fromaddr < self.free:
-            size_gc_header = self.gcheaderbuilder.size_gc_header
-            tid = llmemory.cast_adr_to_ptr(fromaddr, lltype.Ptr(self.HDR)).tid
-            obj = fromaddr + size_gc_header
-            objsize = self.get_size(obj)
-            objtotalsize = size_gc_header + objsize
-            if self.marked(obj):
-                copy_has_hash_field = ((tid & GCFLAG_HASHFIELD) != 0 or
-                                       ((tid & GCFLAG_HASHTAKEN) != 0 and
-                                        addraftercollect < fromaddr))
-                addraftercollect += raw_malloc_usage(objtotalsize)
-                if copy_has_hash_field:
-                    addraftercollect += llmemory.sizeof(lltype.Signed)
-            num += 1
-            fromaddr += objtotalsize
-            if tid & GCFLAG_HASHFIELD:
-                fromaddr += llmemory.sizeof(lltype.Signed)
-        ll_assert(addraftercollect <= fromaddr,
-                  "markcompactcollect() is trying to increase memory usage")
-        self.totalsize_of_objs = addraftercollect - self.space
-        return num
+    def _emergency_initial_block(self, requested_size):
+        # xxx before the GC is fully setup, we might get there.  Hopefully
+        # we will only allocate a couple of strings, e.g. in read_from_env().
+        # Just allocate them raw and leak them.
+        debug_start("gc-initial-block")
+        debug_print("leaking", requested_size, "bytes")
+        debug_stop("gc-initial-block")
+        return llmemory.raw_malloc(requested_size)
 
     def collect(self, gen=0):
         self.markcompactcollect()
-    
-    def markcompactcollect(self, needed=0):
-        start_time = self.debug_collect_start()
+
+    def markcompactcollect(self, requested_size=0):
+        self.debug_collect_start(requested_size)
         self.debug_check_consistency()
-        self.to_see = self.AddressStack()
-        self.mark_roots_recursively()
-        if (self.objects_with_finalizers.non_empty() or
-            self.run_finalizers.non_empty()):
-            self.mark_objects_with_finalizers()
-            self._trace_and_mark()
+        #
+        # Mark alive objects
+        #
+        self.to_see = self.AddressDeque()
+        self.trace_from_roots()
         self.to_see.delete()
-        num_of_alive_objs = self.compute_alive_objects()
-        size_of_alive_objs = self.totalsize_of_objs
-        totalsize = self.new_space_size(size_of_alive_objs, needed +
-                                        num_of_alive_objs * BYTES_PER_TID)
-        tid_backup_size = (llmemory.sizeof(self.TID_BACKUP, 0) +
-                           llmemory.sizeof(TID_TYPE) * num_of_alive_objs)
-        used_space_now = self.next_collect_after + raw_malloc_usage(tid_backup_size)
-        if totalsize >= self.space_size or used_space_now >= self.space_size:
-            toaddr = self.double_space_size(totalsize)
-            llarena.arena_reserve(toaddr + size_of_alive_objs, tid_backup_size)
-            self.tid_backup = llmemory.cast_adr_to_ptr(
-                toaddr + size_of_alive_objs,
-                lltype.Ptr(self.TID_BACKUP))
-            resizing = True
-        else:
-            toaddr = llarena.arena_new_view(self.space)
-            llarena.arena_reserve(self.top_of_space, tid_backup_size)
-            self.tid_backup = llmemory.cast_adr_to_ptr(
-                self.top_of_space,
-                lltype.Ptr(self.TID_BACKUP))
-            resizing = False
-        self.next_collect_after = totalsize
-        weakref_offsets = self.collect_weakref_offsets()
-        finaladdr = self.update_forward_pointers(toaddr, num_of_alive_objs)
+        #
+        # Prepare new views on the same memory
+        #
+        toaddr = llarena.arena_new_view(self.space)
+        maxnum = self.space_size - (self.free - self.space)
+        maxnum /= BYTES_PER_TID
+        llarena.arena_reserve(self.free, llmemory.sizeof(TID_BACKUP, maxnum))
+        self.tid_backup = llmemory.cast_adr_to_ptr(self.free,
+                                                   lltype.Ptr(TID_BACKUP))
+        #
+        # Walk all objects and assign forward pointers in the same order,
+        # also updating all references
+        #
+        self.update_forward_pointers(toaddr, maxnum)
         if (self.run_finalizers.non_empty() or
             self.objects_with_finalizers.non_empty()):
             self.update_run_finalizers()
-        if self.objects_with_weakrefs.non_empty():
-            self.invalidate_weakrefs(weakref_offsets)
+
         self.update_objects_with_id()
-        self.compact(resizing)
-        if not resizing:
-            size = toaddr + self.space_size - finaladdr
-            llarena.arena_reset(finaladdr, size, True)
-        else:
-            if we_are_translated():
-                # because we free stuff already in raw_memmove, we
-                # would get double free here. Let's free it anyway
-                llarena.arena_free(self.space)
-            llarena.arena_reset(toaddr + size_of_alive_objs, tid_backup_size,
-                                True)
-        self.space        = toaddr
-        self.free         = finaladdr
-        self.top_of_space = toaddr + self.next_collect_after
+        self.compact()
+        #
+        self.tid_backup = lltype.nullptr(TID_BACKUP)
+        self.free = self.finaladdr
+        self.next_collect_after = self.next_collection(self.finaladdr - toaddr,
+                                                       self.num_alive_objs,
+                                                       requested_size)
+        #
+        if not translated_to_c():
+            remaining_size = (toaddr + self.space_size) - self.finaladdr
+            llarena.arena_reset(self.finaladdr, remaining_size, False)
+            llarena.arena_free(self.space)
+            self.space = toaddr
+        #
         self.debug_check_consistency()
-        self.tid_backup = lltype.nullptr(self.TID_BACKUP)
+        self.debug_collect_finish()
+        if self.next_collect_after < 0:
+            raise MemoryError
+        #
         if self.run_finalizers.non_empty():
             self.execute_finalizers()
-        self.debug_collect_finish(start_time)
-        
-    def collect_weakref_offsets(self):
-        weakrefs = self.objects_with_weakrefs
-        new_weakrefs = self.AddressStack()
-        weakref_offsets = lltype.malloc(self.WEAKREF_OFFSETS,
-                                        weakrefs.length(), flavor='raw')
-        i = 0
-        while weakrefs.non_empty():
-            obj = weakrefs.pop()
-            offset = self.weakpointer_offset(self.get_type_id(obj))
-            weakref_offsets[i] = offset
-            new_weakrefs.append(obj)
-            i += 1
-        self.objects_with_weakrefs = new_weakrefs
-        weakrefs.delete()
-        return weakref_offsets
-
-    def debug_collect_start(self):
-        if self.config.gcconfig.debugprint:
-            llop.debug_print(lltype.Void)
-            llop.debug_print(lltype.Void,
-                             ".----------- Full collection ------------------")
-            start_time = time.time()
-            return start_time 
-
-    def debug_collect_finish(self, start_time):
-        if self.config.gcconfig.debugprint:
-            end_time = time.time()
-            elapsed_time = end_time - start_time
-            self.total_collection_time += elapsed_time
-            self.total_collection_count += 1
-            total_program_time = end_time - self.program_start_time
-            ct = self.total_collection_time
-            cc = self.total_collection_count
-            llop.debug_print(lltype.Void,
-                             "| number of collections so far       ", 
-                             cc)
-            llop.debug_print(lltype.Void,
-                             "| total collections per second:      ",
-                             cc / total_program_time)
-            llop.debug_print(lltype.Void,
-                             "| total time in markcompact-collect: ",
-                             ct, "seconds")
-            llop.debug_print(lltype.Void,
-                             "| percentage collection<->total time:",
-                             ct * 100.0 / total_program_time, "%")
-            llop.debug_print(lltype.Void,
-                             "`----------------------------------------------")
+            return True      # executed some finalizers
+        else:
+            return False     # no finalizer executed
+
+    def debug_collect_start(self, requested_size):
+        if 1:# have_debug_prints():
+            debug_start("gc-collect")
+            debug_print()
+            debug_print(".----------- Full collection -------------------")
+            debug_print("| requested size:",
+                        requested_size)
+            #start_time = time.time()
+            #return start_time
+        #return -1
+
+    def debug_collect_finish(self):
+        if 1:# start_time != -1:
+            #end_time = time.time()
+            #elapsed_time = end_time - start_time
+            #self.total_collection_time += elapsed_time
+            #self.total_collection_count += 1
+            #total_program_time = end_time - self.program_start_time
+            #ct = self.total_collection_time
+            #cc = self.total_collection_count
+            #debug_print("| number of collections so far       ", 
+            #            cc)
+            debug_print("| total space size                   ", 
+                        self.space_size)
+            debug_print("| number of objects alive            ", 
+                        self.num_alive_objs)
+            debug_print("| used space size                    ", 
+                        self.free - self.space)
+            debug_print("| next collection after              ", 
+                        self.next_collect_after)
+            #debug_print("| total collections per second:      ",
+            #            cc / total_program_time)
+            #debug_print("| total time in markcompact-collect: ",
+            #            ct, "seconds")
+            #debug_print("| percentage collection<->total time:",
+            #            ct * 100.0 / total_program_time, "%")
+            debug_print("`----------------------------------------------")
+            debug_stop("gc-collect")
 
 
     def update_run_finalizers(self):
-        run_finalizers = self.AddressDeque()
-        while self.run_finalizers.non_empty():
-            obj = self.run_finalizers.popleft()
-            run_finalizers.append(self.get_forwarding_address(obj))
-        self.run_finalizers.delete()
-        self.run_finalizers = run_finalizers
+        if self.run_finalizers.non_empty():     # uncommon case
+            run_finalizers = self.AddressDeque()
+            while self.run_finalizers.non_empty():
+                obj = self.run_finalizers.popleft()
+                run_finalizers.append(self.get_forwarding_address(obj))
+            self.run_finalizers.delete()
+            self.run_finalizers = run_finalizers
+        #
         objects_with_finalizers = self.AddressDeque()
         while self.objects_with_finalizers.non_empty():
             obj = self.objects_with_finalizers.popleft()
@@ -356,90 +360,156 @@
         tid = self.header(addr).tid
         return llop.extract_ushort(llgroup.HALFWORD, tid)
 
-    def mark_roots_recursively(self):
+    def trace_from_roots(self):
         self.root_walker.walk_roots(
-            MarkCompactGC._mark_root_recursively,  # stack roots
-            MarkCompactGC._mark_root_recursively,  # static in prebuilt non-gc structures
-            MarkCompactGC._mark_root_recursively)  # static in prebuilt gc objects
+            MarkCompactGC._mark_root,  # stack roots
+            MarkCompactGC._mark_root,  # static in prebuilt non-gc structures
+            MarkCompactGC._mark_root)  # static in prebuilt gc objects
+        if (self.objects_with_finalizers.non_empty() or
+            self.run_finalizers.non_empty()):
+            self.trace_from_objects_with_finalizers()
         self._trace_and_mark()
 
     def _trace_and_mark(self):
-        # XXX depth-first tracing... it can consume a lot of rawmalloced
-        # memory for very long stacks in some cases
         while self.to_see.non_empty():
-            obj = self.to_see.pop()
+            obj = self.to_see.popleft()
             self.trace(obj, self._mark_obj, None)
 
     def _mark_obj(self, pointer, ignored):
-        obj = pointer.address[0]
-        if self.marked(obj):
-            return
-        self.mark(obj)
-        self.to_see.append(obj)
+        self.mark(pointer.address[0])
 
-    def _mark_root_recursively(self, root):
+    def _mark_root(self, root):
         self.mark(root.address[0])
-        self.to_see.append(root.address[0])
 
     def mark(self, obj):
-        self.header(obj).tid |= GCFLAG_MARKBIT
+        if not self.marked(obj):
+            self.header(obj).tid |= GCFLAG_MARKBIT
+            self.to_see.append(obj)
 
     def marked(self, obj):
-        return self.header(obj).tid & GCFLAG_MARKBIT
+        # should work both if tid contains a CombinedSymbolic (for dying
+        # objects, at this point), or a plain integer.
+        return MovingGCBase.header(self, obj).tid & GCFLAG_MARKBIT
+
+    def toaddr_smaller_than_fromaddr(self, toaddr, fromaddr):
+        if translated_to_c():
+            return toaddr < fromaddr
+        else:
+            # convert the addresses to integers, because they are
+            # theoretically not from the same arena
+            return toaddr - self.base_forwarding_addr < fromaddr - self.space
 
-    def update_forward_pointers(self, toaddr, num_of_alive_objs):
-        self.base_forwarding_addr = toaddr
+    def update_forward_pointers(self, toaddr, maxnum):
+        self.base_forwarding_addr = base_forwarding_addr = toaddr
         fromaddr = self.space
         size_gc_header = self.gcheaderbuilder.size_gc_header
-        i = 0
+        num = 0
         while fromaddr < self.free:
             hdr = llmemory.cast_adr_to_ptr(fromaddr, lltype.Ptr(self.HDR))
             obj = fromaddr + size_gc_header
-            objsize = self.get_size(obj)
-            totalsize = size_gc_header + objsize
-            if not self.marked(obj):
-                self.set_null_forwarding_address(obj, i)
-            else:
-                llarena.arena_reserve(toaddr, totalsize)
-                self.set_forwarding_address(obj, toaddr, i)
-                toaddr += totalsize
-            i += 1
-            fromaddr += totalsize
+            # compute the original object size, including the
+            # optional hash field
+            basesize = size_gc_header + self.get_size(obj)
+            totalsrcsize = basesize
+            if hdr.tid & GCFLAG_HASHFIELD:  # already a hash field, copy it too
+                totalsrcsize += llmemory.sizeof(lltype.Signed)
+            #
+            if self.marked(obj):
+                # the object is marked as suriving.  Compute the new object
+                # size
+                totaldstsize = totalsrcsize
+                if (hdr.tid & (GCFLAG_HASHTAKEN|GCFLAG_HASHFIELD) ==
+                               GCFLAG_HASHTAKEN):
+                    # grow a new hash field -- with the exception: if
+                    # the object actually doesn't move, don't
+                    # (otherwise, we get a bogus toaddr > fromaddr)
+                    if self.toaddr_smaller_than_fromaddr(toaddr, fromaddr):
+                        totaldstsize += llmemory.sizeof(lltype.Signed)
+                #
+                if not translated_to_c():
+                    llarena.arena_reserve(toaddr, basesize)
+                    if (raw_malloc_usage(totaldstsize) >
+                        raw_malloc_usage(basesize)):
+                        llarena.arena_reserve(toaddr + basesize,
+                                              llmemory.sizeof(lltype.Signed))
+                #
+                # save the field hdr.tid in the array tid_backup
+                ll_assert(num < maxnum, "overflow of the tid_backup table")
+                self.tid_backup[num] = self.get_type_id(obj)
+                num += 1
+                # compute forward_offset, the offset to the future copy
+                # of this object
+                forward_offset = toaddr - base_forwarding_addr
+                # copy the first two gc flags in forward_offset
+                ll_assert(forward_offset & 3 == 0, "misalignment!")
+                forward_offset |= (hdr.tid >> first_gcflag_bit) & 3
+                hdr.tid = forward_offset | GCFLAG_MARKBIT
+                ll_assert(self.marked(obj), "re-marking object failed!")
+                # done
+                toaddr += totaldstsize
+            #
+            fromaddr += totalsrcsize
+            if not translated_to_c():
+                assert toaddr - base_forwarding_addr <= fromaddr - self.space
+        self.num_alive_objs = num
+        self.finaladdr = toaddr
 
         # now update references
         self.root_walker.walk_roots(
-            MarkCompactGC._update_root,  # stack roots
-            MarkCompactGC._update_root,  # static in prebuilt non-gc structures
-            MarkCompactGC._update_root)  # static in prebuilt gc objects
+            MarkCompactGC._update_ref,  # stack roots
+            MarkCompactGC._update_ref,  # static in prebuilt non-gc structures
+            MarkCompactGC._update_ref)  # static in prebuilt gc objects
+        self.walk_marked_objects(MarkCompactGC.trace_and_update_ref)
+
+    def walk_marked_objects(self, callback):
+        num = 0
+        size_gc_header = self.gcheaderbuilder.size_gc_header
         fromaddr = self.space
-        i = 0
+        toaddr = self.base_forwarding_addr
         while fromaddr < self.free:
             hdr = llmemory.cast_adr_to_ptr(fromaddr, lltype.Ptr(self.HDR))
             obj = fromaddr + size_gc_header
-            objsize = self.get_size_from_backup(obj, i)
-            totalsize = size_gc_header + objsize
-            if not self.surviving(obj):
-                pass
+            survives = self.marked(obj)
+            if survives:
+                typeid = self.get_typeid_from_backup(num)
+                num += 1
             else:
-                self.trace_with_backup(obj, self._update_ref, i)
-            fromaddr += totalsize
-            i += 1
-        return toaddr
+                typeid = self.get_type_id(obj)
+            baseobjsize = self._get_size_for_typeid(obj, typeid)
+            basesize = size_gc_header + baseobjsize
+            totalsrcsize = basesize
+            #
+            if survives:
+                grow_hash_field = False
+                if hdr.tid & GCFLAG_SAVED_HASHFIELD:
+                    totalsrcsize += llmemory.sizeof(lltype.Signed)
+                totaldstsize = totalsrcsize
+                if (hdr.tid & (GCFLAG_SAVED_HASHTAKEN|GCFLAG_SAVED_HASHFIELD)
+                            == GCFLAG_SAVED_HASHTAKEN):
+                    if self.toaddr_smaller_than_fromaddr(toaddr, fromaddr):
+                        grow_hash_field = True
+                        totaldstsize += llmemory.sizeof(lltype.Signed)
+                callback(self, obj, typeid, basesize, toaddr, grow_hash_field)
+                toaddr += totaldstsize
+            else:
+                if hdr.tid & GCFLAG_HASHFIELD:
+                    totalsrcsize += llmemory.sizeof(lltype.Signed)
+            #
+            fromaddr += totalsrcsize
+    walk_marked_objects._annspecialcase_ = 'specialize:arg(1)'
 
-    def trace_with_backup(self, obj, callback, arg):
+    def trace_and_update_ref(self, obj, typeid, _1, _2, _3):
         """Enumerate the locations inside the given obj that can contain
         GC pointers.  For each such location, callback(pointer, arg) is
         called, where 'pointer' is an address inside the object.
         Typically, 'callback' is a bound method and 'arg' can be None.
         """
-        typeid = self.get_typeid_from_backup(arg)
         if self.is_gcarrayofgcptr(typeid):
             # a performance shortcut for GcArray(gcptr)
             length = (obj + llmemory.gcarrayofptr_lengthoffset).signed[0]
             item = obj + llmemory.gcarrayofptr_itemsoffset
             while length > 0:
-                if self.points_to_valid_gc_object(item):
-                    callback(item, arg)
+                self._update_ref(item)
                 item += llmemory.gcarrayofptr_singleitemoffset
                 length -= 1
             return
@@ -447,8 +517,7 @@
         i = 0
         while i < len(offsets):
             item = obj + offsets[i]
-            if self.points_to_valid_gc_object(item):
-                callback(item, arg)
+            self._update_ref(item)
             i += 1
         if self.has_gcptr_in_varsize(typeid):
             item = obj + self.varsize_offset_to_variable_part(typeid)
@@ -459,171 +528,122 @@
                 j = 0
                 while j < len(offsets):
                     itemobj = item + offsets[j]
-                    if self.points_to_valid_gc_object(itemobj):
-                        callback(itemobj, arg)
+                    self._update_ref(itemobj)
                     j += 1
                 item += itemlength
                 length -= 1
-    trace_with_backup._annspecialcase_ = 'specialize:arg(2)'
-
-    def _update_root(self, pointer):
-        if pointer.address[0] != NULL:
-            pointer.address[0] = self.get_forwarding_address(pointer.address[0])
-
-    def _update_ref(self, pointer, ignore):
-        if pointer.address[0] != NULL:
-            pointer.address[0] = self.get_forwarding_address(pointer.address[0])
+        else:
+            weakofs = self.weakpointer_offset(typeid)
+            if weakofs >= 0:
+                self._update_weakref(obj + weakofs)
+
+    def _update_ref(self, pointer):
+        if self.points_to_valid_gc_object(pointer):
+            pointer.address[0] = self.get_forwarding_address(
+                pointer.address[0])
+
+    def _update_weakref(self, pointer):
+        # either update the weak pointer's destination, or
+        # if it dies, write a NULL
+        if self.points_to_valid_gc_object(pointer):
+            if self.marked(pointer.address[0]):
+                pointer.address[0] = self.get_forwarding_address(
+                    pointer.address[0])
+            else:
+                pointer.address[0] = NULL
 
     def _is_external(self, obj):
-        return not (self.space <= obj < self.top_of_space)
+        return not (self.space <= obj < self.free)
 
     def get_forwarding_address(self, obj):
         if self._is_external(obj):
             return obj
         return self.get_header_forwarded_addr(obj)
 
-    def set_null_forwarding_address(self, obj, num):
-        self.backup_typeid(num, obj)
-        hdr = self.header(obj)
-        hdr.tid = -1          # make the object forwarded to NULL
-
-    def set_forwarding_address(self, obj, newobjhdr, num):
-        self.backup_typeid(num, obj)
-        forward_offset = newobjhdr - self.base_forwarding_addr
-        hdr = self.header(obj)
-        hdr.tid = forward_offset     # make the object forwarded to newobj
-
-    def restore_normal_header(self, obj, num):
-        # Reverse of set_forwarding_address().
-        typeid16 = self.get_typeid_from_backup(num)
-        hdr = self.header_forwarded(obj)
-        hdr.tid = self.combine(typeid16, 0)      # restore the normal header
-
     def get_header_forwarded_addr(self, obj):
-        return (self.base_forwarding_addr +
-                self.header_forwarded(obj).tid +
-                self.gcheaderbuilder.size_gc_header)
+        tid = self.header_forwarded(obj).tid
+        ll_assert(tid & GCFLAG_MARKBIT != 0, "dying object is not forwarded")
+        GCFLAG_MASK = ~(GCFLAG_MARKBIT | 3)
+        res = (self.base_forwarding_addr + (tid & GCFLAG_MASK) +
+               self.gcheaderbuilder.size_gc_header)
+        ll_assert(res < self.finaladdr, "forwarded address >= self.finaladdr")
+        return res
 
     def surviving(self, obj):
-        return self._is_external(obj) or self.header_forwarded(obj).tid != -1
-
-    def backup_typeid(self, num, obj):
-        self.tid_backup[num] = self.get_type_id(obj)
+        return self.marked(obj)
 
     def get_typeid_from_backup(self, num):
         return self.tid_backup[num]
 
-    def get_size_from_backup(self, obj, num):
-        typeid = self.get_typeid_from_backup(num)
-        size = self.fixed_size(typeid)
-        if self.is_varsize(typeid):
-            lenaddr = obj + self.varsize_offset_to_length(typeid)
-            length = lenaddr.signed[0]
-            size += length * self.varsize_item_sizes(typeid)
-            size = llarena.round_up_for_allocation(size)
-            # XXX maybe we should parametrize round_up_for_allocation()
-            # per GC; if we do, we also need to fix the call in
-            # gctypelayout.encode_type_shape()
-        return size
+    def compact(self):
+        self.walk_marked_objects(MarkCompactGC.copy_and_compact)
 
-    def compact(self, resizing):
-        fromaddr = self.space
-        size_gc_header = self.gcheaderbuilder.size_gc_header
-        start = fromaddr
-        end = fromaddr
-        num = 0
-        while fromaddr < self.free:
-            obj = fromaddr + size_gc_header
-            objsize = self.get_size_from_backup(obj, num)
-            totalsize = size_gc_header + objsize
-            if not self.surviving(obj): 
-                # this object dies. Following line is a noop in C,
-                # we clear it to make debugging easier
-                llarena.arena_reset(fromaddr, totalsize, False)
-            else:
-                if resizing:
-                    end = fromaddr
-                forward_obj = self.get_header_forwarded_addr(obj)
-                self.restore_normal_header(obj, num)
-                if obj != forward_obj:
-                    #llop.debug_print(lltype.Void, "Copying from to",
-                    #                 fromaddr, forward_ptr, totalsize)
-                    llmemory.raw_memmove(fromaddr,
-                                         forward_obj - size_gc_header,
-                                         totalsize)
-                if resizing and end - start > GC_CLEARANCE:
-                    diff = end - start
-                    #llop.debug_print(lltype.Void, "Cleaning", start, diff)
-                    diff = (diff / GC_CLEARANCE) * GC_CLEARANCE
-                    #llop.debug_print(lltype.Void, "Cleaning", start, diff)
-                    end = start + diff
-                    if we_are_translated():
-                        # XXX wuaaaaa.... those objects are freed incorrectly
-                        #                 here in case of test_gc
-                        llarena.arena_reset(start, diff, True)
-                    start += diff
-            num += 1
-            fromaddr += totalsize
+    def copy_and_compact(self, obj, typeid, basesize, toaddr, grow_hash_field):
+        # 'basesize' is the size without any hash field
+        # restore the normal header
+        hdr = self.header_forwarded(obj)
+        gcflags = hdr.tid & 3
+        if grow_hash_field:
+            gcflags |= GCFLAG_SAVED_HASHFIELD
+            hashvalue = self.get_identityhash_from_addr(obj)
+        elif gcflags & GCFLAG_SAVED_HASHFIELD:
+            fromaddr = llarena.getfakearenaaddress(obj)
+            fromaddr -= self.gcheaderbuilder.size_gc_header
+            hashvalue = (fromaddr + basesize).signed[0]
+        else:
+            hashvalue = 0     # not used
+        #
+        hdr.tid = self.combine(typeid, gcflags << first_gcflag_bit)
+        #
+        fromaddr = obj - self.gcheaderbuilder.size_gc_header
+        if translated_to_c():
+            llmemory.raw_memmove(fromaddr, toaddr, basesize)
+        else:
+            llmemory.raw_memcopy(fromaddr, toaddr, basesize)
+        #
+        if gcflags & GCFLAG_SAVED_HASHFIELD:
+            (toaddr + basesize).signed[0] = hashvalue
 
     def debug_check_object(self, obj):
-        # not sure what to check here
-        pass
-
-    def mark_objects_with_finalizers(self):
+        type_id = self.get_type_id(obj)
+        self.has_gcptr_in_varsize(type_id)   # checks that the type_id is valid
+        #
+        tid = self.header(obj).tid
+        if self._is_external(obj):
+            # All external objects have GCFLAG_MARKBIT and GCFLAG_HASHTAKEN
+            # set.
+            assert tid & GCFLAG_MARKBIT
+            assert tid & GCFLAG_HASHTAKEN
+        else:
+            # Non-external objects have GCFLAG_MARKBIT that should not be set
+            # at the very start or at the very end of a collection -- only
+            # temporarily during the collection.
+            assert tid & GCFLAG_MARKBIT == 0
+
+    def trace_from_objects_with_finalizers(self):
+        if self.run_finalizers.non_empty():   # uncommon case
+            new_run_finalizers = self.AddressDeque()
+            while self.run_finalizers.non_empty():
+                x = self.run_finalizers.popleft()
+                self.mark(x)
+                new_run_finalizers.append(x)
+            self.run_finalizers.delete()
+            self.run_finalizers = new_run_finalizers
+        #
+        # xxx we get to run the finalizers in a random order
+        self._trace_and_mark()
         new_with_finalizers = self.AddressDeque()
-        run_finalizers = self.run_finalizers
-        new_run_finalizers = self.AddressDeque()
-        while run_finalizers.non_empty():
-            x = run_finalizers.popleft()
-            self.mark(x)
-            self.to_see.append(x)
-            new_run_finalizers.append(x)
-        run_finalizers.delete()
-        self.run_finalizers = new_run_finalizers
         while self.objects_with_finalizers.non_empty():
             x = self.objects_with_finalizers.popleft()
             if self.marked(x):
                 new_with_finalizers.append(x)
             else:
-                new_run_finalizers.append(x)
+                self.run_finalizers.append(x)
                 self.mark(x)
-                self.to_see.append(x)
+                self._trace_and_mark()
         self.objects_with_finalizers.delete()
         self.objects_with_finalizers = new_with_finalizers
 
-    def invalidate_weakrefs(self, weakref_offsets):
-        # walk over list of objects that contain weakrefs
-        # if the object it references survives then update the weakref
-        # otherwise invalidate the weakref
-        new_with_weakref = self.AddressStack()
-        i = 0
-        while self.objects_with_weakrefs.non_empty():
-            obj = self.objects_with_weakrefs.pop()
-            if not self.surviving(obj):
-                continue # weakref itself dies
-            newobj = self.get_forwarding_address(obj)
-            offset = weakref_offsets[i]
-            pointing_to = (obj + offset).address[0]
-            # XXX I think that pointing_to cannot be NULL here
-            if pointing_to:
-                if self.surviving(pointing_to):
-                    (obj + offset).address[0] = self.get_forwarding_address(
-                        pointing_to)
-                    new_with_weakref.append(newobj)
-                else:
-                    (obj + offset).address[0] = NULL
-            i += 1
-        self.objects_with_weakrefs.delete()
-        self.objects_with_weakrefs = new_with_weakref
-        lltype.free(weakref_offsets, flavor='raw')
-
-    def get_size_incl_hash(self, obj):
-        size = self.get_size(obj)
-        hdr = self.header(obj)
-        if hdr.tid & GCFLAG_HASHFIELD:
-            size += llmemory.sizeof(lltype.Signed)
-        return size
-
     def identityhash(self, gcobj):
         # Unlike SemiSpaceGC.identityhash(), this function does not have
         # to care about reducing top_of_space.  The reason is as
@@ -638,8 +658,23 @@
         hdr = self.header(obj)
         #
         if hdr.tid & GCFLAG_HASHFIELD:  # the hash is in a field at the end
-            obj += self.get_size(obj)
+            obj = llarena.getfakearenaaddress(obj) + self.get_size(obj)
             return obj.signed[0]
         #
         hdr.tid |= GCFLAG_HASHTAKEN
-        return llmemory.cast_adr_to_int(obj)  # direct case
+        return self.get_identityhash_from_addr(obj)
+
+    def get_identityhash_from_addr(self, obj):
+        if translated_to_c():
+            return llmemory.cast_adr_to_int(obj)  # direct case
+        else:
+            try:
+                adr = llarena.getfakearenaaddress(obj)   # -> arena address
+            except RuntimeError:
+                return llmemory.cast_adr_to_int(obj)  # not in an arena...
+            return adr - self.space
+
+# ____________________________________________________________
+
+class CannotAllocateGCArena(Exception):
+    pass

Modified: pypy/branch/fast-forward/pypy/rpython/memory/gc/test/test_direct.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/gc/test/test_direct.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/gc/test/test_direct.py	Thu Sep  9 01:00:13 2010
@@ -67,7 +67,10 @@
         from pypy.config.pypyoption import get_pypy_config
         config = get_pypy_config(translating=True).translation
         self.stackroots = []
-        self.gc = self.GCClass(config, **self.GC_PARAMS)
+        GC_PARAMS = self.GC_PARAMS.copy()
+        if hasattr(meth, 'GC_PARAMS'):
+            GC_PARAMS.update(meth.GC_PARAMS)
+        self.gc = self.GCClass(config, **GC_PARAMS)
         self.gc.DEBUG = True
         self.rootwalker = DirectRootWalker(self)
         self.gc.set_root_walker(self.rootwalker)
@@ -96,7 +99,7 @@
         p[index] = newvalue
 
     def malloc(self, TYPE, n=None):
-        addr = self.gc.malloc(self.get_type_id(TYPE), n)
+        addr = self.gc.malloc(self.get_type_id(TYPE), n, zero=True)
         return llmemory.cast_adr_to_ptr(addr, lltype.Ptr(TYPE))
 
     def test_simple(self):
@@ -311,7 +314,18 @@
         print hash
         assert isinstance(hash, (int, long))
         assert hash == self.gc.identityhash(p_const)
-
+        # (5) p is actually moving (for the markcompact gc)
+        p0 = self.malloc(S)
+        self.stackroots.append(p0)
+        p = self.malloc(S)
+        self.stackroots.append(p)
+        hash = self.gc.identityhash(p)
+        self.stackroots.pop(-2)
+        self.gc.collect()     # p0 goes away, p shifts left
+        assert hash == self.gc.identityhash(self.stackroots[-1])
+        self.gc.collect()
+        assert hash == self.gc.identityhash(self.stackroots[-1])
+        self.stackroots.pop()
 
 class TestSemiSpaceGC(DirectGCTest):
     from pypy.rpython.memory.gc.semispace import SemiSpaceGC as GCClass
@@ -431,3 +445,14 @@
 class TestMarkCompactGC(DirectGCTest):
     from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass
 
+    def test_many_objects(self):
+        DirectGCTest.test_many_objects(self)
+    test_many_objects.GC_PARAMS = {'space_size': 3 * 1024 * WORD}
+
+    def test_varsized_from_stack(self):
+        DirectGCTest.test_varsized_from_stack(self)
+    test_varsized_from_stack.GC_PARAMS = {'space_size': 2 * 1024 * WORD}
+
+    def test_varsized_from_prebuilt_gc(self):
+        DirectGCTest.test_varsized_from_prebuilt_gc(self)
+    test_varsized_from_prebuilt_gc.GC_PARAMS = {'space_size': 3 * 1024 * WORD}

Modified: pypy/branch/fast-forward/pypy/rpython/memory/gctransform/asmgcroot.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/gctransform/asmgcroot.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/gctransform/asmgcroot.py	Thu Sep  9 01:00:13 2010
@@ -18,6 +18,7 @@
 #  The .s file produced by GCC is then parsed by trackgcroot.py.
 #
 
+IS_64_BITS = sys.maxint > 2147483647
 
 class AsmGcRootFrameworkGCTransformer(FrameworkGCTransformer):
     _asmgcc_save_restore_arguments = None
@@ -326,7 +327,7 @@
             ll_assert(reg < CALLEE_SAVED_REGS, "bad register location")
             return callee.regs_stored_at[reg]
         elif kind == LOC_ESP_PLUS:    # in the caller stack frame at N(%esp)
-            esp_in_caller = callee.frame_address + 4
+            esp_in_caller = callee.frame_address + sizeofaddr
             return esp_in_caller + offset
         elif kind == LOC_EBP_PLUS:    # in the caller stack frame at N(%ebp)
             ebp_in_caller = callee.regs_stored_at[INDEX_OF_EBP].address[0]
@@ -415,11 +416,12 @@
     key1 = addr1.address[0]
     key2 = addr2.address[0]
     if key1 < key2:
-        return -1
+        result = -1
     elif key1 == key2:
-        return 0
+        result = 0
     else:
-        return 1
+        result = 1
+    return rffi.cast(rffi.INT, result)
 
 # ____________________________________________________________
 
@@ -464,9 +466,15 @@
 #   - frame address (actually the addr of the retaddr of the current function;
 #                    that's the last word of the frame in memory)
 #
-CALLEE_SAVED_REGS = 4       # there are 4 callee-saved registers
-INDEX_OF_EBP      = 3
-FRAME_PTR         = CALLEE_SAVED_REGS    # the frame is at index 4 in the array
+
+if IS_64_BITS:
+    CALLEE_SAVED_REGS = 6
+    INDEX_OF_EBP      = 5
+    FRAME_PTR         = CALLEE_SAVED_REGS
+else:
+    CALLEE_SAVED_REGS = 4       # there are 4 callee-saved registers
+    INDEX_OF_EBP      = 3
+    FRAME_PTR         = CALLEE_SAVED_REGS    # the frame is at index 4 in the array
 
 ASM_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([], lltype.Void))
 

Modified: pypy/branch/fast-forward/pypy/rpython/memory/gctypelayout.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/gctypelayout.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/gctypelayout.py	Thu Sep  9 01:00:13 2010
@@ -3,6 +3,7 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.debug import ll_assert
+from pypy.rlib.rarithmetic import intmask
 from pypy.tool.identity_dict import identity_dict
 
 
@@ -44,16 +45,18 @@
         self.type_info_group_ptr = type_info_group._as_ptr()
 
     def get(self, typeid):
-        _check_typeid(typeid)
-        return llop.get_group_member(GCData.TYPE_INFO_PTR,
-                                     self.type_info_group_ptr,
-                                     typeid)
+        res = llop.get_group_member(GCData.TYPE_INFO_PTR,
+                                    self.type_info_group_ptr,
+                                    typeid)
+        _check_valid_type_info(res)
+        return res
 
     def get_varsize(self, typeid):
-        _check_typeid(typeid)
-        return llop.get_group_member(GCData.VARSIZE_TYPE_INFO_PTR,
-                                     self.type_info_group_ptr,
-                                     typeid)
+        res = llop.get_group_member(GCData.VARSIZE_TYPE_INFO_PTR,
+                                    self.type_info_group_ptr,
+                                    typeid)
+        _check_valid_type_info_varsize(res)
+        return res
 
     def q_is_varsize(self, typeid):
         infobits = self.get(typeid).infobits
@@ -115,13 +118,24 @@
 
 
 # the lowest 16bits are used to store group member index
-T_MEMBER_INDEX         = 0xffff
+T_MEMBER_INDEX         =  0xffff
 T_IS_VARSIZE           = 0x10000
 T_HAS_GCPTR_IN_VARSIZE = 0x20000
 T_IS_GCARRAY_OF_GCPTR  = 0x40000
 T_IS_WEAKREF           = 0x80000
+T_KEY_MASK             = intmask(0xFF000000)
+T_KEY_VALUE            = intmask(0x7A000000)    # bug detection only
 
-def _check_typeid(typeid):
+def _check_valid_type_info(p):
+    ll_assert(p.infobits & T_KEY_MASK == T_KEY_VALUE, "invalid type_id")
+
+def _check_valid_type_info_varsize(p):
+    ll_assert(p.header.infobits & (T_KEY_MASK | T_IS_VARSIZE) ==
+                                  (T_KEY_VALUE | T_IS_VARSIZE),
+              "invalid varsize type_id")
+
+def check_typeid(typeid):
+    # xxx does not perform a full check of validity, just checks for nonzero
     ll_assert(llop.is_group_member_nonzero(lltype.Bool, typeid),
               "invalid type_id")
 
@@ -165,9 +179,9 @@
             infobits |= T_HAS_GCPTR_IN_VARSIZE
         varinfo.varofstoptrs = builder.offsets2table(offsets, ARRAY.OF)
         varinfo.varitemsize = llmemory.sizeof(ARRAY.OF)
-    if TYPE == WEAKREF:
+    if builder.is_weakref_type(TYPE):
         infobits |= T_IS_WEAKREF
-    info.infobits = infobits
+    info.infobits = infobits | T_KEY_VALUE
 
 # ____________________________________________________________
 
@@ -250,17 +264,21 @@
                 _, TYPE = TYPE._first_struct()
 
     def get_info(self, type_id):
-        return llop.get_group_member(GCData.TYPE_INFO_PTR,
-                                     self.type_info_group._as_ptr(),
-                                     type_id)
+        res = llop.get_group_member(GCData.TYPE_INFO_PTR,
+                                    self.type_info_group._as_ptr(),
+                                    type_id)
+        _check_valid_type_info(res)
+        return res
 
     def get_info_varsize(self, type_id):
-        return llop.get_group_member(GCData.VARSIZE_TYPE_INFO_PTR,
-                                     self.type_info_group._as_ptr(),
-                                     type_id)
+        res = llop.get_group_member(GCData.VARSIZE_TYPE_INFO_PTR,
+                                    self.type_info_group._as_ptr(),
+                                    type_id)
+        _check_valid_type_info_varsize(res)
+        return res
 
-    def is_weakref(self, type_id):
-        return self.get_info(type_id).infobits & T_IS_WEAKREF
+    def is_weakref_type(self, TYPE):
+        return TYPE == WEAKREF
 
     def encode_type_shapes_now(self):
         if not self.can_encode_type_shape:

Modified: pypy/branch/fast-forward/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/gcwrapper.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/gcwrapper.py	Thu Sep  9 01:00:13 2010
@@ -119,6 +119,9 @@
         else:
             return True
 
+    def pyobjectptr(self, klass):
+        raise NotImplementedError(klass)
+
 # ____________________________________________________________
 
 class LLInterpRootWalker:

Modified: pypy/branch/fast-forward/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/test/test_gc.py	Thu Sep  9 01:00:13 2010
@@ -639,12 +639,14 @@
 
 class TestMarkCompactGC(TestSemiSpaceGC):
     from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass
+    GC_PARAMS = {'space_size': 65536+16384}
+    GC_CAN_SHRINK_ARRAY = False
 
     def test_finalizer_order(self):
         py.test.skip("Not implemented yet")
-
-class TestMarkCompactGCGrowing(TestMarkCompactGC):
-    GC_PARAMS = {'space_size': 16*WORD}
+    def test_writebarrier_before_copy(self):
+        py.test.skip("Not relevant, and crashes because llarena does not "
+                     "support empty GcStructs")
 
 class TestHybridGC(TestGenerationalGC):
     from pypy.rpython.memory.gc.hybrid import HybridGC as GCClass

Modified: pypy/branch/fast-forward/pypy/rpython/memory/test/test_gctypelayout.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/test/test_gctypelayout.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/test/test_gctypelayout.py	Thu Sep  9 01:00:13 2010
@@ -101,7 +101,7 @@
     accessor = rclass.FieldListAccessor()
     S3 = lltype.GcStruct('S', ('x', PT), ('y', PT),
                          hints={'immutable_fields': accessor})
-    accessor.initialize(S3, ['x'])
+    accessor.initialize(S3, {'x': ''})
     #
     s1 = lltype.malloc(S1)
     adr = llmemory.cast_ptr_to_adr(s1)

Modified: pypy/branch/fast-forward/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/memory/test/test_transformed_gc.py	Thu Sep  9 01:00:13 2010
@@ -1138,15 +1138,16 @@
 class TestMarkCompactGC(GenericMovingGCTests):
     gcname = 'markcompact'
 
-    def setup_class(cls):
-        py.test.skip("Disabled for now, sorry")
-
     class gcpolicy(gc.FrameworkGcPolicy):
         class transformerclass(framework.FrameworkGCTransformer):
             from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass
-            GC_PARAMS = {'space_size': 512*WORD}
+            GC_PARAMS = {'space_size': 4096*WORD}
             root_stack_depth = 200
 
+    def test_writebarrier_before_copy(self):
+        py.test.skip("Not relevant, and crashes because llarena does not "
+                     "support empty GcStructs")
+
 class TestGenerationGC(GenericMovingGCTests):
     gcname = "generation"
     GC_CAN_SHRINK_ARRAY = True
@@ -1536,3 +1537,12 @@
             GC_PARAMS = {'space_size': 512*WORD,
                          'nursery_size': 32*WORD}
             root_stack_depth = 200
+
+class TestMarkCompactTaggedpointerGC(TaggedPointerGCTests):
+    gcname = 'markcompact'
+
+    class gcpolicy(gc.FrameworkGcPolicy):
+        class transformerclass(framework.FrameworkGCTransformer):
+            from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass
+            GC_PARAMS = {'space_size': 4096*WORD}
+            root_stack_depth = 200

Modified: pypy/branch/fast-forward/pypy/rpython/module/ll_os.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/module/ll_os.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/module/ll_os.py	Thu Sep  9 01:00:13 2010
@@ -6,12 +6,15 @@
 # might be found in doc/rffi.txt
 
 import os, sys, errno
+import py
 from pypy.rpython.module.support import ll_strcpy, OOSupport
-from pypy.tool.sourcetools import func_with_new_name
+from pypy.tool.sourcetools import func_with_new_name, func_renamer
 from pypy.rlib.rarithmetic import r_longlong
-from pypy.rpython.extfunc import BaseLazyRegistering
+from pypy.rpython.extfunc import (
+    BaseLazyRegistering, lazy_register, register_external)
 from pypy.rpython.extfunc import registering, registering_if, extdef
-from pypy.annotation.model import SomeInteger, SomeString, SomeTuple, SomeFloat
+from pypy.annotation.model import (
+    SomeInteger, SomeString, SomeTuple, SomeFloat, SomeUnicodeString)
 from pypy.annotation.model import s_ImpossibleValue, s_None, s_Bool
 from pypy.rpython.lltypesystem import rffi
 from pypy.rpython.lltypesystem import lltype
@@ -26,7 +29,99 @@
 from pypy.rpython.lltypesystem.rstr import STR
 from pypy.rpython.annlowlevel import llstr
 from pypy.rlib import rgc
-from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.objectmodel import keepalive_until_here, specialize
+
+def monkeypatch_rposix(posixfunc, unicodefunc, signature):
+    func_name = posixfunc.__name__
+
+    if hasattr(signature, '_default_signature_'):
+        signature = signature._default_signature_
+    arglist = ['arg%d' % (i,) for i in range(len(signature))]
+    transformed_arglist = arglist[:]
+    for i, arg in enumerate(signature):
+        if arg is unicode:
+            transformed_arglist[i] = transformed_arglist[i] + '.as_unicode()'
+
+    args = ', '.join(arglist)
+    transformed_args = ', '.join(transformed_arglist)
+    main_arg = 'arg%d' % (signature.index(unicode),)
+
+    source = py.code.Source("""
+    def %(func_name)s(%(args)s):
+        if isinstance(%(main_arg)s, str):
+            return posixfunc(%(args)s)
+        else:
+            return unicodefunc(%(transformed_args)s)
+    """ % locals())
+    miniglobals = {'posixfunc'  : posixfunc,
+                   'unicodefunc': unicodefunc,
+                   '__name__':    __name__, # for module name propagation
+                   }
+    exec source.compile() in miniglobals
+    new_func = miniglobals[func_name]
+    specialized_args = [i for i in range(len(signature))
+                        if signature[i] in (unicode, None)]
+    new_func = specialize.argtype(*specialized_args)(new_func)
+
+    # Monkeypatch the function in pypy.rlib.rposix
+    setattr(rposix, func_name, new_func)
+
+class StringTraits:
+    str = str
+    CHAR = rffi.CHAR
+    CCHARP = rffi.CCHARP
+    charp2str = staticmethod(rffi.charp2str)
+    str2charp = staticmethod(rffi.str2charp)
+    free_charp = staticmethod(rffi.free_charp)
+
+    @staticmethod
+    def posix_function_name(name):
+        return underscore_on_windows + name
+
+    @staticmethod
+    def ll_os_name(name):
+        return 'll_os.ll_os_' + name
+
+class UnicodeTraits:
+    str = unicode
+    CHAR = rffi.WCHAR_T
+    CCHARP = rffi.CWCHARP
+    charp2str = staticmethod(rffi.wcharp2unicode)
+    str2charp = staticmethod(rffi.unicode2wcharp)
+    free_charp = staticmethod(rffi.free_wcharp)
+
+    @staticmethod
+    def posix_function_name(name):
+        return underscore_on_windows + 'w' + name
+
+    @staticmethod
+    def ll_os_name(name):
+        return 'll_os.ll_os_w' + name
+
+def registering_str_unicode(posixfunc, condition=True):
+    if not condition:
+        return registering(None, condition=False)
+
+    func_name = posixfunc.__name__
+
+    def register_posixfunc(self, method):
+        val = method(self, StringTraits())
+        register_external(posixfunc, *val.def_args, **val.def_kwds)
+
+        if sys.platform == 'win32':
+            val = method(self, UnicodeTraits())
+            @func_renamer(func_name + "_unicode")
+            def unicodefunc(*args):
+                return posixfunc(*args)
+            register_external(unicodefunc, *val.def_args, **val.def_kwds)
+            signature = val.def_args[0]
+            monkeypatch_rposix(posixfunc, unicodefunc, signature)
+
+    def decorator(method):
+        decorated = lambda self: register_posixfunc(self, method)
+        decorated._registering_func = posixfunc
+        return decorated
+    return decorator
 
 posix = __import__(os.name)
 
@@ -282,8 +377,8 @@
         return extdef([int, int], s_None, llimpl=dup2_llimpl,
                       export_name="ll_os.ll_os_dup2")
 
-    @registering(os.utime)
-    def register_os_utime(self):
+    @registering_str_unicode(os.utime)
+    def register_os_utime(self, traits):
         UTIMBUFP = lltype.Ptr(self.UTIMBUF)
         os_utime = self.llexternal('utime', [rffi.CCHARP, UTIMBUFP], rffi.INT)
 
@@ -336,6 +431,9 @@
         # tp is known to be None, and one version where it is known
         # to be a tuple of 2 floats.
         if not _WIN32:
+            assert traits.str is str
+
+            @specialize.argtype(1)
             def os_utime_llimpl(path, tp):
                 if tp is None:
                     error = os_utime(path, lltype.nullptr(UTIMBUFP.TO))
@@ -346,85 +444,13 @@
                 if error == -1:
                     raise OSError(rposix.get_errno(), "os_utime failed")
         else:
-            from pypy.rlib import rwin32
-            from pypy.rpython.module.ll_os_stat import time_t_to_FILE_TIME
-
-            class CConfig:
-                _compilation_info_ = ExternalCompilationInfo(
-                    includes = ['windows.h'],
-                    )
-
-                FILE_WRITE_ATTRIBUTES = platform.ConstantInteger(
-                    'FILE_WRITE_ATTRIBUTES')
-                OPEN_EXISTING = platform.ConstantInteger(
-                    'OPEN_EXISTING')
-                FILE_FLAG_BACKUP_SEMANTICS = platform.ConstantInteger(
-                    'FILE_FLAG_BACKUP_SEMANTICS')
-            globals().update(platform.configure(CConfig))
-
-            CreateFile = rffi.llexternal(
-                'CreateFileA',
-                [rwin32.LPCSTR, rwin32.DWORD, rwin32.DWORD,
-                 rwin32.LPSECURITY_ATTRIBUTES, rwin32.DWORD, rwin32.DWORD,
-                 rwin32.HANDLE],
-                rwin32.HANDLE,
-                calling_conv='win')
-
-            GetSystemTime = rffi.llexternal(
-                'GetSystemTime',
-                [lltype.Ptr(rwin32.SYSTEMTIME)],
-                lltype.Void,
-                calling_conv='win')
-
-            SystemTimeToFileTime = rffi.llexternal(
-                'SystemTimeToFileTime',
-                [lltype.Ptr(rwin32.SYSTEMTIME),
-                 lltype.Ptr(rwin32.FILETIME)],
-                rwin32.BOOL,
-                calling_conv='win')
-
-            SetFileTime = rffi.llexternal(
-                'SetFileTime',
-                [rwin32.HANDLE,
-                 lltype.Ptr(rwin32.FILETIME),
-                 lltype.Ptr(rwin32.FILETIME),
-                 lltype.Ptr(rwin32.FILETIME)],
-                rwin32.BOOL,
-                calling_conv = 'win')
+            from pypy.rpython.module.ll_win32file import make_utime_impl
+            os_utime_llimpl = make_utime_impl(traits)
 
-            def os_utime_llimpl(path, tp):
-                hFile = CreateFile(path, 
-                                   FILE_WRITE_ATTRIBUTES, 0, 
-                                   None, OPEN_EXISTING,
-                                   FILE_FLAG_BACKUP_SEMANTICS, 0)
-                if hFile == rwin32.INVALID_HANDLE_VALUE:
-                    raise rwin32.lastWindowsError()
-                ctime = lltype.nullptr(rwin32.FILETIME)
-                atime = lltype.malloc(rwin32.FILETIME, flavor='raw')
-                mtime = lltype.malloc(rwin32.FILETIME, flavor='raw')
-                try:
-                    if tp is None:
-                        now = lltype.malloc(rwin32.SYSTEMTIME, flavor='raw')
-                        try:
-                            GetSystemTime(now)
-                            if (not SystemTimeToFileTime(now, atime) or
-                                not SystemTimeToFileTime(now, mtime)):
-                                raise rwin32.lastWindowsError()
-                        finally:
-                            lltype.free(now, flavor='raw')
-                    else:
-                        actime, modtime = tp
-                        time_t_to_FILE_TIME(actime, atime)
-                        time_t_to_FILE_TIME(modtime, mtime)
-                    if not SetFileTime(hFile, ctime, atime, mtime):
-                        raise rwin32.lastWindowsError()
-                finally:
-                    rwin32.CloseHandle(hFile)
-                    lltype.free(atime, flavor='raw')
-                    lltype.free(mtime, flavor='raw')
-        os_utime_llimpl._annspecialcase_ = 'specialize:argtype(1)'
-
-        s_string = SomeString()
+        if traits.str is str:
+            s_string = SomeString()
+        else:
+            s_string = SomeUnicodeString()
         s_tuple_of_2_floats = SomeTuple([SomeFloat(), SomeFloat()])
 
         def os_utime_normalize_args(s_path, s_times):
@@ -445,12 +471,12 @@
             else:
                 raise Exception("os.utime() arg 2 must be None or a tuple of "
                                 "2 floats, got %s" % (s_times,))
+        os_utime_normalize_args._default_signature_ = [traits.str, None]
 
         return extdef(os_utime_normalize_args, s_None,
                       "ll_os.ll_os_utime",
                       llimpl=os_utime_llimpl)
 
-
     @registering(os.times)
     def register_os_times(self):
         if sys.platform.startswith('win'):
@@ -687,22 +713,21 @@
     def register_os_setsid(self):
         return self.extdef_for_os_function_returning_int('setsid')
 
-    @registering(os.open)
-    def register_os_open(self):
-        os_open = self.llexternal(underscore_on_windows+'open',
-                                  [rffi.CCHARP, rffi.INT, rffi.MODE_T],
+    @registering_str_unicode(os.open)
+    def register_os_open(self, traits):
+        os_open = self.llexternal(traits.posix_function_name('open'),
+                                  [traits.CCHARP, rffi.INT, rffi.MODE_T],
                                   rffi.INT)
-
         def os_open_llimpl(path, flags, mode):
             result = rffi.cast(rffi.LONG, os_open(path, flags, mode))
             if result == -1:
                 raise OSError(rposix.get_errno(), "os_open failed")
             return result
 
-        def os_open_oofakeimpl(o_path, flags, mode):
-            return os.open(o_path._str, flags, mode)
+        def os_open_oofakeimpl(path, flags, mode):
+            return os.open(OOSupport.from_rstr(path), flags, mode)
 
-        return extdef([str, int, int], int, "ll_os.ll_os_open",
+        return extdef([traits.str, int, int], int, traits.ll_os_name('open'),
                       llimpl=os_open_llimpl, oofakeimpl=os_open_oofakeimpl)
 
 # ------------------------------- os.read -------------------------------
@@ -862,10 +887,10 @@
                       llimpl=fdatasync_llimpl,
                       export_name="ll_os.ll_os_fdatasync")
 
-    @registering(os.access)
-    def register_os_access(self):
-        os_access = self.llexternal(underscore_on_windows + 'access',
-                                    [rffi.CCHARP, rffi.INT],
+    @registering_str_unicode(os.access)
+    def register_os_access(self, traits):
+        os_access = self.llexternal(traits.posix_function_name('access'),
+                                    [traits.CCHARP, rffi.INT],
                                     rffi.INT)
 
         if sys.platform.startswith('win'):
@@ -882,44 +907,22 @@
         def os_access_oofakeimpl(path, mode):
             return os.access(OOSupport.from_rstr(path), mode)
 
-        return extdef([str, int], s_Bool, llimpl=access_llimpl,
-                      export_name="ll_os.ll_os_access",
+        return extdef([traits.str, int], s_Bool, llimpl=access_llimpl,
+                      export_name=traits.ll_os_name("access"),
                       oofakeimpl=os_access_oofakeimpl)
 
-    @registering_if(posix, '_getfullpathname')
-    def register_posix__getfullpathname(self):
-        from pypy.rlib import rwin32
+    @registering_str_unicode(getattr(posix, '_getfullpathname', None),
+                             condition=sys.platform=='win32')
+    def register_posix__getfullpathname(self, traits):
         # this nt function is not exposed via os, but needed
         # to get a correct implementation of os.abspath
-        # XXX why do we ignore WINAPI conventions everywhere?
-        LPSTRP = rffi.CArrayPtr(rwin32.LPSTR)
-        # XXX unicode?
-        GetFullPathName = self.llexternal(
-            'GetFullPathNameA',
-            [rwin32.LPCSTR,
-             rwin32.DWORD,
-             rwin32.LPSTR,
-             rffi.CArrayPtr(rwin32.LPSTR)],
-            rwin32.DWORD)
-
-        def _getfullpathname_llimpl(lpFileName):
-            nBufferLength = rwin32.MAX_PATH + 1
-            lpBuffer = lltype.malloc(rwin32.LPSTR.TO, nBufferLength, flavor='raw')
-            try:
-                res = GetFullPathName(
-                    lpFileName, rffi.cast(rwin32.DWORD, nBufferLength),
-                    lpBuffer, lltype.nullptr(LPSTRP.TO))
-                if res == 0:
-                    raise rwin32.lastWindowsError("_getfullpathname failed")
-                result = rffi.charp2str(lpBuffer)
-                return result
-            finally:
-                lltype.free(lpBuffer, flavor='raw')
+        from pypy.rpython.module.ll_win32file import make_getfullpathname_impl
+        getfullpathname_llimpl = make_getfullpathname_impl(traits)
 
-        return extdef([str],  # a single argument which is a str
-                      str,    # returns a string
-                      "ll_os.posix__getfullpathname",
-                      llimpl=_getfullpathname_llimpl)
+        return extdef([traits.str],  # a single argument which is a str
+                      traits.str,    # returns a string
+                      traits.ll_os_name('_getfullpathname'),
+                      llimpl=getfullpathname_llimpl)
 
     @registering(os.getcwd)
     def register_os_getcwd(self):
@@ -953,71 +956,42 @@
                       "ll_os.ll_os_getcwd", llimpl=os_getcwd_llimpl,
                       oofakeimpl=os_getcwd_oofakeimpl)
 
-    @registering(os.listdir)
-    def register_os_listdir(self):
-        # we need a different approach on Windows and on Posix
-        if sys.platform.startswith('win'):
-            from pypy.rlib import rwin32
-            class CConfig:
-                _compilation_info_ = ExternalCompilationInfo(
-                    includes = ['windows.h']
-                )
-                WIN32_FIND_DATA = platform.Struct('struct _WIN32_FIND_DATAA',
-                    [('cFileName', lltype.FixedSizeArray(rffi.CHAR, 1))])
-                ERROR_FILE_NOT_FOUND = platform.ConstantInteger(
-                    'ERROR_FILE_NOT_FOUND')
-                ERROR_NO_MORE_FILES = platform.ConstantInteger(
-                    'ERROR_NO_MORE_FILES')
+    @registering(os.getcwdu, condition=sys.platform=='win32')
+    def register_os_getcwdu(self):
+        os_wgetcwd = self.llexternal(underscore_on_windows + 'wgetcwd',
+                                     [rffi.CWCHARP, rffi.SIZE_T],
+                                     rffi.CWCHARP)
 
-            config = platform.configure(CConfig)
-            WIN32_FIND_DATA      = config['WIN32_FIND_DATA']
-            ERROR_FILE_NOT_FOUND = config['ERROR_FILE_NOT_FOUND']
-            ERROR_NO_MORE_FILES  = config['ERROR_NO_MORE_FILES']
-            LPWIN32_FIND_DATA    = lltype.Ptr(WIN32_FIND_DATA)
-
-            FindFirstFile = self.llexternal('FindFirstFile',
-                                            [rwin32.LPCSTR, LPWIN32_FIND_DATA],
-                                            rwin32.HANDLE)
-            FindNextFile = self.llexternal('FindNextFile',
-                                           [rwin32.HANDLE, LPWIN32_FIND_DATA],
-                                           rwin32.BOOL)
-            FindClose = self.llexternal('FindClose',
-                                        [rwin32.HANDLE],
-                                        rwin32.BOOL)
+        def os_getcwd_llimpl():
+            bufsize = 256
+            while True:
+                buf = lltype.malloc(rffi.CWCHARP.TO, bufsize, flavor='raw')
+                res = os_wgetcwd(buf, rffi.cast(rffi.SIZE_T, bufsize))
+                if res:
+                    break   # ok
+                error = rposix.get_errno()
+                lltype.free(buf, flavor='raw')
+                if error != errno.ERANGE:
+                    raise OSError(error, "getcwd failed")
+                # else try again with a larger buffer, up to some sane limit
+                bufsize *= 4
+                if bufsize > 1024*1024:  # xxx hard-coded upper limit
+                    raise OSError(error, "getcwd result too large")
+            result = rffi.wcharp2unicode(res)
+            lltype.free(buf, flavor='raw')
+            return result
 
-            def os_listdir_llimpl(path):
-                if path and path[-1] not in ('/', '\\', ':'):
-                    path += '/'
-                path += '*.*'
-                filedata = lltype.malloc(WIN32_FIND_DATA, flavor='raw')
-                try:
-                    result = []
-                    hFindFile = FindFirstFile(path, filedata)
-                    if hFindFile == rwin32.INVALID_HANDLE_VALUE:
-                        error = rwin32.GetLastError()
-                        if error == ERROR_FILE_NOT_FOUND:
-                            return result
-                        else:
-                            raise WindowsError(error,  "FindFirstFile failed")
-                    while True:
-                        name = rffi.charp2str(rffi.cast(rffi.CCHARP,
-                                                        filedata.c_cFileName))
-                        if name != "." and name != "..":   # skip these
-                            result.append(name)
-                        if not FindNextFile(hFindFile, filedata):
-                            break
-                    # FindNextFile sets error to ERROR_NO_MORE_FILES if
-                    # it got to the end of the directory
-                    error = rwin32.GetLastError()
-                    FindClose(hFindFile)
-                    if error == ERROR_NO_MORE_FILES:
-                        return result
-                    else:
-                        raise WindowsError(error,  "FindNextFile failed")
-                finally:
-                    lltype.free(filedata, flavor='raw')
+        return extdef([], unicode,
+                      "ll_os.ll_os_wgetcwd", llimpl=os_getcwd_llimpl)
 
+    @registering_str_unicode(os.listdir)
+    def register_os_listdir(self, traits):
+        # we need a different approach on Windows and on Posix
+        if sys.platform.startswith('win'):
+            from pypy.rpython.module.ll_win32file import make_listdir_impl
+            os_listdir_llimpl = make_listdir_impl(traits)
         else:
+            assert traits.str is str
             compilation_info = ExternalCompilationInfo(
                 includes = ['sys/types.h', 'dirent.h']
             )
@@ -1057,9 +1031,9 @@
                     raise OSError(error, "os_readdir failed")
                 return result
 
-        return extdef([str],  # a single argument which is a str
-                      [str],  # returns a list of strings
-                      "ll_os.ll_os_listdir",
+        return extdef([traits.str],  # a single argument which is a str
+                      [traits.str],  # returns a list of strings
+                      traits.ll_os_name('listdir'),
                       llimpl=os_listdir_llimpl)
 
     @registering(os.pipe)
@@ -1234,38 +1208,40 @@
         return extdef([str], int, llimpl=system_llimpl,
                       export_name="ll_os.ll_os_system")
 
-    @registering(os.unlink)
-    def register_os_unlink(self):
-        os_unlink = self.llexternal(underscore_on_windows+'unlink', [rffi.CCHARP], rffi.INT)
+    @registering_str_unicode(os.unlink)
+    def register_os_unlink(self, traits):
+        os_unlink = self.llexternal(traits.posix_function_name('unlink'),
+                                    [traits.CCHARP], rffi.INT)
 
         def unlink_llimpl(pathname):
             res = rffi.cast(lltype.Signed, os_unlink(pathname))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_unlink failed")
 
-        return extdef([str], s_None, llimpl=unlink_llimpl,
-                      export_name="ll_os.ll_os_unlink")
+        return extdef([traits.str], s_None, llimpl=unlink_llimpl,
+                      export_name=traits.ll_os_name('unlink'))
 
-    @registering(os.chdir)
-    def register_os_chdir(self):
-        os_chdir = self.llexternal(underscore_on_windows+'chdir', [rffi.CCHARP], rffi.INT)
+    @registering_str_unicode(os.chdir)
+    def register_os_chdir(self, traits):
+        os_chdir = self.llexternal(traits.posix_function_name('chdir'),
+                                   [traits.CCHARP], rffi.INT)
 
         def chdir_llimpl(path):
             res = rffi.cast(lltype.Signed, os_chdir(path))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_chdir failed")
 
-        return extdef([str], s_None, llimpl=chdir_llimpl,
-                      export_name="ll_os.ll_os_chdir")
+        return extdef([traits.str], s_None, llimpl=chdir_llimpl,
+                      export_name=traits.ll_os_name('chdir'))
 
-    @registering(os.mkdir)
-    def register_os_mkdir(self):
+    @registering_str_unicode(os.mkdir)
+    def register_os_mkdir(self, traits):
         if os.name == 'nt':
             ARG2 = []         # no 'mode' argument on Windows - just ignored
         else:
             ARG2 = [rffi.MODE_T]
-        os_mkdir = self.llexternal(underscore_on_windows+'mkdir',
-                                   [rffi.CCHARP]+ARG2, rffi.INT)
+        os_mkdir = self.llexternal(traits.posix_function_name('mkdir'),
+                                   [traits.CCHARP] + ARG2, rffi.INT)
         IGNORE_MODE = len(ARG2) == 0
 
         def mkdir_llimpl(pathname, mode):
@@ -1277,46 +1253,47 @@
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_mkdir failed")
 
-        return extdef([str, int], s_None, llimpl=mkdir_llimpl,
-                      export_name="ll_os.ll_os_mkdir")
+        return extdef([traits.str, int], s_None, llimpl=mkdir_llimpl,
+                      export_name=traits.ll_os_name('mkdir'))
 
-    @registering(os.rmdir)
-    def register_os_rmdir(self):
-        os_rmdir = self.llexternal(underscore_on_windows+'rmdir', [rffi.CCHARP], rffi.INT)
+    @registering_str_unicode(os.rmdir)
+    def register_os_rmdir(self, traits):
+        os_rmdir = self.llexternal(traits.posix_function_name('rmdir'),
+                                   [traits.CCHARP], rffi.INT)
 
         def rmdir_llimpl(pathname):
             res = rffi.cast(lltype.Signed, os_rmdir(pathname))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_rmdir failed")
 
-        return extdef([str], s_None, llimpl=rmdir_llimpl,
-                      export_name="ll_os.ll_os_rmdir")
+        return extdef([traits.str], s_None, llimpl=rmdir_llimpl,
+                      export_name=traits.ll_os_name('rmdir'))
 
-    @registering(os.chmod)
-    def register_os_chmod(self):
-        os_chmod = self.llexternal(underscore_on_windows+'chmod', [rffi.CCHARP, rffi.MODE_T],
-                                   rffi.INT)
+    @registering_str_unicode(os.chmod)
+    def register_os_chmod(self, traits):
+        os_chmod = self.llexternal(traits.posix_function_name('chmod'),
+                                   [traits.CCHARP, rffi.MODE_T], rffi.INT)
 
         def chmod_llimpl(path, mode):
             res = rffi.cast(lltype.Signed, os_chmod(path, rffi.cast(rffi.MODE_T, mode)))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_chmod failed")
 
-        return extdef([str, int], s_None, llimpl=chmod_llimpl,
-                      export_name="ll_os.ll_os_chmod")
+        return extdef([traits.str, int], s_None, llimpl=chmod_llimpl,
+                      export_name=traits.ll_os_name('chmod'))
 
-    @registering(os.rename)
-    def register_os_rename(self):
-        os_rename = self.llexternal('rename', [rffi.CCHARP, rffi.CCHARP],
-                                    rffi.INT)
+    @registering_str_unicode(os.rename)
+    def register_os_rename(self, traits):
+        os_rename = self.llexternal(traits.posix_function_name('rename'),
+                                    [traits.CCHARP, traits.CCHARP], rffi.INT)
 
         def rename_llimpl(oldpath, newpath):
             res = rffi.cast(lltype.Signed, os_rename(oldpath, newpath))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_rename failed")
 
-        return extdef([str, str], s_None, llimpl=rename_llimpl,
-                      export_name="ll_os.ll_os_rename")
+        return extdef([traits.str, traits.str], s_None, llimpl=rename_llimpl,
+                      export_name=traits.ll_os_name('rename'))
 
     @registering(os.umask)
     def register_os_umask(self):
@@ -1425,17 +1402,17 @@
     @registering(os.fstat)
     def register_os_fstat(self):
         from pypy.rpython.module import ll_os_stat
-        ll_os_stat.register_stat_variant('fstat')
+        return ll_os_stat.register_stat_variant('fstat', StringTraits())
 
-    @registering(os.stat)
-    def register_os_stat(self):
+    @registering_str_unicode(os.stat)
+    def register_os_stat(self, traits):
         from pypy.rpython.module import ll_os_stat
-        ll_os_stat.register_stat_variant('stat')
+        return ll_os_stat.register_stat_variant('stat', traits)
 
-    @registering(os.lstat)
-    def register_os_lstat(self):
+    @registering_str_unicode(os.lstat)
+    def register_os_lstat(self, traits):
         from pypy.rpython.module import ll_os_stat
-        ll_os_stat.register_stat_variant('lstat')
+        return ll_os_stat.register_stat_variant('lstat', traits)
 
     # ------------------------------- os.W* ---------------------------------
 

Modified: pypy/branch/fast-forward/pypy/rpython/module/ll_os_stat.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/module/ll_os_stat.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/module/ll_os_stat.py	Thu Sep  9 01:00:13 2010
@@ -5,13 +5,14 @@
 import os, sys
 from pypy.annotation import model as annmodel
 from pypy.tool.pairtype import pairtype
-from pypy.tool.sourcetools import func_with_new_name
+from pypy.tool.sourcetools import func_with_new_name, func_renamer
 from pypy.rpython import extregistry
-from pypy.rpython.extfunc import register_external
+from pypy.rpython.extfunc import register_external, extdef
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.tool import rffi_platform as platform
 from pypy.rpython.lltypesystem.rtupletype import TUPLE_TYPE
 from pypy.rlib import rposix
+from pypy.rlib.objectmodel import specialize
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rpython.annlowlevel import hlstr
 
@@ -211,13 +212,27 @@
     return make_stat_result(result)
 
 
-def register_stat_variant(name):
-    if sys.platform.startswith('win'):
-        _functions = {'stat':  '_stati64',
-                      'fstat': '_fstati64',
-                      'lstat': '_stati64'}    # no lstat on Windows
-        c_func_name = _functions[name]
-    elif sys.platform.startswith('linux'):
+def register_stat_variant(name, traits):
+    if name != 'fstat':
+        arg_is_path = True
+        s_arg = traits.str
+        ARG1 = traits.CCHARP
+    else:
+        arg_is_path = False
+        s_arg = int
+        ARG1 = rffi.INT
+
+    if sys.platform == 'win32':
+        # See Win32 implementation below
+        posix_stat_llimpl = make_win32_stat_impl(name, traits)
+
+        return extdef(
+            [s_arg], s_StatResult, traits.ll_os_name(name),
+            llimpl=posix_stat_llimpl)
+
+    assert traits.str is str
+
+    if sys.platform.startswith('linux'):
         # because we always use _FILE_OFFSET_BITS 64 - this helps things work that are not a c compiler 
         _functions = {'stat':  'stat64',
                       'fstat': 'fstat64',
@@ -226,22 +241,26 @@
     else:
         c_func_name = name
 
-    arg_is_path = (name != 'fstat')
+    posix_mystat = rffi.llexternal(c_func_name,
+                                   [ARG1, STAT_STRUCT], rffi.INT,
+                                   compilation_info=compilation_info)
 
+    @func_renamer('os_%s_llimpl' % (name,))
     def posix_stat_llimpl(arg):
         stresult = lltype.malloc(STAT_STRUCT.TO, flavor='raw')
         try:
             if arg_is_path:
-                arg = rffi.str2charp(arg)
+                arg = traits.str2charp(arg)
             error = rffi.cast(rffi.LONG, posix_mystat(arg, stresult))
             if arg_is_path:
-                rffi.free_charp(arg)
+                traits.free_charp(arg)
             if error != 0:
                 raise OSError(rposix.get_errno(), "os_?stat failed")
             return build_stat_result(stresult)
         finally:
             lltype.free(stresult, flavor='raw')
 
+    @func_renamer('os_%s_fake' % (name,))
     def posix_fakeimpl(arg):
         if s_arg == str:
             arg = hlstr(arg)
@@ -259,40 +278,17 @@
                 setattr(ll_tup, 'item%d' % i, val)
         return ll_tup
 
-    if arg_is_path:
-        s_arg = str
-        ARG1 = rffi.CCHARP
-    else:
-        s_arg = int
-        ARG1 = rffi.INT
+    return extdef(
+        [s_arg], s_StatResult, "ll_os.ll_os_%s" % (name,),
+        llimpl=posix_stat_llimpl, llfakeimpl=posix_fakeimpl)
 
-    if sys.platform != 'win32':
-        posix_mystat = rffi.llexternal(c_func_name,
-                                       [ARG1, STAT_STRUCT], rffi.INT,
-                                       compilation_info=compilation_info)
-
-        register_external(
-            getattr(os, name), [s_arg], s_StatResult,
-            "ll_os.ll_os_%s" % (name,),
-            llimpl=func_with_new_name(posix_stat_llimpl,
-                                      'os_%s_llimpl' % (name,)),
-            llfakeimpl=func_with_new_name(posix_fakeimpl,
-                                          'os_%s_fake' % (name,)),
-            )
-    else:
-        # See Win32 implementation below
-        register_external(
-            getattr(os, name), [s_arg], s_StatResult,
-            "ll_os.ll_os_%s" % (name,),
-            llimpl=func_with_new_name(globals()['win32_%s_llimpl' % (name,)],
-                                      'os_%s_llimpl' % (name,)),
-            )
+def make_win32_stat_impl(name, traits):
+    from pypy.rlib import rwin32
+    from pypy.rpython.module.ll_win32file import make_win32_traits
+    win32traits = make_win32_traits(traits)
 
-# ____________________________________________________________
-if sys.platform == 'win32':
     # The CRT of Windows has a number of flaws wrt. its stat() implementation:
-    # - for when we implement subsecond resolution in RPython, time stamps
-    #   would be restricted to second resolution
+    # - time stamps are restricted to second resolution
     # - file modification times suffer from forth-and-back conversions between
     #   UTC and local time
     # Therefore, we implement our own stat, based on the Win32 API directly.
@@ -302,122 +298,18 @@
 
     assert len(STAT_FIELDS) == 10    # no extra fields on Windows
 
-    class CConfig:
-        _compilation_info_ = ExternalCompilationInfo(
-            includes = ['windows.h', 'winbase.h', 'sys/stat.h'],
-            )
-
-        GetFileExInfoStandard = platform.ConstantInteger(
-            'GetFileExInfoStandard')
-        FILE_ATTRIBUTE_DIRECTORY = platform.ConstantInteger(
-            'FILE_ATTRIBUTE_DIRECTORY')
-        FILE_ATTRIBUTE_READONLY = platform.ConstantInteger(
-            'FILE_ATTRIBUTE_READONLY')
-        ERROR_SHARING_VIOLATION = platform.ConstantInteger(
-            'ERROR_SHARING_VIOLATION')
-        _S_IFDIR = platform.ConstantInteger('_S_IFDIR')
-        _S_IFREG = platform.ConstantInteger('_S_IFREG')
-        _S_IFCHR = platform.ConstantInteger('_S_IFCHR')
-        _S_IFIFO = platform.ConstantInteger('_S_IFIFO')
-        FILE_TYPE_UNKNOWN = platform.ConstantInteger('FILE_TYPE_UNKNOWN')
-        FILE_TYPE_CHAR = platform.ConstantInteger('FILE_TYPE_CHAR')
-        FILE_TYPE_PIPE = platform.ConstantInteger('FILE_TYPE_PIPE')
-
-        WIN32_FILE_ATTRIBUTE_DATA = platform.Struct(
-            'WIN32_FILE_ATTRIBUTE_DATA',
-            [('dwFileAttributes', rwin32.DWORD),
-             ('nFileSizeHigh', rwin32.DWORD),
-             ('nFileSizeLow', rwin32.DWORD),
-             ('ftCreationTime', rwin32.FILETIME),
-             ('ftLastAccessTime', rwin32.FILETIME),
-             ('ftLastWriteTime', rwin32.FILETIME)])
-
-        BY_HANDLE_FILE_INFORMATION = platform.Struct(
-            'BY_HANDLE_FILE_INFORMATION',
-            [('dwFileAttributes', rwin32.DWORD),
-             ('nFileSizeHigh', rwin32.DWORD),
-             ('nFileSizeLow', rwin32.DWORD),
-             ('nNumberOfLinks', rwin32.DWORD),
-             ('nFileIndexHigh', rwin32.DWORD),
-             ('nFileIndexLow', rwin32.DWORD),
-             ('ftCreationTime', rwin32.FILETIME),
-             ('ftLastAccessTime', rwin32.FILETIME),
-             ('ftLastWriteTime', rwin32.FILETIME)])
-
-        WIN32_FIND_DATA = platform.Struct(
-            'WIN32_FIND_DATAA',
-            # Only interesting fields
-            [('dwFileAttributes', rwin32.DWORD),
-             ('nFileSizeHigh', rwin32.DWORD),
-             ('nFileSizeLow', rwin32.DWORD),
-             ('ftCreationTime', rwin32.FILETIME),
-             ('ftLastAccessTime', rwin32.FILETIME),
-             ('ftLastWriteTime', rwin32.FILETIME)])
-
-    globals().update(platform.configure(CConfig))
-    GET_FILEEX_INFO_LEVELS = rffi.ULONG # an enumeration
-
-    GetFileAttributesEx = rffi.llexternal(
-        'GetFileAttributesExA',
-        [rffi.CCHARP, GET_FILEEX_INFO_LEVELS,
-         lltype.Ptr(WIN32_FILE_ATTRIBUTE_DATA)],
-        rwin32.BOOL,
-        calling_conv='win')
-
-    GetFileInformationByHandle = rffi.llexternal(
-        'GetFileInformationByHandle',
-        [rwin32.HANDLE, lltype.Ptr(BY_HANDLE_FILE_INFORMATION)],
-        rwin32.BOOL,
-        calling_conv='win')
-
-    GetFileType = rffi.llexternal(
-        'GetFileType',
-        [rwin32.HANDLE],
-        rwin32.DWORD,
-        calling_conv='win')
-
-    FindFirstFile = rffi.llexternal(
-        'FindFirstFileA',
-        [rffi.CCHARP, lltype.Ptr(WIN32_FIND_DATA)],
-        rwin32.HANDLE,
-        calling_conv='win')
-
-    FindClose = rffi.llexternal(
-        'FindClose',
-        [rwin32.HANDLE],
-        rwin32.BOOL,
-        calling_conv='win')
-
     def attributes_to_mode(attributes):
         m = 0
-        if attributes & FILE_ATTRIBUTE_DIRECTORY:
-            m |= _S_IFDIR | 0111 # IFEXEC for user,group,other
+        if attributes & win32traits.FILE_ATTRIBUTE_DIRECTORY:
+            m |= win32traits._S_IFDIR | 0111 # IFEXEC for user,group,other
         else:
-            m |= _S_IFREG
-        if attributes & FILE_ATTRIBUTE_READONLY:
+            m |= win32traits._S_IFREG
+        if attributes & win32traits.FILE_ATTRIBUTE_READONLY:
             m |= 0444
         else:
             m |= 0666
         return m
 
-    def make_longlong(high, low):
-        return (lltype.r_longlong(high) << 32) + lltype.r_longlong(low)
-
-    # Seconds between 1.1.1601 and 1.1.1970
-    secs_between_epochs = lltype.r_longlong(11644473600)
-
-    def FILE_TIME_to_time_t_nsec(filetime):
-        ft = make_longlong(filetime.c_dwHighDateTime, filetime.c_dwLowDateTime)
-        # FILETIME is in units of 100 nsec
-        nsec = (ft % 10000000) * 100
-        time = (ft / 10000000) - secs_between_epochs
-        return time, nsec
-
-    def time_t_to_FILE_TIME(time, filetime):
-        ft = lltype.r_longlong((time + secs_between_epochs) * 10000000)
-        filetime.c_dwHighDateTime = lltype.r_uint(ft >> 32)
-        filetime.c_dwLowDateTime = lltype.r_uint(ft & ((1 << 32) - 1))
-        
     def attribute_data_to_stat(info):
         st_mode = attributes_to_mode(info.c_dwFileAttributes)
         st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow)
@@ -456,65 +348,94 @@
         return make_stat_result(result)
 
     def attributes_from_dir(l_path, data):
-        filedata = lltype.malloc(WIN32_FIND_DATA, flavor='raw')
-        hFindFile = FindFirstFile(l_path, filedata)
-        if hFindFile == rwin32.INVALID_HANDLE_VALUE:
-            return 0
-        FindClose(hFindFile)
-        data.c_dwFileAttributes = filedata.c_dwFileAttributes
-        rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime)
-        rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime)
-        rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime)
-        data.c_nFileSizeHigh    = filedata.c_nFileSizeHigh
-        data.c_nFileSizeLow     = filedata.c_nFileSizeLow
-        return 1
+        filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw')
+        try:
+            hFindFile = win32traits.FindFirstFile(l_path, filedata)
+            if hFindFile == rwin32.INVALID_HANDLE_VALUE:
+                return 0
+            win32traits.FindClose(hFindFile)
+            data.c_dwFileAttributes = filedata.c_dwFileAttributes
+            rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime)
+            rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime)
+            rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime)
+            data.c_nFileSizeHigh    = filedata.c_nFileSizeHigh
+            data.c_nFileSizeLow     = filedata.c_nFileSizeLow
+            return 1
+        finally:
+            lltype.free(filedata, flavor='raw')
 
     def win32_stat_llimpl(path):
-        data = lltype.malloc(WIN32_FILE_ATTRIBUTE_DATA, flavor='raw')
+        data = lltype.malloc(win32traits.WIN32_FILE_ATTRIBUTE_DATA, flavor='raw')
         try:
-            l_path = rffi.str2charp(path)
-            res = GetFileAttributesEx(l_path, GetFileExInfoStandard, data)
+            l_path = traits.str2charp(path)
+            res = win32traits.GetFileAttributesEx(l_path, win32traits.GetFileExInfoStandard, data)
             errcode = rwin32.GetLastError()
             if res == 0:
-                if errcode == ERROR_SHARING_VIOLATION:
+                if errcode == win32traits.ERROR_SHARING_VIOLATION:
                     res = attributes_from_dir(l_path, data)
                     errcode = rwin32.GetLastError()
-            rffi.free_charp(l_path)
+            traits.free_charp(l_path)
             if res == 0:
                 raise WindowsError(errcode, "os_stat failed")
             return attribute_data_to_stat(data)
         finally:
             lltype.free(data, flavor='raw')
-    win32_lstat_llimpl = win32_stat_llimpl
 
     def win32_fstat_llimpl(fd):
         handle = rwin32._get_osfhandle(fd)
 
-        filetype = GetFileType(handle)
-        if filetype == FILE_TYPE_CHAR:
+        filetype = win32traits.GetFileType(handle)
+        if filetype == win32traits.FILE_TYPE_CHAR:
             # console or LPT device
-            return make_stat_result((_S_IFCHR,
+            return make_stat_result((win32traits._S_IFCHR,
                                      0, 0, 0, 0, 0,
                                      0, 0, 0, 0))
-        elif filetype == FILE_TYPE_PIPE:
+        elif filetype == win32traits.FILE_TYPE_PIPE:
             # socket or named pipe
-            return make_stat_result((_S_IFIFO,
+            return make_stat_result((win32traits._S_IFIFO,
                                      0, 0, 0, 0, 0,
                                      0, 0, 0, 0))
-        elif filetype == FILE_TYPE_UNKNOWN:
+        elif filetype == win32traits.FILE_TYPE_UNKNOWN:
             error = rwin32.GetLastError()
             if error != 0:
                 raise WindowsError(error, "os_fstat failed")
             # else: unknown but valid file
 
         # normal disk file (FILE_TYPE_DISK)
-        info = lltype.malloc(BY_HANDLE_FILE_INFORMATION, flavor='raw',
-                             zero=True)
+        info = lltype.malloc(win32traits.BY_HANDLE_FILE_INFORMATION,
+                             flavor='raw', zero=True)
         try:
-            res = GetFileInformationByHandle(handle, info)
+            res = win32traits.GetFileInformationByHandle(handle, info)
             if res == 0:
                 raise WindowsError(rwin32.GetLastError(), "os_fstat failed")
             return by_handle_info_to_stat(info)
         finally:
             lltype.free(info, flavor='raw')
 
+    if name == 'fstat':
+        return win32_fstat_llimpl
+    else:
+        return win32_stat_llimpl
+
+
+#__________________________________________________
+# Helper functions for win32
+
+def make_longlong(high, low):
+    return (lltype.r_longlong(high) << 32) + lltype.r_longlong(low)
+
+# Seconds between 1.1.1601 and 1.1.1970
+secs_between_epochs = lltype.r_longlong(11644473600)
+
+def FILE_TIME_to_time_t_nsec(filetime):
+    ft = make_longlong(filetime.c_dwHighDateTime, filetime.c_dwLowDateTime)
+    # FILETIME is in units of 100 nsec
+    nsec = (ft % 10000000) * 100
+    time = (ft / 10000000) - secs_between_epochs
+    return time, nsec
+
+def time_t_to_FILE_TIME(time, filetime):
+    ft = lltype.r_longlong((time + secs_between_epochs) * 10000000)
+    filetime.c_dwHighDateTime = lltype.r_uint(ft >> 32)
+    filetime.c_dwLowDateTime = lltype.r_uint(ft & ((1 << 32) - 1))
+

Modified: pypy/branch/fast-forward/pypy/rpython/module/ll_time.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/module/ll_time.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/module/ll_time.py	Thu Sep  9 01:00:13 2010
@@ -9,6 +9,7 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.extfunc import BaseLazyRegistering, registering, extdef
 from pypy.rlib import rposix
+from pypy.rlib.rarithmetic import intmask
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 if sys.platform == 'win32':
@@ -119,7 +120,8 @@
             if self.HAVE_FTIME:
                 t = lltype.malloc(self.TIMEB, flavor='raw')
                 c_ftime(t)
-                result = float(int(t.c_time)) + float(int(t.c_millitm)) * 0.001
+                result = (float(intmask(t.c_time)) +
+                          float(intmask(t.c_millitm)) * 0.001)
                 lltype.free(t, flavor='raw')
                 return result
             return float(c_time(void))

Modified: pypy/branch/fast-forward/pypy/rpython/module/test/test_ll_os_stat.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/module/test/test_ll_os_stat.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/module/test/test_ll_os_stat.py	Thu Sep  9 01:00:13 2010
@@ -1,4 +1,4 @@
-from pypy.rpython.module import ll_os_stat
+from pypy.rpython.module import ll_os_stat, ll_os
 import sys, os
 import py
 
@@ -8,14 +8,18 @@
             py.test.skip("win32 specific tests")
 
     def test_stat(self):
-        stat = ll_os_stat.win32_stat_llimpl
+        stat = ll_os_stat.make_win32_stat_impl('stat', ll_os.StringTraits())
+        wstat = ll_os_stat.make_win32_stat_impl('stat', ll_os.UnicodeTraits())
         def check(f):
-            assert stat(f).st_mtime == os.stat(f).st_mtime
+            expected = os.stat(f).st_mtime
+            assert stat(f).st_mtime == expected
+            assert wstat(unicode(f)).st_mtime == expected
 
         check('c:/')
         check('c:/temp')
         check('c:/pagefile.sys')
 
     def test_fstat(self):
-        stat = ll_os_stat.win32_fstat_llimpl(0) # stdout
+        fstat = ll_os_stat.make_win32_stat_impl('fstat', ll_os.StringTraits())
+        stat = fstat(0) # stdout
         assert stat.st_mode != 0

Modified: pypy/branch/fast-forward/pypy/rpython/ootypesystem/ootype.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/ootypesystem/ootype.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/ootypesystem/ootype.py	Thu Sep  9 01:00:13 2010
@@ -267,6 +267,14 @@
             return self._fields_with_default[:]
         return self._superclass._get_fields_with_default() + self._fields_with_default
 
+    def _immutable_field(self, field):
+        if 'immutable_fields' in self._hints:
+            try:
+                s = self._hints['immutable_fields'].fields[field]
+                return s or True
+            except KeyError:
+                pass
+        return self._hints.get('immutable', False)
 
 
 class SpecializableType(OOType):

Modified: pypy/branch/fast-forward/pypy/rpython/ootypesystem/rclass.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/ootypesystem/rclass.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/ootypesystem/rclass.py	Thu Sep  9 01:00:13 2010
@@ -194,6 +194,7 @@
             self.lowleveltype._hints.update(hints)
 
         if self.classdef is None:
+            self.fields = {}
             self.allfields = {}
             self.allmethods = {}
             self.allclassattributes = {}
@@ -210,6 +211,7 @@
             allclassattributes = {}
 
         fields = {}
+        nonmangledfields = []
         fielddefaults = {}
 
         if llfields:
@@ -224,6 +226,7 @@
                 allfields[mangled] = repr
                 oot = repr.lowleveltype
                 fields[mangled] = oot
+                nonmangledfields.append(name)
                 try:
                     value = self.classdef.classdesc.read_attribute(name)
                     fielddefaults[mangled] = repr.convert_desc_or_const(value)
@@ -294,6 +297,7 @@
                     if not attrdef.s_value.is_constant():
                         classattributes[mangled] = attrdef.s_value, value
 
+        self.fields = nonmangledfields
         self.allfields = allfields
         self.allmethods = allmethods
         self.allclassattributes = allclassattributes

Modified: pypy/branch/fast-forward/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/rbuiltin.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/rbuiltin.py	Thu Sep  9 01:00:13 2010
@@ -542,16 +542,25 @@
     return hop.genop('raw_malloc_usage', [v_size], resulttype=lltype.Signed)
 
 def rtype_raw_free(hop):
+    s_addr = hop.args_s[0]
+    if s_addr.is_null_address():
+        raise TyperError("raw_free(x) where x is the constant NULL")
     v_addr, = hop.inputargs(llmemory.Address)
     hop.exception_cannot_occur()
     return hop.genop('raw_free', [v_addr])
 
 def rtype_raw_memcopy(hop):
+    for s_addr in hop.args_s[:2]:
+        if s_addr.is_null_address():
+            raise TyperError("raw_memcopy() with a constant NULL")
     v_list = hop.inputargs(llmemory.Address, llmemory.Address, lltype.Signed)
     hop.exception_cannot_occur()
     return hop.genop('raw_memcopy', v_list)
 
 def rtype_raw_memclear(hop):
+    s_addr = hop.args_s[0]
+    if s_addr.is_null_address():
+        raise TyperError("raw_memclear(x, n) where x is the constant NULL")
     v_list = hop.inputargs(llmemory.Address, lltype.Signed)
     return hop.genop('raw_memclear', v_list)
 

Modified: pypy/branch/fast-forward/pypy/rpython/rclass.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/rclass.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/rclass.py	Thu Sep  9 01:00:13 2010
@@ -9,6 +9,7 @@
 class FieldListAccessor(object):
 
     def initialize(self, TYPE, fields):
+        assert type(fields) is dict
         self.TYPE = TYPE
         self.fields = fields
 
@@ -18,6 +19,10 @@
     def _freeze_(self):
         return True
 
+class ImmutableConflictError(Exception):
+    """Raised when the _immutable_ or _immutable_fields_ hints are
+    not consistent across a class hierarchy."""
+
 
 def getclassrepr(rtyper, classdef):
     try:
@@ -153,12 +158,16 @@
         pass
 
     def _check_for_immutable_hints(self, hints):
-        if '_immutable_' in self.classdef.classdesc.classdict:
+        if self.classdef.classdesc.lookup('_immutable_') is not None:
             hints = hints.copy()
             hints['immutable'] = True
-        if '_immutable_fields_' in self.classdef.classdesc.classdict:
+        self.immutable_field_list = []  # unless overwritten below
+        if self.classdef.classdesc.lookup('_immutable_fields_') is not None:
             hints = hints.copy()
-            self.immutable_field_list = self.classdef.classdesc.classdict['_immutable_fields_'].value
+            immutable_fields = self.classdef.classdesc.classdict.get(
+                '_immutable_fields_')
+            if immutable_fields is not None:
+                self.immutable_field_list = immutable_fields.value
             accessor = FieldListAccessor()
             hints['immutable_fields'] = accessor
         return hints
@@ -178,10 +187,20 @@
         return 'InstanceR %s' % (clsname,)
 
     def _setup_repr_final(self):
+        self._setup_immutable_field_list()
+        self._check_for_immutable_conflicts()
+
+    def _setup_immutable_field_list(self):
         hints = self.object_type._hints
         if "immutable_fields" in hints:
             accessor = hints["immutable_fields"]
-            self._parse_field_list(self.immutable_field_list, accessor)
+            if not hasattr(accessor, 'fields'):
+                immutable_fields = []
+                rbase = self
+                while rbase.classdef is not None:
+                    immutable_fields += rbase.immutable_field_list
+                    rbase = rbase.rbase
+                self._parse_field_list(immutable_fields, accessor)
 
     def _parse_field_list(self, fields, accessor):
         with_suffix = {}
@@ -191,11 +210,44 @@
                 suffix = '[*]'
             else:
                 suffix = ''
-            mangled_name, r = self._get_field(name)
+            try:
+                mangled_name, r = self._get_field(name)
+            except KeyError:
+                continue
             with_suffix[mangled_name] = suffix
         accessor.initialize(self.object_type, with_suffix)
         return with_suffix
 
+    def _check_for_immutable_conflicts(self):
+        # check for conflicts, i.e. a field that is defined normally as
+        # mutable in some parent class but that is now declared immutable
+        from pypy.rpython.lltypesystem.lltype import Void
+        is_self_immutable = "immutable" in self.object_type._hints
+        base = self
+        while base.classdef is not None:
+            base = base.rbase
+            for fieldname in base.fields:
+                try:
+                    mangled, r = base._get_field(fieldname)
+                except KeyError:
+                    continue
+                if r.lowleveltype == Void:
+                    continue
+                base._setup_immutable_field_list()
+                if base.object_type._immutable_field(mangled):
+                    continue
+                # 'fieldname' is a mutable, non-Void field in the parent
+                if is_self_immutable:
+                    raise ImmutableConflictError(
+                        "class %r has _immutable_=True, but parent class %r "
+                        "defines (at least) the mutable field %r" % (
+                        self, base, fieldname))
+                if fieldname in self.immutable_field_list:
+                    raise ImmutableConflictError(
+                        "field %r is defined mutable in class %r, but "
+                        "listed in _immutable_fields_ in subclass %r" % (
+                        fieldname, base, self))
+
     def new_instance(self, llops, classcallhop=None):
         raise NotImplementedError
 

Modified: pypy/branch/fast-forward/pypy/rpython/rstr.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/rstr.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/rstr.py	Thu Sep  9 01:00:13 2010
@@ -291,8 +291,8 @@
         if not hop.args_s[1].is_constant():
             raise TyperError("encoding must be constant")
         encoding = hop.args_s[1].const
-        if encoding == "ascii":
-            expect = self.lowleveltype   # can be a UniChar
+        if encoding == "ascii" and self.lowleveltype == UniChar:
+            expect = UniChar             # only for unichar.encode('ascii')
         else:
             expect = self.repr           # must be a regular unicode string
         v_self = hop.inputarg(expect, 0)

Modified: pypy/branch/fast-forward/pypy/rpython/test/test_extfunc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/test/test_extfunc.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/test/test_extfunc.py	Thu Sep  9 01:00:13 2010
@@ -6,150 +6,164 @@
 from pypy.annotation.policy import AnnotatorPolicy
 from pypy.rpython.test.test_llinterp import interpret
 
-def b(x):
-    return eval("x+40")
+class TestExtFuncEntry:
 
-class BTestFuncEntry(ExtFuncEntry):
-    _about_ = b
-    name = 'b'
-    signature_args = [annmodel.SomeInteger()]
-    signature_result = annmodel.SomeInteger()
-
-def test_annotation_b():
-    def f():
-        return b(1)
-    
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeInteger)
-
-def test_rtyping_b():
-    def f():
-        return b(2)
-
-    res = interpret(f, [])
-    assert res == 42
-
-def c(y, x):
-    yyy
-
-class CTestFuncEntry(ExtFuncEntry):
-    _about_ = c
-    name = 'ccc'
-    signature_args = [annmodel.SomeInteger()] * 2
-    signature_result = annmodel.SomeInteger()
-
-    def lltypeimpl(y, x):
-        return y + x
-    lltypeimpl = staticmethod(lltypeimpl)
-
-def test_interp_c():
-    def f():
-        return c(3, 4)
-
-    res = interpret(f, [])
-    assert res == 7
-
-def d(y):
-    return eval("y()")
-
-class DTestFuncEntry(ExtFuncEntry):
-    _about_ = d
-    name = 'd'
-    signature_args = [annmodel.SomeGenericCallable(args=[], result=
-                                                   annmodel.SomeFloat())]
-    signature_result = annmodel.SomeFloat()
-
-def test_callback():
-    def callback():
-        return 2.5
-
-    def f():
-        return d(callback)
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeFloat)
-    assert a.translator._graphof(callback)
-
-def dd():
-    pass
-
-register_external(dd, [int], int)
-
-def test_register_external_signature():
-    def f():
-        return dd(3)
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeInteger)
-
-
-def function_with_tuple_arg():
-    """
-    Dummy function which is declared via register_external to take a tuple as
-    an argument so that register_external's behavior for tuple-taking functions
-    can be verified.
-    """
-register_external(function_with_tuple_arg, [(int,)], int)
-
-def test_register_external_tuple_args():
-    """
-    Verify the annotation of a registered external function which takes a tuple
-    argument.
-    """
-    def f():
-        return function_with_tuple_arg((1,))
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-
-    # Not a very good assertion, but at least it means _something_ happened.
-    assert isinstance(s, annmodel.SomeInteger)
-
-def function_with_list():
-    pass
-register_external(function_with_list, [[int]], int)
-
-def function_returning_list():
-    pass
-register_external(function_returning_list, [], [int])
-
-def test_register_external_return_goes_back():
-    """
-    Check whether it works to pass the same list from one external
-    fun to another
-    [bookkeeper and list joining issues]
-    """
-    def f():
-        return function_with_list(function_returning_list())
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeInteger)
-
-def function_withspecialcase(arg):
-    return repr(arg)
-register_external(function_withspecialcase, args=None, result=str)
-
-def test_register_external_specialcase():
-    def f():
-        x = function_withspecialcase
-        return x(33) + x("aaa") + x([]) + "\n"
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeString)
+    def test_basic(self):
+        """
+        A ExtFuncEntry provides an annotation for a function, no need to flow
+        its graph.
+        """
+        def b(x):
+            "NOT_RPYTHON"
+            return eval("x+40")
+
+        class BTestFuncEntry(ExtFuncEntry):
+            _about_ = b
+            name = 'b'
+            signature_args = [annmodel.SomeInteger()]
+            signature_result = annmodel.SomeInteger()
+
+        def f():
+            return b(2)
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeInteger)
+
+        res = interpret(f, [])
+        assert res == 42
+
+    def test_lltypeimpl(self):
+        """
+        interpret() calls lltypeimpl instead of of the function/
+        """
+        def c(y, x):
+            yyy
+
+        class CTestFuncEntry(ExtFuncEntry):
+            _about_ = c
+            name = 'ccc'
+            signature_args = [annmodel.SomeInteger()] * 2
+            signature_result = annmodel.SomeInteger()
+
+            def lltypeimpl(y, x):
+                return y + x
+            lltypeimpl = staticmethod(lltypeimpl)
+
+        def f():
+            return c(3, 4)
+
+        res = interpret(f, [])
+        assert res == 7
+
+    def test_callback(self):
+        """
+        Verify annotation when a callback function is in the arguments list.
+        """
+        def d(y):
+            return eval("y()")
+
+        class DTestFuncEntry(ExtFuncEntry):
+            _about_ = d
+            name = 'd'
+            signature_args = [annmodel.SomeGenericCallable(args=[], result=
+                                                           annmodel.SomeFloat())]
+            signature_result = annmodel.SomeFloat()
+
+        def callback():
+            return 2.5
+
+        def f():
+            return d(callback)
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeFloat)
+        assert a.translator._graphof(callback)
+
+    def test_register_external_signature(self):
+        """
+        Test the standard interface for external functions.
+        """
+        def dd():
+            pass
+        register_external(dd, [int], int)
+
+        def f():
+            return dd(3)
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeInteger)
+
+    def test_register_external_tuple_args(self):
+        """
+        Verify the annotation of a registered external function which takes a
+        tuple argument.
+        """
+
+        def function_with_tuple_arg():
+            """
+            Dummy function which is declared via register_external to take a
+            tuple as an argument so that register_external's behavior for
+            tuple-taking functions can be verified.
+            """
+        register_external(function_with_tuple_arg, [(int,)], int)
+
+        def f():
+            return function_with_tuple_arg((1,))
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+
+        # Not a very good assertion, but at least it means _something_ happened.
+        assert isinstance(s, annmodel.SomeInteger)
+
+    def test_register_external_return_goes_back(self):
+        """
+        Check whether it works to pass the same list from one external
+        fun to another
+        [bookkeeper and list joining issues]
+        """
+        def function_with_list():
+            pass
+        register_external(function_with_list, [[int]], int)
+
+        def function_returning_list():
+            pass
+        register_external(function_returning_list, [], [int])
+
+        def f():
+            return function_with_list(function_returning_list())
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeInteger)
+
+    def test_register_external_specialcase(self):
+        """
+        When args=None, the external function accepts any arguments unmodified.
+        """
+        def function_withspecialcase(arg):
+            return repr(arg)
+        register_external(function_withspecialcase, args=None, result=str)
+
+        def f():
+            x = function_withspecialcase
+            return x(33) + x("aaa") + x([]) + "\n"
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeString)

Modified: pypy/branch/fast-forward/pypy/rpython/test/test_rclass.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/test/test_rclass.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/test/test_rclass.py	Thu Sep  9 01:00:13 2010
@@ -738,27 +738,150 @@
         assert accessor.fields == {"inst_x" : "", "inst_y" : "[*]"} or \
                accessor.fields == {"ox" : "", "oy" : "[*]"} # for ootype
 
-    def test_immutable_inheritance(self):
-        class I(object):
-            def __init__(self, v):
-                self.v = v
-        
-        class J(I):
+    def test_immutable_fields_subclass_1(self):
+        from pypy.jit.metainterp.typesystem import deref
+        class A(object):
+            _immutable_fields_ = ["x"]
+            def __init__(self, x):
+                self.x = x
+        class B(A):
+            def __init__(self, x, y):
+                A.__init__(self, x)
+                self.y = y
+
+        def f():
+            return B(3, 5)
+        t, typer, graph = self.gengraph(f, [])
+        B_TYPE = deref(graph.getreturnvar().concretetype)
+        accessor = B_TYPE._hints["immutable_fields"]
+        assert accessor.fields == {"inst_x" : ""} or \
+               accessor.fields == {"ox" : ""} # for ootype
+
+    def test_immutable_fields_subclass_2(self):
+        from pypy.jit.metainterp.typesystem import deref
+        class A(object):
+            _immutable_fields_ = ["x"]
+            def __init__(self, x):
+                self.x = x
+        class B(A):
+            _immutable_fields_ = ["y"]
+            def __init__(self, x, y):
+                A.__init__(self, x)
+                self.y = y
+
+        def f():
+            return B(3, 5)
+        t, typer, graph = self.gengraph(f, [])
+        B_TYPE = deref(graph.getreturnvar().concretetype)
+        accessor = B_TYPE._hints["immutable_fields"]
+        assert accessor.fields == {"inst_x" : "", "inst_y" : ""} or \
+               accessor.fields == {"ox" : "", "oy" : ""} # for ootype
+
+    def test_immutable_fields_only_in_subclass(self):
+        from pypy.jit.metainterp.typesystem import deref
+        class A(object):
+            def __init__(self, x):
+                self.x = x
+        class B(A):
+            _immutable_fields_ = ["y"]
+            def __init__(self, x, y):
+                A.__init__(self, x)
+                self.y = y
+
+        def f():
+            return B(3, 5)
+        t, typer, graph = self.gengraph(f, [])
+        B_TYPE = deref(graph.getreturnvar().concretetype)
+        accessor = B_TYPE._hints["immutable_fields"]
+        assert accessor.fields == {"inst_y" : ""} or \
+               accessor.fields == {"oy" : ""} # for ootype
+
+    def test_immutable_forbidden_inheritance_1(self):
+        from pypy.rpython.rclass import ImmutableConflictError
+        class A(object):
+            pass
+        class B(A):
+            _immutable_fields_ = ['v']
+        def f():
+            A().v = 123
+            B()             # crash: class B says 'v' is immutable,
+                            # but it is defined on parent class A
+        py.test.raises(ImmutableConflictError, self.gengraph, f, [])
+
+    def test_immutable_forbidden_inheritance_2(self):
+        from pypy.rpython.rclass import ImmutableConflictError
+        class A(object):
+            pass
+        class B(A):
             _immutable_ = True
-            def __init__(self, v, w):
-                self.w = w
-                I.__init__(self, v)
-
-        j = J(3, 4)
-        def f():
-            j.v = j.v * 1 # make the annotator think it is mutated
-            j.w = j.w * 1 # make the annotator think it is mutated
-            return j.v + j.w
-
-        t, typer, graph = self.gengraph(f, [], backendopt=True)
-        f_summary = summary(graph)
-        assert f_summary == {"setfield": 2} or \
-               f_summary == {"oosetfield": 2} # for ootype
+        def f():
+            A().v = 123
+            B()             # crash: class B has _immutable_ = True
+                            # but class A defines 'v' to be mutable
+        py.test.raises(ImmutableConflictError, self.gengraph, f, [])
+
+    def test_immutable_ok_inheritance_2(self):
+        from pypy.jit.metainterp.typesystem import deref
+        class A(object):
+            _immutable_fields_ = ['v']
+        class B(A):
+            _immutable_ = True
+        def f():
+            A().v = 123
+            B().w = 456
+            return B()
+        t, typer, graph = self.gengraph(f, [])
+        B_TYPE = deref(graph.getreturnvar().concretetype)
+        assert B_TYPE._hints["immutable"]
+        try:
+            A_TYPE = B_TYPE.super
+        except AttributeError:
+            A_TYPE = B_TYPE._superclass  # for ootype
+        accessor = A_TYPE._hints["immutable_fields"]
+        assert accessor.fields == {"inst_v" : ""} or \
+               accessor.fields == {"ov" : ""} # for ootype
+
+    def test_immutable_subclass_1(self):
+        from pypy.jit.metainterp.typesystem import deref
+        class A(object):
+            _immutable_ = True
+        class B(A):
+            pass
+        def f():
+            B().v = 123
+            return B()
+        t, typer, graph = self.gengraph(f, [])
+        B_TYPE = deref(graph.getreturnvar().concretetype)
+        assert B_TYPE._hints["immutable"]    # inherited from A
+
+    def test_immutable_subclass_2(self):
+        from pypy.jit.metainterp.typesystem import deref
+        class A(object):
+            pass
+        class B(A):
+            _immutable_ = True
+        def f():
+            B().v = 123
+            return B()
+        t, typer, graph = self.gengraph(f, [])
+        B_TYPE = deref(graph.getreturnvar().concretetype)
+        assert B_TYPE._hints["immutable"]
+
+    def test_immutable_subclass_void(self):
+        from pypy.jit.metainterp.typesystem import deref
+        class A(object):
+            pass
+        class B(A):
+            _immutable_ = True
+        def myfunc():
+            pass
+        def f():
+            A().f = myfunc    # it's ok to add Void attributes to A
+            B().v = 123       # even though only B is declared _immutable_
+            return B()
+        t, typer, graph = self.gengraph(f, [])
+        B_TYPE = deref(graph.getreturnvar().concretetype)
+        assert B_TYPE._hints["immutable"]
 
 
 class TestLLtype(BaseTestRclass, LLRtypeMixin):

Modified: pypy/branch/fast-forward/pypy/rpython/test/test_rint.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/test/test_rint.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/test/test_rint.py	Thu Sep  9 01:00:13 2010
@@ -117,10 +117,10 @@
         assert self.ll_to_string(res) == '413974738222117'
 
     def test_unsigned(self):
-        bigvalue = sys.maxint + 17
+        bigvalue = r_uint(sys.maxint + 17)
         def dummy(i):
             i = r_uint(i)
-            j = r_uint(bigvalue)
+            j = bigvalue
             return i < j
 
         res = self.interpret(dummy,[0])

Modified: pypy/branch/fast-forward/pypy/rpython/tool/rfficache.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/tool/rfficache.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/tool/rfficache.py	Thu Sep  9 01:00:13 2010
@@ -29,7 +29,7 @@
     }
     ''' % (include_string, add_source, str(question)))
     c_file = udir.join("gcctest.c")
-    c_file.write(c_source)
+    c_file.write(str(c_source) + '\n')
     eci = ExternalCompilationInfo()
     return build_executable_cache([c_file], eci)
 

Modified: pypy/branch/fast-forward/pypy/tool/release/package.py
==============================================================================
--- pypy/branch/fast-forward/pypy/tool/release/package.py	(original)
+++ pypy/branch/fast-forward/pypy/tool/release/package.py	Thu Sep  9 01:00:13 2010
@@ -11,11 +11,12 @@
 import py
 import os
 import fnmatch
-import tarfile
 from pypy.tool.udir import udir
 
 if sys.version_info < (2,6): py.test.skip("requires 2.6 so far")
 
+USE_TARFILE_MODULE = sys.platform == 'win32'
+
 def ignore_patterns(*patterns):
     """Function that can be used as copytree() ignore parameter.
 
@@ -69,9 +70,17 @@
     old_dir = os.getcwd()
     try:
         os.chdir(str(builddir))
-        os.system("strip " + str(archive_pypy_c))
-        os.system('tar cvjf ' + str(builddir.join(name + '.tar.bz2')) +
-                  " " + name)
+        os.system("strip " + str(archive_pypy_c))    # ignore errors
+        if USE_TARFILE_MODULE:
+            import tarfile
+            tf = tarfile.open(str(builddir.join(name + '.tar.bz2')), 'w:bz2')
+            tf.add(name)
+            tf.close()
+        else:
+            e = os.system('tar cvjf ' + str(builddir.join(name + '.tar.bz2')) +
+                          " " + name)
+            if e:
+                raise OSError('"tar" returned exit status %r' % e)
     finally:
         os.chdir(old_dir)
     if copy_to_dir is not None:

Modified: pypy/branch/fast-forward/pypy/tool/release/test/test_package.py
==============================================================================
--- pypy/branch/fast-forward/pypy/tool/release/test/test_package.py	(original)
+++ pypy/branch/fast-forward/pypy/tool/release/test/test_package.py	Thu Sep  9 01:00:13 2010
@@ -5,7 +5,7 @@
 from pypy.module.sys.version import  CPYTHON_VERSION
 import tarfile, os
 
-def test_dir_structure():
+def test_dir_structure(test='test'):
     # make sure we have sort of pypy-c
     pypy_c = py.path.local(pypydir).join('translator', 'goal', 'pypy-c')
     if not pypy_c.check():
@@ -14,8 +14,8 @@
     else:
         fake_pypy_c = False
     try:
-        builddir = package(py.path.local(pypydir).dirpath(), 'test')
-        prefix = builddir.join('test')
+        builddir = package(py.path.local(pypydir).dirpath(), test)
+        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()
@@ -24,18 +24,27 @@
         assert not prefix.join('lib_pypy', 'ctypes_configure').check()
         assert prefix.join('LICENSE').check()
         assert prefix.join('README').check()
-        th = tarfile.open(str(builddir.join('test.tar.bz2')))
-        assert th.getmember('test/lib_pypy/syslog.py')
+        th = tarfile.open(str(builddir.join('%s.tar.bz2' % test)))
+        assert th.getmember('%s/lib_pypy/syslog.py' % test)
 
         # the headers file could be not there, because they are copied into
         # trunk/include only during translation
         includedir = py.path.local(pypydir).dirpath().join('include')
         def check_include(name):
             if includedir.join(name).check(file=True):
-                assert th.getmember('test/include/%s' % name)
+                assert th.getmember('%s/include/%s' % (test, name))
         check_include('Python.h')
         check_include('modsupport.inl')
         check_include('pypy_decl.h')
     finally:
         if fake_pypy_c:
             pypy_c.remove()
+
+def test_with_tarfile_module():
+    from pypy.tool.release import package
+    prev = package.USE_TARFILE_MODULE
+    try:
+        package.USE_TARFILE_MODULE = True
+        test_dir_structure(test='testtarfile')
+    finally:
+        package.USE_TARFILE_MODULE = prev

Modified: pypy/branch/fast-forward/pypy/tool/runsubprocess.py
==============================================================================
--- pypy/branch/fast-forward/pypy/tool/runsubprocess.py	(original)
+++ pypy/branch/fast-forward/pypy/tool/runsubprocess.py	Thu Sep  9 01:00:13 2010
@@ -70,5 +70,5 @@
         assert results.startswith('(')
         results = eval(results)
         if results[0] is None:
-            raise OSError(results[1])
+            raise OSError('%s: %s' % (args[0], results[1]))
         return results

Modified: pypy/branch/fast-forward/pypy/translator/backendopt/test/test_constfold.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/backendopt/test/test_constfold.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/backendopt/test/test_constfold.py	Thu Sep  9 01:00:13 2010
@@ -49,7 +49,7 @@
     accessor = rclass.FieldListAccessor()
     S2 = lltype.GcStruct('S2', ('x', lltype.Signed),
                          hints={'immutable_fields': accessor})
-    accessor.initialize(S2, ['x'])
+    accessor.initialize(S2, {'x': ''})
     test_simple(S2)
 
 

Modified: pypy/branch/fast-forward/pypy/translator/c/database.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/database.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/database.py	Thu Sep  9 01:00:13 2010
@@ -213,7 +213,7 @@
                         forcename = self.idelayedfunctionnames[obj][0]
                         node = self.getcontainernode(container,
                                                      forcename=forcename)
-                        assert node.ptrname == forcename
+                        assert node.getptrname() == forcename
                         return forcename
                     # /hack hack hack
 
@@ -222,7 +222,7 @@
                     return '((%s) %d)' % (cdecl(self.gettype(T), ''),
                                           obj._obj)
                 node = self.getcontainernode(container)
-                return node.ptrname
+                return node.getptrname()
             else:
                 return '((%s) NULL)' % (cdecl(self.gettype(T), ''), )
         else:

Modified: pypy/branch/fast-forward/pypy/translator/c/gc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/gc.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/gc.py	Thu Sep  9 01:00:13 2010
@@ -172,7 +172,9 @@
         defnode = db.gettypedefnode(obj.about)
         self.implementationtypename = 'void (@)(void *)'
         self.name = defnode.gcinfo.static_deallocator
-        self.ptrname = '((void (*)(void *)) %s)' % (self.name,)
+
+    def getptrname(self):
+        return '((void (*)(void *)) %s)' % (self.name,)
 
     def enum_dependencies(self):
         return []
@@ -266,7 +268,9 @@
         defnode = db.gettypedefnode(obj.about)
         self.implementationtypename = self.typename
         self.name = self.db.namespace.uniquename('g_rtti_v_'+ defnode.barename)
-        self.ptrname = '(&%s)' % (self.name,)
+
+    def getptrname(self):
+        return '(&%s)' % (self.name,)
 
     def enum_dependencies(self):
         return []

Modified: pypy/branch/fast-forward/pypy/translator/c/gcc/instruction.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/gcc/instruction.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/gcc/instruction.py	Thu Sep  9 01:00:13 2010
@@ -5,6 +5,14 @@
 LOC_MASK      = 0x03
 LOC_NOWHERE   = LOC_REG | 0
 
+# x86-32 registers sometimes used to pass arguments when gcc optimizes
+# a function's calling convention
+ARGUMENT_REGISTERS_32 = ('%eax', '%edx', '%ecx')
+
+# x86-64 registers used to pass arguments
+ARGUMENT_REGISTERS_64 = ('%rdi', '%rsi', '%rdx', '%rcx', '%r8', '%r9')
+
+
 def frameloc_esp(offset):
     assert offset >= 0
     assert offset % 4 == 0
@@ -19,7 +27,8 @@
 
 
 class SomeNewValue(object):
-    pass
+    def __repr__(self):
+        return 'somenewvalue'
 somenewvalue = SomeNewValue()
 
 class LocalVar(object):
@@ -42,7 +51,7 @@
         else:
             return 1
 
-    def getlocation(self, framesize, uses_frame_pointer):
+    def getlocation(self, framesize, uses_frame_pointer, wordsize):
         if (self.hint == 'esp' or not uses_frame_pointer
             or self.ofs_from_frame_end % 2 != 0):
             # try to use esp-relative addressing
@@ -52,7 +61,7 @@
             # we can get an odd value if the framesize is marked as bogus
             # by visit_andl()
         assert uses_frame_pointer
-        ofs_from_ebp = self.ofs_from_frame_end + 4
+        ofs_from_ebp = self.ofs_from_frame_end + wordsize
         return frameloc_ebp(ofs_from_ebp)
 
 
@@ -81,22 +90,28 @@
         self.previous_insns = []   # all insns that jump (or fallthrough) here
 
 class InsnFunctionStart(Insn):
+    _args_ = ['arguments']
     framesize = 0
     previous_insns = ()
-    def __init__(self, registers):
+    def __init__(self, registers, wordsize):
         self.arguments = {}
         for reg in registers:
             self.arguments[reg] = somenewvalue
+        self.wordsize = wordsize
 
     def source_of(self, localvar, tag):
         if localvar not in self.arguments:
-            if localvar in ('%eax', '%edx', '%ecx'):
+            if self.wordsize == 4 and localvar in ARGUMENT_REGISTERS_32:
                 # xxx this might show a bug in trackgcroot.py failing to
                 # figure out which instruction stored a value in these
                 # registers.  However, this case also occurs when the
                 # the function's calling convention was optimized by gcc:
                 # the 3 registers above are then used to pass arguments
                 pass
+            elif self.wordsize == 8 and localvar in ARGUMENT_REGISTERS_64:
+                # this is normal: these registers are always used to
+                # pass arguments
+                pass
             else:
                 assert (isinstance(localvar, LocalVar) and
                         localvar.ofs_from_frame_end > 0), (
@@ -218,15 +233,16 @@
         return {self.loc: None}
 
 class InsnPrologue(Insn):
+    def __init__(self, wordsize):
+        self.wordsize = wordsize
     def __setattr__(self, attr, value):
         if attr == 'framesize':
-            assert value == 4, ("unrecognized function prologue - "
-                                "only supports push %ebp; movl %esp, %ebp")
+            assert value == self.wordsize, (
+                "unrecognized function prologue - "
+                "only supports push %ebp; movl %esp, %ebp")
         Insn.__setattr__(self, attr, value)
 
 class InsnEpilogue(Insn):
     def __init__(self, framesize=None):
         if framesize is not None:
             self.framesize = framesize
-
-

Modified: pypy/branch/fast-forward/pypy/translator/c/gcc/test/conftest.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/gcc/test/conftest.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/gcc/test/conftest.py	Thu Sep  9 01:00:13 2010
@@ -1,8 +1,6 @@
 import py
 from pypy.jit.backend import detect_cpu
-
 cpu = detect_cpu.autodetect()
 def pytest_runtest_setup(item):
-    if cpu != 'x86':
+    if cpu not in ('x86', 'x86_64'):
         py.test.skip("x86 directory skipped: cpu is %r" % (cpu,))
-    

Modified: pypy/branch/fast-forward/pypy/translator/c/gcc/test/test_trackgcroot.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/gcc/test/test_trackgcroot.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/gcc/test/test_trackgcroot.py	Thu Sep  9 01:00:13 2010
@@ -1,51 +1,52 @@
 import py
 import sys, re
-from pypy.translator.c.gcc.trackgcroot import format_location
-from pypy.translator.c.gcc.trackgcroot import format_callshape
 from pypy.translator.c.gcc.trackgcroot import LOC_NOWHERE, LOC_REG
 from pypy.translator.c.gcc.trackgcroot import LOC_EBP_PLUS, LOC_EBP_MINUS
 from pypy.translator.c.gcc.trackgcroot import LOC_ESP_PLUS
 from pypy.translator.c.gcc.trackgcroot import ElfAssemblerParser
 from pypy.translator.c.gcc.trackgcroot import DarwinAssemblerParser
-from pypy.translator.c.gcc.trackgcroot import compress_callshape
-from pypy.translator.c.gcc.trackgcroot import decompress_callshape
 from pypy.translator.c.gcc.trackgcroot import PARSERS
+from pypy.translator.c.gcc.trackgcroot import ElfFunctionGcRootTracker32
 from StringIO import StringIO
+import py.test
 
 this_dir = py.path.local(__file__).dirpath()
 
 
 def test_format_location():
-    assert format_location(LOC_NOWHERE) == '?'
-    assert format_location(LOC_REG | (1<<2)) == '%ebx'
-    assert format_location(LOC_REG | (2<<2)) == '%esi'
-    assert format_location(LOC_REG | (3<<2)) == '%edi'
-    assert format_location(LOC_REG | (4<<2)) == '%ebp'
-    assert format_location(LOC_EBP_PLUS + 0) == '(%ebp)'
-    assert format_location(LOC_EBP_PLUS + 4) == '4(%ebp)'
-    assert format_location(LOC_EBP_MINUS + 4) == '-4(%ebp)'
-    assert format_location(LOC_ESP_PLUS + 0) == '(%esp)'
-    assert format_location(LOC_ESP_PLUS + 4) == '4(%esp)'
+    cls = ElfFunctionGcRootTracker32
+    assert cls.format_location(LOC_NOWHERE) == '?'
+    assert cls.format_location(LOC_REG | (1<<2)) == '%ebx'
+    assert cls.format_location(LOC_REG | (2<<2)) == '%esi'
+    assert cls.format_location(LOC_REG | (3<<2)) == '%edi'
+    assert cls.format_location(LOC_REG | (4<<2)) == '%ebp'
+    assert cls.format_location(LOC_EBP_PLUS + 0) == '(%ebp)'
+    assert cls.format_location(LOC_EBP_PLUS + 4) == '4(%ebp)'
+    assert cls.format_location(LOC_EBP_MINUS + 4) == '-4(%ebp)'
+    assert cls.format_location(LOC_ESP_PLUS + 0) == '(%esp)'
+    assert cls.format_location(LOC_ESP_PLUS + 4) == '4(%esp)'
 
 def test_format_callshape():
+    cls = ElfFunctionGcRootTracker32
     expected = ('{4(%ebp) '               # position of the return address
                 '| 8(%ebp), 12(%ebp), 16(%ebp), 20(%ebp) '  # 4 saved regs
                 '| 24(%ebp), 28(%ebp)}')                    # GC roots
-    assert format_callshape((LOC_EBP_PLUS+4,
-                             LOC_EBP_PLUS+8,
-                             LOC_EBP_PLUS+12,
-                             LOC_EBP_PLUS+16,
-                             LOC_EBP_PLUS+20,
-                             LOC_EBP_PLUS+24,
-                             LOC_EBP_PLUS+28)) == expected
+    assert cls.format_callshape((LOC_EBP_PLUS+4,
+                                 LOC_EBP_PLUS+8,
+                                 LOC_EBP_PLUS+12,
+                                 LOC_EBP_PLUS+16,
+                                 LOC_EBP_PLUS+20,
+                                 LOC_EBP_PLUS+24,
+                                 LOC_EBP_PLUS+28)) == expected
 
 def test_compress_callshape():
+    cls = ElfFunctionGcRootTracker32
     shape = (1, 127, 0x1234, 0x5678, 0x234567,
              0x765432, 0x61626364, 0x41424344)
-    bytes = list(compress_callshape(shape))
+    bytes = list(cls.compress_callshape(shape))
     print bytes
     assert len(bytes) == 1+1+2+3+4+4+5+5+1
-    assert decompress_callshape(bytes) == list(shape)
+    assert cls.decompress_callshape(bytes) == list(shape)
 
 def test_find_functions_elf():
     source = """\
@@ -108,7 +109,7 @@
  
 def test_computegcmaptable():
     tests = []
-    for format in ('elf', 'darwin', 'msvc'):
+    for format in ('elf', 'darwin', 'msvc', 'elf64'):
         for path in this_dir.join(format).listdir("track*.s"):
             n = path.purebasename[5:]
             try:
@@ -138,7 +139,7 @@
     tabledict = {}
     seen = {}
     for entry in table:
-        print '%s: %s' % (entry[0], format_callshape(entry[1]))
+        print '%s: %s' % (entry[0], tracker.format_callshape(entry[1]))
         tabledict[entry[0]] = entry[1]
     # find the ";; expected" lines
     prevline = ""
@@ -151,7 +152,7 @@
             label = prevmatch.group(1)
             assert label in tabledict
             got = tabledict[label]
-            assert format_callshape(got) == expected
+            assert tracker.format_callshape(got) == expected
             seen[label] = True
             if format == 'msvc':
                 expectedlines.insert(i-2, 'PUBLIC\t%s\n' % (label,))

Modified: pypy/branch/fast-forward/pypy/translator/c/gcc/trackgcroot.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/gcc/trackgcroot.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/gcc/trackgcroot.py	Thu Sep  9 01:00:13 2010
@@ -72,7 +72,7 @@
             if self.is_stack_bottom:
                 retaddr = LOC_NOWHERE     # end marker for asmgcroot.py
             elif self.uses_frame_pointer:
-                retaddr = frameloc_ebp(4)
+                retaddr = frameloc_ebp(self.WORD)
             else:
                 retaddr = frameloc_esp(insn.framesize)
             shape = [retaddr]
@@ -84,7 +84,8 @@
             for localvar, tag in insn.gcroots.items():
                 if isinstance(localvar, LocalVar):
                     loc = localvar.getlocation(insn.framesize,
-                                               self.uses_frame_pointer)
+                                               self.uses_frame_pointer,
+                                               self.WORD)
                 elif localvar in self.REG2LOC:
                     loc = self.REG2LOC[localvar]
                 else:
@@ -148,7 +149,7 @@
             lst.append(previnsn)
 
     def parse_instructions(self):
-        self.insns = [InsnFunctionStart(self.CALLEE_SAVE_REGISTERS)]
+        self.insns = [InsnFunctionStart(self.CALLEE_SAVE_REGISTERS, self.WORD)]
         ignore_insns = False
         for lineno, line in enumerate(self.lines):
             if lineno < self.skip:
@@ -263,7 +264,7 @@
                     ofs_from_ebp = int(match.group(1) or '0')
                     if self.format == 'msvc':
                         ofs_from_ebp += int(match.group(2) or '0')
-                    localvar = ofs_from_ebp - 4
+                    localvar = ofs_from_ebp - self.WORD
                     assert localvar != 0    # that's the return address
                     return LocalVar(localvar, hint='ebp')
             return localvar
@@ -357,6 +358,56 @@
                 self.lines.insert(call.lineno+1, '\t.globl\t%s\n' % (label,))
         call.global_label = label
 
+    @classmethod
+    def compress_callshape(cls, shape):
+        # For a single shape, this turns the list of integers into a list of
+        # bytes and reverses the order of the entries.  The length is
+        # encoded by inserting a 0 marker after the gc roots coming from
+        # shape[N:] and before the N values coming from shape[N-1] to
+        # shape[0] (for N == 5 on 32-bit or 7 on 64-bit platforms).
+        # In practice it seems that shapes contain many integers
+        # whose value is up to a few thousands, which the algorithm below
+        # compresses down to 2 bytes.  Very small values compress down to a
+        # single byte.
+
+        # Callee-save regs plus ret addr
+        min_size = len(cls.CALLEE_SAVE_REGISTERS) + 1
+
+        assert len(shape) >= min_size
+        shape = list(shape)
+        assert 0 not in shape[min_size:]
+        shape.insert(min_size, 0)
+        result = []
+        for loc in shape:
+            assert loc >= 0
+            flag = 0
+            while loc >= 0x80:
+                result.append(int(loc & 0x7F) | flag)
+                flag = 0x80
+                loc >>= 7
+            result.append(int(loc) | flag)
+        result.reverse()
+        return result
+
+    @classmethod
+    def decompress_callshape(cls, bytes):
+        # For tests.  This logic is copied in asmgcroot.py.
+        result = []
+        n = 0
+        while n < len(bytes):
+            value = 0
+            while True:
+                b = bytes[n]
+                n += 1
+                value += b
+                if b < 0x80:
+                    break
+                value = (value - 0x80) << 7
+            result.append(value)
+        result.reverse()
+        assert result[5] == 0
+        del result[5]
+        return result
     # ____________________________________________________________
 
     CANNOT_COLLECT = {    # some of the most used functions that cannot collect
@@ -375,7 +426,7 @@
 
     IGNORE_OPS_WITH_PREFIXES = dict.fromkeys([
         'cmp', 'test', 'set', 'sahf', 'lahf', 'cltd', 'cld', 'std',
-        'rep', 'movs', 'lods', 'stos', 'scas', 'cwtl', 'prefetch',
+        'rep', 'movs', 'lods', 'stos', 'scas', 'cwtl', 'cwde', 'prefetch',
         # floating-point operations cannot produce GC pointers
         'f',
         'cvt', 'ucomi', 'comi', 'subs', 'subp' , 'adds', 'addp', 'xorp',
@@ -385,10 +436,9 @@
         'inc', 'dec', 'not', 'neg', 'or', 'and', 'sbb', 'adc',
         'shl', 'shr', 'sal', 'sar', 'rol', 'ror', 'mul', 'imul', 'div', 'idiv',
         'bswap', 'bt', 'rdtsc',
+        'punpck', 'pshufd', 
         # zero-extending moves should not produce GC pointers
         'movz',
-        # quadword operations
-        'movq',
         ])
 
     visit_movb = visit_nop
@@ -400,7 +450,7 @@
     visit_xorb = visit_nop
     visit_xorw = visit_nop
 
-    def visit_addl(self, line, sign=+1):
+    def _visit_add(self, line, sign=+1):
         match = self.r_binaryinsn.match(line)
         source = match.group("source")
         target = match.group("target")
@@ -415,8 +465,8 @@
         else:
             return []
 
-    def visit_subl(self, line):
-        return self.visit_addl(line, sign=-1)
+    def _visit_sub(self, line):
+        return self._visit_add(line, sign=-1)
 
     def unary_insn(self, line):
         match = self.r_unaryinsn.match(line)
@@ -439,8 +489,6 @@
         else:
             return []
 
-    visit_xorl = binary_insn   # used in "xor reg, reg" to create a NULL GC ptr
-    visit_orl = binary_insn
     # The various cmov* operations
     for name in '''
         e ne g ge l le a ae b be p np s ns o no
@@ -448,7 +496,7 @@
         locals()['visit_cmov' + name] = binary_insn
         locals()['visit_cmov' + name + 'l'] = binary_insn
 
-    def visit_andl(self, line):
+    def _visit_and(self, line):
         match = self.r_binaryinsn.match(line)
         target = match.group("target")
         if target == self.ESP:
@@ -460,9 +508,7 @@
         else:
             return self.binary_insn(line)
 
-    visit_and = visit_andl
-
-    def visit_leal(self, line):
+    def _visit_lea(self, line):
         match = self.r_binaryinsn.match(line)
         target = match.group("target")
         if target == self.ESP:
@@ -474,7 +520,7 @@
                     raise UnrecognizedOperation('epilogue without prologue')
                 ofs_from_ebp = int(match.group(1) or '0')
                 assert ofs_from_ebp <= 0
-                framesize = 4 - ofs_from_ebp
+                framesize = self.WORD - ofs_from_ebp
             else:
                 match = self.r_localvar_esp.match(source)
                 # leal 12(%esp), %esp
@@ -489,17 +535,23 @@
     def insns_for_copy(self, source, target):
         source = self.replace_symbols(source)
         target = self.replace_symbols(target)
-        if source == self.ESP or target == self.ESP:
+        if target == self.ESP:
             raise UnrecognizedOperation('%s -> %s' % (source, target))
         elif self.r_localvar.match(target):
             if self.r_localvar.match(source):
+                # eg, movl %eax, %ecx: possibly copies a GC root
                 return [InsnCopyLocal(source, target)]
             else:
+                # eg, movl (%eax), %edi or mov %esp, %edi: load a register
+                # from "outside".  If it contains a pointer to a GC root,
+                # it will be announced later with the GCROOT macro.
                 return [InsnSetLocal(target, [source])]
         else:
+            # eg, movl %ebx, (%edx) or mov %ebp, %esp: does not write into
+            # a general register
             return []
 
-    def visit_movl(self, line):
+    def _visit_mov(self, line):
         match = self.r_binaryinsn.match(line)
         source = match.group("source")
         target = match.group("target")
@@ -513,34 +565,24 @@
                           # gcc -fno-unit-at-a-time.
         return self.insns_for_copy(source, target)
 
-    visit_mov = visit_movl
-
-    def visit_pushl(self, line):
+    def _visit_push(self, line):
         match = self.r_unaryinsn.match(line)
         source = match.group(1)
-        return [InsnStackAdjust(-4)] + self.insns_for_copy(source, self.TOP_OF_STACK)
-
-    def visit_pushw(self, line):
-        return [InsnStackAdjust(-2)]   # rare but not impossible
+        return [InsnStackAdjust(-self.WORD)] + self.insns_for_copy(source, self.TOP_OF_STACK)
 
     def _visit_pop(self, target):
-        return self.insns_for_copy(self.TOP_OF_STACK, target) + [InsnStackAdjust(+4)]
-
-    def visit_popl(self, line):
-        match = self.r_unaryinsn.match(line)
-        target = match.group(1)
-        return self._visit_pop(target)
+        return self.insns_for_copy(self.TOP_OF_STACK, target) + [InsnStackAdjust(+self.WORD)]
 
     def _visit_prologue(self):
         # for the prologue of functions that use %ebp as frame pointer
         self.uses_frame_pointer = True
         self.r_localvar = self.r_localvarfp
-        return [InsnPrologue()]
+        return [InsnPrologue(self.WORD)]
 
     def _visit_epilogue(self):
         if not self.uses_frame_pointer:
             raise UnrecognizedOperation('epilogue without prologue')
-        return [InsnEpilogue(4)]
+        return [InsnEpilogue(self.WORD)]
 
     def visit_leave(self, line):
         return self._visit_epilogue() + self._visit_pop(self.EBP)
@@ -662,7 +704,7 @@
     visit_jc = conditional_jump
     visit_jnc = conditional_jump
 
-    def visit_xchgl(self, line):
+    def _visit_xchg(self, line):
         # only support the format used in VALGRIND_DISCARD_TRANSLATIONS
         # which is to use a marker no-op "xchgl %ebx, %ebx"
         match = self.r_binaryinsn.match(line)
@@ -741,8 +783,172 @@
                 insns.append(InsnStackAdjust(16))
         return insns
 
+    # __________ debugging output __________
+
+    @classmethod
+    def format_location(cls, loc):
+        # A 'location' is a single number describing where a value is stored
+        # across a call.  It can be in one of the CALLEE_SAVE_REGISTERS, or
+        # in the stack frame at an address relative to either %esp or %ebp.
+        # The last two bits of the location number are used to tell the cases
+        # apart; see format_location().
+        assert loc >= 0
+        kind = loc & LOC_MASK
+        if kind == LOC_REG:
+            if loc == LOC_NOWHERE:
+                return '?'
+            reg = (loc >> 2) - 1
+            return '%' + cls.CALLEE_SAVE_REGISTERS[reg].replace("%", "")
+        else:
+            offset = loc & ~ LOC_MASK
+            if kind == LOC_EBP_PLUS:
+                result = '(%' + cls.EBP.replace("%", "") + ')'
+            elif kind == LOC_EBP_MINUS:
+                result = '(%' + cls.EBP.replace("%", "") + ')'
+                offset = -offset
+            elif kind == LOC_ESP_PLUS:
+                result = '(%' + cls.ESP.replace("%", "") + ')'
+            else:
+                assert 0, kind
+            if offset != 0:
+                result = str(offset) + result
+            return result
+
+    @classmethod
+    def format_callshape(cls, shape):
+        # A 'call shape' is a tuple of locations in the sense of
+        # format_location().  They describe where in a function frame
+        # interesting values are stored, when this function executes a 'call'
+        # instruction.
+        #
+        #   shape[0]    is the location that stores the fn's own return
+        #               address (not the return address for the currently
+        #               executing 'call')
+        #
+        #   shape[1..N] is where the fn saved its own caller's value of a
+        #               certain callee save register. (where N is the number
+        #               of callee save registers.)
+        #
+        #   shape[>N]   are GC roots: where the fn has put its local GCPTR
+        #               vars
+        #
+        num_callee_save_regs = len(cls.CALLEE_SAVE_REGISTERS)
+        assert isinstance(shape, tuple)
+        # + 1 for the return address
+        assert len(shape) >= (num_callee_save_regs + 1)
+        result = [cls.format_location(loc) for loc in shape]
+        return '{%s | %s | %s}' % (result[0],
+                                   ', '.join(result[1:(num_callee_save_regs+1)]),
+                                   ', '.join(result[(num_callee_save_regs+1):]))
+
+
+class FunctionGcRootTracker32(FunctionGcRootTracker):
+    WORD = 4
+
+    visit_mov = FunctionGcRootTracker._visit_mov
+    visit_movl = FunctionGcRootTracker._visit_mov
+    visit_pushl = FunctionGcRootTracker._visit_push
+    visit_leal = FunctionGcRootTracker._visit_lea
+
+    visit_addl = FunctionGcRootTracker._visit_add
+    visit_subl = FunctionGcRootTracker._visit_sub
+    visit_andl = FunctionGcRootTracker._visit_and
+    visit_and = FunctionGcRootTracker._visit_and
+
+    visit_xchgl = FunctionGcRootTracker._visit_xchg
+
+    # used in "xor reg, reg" to create a NULL GC ptr
+    visit_xorl = FunctionGcRootTracker.binary_insn
+    visit_orl = FunctionGcRootTracker.binary_insn     # unsure about this one
+
+    # occasionally used on 32-bits to move floats around
+    visit_movq = FunctionGcRootTracker.visit_nop
+
+    def visit_pushw(self, line):
+        return [InsnStackAdjust(-2)]   # rare but not impossible
 
-class ElfFunctionGcRootTracker(FunctionGcRootTracker):
+    def visit_popl(self, line):
+        match = self.r_unaryinsn.match(line)
+        target = match.group(1)
+        return self._visit_pop(target)
+
+class FunctionGcRootTracker64(FunctionGcRootTracker):
+    WORD = 8
+
+    # Regex ignores destination
+    r_save_xmm_register = re.compile(r"\tmovaps\s+%xmm(\d+)")
+
+    def _maybe_32bit_dest(func):
+        def wrapper(self, line):
+            # Using a 32-bit reg as a destination in 64-bit mode zero-extends
+            # to 64-bits, so sometimes gcc uses a 32-bit operation to copy a
+            # statically known pointer to a register
+
+            # %eax -> %rax
+            new_line = re.sub(r"%e(ax|bx|cx|dx|di|si)$", r"%r\1", line)
+            # %r10d -> %r10
+            new_line = re.sub(r"%r(\d+)d$", r"%r\1", new_line)
+            return func(self, new_line)
+        return wrapper
+
+    visit_addl = FunctionGcRootTracker.visit_nop
+    visit_subl = FunctionGcRootTracker.visit_nop
+    visit_leal = FunctionGcRootTracker.visit_nop
+
+    visit_cltq = FunctionGcRootTracker.visit_nop
+
+    visit_movq = FunctionGcRootTracker._visit_mov
+    # just a special assembler mnemonic for mov
+    visit_movabsq = FunctionGcRootTracker._visit_mov
+    visit_mov = _maybe_32bit_dest(FunctionGcRootTracker._visit_mov)
+    visit_movl = visit_mov
+
+    visit_xorl = _maybe_32bit_dest(FunctionGcRootTracker.binary_insn)
+    
+    visit_pushq = FunctionGcRootTracker._visit_push
+
+    visit_addq = FunctionGcRootTracker._visit_add
+    visit_subq = FunctionGcRootTracker._visit_sub
+
+    visit_leaq = FunctionGcRootTracker._visit_lea
+
+    visit_xorq = FunctionGcRootTracker.binary_insn
+
+    # FIXME: similar to visit_popl for 32-bit
+    def visit_popq(self, line):
+        match = self.r_unaryinsn.match(line)
+        target = match.group(1)
+        return self._visit_pop(target)
+
+    def visit_jmp(self, line):
+        # On 64-bit, %al is used when calling varargs functions to specify an
+        # upper-bound on the number of xmm registers used in the call. gcc
+        # uses %al to compute an indirect jump that looks like:
+        #
+        #     jmp *[some register]
+        #     movaps %xmm7, [stack location]
+        #     movaps %xmm6, [stack location]
+        #     movaps %xmm5, [stack location]
+        #     movaps %xmm4, [stack location]
+        #     movaps %xmm3, [stack location]
+        #     movaps %xmm2, [stack location]
+        #     movaps %xmm1, [stack location]
+        #     movaps %xmm0, [stack location]
+        #
+        # The jmp is always to somewhere in the block of "movaps"
+        # instructions, according to how many xmm registers need to be saved
+        # to the stack. The point of all this is that we can safely ignore
+        # jmp instructions of that form.
+        if (self.currentlineno + 8) < len(self.lines) and self.r_unaryinsn_star.match(line):
+            matches = [self.r_save_xmm_register.match(self.lines[self.currentlineno + 1 + i]) for i in range(8)]
+            if all(m and int(m.group(1)) == (7 - i) for i, m in enumerate(matches)):
+                return []
+
+        return FunctionGcRootTracker.visit_jmp(self, line)
+
+
+
+class ElfFunctionGcRootTracker32(FunctionGcRootTracker32):
     format = 'elf'
 
     ESP     = '%esp'
@@ -791,7 +997,65 @@
         match = self.r_functionend.match(lines[-1])
         assert funcname == match.group(1)
         assert funcname == match.group(2)
-        super(ElfFunctionGcRootTracker, self).__init__(
+        super(ElfFunctionGcRootTracker32, self).__init__(
+            funcname, lines, filetag)
+
+    def extract_immediate(self, value):
+        if not value.startswith('$'):
+            return None
+        return int(value[1:])
+
+ElfFunctionGcRootTracker32.init_regexp()
+
+class ElfFunctionGcRootTracker64(FunctionGcRootTracker64):
+    format = 'elf64'
+    ESP = '%rsp'
+    EBP = '%rbp'
+    EAX = '%rax'
+    CALLEE_SAVE_REGISTERS = ['%rbx', '%r12', '%r13', '%r14', '%r15', '%rbp']
+    REG2LOC = dict((_reg, LOC_REG | ((_i+1)<<2))
+                   for _i, _reg in enumerate(CALLEE_SAVE_REGISTERS))
+    OPERAND = r'(?:[-\w$%+.:@"]+(?:[(][\w%,]+[)])?|[(][\w%,]+[)])'
+    LABEL   = r'([a-zA-Z_$.][a-zA-Z0-9_$@.]*)'
+    OFFSET_LABELS   = 2**30
+    TOP_OF_STACK = '0(%rsp)'
+
+    r_functionstart = re.compile(r"\t.type\s+"+LABEL+",\s*[@]function\s*$")
+    r_functionend   = re.compile(r"\t.size\s+"+LABEL+",\s*[.]-"+LABEL+"\s*$")
+    LOCALVAR = r"%rax|%rbx|%rcx|%rdx|%rdi|%rsi|%rbp|%r8|%r9|%r10|%r11|%r12|%r13|%r14|%r15|-?\d*[(]%rsp[)]"
+    LOCALVARFP = LOCALVAR + r"|-?\d*[(]%rbp[)]"
+    r_localvarnofp  = re.compile(LOCALVAR)
+    r_localvarfp    = re.compile(LOCALVARFP)
+    r_localvar_esp  = re.compile(r"(-?\d*)[(]%rsp[)]")
+    r_localvar_ebp  = re.compile(r"(-?\d*)[(]%rbp[)]")
+
+    r_rel_label      = re.compile(r"(\d+):\s*$")
+    r_jump_rel_label = re.compile(r"\tj\w+\s+"+"(\d+)f"+"\s*$")
+
+    r_unaryinsn_star= re.compile(r"\t[a-z]\w*\s+[*]("+OPERAND+")\s*$")
+    r_jmptable_item = re.compile(r"\t.quad\t"+LABEL+"(-\"[A-Za-z0-9$]+\")?\s*$")
+    r_jmptable_end  = re.compile(r"\t.text|\t.section\s+.text|\t\.align|"+LABEL)
+
+    r_gcroot_marker = re.compile(r"\t/[*] GCROOT ("+LOCALVARFP+") [*]/")
+    r_gcnocollect_marker = re.compile(r"\t/[*] GC_NOCOLLECT ("+OPERAND+") [*]/")
+    r_bottom_marker = re.compile(r"\t/[*] GC_STACK_BOTTOM [*]/")
+
+    FUNCTIONS_NOT_RETURNING = {
+        'abort': None,
+        '_exit': None,
+        '__assert_fail': None,
+        '___assert_rtn': None,
+        'L___assert_rtn$stub': None,
+        'L___eprintf$stub': None,
+        }
+
+    def __init__(self, lines, filetag=0):
+        match = self.r_functionstart.match(lines[0])
+        funcname = match.group(1)
+        match = self.r_functionend.match(lines[-1])
+        assert funcname == match.group(1)
+        assert funcname == match.group(2)
+        super(ElfFunctionGcRootTracker64, self).__init__(
             funcname, lines, filetag)
 
     def extract_immediate(self, value):
@@ -799,9 +1063,9 @@
             return None
         return int(value[1:])
 
-ElfFunctionGcRootTracker.init_regexp()
+ElfFunctionGcRootTracker64.init_regexp()
 
-class DarwinFunctionGcRootTracker(ElfFunctionGcRootTracker):
+class DarwinFunctionGcRootTracker(ElfFunctionGcRootTracker32):
     format = 'darwin'
 
     r_functionstart = re.compile(r"_(\w+):\s*$")
@@ -810,7 +1074,7 @@
     def __init__(self, lines, filetag=0):
         match = self.r_functionstart.match(lines[0])
         funcname = '_' + match.group(1)
-        FunctionGcRootTracker.__init__(self, funcname, lines, filetag)
+        FunctionGcRootTracker32.__init__(self, funcname, lines, filetag)
 
 class Mingw32FunctionGcRootTracker(DarwinFunctionGcRootTracker):
     format = 'mingw32'
@@ -821,7 +1085,7 @@
         '__assert': None,
         }
 
-class MsvcFunctionGcRootTracker(FunctionGcRootTracker):
+class MsvcFunctionGcRootTracker(FunctionGcRootTracker32):
     format = 'msvc'
     ESP = 'esp'
     EBP = 'ebp'
@@ -906,12 +1170,12 @@
         push pop mov lea
         xor sub add
         '''.split():
-        locals()['visit_' + name] = getattr(FunctionGcRootTracker,
+        locals()['visit_' + name] = getattr(FunctionGcRootTracker32,
                                             'visit_' + name + 'l')
 
-    visit_int = FunctionGcRootTracker.visit_nop
+    visit_int = FunctionGcRootTracker32.visit_nop
     # probably not GC pointers
-    visit_cdq  = FunctionGcRootTracker.visit_nop
+    visit_cdq  = FunctionGcRootTracker32.visit_nop
 
     def visit_npad(self, line):
         # MASM has a nasty bug: it implements "npad 5" with "add eax, 0"
@@ -1038,7 +1302,7 @@
         table = tracker.computegcmaptable(self.verbose)
         if self.verbose > 1:
             for label, state in table:
-                print >> sys.stderr, label, '\t', format_callshape(state)
+                print >> sys.stderr, label, '\t', tracker.format_callshape(state)
         table = compress_gcmaptable(table)
         if self.shuffle and random.random() < 0.5:
             self.gcmaptable[:0] = table
@@ -1049,7 +1313,7 @@
 
 class ElfAssemblerParser(AssemblerParser):
     format = "elf"
-    FunctionGcRootTracker = ElfFunctionGcRootTracker
+    FunctionGcRootTracker = ElfFunctionGcRootTracker32
 
     def find_functions(self, iterlines):
         functionlines = []
@@ -1072,6 +1336,10 @@
             "missed the end of the previous function")
         yield False, functionlines
 
+class ElfAssemblerParser64(ElfAssemblerParser):
+    format = "elf64"
+    FunctionGcRootTracker = ElfFunctionGcRootTracker64
+
 class DarwinAssemblerParser(AssemblerParser):
     format = "darwin"
     FunctionGcRootTracker = DarwinFunctionGcRootTracker
@@ -1241,6 +1509,7 @@
 
 PARSERS = {
     'elf': ElfAssemblerParser,
+    'elf64': ElfAssemblerParser64,
     'darwin': DarwinAssemblerParser,
     'mingw32': Mingw32AssemblerParser,
     'msvc': MsvcAssemblerParser,
@@ -1281,6 +1550,13 @@
             txt = kwargs[self.format]
             print >> output, "\t%s" % txt
 
+        if self.format == 'elf64':
+            word_decl = '.quad'
+        else:
+            word_decl = '.long'
+
+        tracker_cls = PARSERS[self.format].FunctionGcRootTracker
+
         # The pypy_asm_stackwalk() function
 
         if self.format == 'msvc':
@@ -1327,7 +1603,56 @@
                }
             }
             """
+        elif self.format == 'elf64':
+            print >> output, "\t.text"
+            print >> output, "\t.globl %s" % _globalname('pypy_asm_stackwalk')
+            print >> output, "\t.type pypy_asm_stackwalk, @function"
+            print >> output, "%s:" % _globalname('pypy_asm_stackwalk')
+
+            print >> output, """\
+            /* See description in asmgcroot.py */
+            movq\t%rdi, %rdx\t/* 1st argument, which is the callback */
+            movq\t%rsi, %rcx\t/* 2nd argument, which is gcrootanchor */
+            movq\t%rsp, %rax\t/* my frame top address */
+            pushq\t%rax\t\t/* ASM_FRAMEDATA[8] */
+            pushq\t%rbp\t\t/* ASM_FRAMEDATA[7] */
+            pushq\t%r15\t\t/* ASM_FRAMEDATA[6] */
+            pushq\t%r14\t\t/* ASM_FRAMEDATA[5] */
+            pushq\t%r13\t\t/* ASM_FRAMEDATA[4] */
+            pushq\t%r12\t\t/* ASM_FRAMEDATA[3] */
+            pushq\t%rbx\t\t/* ASM_FRAMEDATA[2] */
+
+            /* Add this ASM_FRAMEDATA to the front of the circular linked */
+            /* list.  Let's call it 'self'.                               */
 
+            movq\t8(%rcx), %rax\t/* next = gcrootanchor->next */
+            pushq\t%rax\t\t\t\t/* self->next = next */
+            pushq\t%rcx\t\t\t/* self->prev = gcrootanchor */
+            movq\t%rsp, 8(%rcx)\t/* gcrootanchor->next = self */
+            movq\t%rsp, 0(%rax)\t\t\t/* next->prev = self */
+
+            /* note: the Mac OS X 16 bytes aligment must be respected. */
+            call\t*%rdx\t\t/* invoke the callback */
+
+            /* Detach this ASM_FRAMEDATA from the circular linked list */
+            popq\t%rsi\t\t/* prev = self->prev */
+            popq\t%rdi\t\t/* next = self->next */
+            movq\t%rdi, 8(%rsi)\t/* prev->next = next */
+            movq\t%rsi, 0(%rdi)\t/* next->prev = prev */
+
+            popq\t%rbx\t\t/* restore from ASM_FRAMEDATA[2] */
+            popq\t%r12\t\t/* restore from ASM_FRAMEDATA[3] */
+            popq\t%r13\t\t/* restore from ASM_FRAMEDATA[4] */
+            popq\t%r14\t\t/* restore from ASM_FRAMEDATA[5] */
+            popq\t%r15\t\t/* restore from ASM_FRAMEDATA[6] */
+            popq\t%rbp\t\t/* restore from ASM_FRAMEDATA[7] */
+            popq\t%rcx\t\t/* ignored      ASM_FRAMEDATA[8] */
+
+            /* the return value is the one of the 'call' above, */
+            /* because %rax (and possibly %rdx) are unmodified  */
+            ret
+            .size pypy_asm_stackwalk, .-pypy_asm_stackwalk
+            """
         else:
             print >> output, "\t.text"
             print >> output, "\t.globl %s" % _globalname('pypy_asm_stackwalk')
@@ -1401,7 +1726,7 @@
                     n = shapes[state]
                 except KeyError:
                     n = shapes[state] = shapeofs
-                    bytes = [str(b) for b in compress_callshape(state)]
+                    bytes = [str(b) for b in tracker_cls.compress_callshape(state)]
                     shapelines.append('\t%s,\t/* %s */\n' % (
                             ', '.join(bytes),
                             shapeofs))
@@ -1433,17 +1758,18 @@
                     n = shapes[state]
                 except KeyError:
                     n = shapes[state] = shapeofs
-                    bytes = [str(b) for b in compress_callshape(state)]
+                    bytes = [str(b) for b in tracker_cls.compress_callshape(state)]
                     shapelines.append('\t/*%d*/\t.byte\t%s\n' % (
                         shapeofs,
                         ', '.join(bytes)))
                     shapeofs += len(bytes)
                 if is_range:
                     n = ~ n
-                print >> output, '\t.long\t%s-%d' % (
+                print >> output, '\t%s\t%s-%d' % (
+                    word_decl,
                     label,
-                    PARSERS[self.format].FunctionGcRootTracker.OFFSET_LABELS)
-                print >> output, '\t.long\t%d' % (n,)
+                    tracker_cls.OFFSET_LABELS)
+                print >> output, '\t%s\t%d' % (word_decl, n)
 
             print >> output, """\
             .globl __gcmapend
@@ -1451,6 +1777,7 @@
             """.replace("__gcmapend", _globalname("__gcmapend"))
 
             _variant(elf='.section\t.rodata',
+                     elf64='.section\t.rodata',
                      darwin='.const',
                      mingw32='')
 
@@ -1483,56 +1810,6 @@
     pass
 
 
-# __________ debugging output __________
-
-def format_location(loc):
-    # A 'location' is a single number describing where a value is stored
-    # across a call.  It can be in one of the CALLEE_SAVE_REGISTERS, or
-    # in the stack frame at an address relative to either %esp or %ebp.
-    # The last two bits of the location number are used to tell the cases
-    # apart; see format_location().
-    assert loc >= 0
-    kind = loc & LOC_MASK
-    if kind == LOC_REG:
-        if loc == LOC_NOWHERE:
-            return '?'
-        reg = (loc >> 2) - 1
-        return ElfFunctionGcRootTracker.CALLEE_SAVE_REGISTERS[reg]
-    else:
-        offset = loc & ~ LOC_MASK
-        if kind == LOC_EBP_PLUS:
-            result = '(%ebp)'
-        elif kind == LOC_EBP_MINUS:
-            result = '(%ebp)'
-            offset = -offset
-        elif kind == LOC_ESP_PLUS:
-            result = '(%esp)'
-        else:
-            assert 0, kind
-        if offset != 0:
-            result = str(offset) + result
-        return result
-
-def format_callshape(shape):
-    # A 'call shape' is a tuple of locations in the sense of format_location().
-    # They describe where in a function frame interesting values are stored,
-    # when this function executes a 'call' instruction.
-    #
-    #   shape[0] is the location that stores the fn's own return address
-    #            (not the return address for the currently executing 'call')
-    #   shape[1] is where the fn saved its own caller's %ebx value
-    #   shape[2] is where the fn saved its own caller's %esi value
-    #   shape[3] is where the fn saved its own caller's %edi value
-    #   shape[4] is where the fn saved its own caller's %ebp value
-    #   shape[>=5] are GC roots: where the fn has put its local GCPTR vars
-    #
-    assert isinstance(shape, tuple)
-    assert len(shape) >= 5
-    result = [format_location(loc) for loc in shape]
-    return '{%s | %s | %s}' % (result[0],
-                               ', '.join(result[1:5]),
-                               ', '.join(result[5:]))
-
 # __________ table compression __________
 
 def compress_gcmaptable(table):
@@ -1559,49 +1836,6 @@
         yield (label1, state, is_range)
         i = j
 
-def compress_callshape(shape):
-    # For a single shape, this turns the list of integers into a list of
-    # bytes and reverses the order of the entries.  The length is
-    # encoded by inserting a 0 marker after the gc roots coming from
-    # shape[5:] and before the 5 values coming from shape[4] to
-    # shape[0].  In practice it seems that shapes contain many integers
-    # whose value is up to a few thousands, which the algorithm below
-    # compresses down to 2 bytes.  Very small values compress down to a
-    # single byte.
-    assert len(shape) >= 5
-    shape = list(shape)
-    assert 0 not in shape[5:]
-    shape.insert(5, 0)
-    result = []
-    for loc in shape:
-        assert loc >= 0
-        flag = 0
-        while loc >= 0x80:
-            result.append(int(loc & 0x7F) | flag)
-            flag = 0x80
-            loc >>= 7
-        result.append(int(loc) | flag)
-    result.reverse()
-    return result
-
-def decompress_callshape(bytes):
-    # For tests.  This logic is copied in asmgcroot.py.
-    result = []
-    n = 0
-    while n < len(bytes):
-        value = 0
-        while True:
-            b = bytes[n]
-            n += 1
-            value += b
-            if b < 0x80:
-                break
-            value = (value - 0x80) << 7
-        result.append(value)
-    result.reverse()
-    assert result[5] == 0
-    del result[5]
-    return result
 
 def getidentifier(s):
     def mapchar(c):
@@ -1626,7 +1860,10 @@
     elif sys.platform == 'win32':
         format = 'mingw32'
     else:
-        format = 'elf'
+        if sys.maxint > 2147483647:
+            format = 'elf64'
+        else:
+            format = 'elf'
     entrypoint = 'main'
     while len(sys.argv) > 1:
         if sys.argv[1] == '-v':

Modified: pypy/branch/fast-forward/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/genc.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/genc.py	Thu Sep  9 01:00:13 2010
@@ -1,7 +1,6 @@
 import autopath
 import py
 import sys, os
-from pypy.translator.c.node import PyObjectNode, FuncNode
 from pypy.translator.c.database import LowLevelDatabase
 from pypy.translator.c.extfunc import pre_include_code_lines
 from pypy.translator.llsupport.wrapper import new_wrapper
@@ -196,7 +195,7 @@
 
         all = []
         for node in self.db.globalcontainers():
-            eci = getattr(node, 'compilation_info', None)
+            eci = node.compilation_info()
             if eci:
                 all.append(eci)
         self.merge_eci(*all)
@@ -222,7 +221,7 @@
         graphs = db.all_graphs()
         db.gctransformer.prepare_inline_helpers(graphs)
         for node in db.containerlist:
-            if isinstance(node, FuncNode):
+            if hasattr(node, 'funcgens'):
                 for funcgen in node.funcgens:
                     funcgen.patch_graph(copy_graph=False)
         return db

Modified: pypy/branch/fast-forward/pypy/translator/c/node.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/node.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/node.py	Thu Sep  9 01:00:13 2010
@@ -77,6 +77,8 @@
             if db.gcpolicy.need_no_typeptr():
                 assert self.fieldnames == ('typeptr',)
                 self.fieldnames = ()
+        #
+        self.fulltypename = '%s %s @' % (self.typetag, self.name)
 
     def setup(self):
         # this computes self.fields
@@ -119,7 +121,7 @@
     gcinfo = defaultproperty(computegcinfo)
 
     def gettype(self):
-        return '%s %s @' % (self.typetag, self.name)
+        return self.fulltypename
 
     def c_struct_field_name(self, name):
         # occasionally overridden in __init__():
@@ -211,6 +213,8 @@
          self.name) = db.namespace.uniquename(basename, with_number=with_number,
                                               bare=True)
         self.dependencies = {}
+        self.fulltypename =  '%s %s @' % (self.typetag, self.name)
+        self.fullptrtypename = '%s %s *@' % (self.typetag, self.name)
 
     def setup(self):
         if hasattr(self, 'itemtypename'):
@@ -236,10 +240,10 @@
     gcinfo = defaultproperty(computegcinfo)
 
     def gettype(self):
-        return '%s %s @' % (self.typetag, self.name)
+        return self.fulltypename
 
     def getptrtype(self):
-        return '%s %s *@' % (self.typetag, self.name)
+        return self.fullptrtypename
 
     def access_expr(self, baseexpr, index):
         return '%s.items[%s]' % (baseexpr, index)
@@ -336,16 +340,19 @@
         if ARRAY._hints.get("render_as_void"):
             contained_type = Void
         self.itemtypename = db.gettype(contained_type, who_asks=self)
+        self.fulltypename = self.itemtypename.replace('@', '(@)[%d]' %
+                                                      (self.varlength,))
+        self.fullptrtypename = self.itemtypename.replace('@', '*@')
 
     def setup(self):
         """Array loops are forbidden by ForwardReference.become() because
         there is no way to declare them in C."""
 
     def gettype(self):
-        return self.itemtypename.replace('@', '(@)[%d]' % (self.varlength,))
+        return self.fulltypename
 
     def getptrtype(self):
-        return self.itemtypename.replace('@', '*@')
+        return self.fullptrtypename
 
     def access_expr(self, baseexpr, index):
         return '%s[%d]' % (baseexpr, index)
@@ -383,17 +390,19 @@
         self.LLTYPE = FIXEDARRAY
         self.dependencies = {}
         self.itemtypename = db.gettype(FIXEDARRAY.OF, who_asks=self)
+        self.fulltypename = self.itemtypename.replace('@', '(@)[%d]' %
+                                                      FIXEDARRAY.length)
+        self.fullptrtypename = self.itemtypename.replace('@', '*@')
 
     def setup(self):
         """Loops are forbidden by ForwardReference.become() because
         there is no way to declare them in C."""
 
     def gettype(self):
-        FIXEDARRAY = self.FIXEDARRAY
-        return self.itemtypename.replace('@', '(@)[%d]' % FIXEDARRAY.length)
+        return self.fulltypename
 
     def getptrtype(self):
-        return self.itemtypename.replace('@', '*@')
+        return self.fullptrtypename
 
     def access_expr(self, baseexpr, index, dummy=False):
         if not isinstance(index, int):
@@ -466,15 +475,15 @@
 
 
 class ContainerNode(object):
-    if USESLOTS:
-        __slots__ = """db T obj 
+    if USESLOTS:      # keep the number of slots down!
+        __slots__ = """db obj 
                        typename implementationtypename
-                        name ptrname compilation_info
+                        name
                         globalcontainer""".split()
+    eci_name = '_compilation_info'
 
     def __init__(self, db, T, obj):
         self.db = db
-        self.T = T
         self.obj = obj
         #self.dependencies = {}
         self.typename = db.gettype(T)  #, who_asks=self)
@@ -489,16 +498,24 @@
         else:
             self.globalcontainer = False
             parentnode = db.getcontainernode(parent)
-            defnode = db.gettypedefnode(parentnode.T)
+            defnode = db.gettypedefnode(parentnode.getTYPE())
             self.name = defnode.access_expr(parentnode.name, parentindex)
         if self.typename != self.implementationtypename:
             if db.gettypedefnode(T).extra_union_for_varlength:
                 self.name += '.b'
-        self.compilation_info = getattr(obj, '_compilation_info', None)
-        self.ptrname = '(&%s)' % self.name
+
+    def getptrname(self):
+        return '(&%s)' % self.name
+
+    def getTYPE(self):
+        return typeOf(self.obj)
 
     def is_thread_local(self):
-        return hasattr(self.T, "_hints") and self.T._hints.get('thread_local')
+        T = self.getTYPE()
+        return hasattr(T, "_hints") and T._hints.get('thread_local')
+
+    def compilation_info(self):
+        return getattr(self.obj, self.eci_name, None)
 
     def get_declaration(self):
         if self.name[-2:] == '.b':
@@ -546,27 +563,31 @@
         __slots__ = ()
 
     def basename(self):
-        return self.T._name
+        T = self.getTYPE()
+        return T._name
 
     def enum_dependencies(self):
-        for name in self.T._names:
+        T = self.getTYPE()
+        for name in T._names:
             yield getattr(self.obj, name)
 
     def getlength(self):
-        if self.T._arrayfld is None:
+        T = self.getTYPE()
+        if T._arrayfld is None:
             return 1
         else:
-            array = getattr(self.obj, self.T._arrayfld)
+            array = getattr(self.obj, T._arrayfld)
             return len(array.items)
 
     def initializationexpr(self, decoration=''):
+        T = self.getTYPE()
         is_empty = True
         yield '{'
-        defnode = self.db.gettypedefnode(self.T)
+        defnode = self.db.gettypedefnode(T)
 
         data = []
 
-        if needs_gcheader(self.T):
+        if needs_gcheader(T):
             gc_init = self.db.gcpolicy.struct_gcheader_initdata(self)
             data.append(('gcheader', gc_init))
 
@@ -578,16 +599,16 @@
         # '.fieldname = value'.  But here we don't know which of the
         # fields need initialization, so XXX we pick the first one
         # arbitrarily.
-        if hasattr(self.T, "_hints") and self.T._hints.get('union'):
+        if hasattr(T, "_hints") and T._hints.get('union'):
             data = data[0:1]
 
-        if 'get_padding_drop' in self.T._hints:
+        if 'get_padding_drop' in T._hints:
             d = {}
             for name, _ in data:
-                T = defnode.c_struct_field_type(name)
-                typename = self.db.gettype(T)
+                T1 = defnode.c_struct_field_type(name)
+                typename = self.db.gettype(T1)
                 d[name] = cdecl(typename, '')
-            padding_drop = self.T._hints['get_padding_drop'](d)
+            padding_drop = T._hints['get_padding_drop'](d)
         else:
             padding_drop = []
 
@@ -617,9 +638,10 @@
         return 'struct _hashT_%s @' % self.name
 
     def forward_declaration(self):
+        T = self.getTYPE()
         assert self.typename == self.implementationtypename  # no array part
         hash_typename = self.get_hash_typename()
-        hash_offset = self.db.gctransformer.get_hash_offset(self.T)
+        hash_offset = self.db.gctransformer.get_hash_offset(T)
         yield '%s {' % cdecl(hash_typename, '')
         yield '\tunion {'
         yield '\t\t%s;' % cdecl(self.implementationtypename, 'head')
@@ -656,10 +678,10 @@
     if USESLOTS:
         __slots__ = ()
 
-    def __init__(self, db, T, obj):
-        ContainerNode.__init__(self, db, T, obj)
-        if barebonearray(T):
-            self.ptrname = self.name
+    def getptrname(self):
+        if barebonearray(self.getTYPE()):
+            return self.name
+        return ContainerNode.getptrname(self)
 
     def basename(self):
         return 'array'
@@ -671,22 +693,23 @@
         return len(self.obj.items)
 
     def initializationexpr(self, decoration=''):
-        defnode = self.db.gettypedefnode(self.T)
+        T = self.getTYPE()
+        defnode = self.db.gettypedefnode(T)
         yield '{'
-        if needs_gcheader(self.T):
+        if needs_gcheader(T):
             gc_init = self.db.gcpolicy.array_gcheader_initdata(self)
             lines = generic_initializationexpr(self.db, gc_init, 'gcheader',
                                                '%sgcheader' % (decoration,))
             for line in lines:
                 yield line
-        if self.T._hints.get('nolength', False):
+        if T._hints.get('nolength', False):
             length = ''
         else:
             length = '%d, ' % len(self.obj.items)
-        if self.T.OF is Void or len(self.obj.items) == 0:
+        if T.OF is Void or len(self.obj.items) == 0:
             yield '\t%s' % length.rstrip(', ')
             yield '}'
-        elif self.T.OF == Char:
+        elif T.OF == Char:
             if len(self.obj.items) and self.obj.items[0] is None:
                 s = ''.join([self.obj.getitem(i) for i in range(len(self.obj.items))])
             else:
@@ -694,7 +717,7 @@
             yield '\t%s%s' % (length, c_char_array_constant(s))
             yield '}'
         else:
-            barebone = barebonearray(self.T)
+            barebone = barebonearray(T)
             if not barebone:
                 yield '\t%s{' % length
             for j in range(len(self.obj.items)):
@@ -716,13 +739,14 @@
     if USESLOTS:
         __slots__ = ()
 
-    def __init__(self, db, T, obj):
-        ContainerNode.__init__(self, db, T, obj)
-        if not isinstance(obj, _subarray):   # XXX hackish
-            self.ptrname = self.name
+    def getptrname(self):
+        if not isinstance(self.obj, _subarray):   # XXX hackish
+            return self.name
+        return ContainerNode.getptrname(self)
 
     def basename(self):
-        return self.T._name
+        T = self.getTYPE()
+        return T._name
 
     def enum_dependencies(self):
         for i in range(self.obj.getlength()):
@@ -732,11 +756,12 @@
         return 1    # not variable-sized!
 
     def initializationexpr(self, decoration=''):
+        T = self.getTYPE()
         assert self.typename == self.implementationtypename  # not var-sized
         is_empty = True
         yield '{'
         # _names == ['item0', 'item1', ...]
-        for j, name in enumerate(self.T._names):
+        for j, name in enumerate(T._names):
             value = getattr(self.obj, name)
             lines = generic_initializationexpr(self.db, value,
                                                '%s[%d]' % (self.name, j),
@@ -777,6 +802,7 @@
 
 class FuncNode(ContainerNode):
     nodekind = 'func'
+    eci_name = 'compilation_info'
     # there not so many node of this kind, slots should not
     # be necessary
 
@@ -794,11 +820,12 @@
         else:
             self.name = (forcename or
                          db.namespace.uniquename('g_' + self.basename()))
-        self.compilation_info = getattr(obj, 'compilation_info', None)
         self.make_funcgens()
         #self.dependencies = {}
         self.typename = db.gettype(T)  #, who_asks=self)
-        self.ptrname = self.name
+
+    def getptrname(self):
+        return self.name
 
     def make_funcgens(self):
         self.funcgens = select_function_code_generators(self.obj, self.db, self.name)
@@ -939,18 +966,20 @@
         return []
 
     def initializationexpr(self, decoration=''):
-        yield 'RPyOpaque_INITEXPR_%s' % (self.T.tag,)
+        T = self.getTYPE()
+        yield 'RPyOpaque_INITEXPR_%s' % (T.tag,)
 
     def startupcode(self):
-        args = [self.ptrname]
+        T = self.getTYPE()
+        args = [self.getptrname()]
         # XXX how to make this code more generic?
-        if self.T.tag == 'ThreadLock':
+        if T.tag == 'ThreadLock':
             lock = self.obj.externalobj
             if lock.locked():
                 args.append('1')
             else:
                 args.append('0')
-        yield 'RPyOpaque_SETUP_%s(%s);' % (self.T.tag, ', '.join(args))
+        yield 'RPyOpaque_SETUP_%s(%s);' % (T.tag, ', '.join(args))
 
 
 def opaquenode_factory(db, T, obj):
@@ -974,13 +1003,15 @@
         self.obj = obj
         value = obj.value
         self.name = self._python_c_name(value)
-        self.ptrname = self.name
         self.exported_name = self.name
         # a list of expressions giving places where this constant PyObject
         # must be copied.  Normally just in the global variable of the same
         # name, but see also StructNode.initializationexpr()  :-(
         self.where_to_copy_me = []
 
+    def getptrname(self):
+        return self.name
+
     def _python_c_name(self, value):
         # just some minimal cases: None and builtin exceptions
         if value is None:

Modified: pypy/branch/fast-forward/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/test/test_newgc.py	Thu Sep  9 01:00:13 2010
@@ -67,9 +67,8 @@
             if not fullname.startswith('define'):
                 continue
             keyword = conftest.option.keyword
-            if keyword:
-                if keyword.startswith('test_'):
-                    keyword = keyword[len('test_'):]
+            if keyword.startswith('test_'):
+                keyword = keyword[len('test_'):]
                 if keyword not in fullname:
                     continue
             prefix, name = fullname.split('_', 1)
@@ -1072,21 +1071,66 @@
     should_be_moving = True
     GC_CAN_SHRINK_ARRAY = False
 
-    def setup_class(cls):
-        py.test.skip("Disabled for now")
-
     def test_gc_set_max_heap_size(self):
         py.test.skip("not implemented")
 
+    def test_gc_heap_stats(self):
+        py.test.skip("not implemented")
+
     def test_finalizer_order(self):
         py.test.skip("not implemented")
 
+    def define_adding_a_hash(cls):
+        from pypy.rlib.objectmodel import compute_identity_hash
+        S1 = lltype.GcStruct('S1', ('x', lltype.Signed))
+        S2 = lltype.GcStruct('S2', ('p1', lltype.Ptr(S1)),
+                                   ('p2', lltype.Ptr(S1)),
+                                   ('p3', lltype.Ptr(S1)),
+                                   ('p4', lltype.Ptr(S1)),
+                                   ('p5', lltype.Ptr(S1)),
+                                   ('p6', lltype.Ptr(S1)),
+                                   ('p7', lltype.Ptr(S1)),
+                                   ('p8', lltype.Ptr(S1)),
+                                   ('p9', lltype.Ptr(S1)))
+        def g():
+            lltype.malloc(S1)   # forgotten, will be shifted over
+            s2 = lltype.malloc(S2)   # a big object, overlaps its old position
+            s2.p1 = lltype.malloc(S1); s2.p1.x = 1010
+            s2.p2 = lltype.malloc(S1); s2.p2.x = 1020
+            s2.p3 = lltype.malloc(S1); s2.p3.x = 1030
+            s2.p4 = lltype.malloc(S1); s2.p4.x = 1040
+            s2.p5 = lltype.malloc(S1); s2.p5.x = 1050
+            s2.p6 = lltype.malloc(S1); s2.p6.x = 1060
+            s2.p7 = lltype.malloc(S1); s2.p7.x = 1070
+            s2.p8 = lltype.malloc(S1); s2.p8.x = 1080
+            s2.p9 = lltype.malloc(S1); s2.p9.x = 1090
+            return s2
+        def f():
+            rgc.collect()
+            s2 = g()
+            h2 = compute_identity_hash(s2)
+            rgc.collect()    # shift s2 to the left, but add a hash field
+            assert s2.p1.x == 1010
+            assert s2.p2.x == 1020
+            assert s2.p3.x == 1030
+            assert s2.p4.x == 1040
+            assert s2.p5.x == 1050
+            assert s2.p6.x == 1060
+            assert s2.p7.x == 1070
+            assert s2.p8.x == 1080
+            assert s2.p9.x == 1090
+            return h2 - compute_identity_hash(s2)
+        return f
+
+    def test_adding_a_hash(self):
+        res = self.run("adding_a_hash")
+        assert res == 0
+
 # ____________________________________________________________________
 
-class TestHybridTaggedPointers(TestHybridGC):
+class TaggedPointersTest(object):
     taggedpointers = True
 
-
     def define_tagged(cls):
         class Unrelated(object):
             pass
@@ -1129,3 +1173,10 @@
     __slots__ = 'smallint'
     def meth(self, x):
         return self.smallint + x + 3
+
+
+class TestHybridTaggedPointers(TaggedPointersTest, TestHybridGC):
+    pass
+
+class TestMarkCompactGCMostCompact(TaggedPointersTest, TestMarkCompactGC):
+    removetypeptr = True

Modified: pypy/branch/fast-forward/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/c/test/test_standalone.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/c/test/test_standalone.py	Thu Sep  9 01:00:13 2010
@@ -604,6 +604,33 @@
         out, err = cbuilder.cmdexec("a b")
         assert out == "3"
 
+    def test_gcc_options(self):
+        # check that the env var CC is correctly interpreted, even if
+        # it contains the compiler name followed by some options.
+        if sys.platform == 'win32':
+            py.test.skip("only for gcc")
+
+        from pypy.rpython.lltypesystem import lltype, rffi
+        dir = udir.ensure('test_gcc_options', dir=1)
+        dir.join('someextraheader.h').write('#define someextrafunc() 42\n')
+        eci = ExternalCompilationInfo(includes=['someextraheader.h'])
+        someextrafunc = rffi.llexternal('someextrafunc', [], lltype.Signed,
+                                        compilation_info=eci)
+
+        def entry_point(argv):
+            return someextrafunc()
+
+        old_cc = os.environ.get('CC')
+        try:
+            os.environ['CC'] = 'gcc -I%s' % dir
+            t, cbuilder = self.compile(entry_point)
+        finally:
+            if old_cc is None:
+                del os.environ['CC']
+            else:
+                os.environ['CC'] = old_cc
+
+
 class TestMaemo(TestStandalone):
     def setup_class(cls):
         py.test.skip("TestMaemo: tests skipped for now")

Modified: pypy/branch/fast-forward/pypy/translator/exceptiontransform.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/exceptiontransform.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/exceptiontransform.py	Thu Sep  9 01:00:13 2010
@@ -197,7 +197,7 @@
         for graph in self.translator.graphs:
             self.create_exception_handling(graph)
 
-    def create_exception_handling(self, graph, always_exc_clear=False):
+    def create_exception_handling(self, graph):
         """After an exception in a direct_call (or indirect_call), that is not caught
         by an explicit
         except statement, we need to reraise the exception. So after this
@@ -212,7 +212,6 @@
             self.raise_analyzer.analyze_direct_call(graph)
             graph.exceptiontransformed = self.exc_data_ptr
 
-        self.always_exc_clear = always_exc_clear
         join_blocks(graph)
         # collect the blocks before changing them
         n_need_exc_matching_blocks = 0
@@ -455,13 +454,18 @@
         block.recloseblock(l0, l)
 
         insert_zeroing_op = False
-        # XXX this is not right. it also inserts zero_gc_pointers_inside
-        # XXX on a path that malloc_nonmovable returns null, but does not raise
-        # XXX which might end up with a segfault. But we don't have such gc now
-        if spaceop.opname == 'malloc' or spaceop.opname == 'malloc_nonmovable':
+        if spaceop.opname == 'malloc':
             flavor = spaceop.args[1].value['flavor']
             if flavor == 'gc':
                 insert_zeroing_op = True
+        elif spaceop.opname == 'malloc_nonmovable':
+            # xxx we cannot insert zero_gc_pointers_inside after
+            # malloc_nonmovable, because it can return null.  For now
+            # we simply always force the zero=True flag on
+            # malloc_nonmovable.
+            c_flags = spaceop.args[1]
+            c_flags.value = c_flags.value.copy()
+            spaceop.args[1].value['zero'] = True
 
         if insert_zeroing_op:
             if normalafterblock is None:
@@ -479,16 +483,6 @@
                                   [v_result_after],
                                   varoftype(lltype.Void)))
 
-        if self.always_exc_clear:
-            # insert code that clears the exception even in the non-exceptional
-            # case...  this is a hint for the JIT, but pointless otherwise
-            if normalafterblock is None:
-                normalafterblock = insert_empty_block(None, l0)
-            llops = rtyper.LowLevelOpList(None)
-            self.gen_setfield('exc_value', self.c_null_evalue, llops)
-            self.gen_setfield('exc_type',  self.c_null_etype,  llops)
-            normalafterblock.operations[:0] = llops
-
 
 class LLTypeExceptionTransformer(BaseExceptionTransformer):
 

Modified: pypy/branch/fast-forward/pypy/translator/goal/app_main.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/goal/app_main.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/goal/app_main.py	Thu Sep  9 01:00:13 2010
@@ -223,7 +223,6 @@
     path = os.getenv('PYTHONPATH')
     if path:
         newpath = path.split(os.pathsep) + newpath
-    newpath.insert(0, '')
     # remove duplicates
     _seen = {}
     del sys.path[:]
@@ -349,8 +348,8 @@
         else:
             raise CommandLineError('unrecognized option %r' % (arg,))
         i += 1
-    sys.argv = argv[i:]
-    if not sys.argv:
+    sys.argv[:] = argv[i:]    # don't change the list that sys.argv is bound to
+    if not sys.argv:          # (relevant in case of "reload(sys)")
         sys.argv.append('')
         options["run_stdin"] = True
     if print_sys_flags:
@@ -393,6 +392,10 @@
         except:
             print >> sys.stderr, "'import site' failed"
 
+    # update sys.path *after* loading site.py, in case there is a
+    # "site.py" file in the script's directory.
+    sys.path.insert(0, '')
+
     if warnoptions:
         sys.warnoptions.append(warnoptions)
         from warnings import _processoptions
@@ -541,6 +544,10 @@
         reset.append(('PYTHONINSPECT', os.environ.get('PYTHONINSPECT', '')))
         os.environ['PYTHONINSPECT'] = os.environ['PYTHONINSPECT_']
 
+    # no one should change to which lists sys.argv and sys.path are bound
+    old_argv = sys.argv
+    old_path = sys.path
+
     from pypy.module.sys.version import PYPY_VERSION
     sys.pypy_version_info = PYPY_VERSION
     sys.pypy_initial_path = pypy_initial_path
@@ -553,3 +560,5 @@
         sys.ps1 = '>>> '     # restore the normal ones, in case
         sys.ps2 = '... '     # we are dropping to CPython's prompt
         import os; os.environ.update(reset)
+        assert old_argv is sys.argv
+        assert old_path is sys.path

Modified: pypy/branch/fast-forward/pypy/translator/goal/test2/test_app_main.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/goal/test2/test_app_main.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/goal/test2/test_app_main.py	Thu Sep  9 01:00:13 2010
@@ -1,10 +1,12 @@
 """
 Tests for the entry point of pypy-c, app_main.py.
 """
+from __future__ import with_statement
 import py
 import sys, os, re
 import autopath
 from pypy.tool.udir import udir
+from contextlib import contextmanager
 
 banner = sys.version.splitlines()[0]
 
@@ -326,8 +328,9 @@
 class TestNonInteractive:
 
     def run(self, cmdline, senddata='', expect_prompt=False,
-            expect_banner=False):
-        cmdline = '%s "%s" %s' % (sys.executable, app_main, cmdline)
+            expect_banner=False, python_flags=''):
+        cmdline = '%s %s "%s" %s' % (sys.executable, python_flags,
+                                     app_main, cmdline)
         print 'POPEN:', cmdline
         child_in, child_out_err = os.popen4(cmdline)
         child_in.write(senddata)
@@ -475,6 +478,43 @@
         assert data == '\x00(STDOUT)\n\x00'    # from stdout
         child_out_err.close()
 
+    def test_proper_sys_path(self, tmpdir):
+
+        @contextmanager
+        def chdir_and_unset_pythonpath(new_cwd):
+            old_cwd = new_cwd.chdir()
+            old_pythonpath = os.getenv('PYTHONPATH')
+            os.unsetenv('PYTHONPATH')
+            try:
+                yield
+            finally:
+                old_cwd.chdir()
+                os.putenv('PYTHONPATH', old_pythonpath)
+        
+        tmpdir.join('site.py').write('print "SHOULD NOT RUN"')
+        runme_py = tmpdir.join('runme.py')
+        runme_py.write('print "some text"')
+
+        cmdline = str(runme_py)
+
+        with chdir_and_unset_pythonpath(tmpdir):
+            data = self.run(cmdline, python_flags='-S')
+
+        assert data == "some text\n"
+
+        runme2_py = tmpdir.mkdir('otherpath').join('runme2.py')
+        runme2_py.write('print "some new text"\n'
+                        'import sys\n'
+                        'print sys.path\n')
+
+        cmdline2 = str(runme2_py)
+
+        with chdir_and_unset_pythonpath(tmpdir):
+            data = self.run(cmdline2, python_flags='-S')
+
+        assert data.startswith("some new text\n")
+        assert repr(str(tmpdir.join('otherpath'))) in data
+
 
 class AppTestAppMain:
 

Modified: pypy/branch/fast-forward/pypy/translator/goal/translate.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/goal/translate.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/goal/translate.py	Thu Sep  9 01:00:13 2010
@@ -18,7 +18,7 @@
                                ArbitraryOption, StrOption, IntOption, Config, \
                                ChoiceOption, OptHelpFormatter
 from pypy.config.translationoption import get_combined_translation_config
-from pypy.config.translationoption import set_opt_level
+from pypy.config.translationoption import set_opt_level, final_check_config
 from pypy.config.translationoption import OPT_LEVELS, DEFAULT_OPT_LEVEL
 from pypy.config.translationoption import PLATFORMS, set_platform
 
@@ -175,6 +175,9 @@
     if 'handle_config' in targetspec_dic:
         targetspec_dic['handle_config'](config, translateconfig)
 
+    # perform checks (if any) on the final config
+    final_check_config(config)
+
     if translateconfig.help:
         opt_parser.print_help()
         if 'print_help' in targetspec_dic:

Modified: pypy/branch/fast-forward/pypy/translator/platform/__init__.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/platform/__init__.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/platform/__init__.py	Thu Sep  9 01:00:13 2010
@@ -38,9 +38,9 @@
     name = "abstract platform"
     c_environ = None
 
-    relevant_environ = []
+    relevant_environ = ()
 
-    so_prefixes = ['']
+    so_prefixes = ('',)
 
     def __init__(self, cc):
         if self.__class__ is Platform:
@@ -99,15 +99,20 @@
                 self.__dict__ == other.__dict__)
 
     def key(self):
-        bits = [self.__class__.__name__, 'cc=%s' % self.cc]
+        bits = [self.__class__.__name__, 'cc=%r' % self.cc]
         for varname in self.relevant_environ:
-            bits.append('%s=%s' % (varname, os.environ.get(varname)))
+            bits.append('%s=%r' % (varname, os.environ.get(varname)))
         return ' '.join(bits)
 
     # some helpers which seem to be cross-platform enough
 
     def _execute_c_compiler(self, cc, args, outname, cwd=None):
         log.execute(cc + ' ' + ' '.join(args))
+        # 'cc' can also contain some options for the C compiler;
+        # e.g. it can be "gcc -m32".  We handle it by splitting on ' '.
+        cclist = cc.split()
+        cc = cclist[0]
+        args = cclist[1:] + args
         returncode, stdout, stderr = _run_subprocess(cc, args, self.c_environ,
                                                      cwd)
         self._handle_error(returncode, stderr, stdout, outname)
@@ -146,7 +151,7 @@
             extra = self.standalone_only
         else:
             extra = self.shared_only
-        cflags = self.cflags + extra
+        cflags = list(self.cflags) + list(extra)
         return (cflags + list(eci.compile_extra) + args)
     
     def _preprocess_library_dirs(self, library_dirs):
@@ -158,10 +163,10 @@
         libraries = self._libs(eci.libraries)
         link_files = self._linkfiles(eci.link_files)
         export_flags = self._exportsymbols_link_flags(eci)
-        return (library_dirs + self.link_flags + export_flags +
+        return (library_dirs + list(self.link_flags) + export_flags +
                 link_files + list(eci.link_extra) + libraries)
 
-    def _exportsymbols_link_flags(self, eci):
+    def _exportsymbols_link_flags(self, eci, relto=None):
         if eci.export_symbols:
             raise ValueError("This platform does not support export symbols")
         return []

Modified: pypy/branch/fast-forward/pypy/translator/platform/darwin.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/platform/darwin.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/platform/darwin.py	Thu Sep  9 01:00:13 2010
@@ -5,10 +5,10 @@
 class Darwin(posix.BasePosix):
     name = "darwin"
 
-    link_flags = ['-mmacosx-version-min=10.4']
-    cflags = ['-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
-    standalone_only = ['-mdynamic-no-pic']
-    shared_only = []
+    link_flags = ('-mmacosx-version-min=10.4',)
+    cflags = ('-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4')
+    standalone_only = ('-mdynamic-no-pic',)
+    shared_only = ()
 
     so_ext = 'so'
     
@@ -18,8 +18,9 @@
         self.cc = cc
 
     def _args_for_shared(self, args):
-        return (self.shared_only + ['-dynamiclib', '-undefined', 'dynamic_lookup']
-                                 + args)
+        return (list(self.shared_only)
+                + ['-dynamiclib', '-undefined', 'dynamic_lookup']
+                + args)
     
     def _preprocess_include_dirs(self, include_dirs):
         res_incl_dirs = list(include_dirs)
@@ -56,7 +57,7 @@
         include_dirs = self._includedirs(eci.include_dirs)
         return (args + frameworks + include_dirs)
 
-    def _exportsymbols_link_flags(self, eci):
+    def _exportsymbols_link_flags(self, eci, relto=None):
         if not eci.export_symbols:
             return []
 
@@ -65,15 +66,19 @@
         for sym in eci.export_symbols:
             f.write("_%s\n" % (sym,))
         f.close()
+
+        if relto:
+            response_file = relto.bestrelpath(response_file)
         return ["-Wl,-exported_symbols_list,%s" % (response_file,)]
 
 class Darwin_i386(Darwin):
     name = "darwin_i386"
-    link_flags = ['-arch', 'i386', '-mmacosx-version-min=10.4']
-    cflags = ['-arch', 'i386', '-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
+    link_flags = ('-arch', 'i386', '-mmacosx-version-min=10.4')
+    cflags = ('-arch', 'i386', '-O3', '-fomit-frame-pointer',
+              '-mmacosx-version-min=10.4')
 
 class Darwin_x86_64(Darwin):
     name = "darwin_x86_64"
-    link_flags = ['-arch', 'x86_64', '-mmacosx-version-min=10.4']
-    cflags = ['-arch', 'x86_64', '-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
-
+    link_flags = ('-arch', 'x86_64', '-mmacosx-version-min=10.4')
+    cflags = ('-arch', 'x86_64', '-O3', '-fomit-frame-pointer',
+              '-mmacosx-version-min=10.4')

Modified: pypy/branch/fast-forward/pypy/translator/platform/freebsd7.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/platform/freebsd7.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/platform/freebsd7.py	Thu Sep  9 01:00:13 2010
@@ -5,10 +5,10 @@
 class Freebsd7(posix.BasePosix):
     name = "freebsd7"
     
-    link_flags = ['-pthread']
-    cflags = ['-O3', '-pthread', '-fomit-frame-pointer']
-    standalone_only = []
-    shared_only = []
+    link_flags = ('-pthread',)
+    cflags = ('-O3', '-pthread', '-fomit-frame-pointer')
+    standalone_only = ()
+    shared_only = ()
     so_ext = 'so'
     make_cmd = 'gmake'
     
@@ -32,4 +32,4 @@
         return ['/usr/local/lib']
 
 class Freebsd7_64(Freebsd7):
-    shared_only = ['-fPIC']
+    shared_only = ('-fPIC',)

Modified: pypy/branch/fast-forward/pypy/translator/platform/linux.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/platform/linux.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/platform/linux.py	Thu Sep  9 01:00:13 2010
@@ -3,15 +3,16 @@
 from pypy.translator.platform import _run_subprocess
 from pypy.translator.platform.posix import BasePosix
 
-class Linux(BasePosix):
+class BaseLinux(BasePosix):
     name = "linux"
     
-    link_flags = ['-pthread', '-lrt']
-    cflags = ['-O3', '-pthread', '-fomit-frame-pointer', '-Wall', '-Wno-unused']
-    standalone_only = []
-    shared_only = ['-fPIC']
+    link_flags = ('-pthread', '-lrt')
+    cflags = ('-O3', '-pthread', '-fomit-frame-pointer',
+              '-Wall', '-Wno-unused')
+    standalone_only = ()
+    shared_only = ('-fPIC',)
     so_ext = 'so'
-    so_prefixes = ['lib', '']
+    so_prefixes = ('lib', '')
     
     def _args_for_shared(self, args):
         return ['-shared'] + args
@@ -24,10 +25,12 @@
         return self._pkg_config("libffi", "--libs-only-L",
                                 ['/usr/lib/libffi'])
 
+
+class Linux(BaseLinux):
     def library_dirs_for_libffi_a(self):
         # places where we need to look for libffi.a
         return self.library_dirs_for_libffi() + ['/usr/lib']
 
 
-class Linux64(Linux):
-    shared_only = ['-fPIC']
+class Linux64(BaseLinux):
+    pass

Modified: pypy/branch/fast-forward/pypy/translator/platform/maemo.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/platform/maemo.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/platform/maemo.py	Thu Sep  9 01:00:13 2010
@@ -13,7 +13,7 @@
 class Maemo(Linux):
     name = "maemo"
     
-    available_includedirs = ['/usr/include', '/tmp']
+    available_includedirs = ('/usr/include', '/tmp')
     copied_cache = {}
 
     def _invent_new_name(self, basepath, base):

Modified: pypy/branch/fast-forward/pypy/translator/platform/posix.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/platform/posix.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/platform/posix.py	Thu Sep  9 01:00:13 2010
@@ -4,17 +4,20 @@
 
 from pypy.translator.platform import Platform, log, _run_subprocess
 from pypy.tool import autopath
-import py, os
+import py, os, sys
 
 class BasePosix(Platform):
     exe_ext = ''
     make_cmd = 'make'
 
-    relevant_environ=['CPATH', 'LIBRARY_PATH', 'C_INCLUDE_PATH']
+    relevant_environ = ('CPATH', 'LIBRARY_PATH', 'C_INCLUDE_PATH')
 
     def __init__(self, cc=None):
         if cc is None:
-            cc = 'gcc'
+            try:
+                cc = os.environ['CC']
+            except KeyError:
+                cc = 'gcc'
         self.cc = cc
 
     def _libs(self, libraries):
@@ -39,7 +42,7 @@
     def _link_args_from_eci(self, eci, standalone):
         return Platform._link_args_from_eci(self, eci, standalone)
 
-    def _exportsymbols_link_flags(self, eci):
+    def _exportsymbols_link_flags(self, eci, relto=None):
         if not eci.export_symbols:
             return []
 
@@ -50,6 +53,9 @@
             f.write("%s;\n" % (sym,))
         f.write("};")
         f.close()
+
+        if relto:
+            response_file = relto.bestrelpath(response_file)
         return ["-Wl,--export-dynamic,--version-script=%s" % (response_file,)]
 
     def _link(self, cc, ofiles, link_args, standalone, exe_name):
@@ -86,11 +92,11 @@
         else:
             exe_name = exe_name.new(ext=self.exe_ext)
 
-        linkflags = self.link_flags[:]
+        linkflags = list(self.link_flags)
         if shared:
             linkflags = self._args_for_shared(linkflags)
 
-        linkflags += self._exportsymbols_link_flags(eci)
+        linkflags += self._exportsymbols_link_flags(eci, relto=path)
 
         if shared:
             libname = exe_name.new(ext='').basename
@@ -98,6 +104,13 @@
         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
+
         m = GnuMakefile(path)
         m.exe_name = exe_name
         m.eci = eci
@@ -126,7 +139,7 @@
             ('LIBS', self._libs(eci.libraries)),
             ('LIBDIRS', self._libdirs(eci.library_dirs)),
             ('INCLUDEDIRS', self._includedirs(rel_includedirs)),
-            ('CFLAGS', self.cflags),
+            ('CFLAGS', cflags),
             ('CFLAGSEXTRA', list(eci.compile_extra)),
             ('LDFLAGS', linkflags),
             ('LDFLAGSEXTRA', list(eci.link_extra)),

Modified: pypy/branch/fast-forward/pypy/translator/platform/test/test_platform.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/platform/test/test_platform.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/platform/test/test_platform.py	Thu Sep  9 01:00:13 2010
@@ -131,7 +131,7 @@
                 self.cc = 'xcc'
         x = XPlatform()
         res = x.key()
-        assert res.startswith('XPlatform cc=xcc CPATH=')
+        assert res.startswith("XPlatform cc='xcc' CPATH=")
 
 def test_equality():
     class X(Platform):

Modified: pypy/branch/fast-forward/pypy/translator/platform/windows.py
==============================================================================
--- pypy/branch/fast-forward/pypy/translator/platform/windows.py	(original)
+++ pypy/branch/fast-forward/pypy/translator/platform/windows.py	Thu Sep  9 01:00:13 2010
@@ -72,10 +72,10 @@
     cc = 'cl.exe'
     link = 'link.exe'
 
-    cflags = ['/MD', '/O2']
-    link_flags = []
-    standalone_only = []
-    shared_only = []
+    cflags = ('/MD', '/O2')
+    link_flags = ()
+    standalone_only = ()
+    shared_only = ()
     environ = None
 
     def __init__(self, cc=None):
@@ -141,7 +141,7 @@
         # Windows needs to resolve all symbols even for DLLs
         return super(MsvcPlatform, self)._link_args_from_eci(eci, standalone=True)
 
-    def _exportsymbols_link_flags(self, eci):
+    def _exportsymbols_link_flags(self, eci, relto=None):
         if not eci.export_symbols:
             return []
 
@@ -150,6 +150,9 @@
         for sym in eci.export_symbols:
             f.write("/EXPORT:%s\n" % (sym,))
         f.close()
+
+        if relto:
+            response_file = relto.bestrelpath(response_file)
         return ["@%s" % (response_file,)]
 
     def _compile_c_file(self, cc, cfile, compile_args):
@@ -215,11 +218,11 @@
         m.exe_name = exe_name
         m.eci = eci
 
-        linkflags = self.link_flags[:]
+        linkflags = list(self.link_flags)
         if shared:
             linkflags = self._args_for_shared(linkflags) + [
                 '/EXPORT:$(PYPY_MAIN_FUNCTION)']
-        linkflags += self._exportsymbols_link_flags(eci)
+        linkflags += self._exportsymbols_link_flags(eci, relto=path)
 
         if shared:
             so_name = exe_name.new(purebasename='lib' + exe_name.purebasename,
@@ -333,10 +336,10 @@
 
 class MingwPlatform(posix.BasePosix):
     name = 'mingw32'
-    standalone_only = []
-    shared_only = []
-    cflags = ['-O3']
-    link_flags = []
+    standalone_only = ()
+    shared_only = ()
+    cflags = ('-O3',)
+    link_flags = ()
     exe_ext = 'exe'
     so_ext = 'dll'
 



More information about the Pypy-commit mailing list