Author: Matti Picus <[email protected]>
Branch: py3.6
Changeset: r98274:d7d279c89e1c
Date: 2019-12-12 13:40 +0200
http://bitbucket.org/pypy/pypy/changeset/d7d279c89e1c/

Log:    merge default into py3.6

diff too long, truncating to 2000 out of 12653 lines

diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -57,3 +57,5 @@
 4a68d8d3d2fc1faec2e83bcb4d28559099092574 release-pypy2.7-v7.2.0rc2
 4a68d8d3d2fc1faec2e83bcb4d28559099092574 release-pypy2.7-v7.2.0
 5da45ced70e515f94686be0df47c59abd1348ebc release-pypy3.6-v7.2.0
+e6471221abc16f4584a07fbfeece7ebcaeb7fc38 release-pypy2.7-v7.3.0rc1
+533398cfd64e5146a07c4824e90a1b629c8b6523 release-pypy3.6-v7.3.0rc1
diff --git a/lib_pypy/_cffi_ssl/_stdssl/__init__.py 
b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
--- a/lib_pypy/_cffi_ssl/_stdssl/__init__.py
+++ b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
@@ -1,4 +1,5 @@
 import sys
+import os
 import time
 import _thread
 import weakref
@@ -1238,6 +1239,10 @@
         return stats
 
     def set_default_verify_paths(self):
+        if not os.environ.get('SSL_CERT_FILE') and not 
os.environ.get('SSL_CERT_DIR'):
+            locations = get_default_verify_paths()
+            self.load_verify_locations(locations[1], locations[3])
+            return
         if not lib.SSL_CTX_set_default_verify_paths(self.ctx):
             raise ssl_error("")
 
@@ -1581,20 +1586,69 @@
     lib.RAND_add(buf, len(buf), entropy)
 
 def get_default_verify_paths():
+    '''
+    Find a certificate store and associated values
 
+    Returns something like 
+    `('SSL_CERT_FILE', '/usr/lib/ssl/cert.pem', 'SSL_CERT_DIR', 
'/usr/lib/ssl/certs')`
+    on Ubuntu and windows10
+
+    `('SSL_CERT_FILE', '/usr/local/cert.pem', 'SSL_CERT_DIR', 
'/usr/local/certs')`
+    on CentOS
+
+    `('SSL_CERT_FILE', 
'/Library/Frameworks/Python.framework/Versions/2.7/etc/openssl/cert.pem',
+      'SSL_CERT_DIR', 
'/Library/Frameworks/Python.framework/Versions/2.7/etc/openssl/certs')`
+    on Darwin
+
+    For portable builds (based on CentOS, but could be running on any glibc
+    linux) we need to check other locations. The list of places to try was 
taken
+    from golang in Dec 2018:
+     https://golang.org/src/crypto/x509/root_unix.go (for the directories),
+     https://golang.org/src/crypto/x509/root_linux.go (for the files)
+    '''
+    certFiles = [
+        "/etc/ssl/certs/ca-certificates.crt",                # 
Debian/Ubuntu/Gentoo etc.
+        "/etc/pki/tls/certs/ca-bundle.crt",                  # Fedora/RHEL 6
+        "/etc/ssl/ca-bundle.pem",                            # OpenSUSE
+        "/etc/pki/tls/cacert.pem",                           # OpenELEC
+        "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", # CentOS/RHEL 7
+        "/etc/ssl/cert.pem",                                 # Alpine Linux
+    ]
+    certDirectories = [
+        "/etc/ssl/certs",               # SLES10/SLES11
+        "/system/etc/security/cacerts", # Android
+        "/usr/local/share/certs",       # FreeBSD
+        "/etc/pki/tls/certs",           # Fedora/RHEL
+        "/etc/openssl/certs",           # NetBSD
+        "/var/ssl/certs",               # AIX
+    ]
+
+    # optimization: reuse the values from a local varaible
+    if getattr(get_default_verify_paths, 'retval', None):
+        return get_default_verify_paths.retval
+
+    # This should never fail, it should always return SSL_CERT_FILE and 
SSL_CERT_DIR
     ofile_env = _cstr_decode_fs(lib.X509_get_default_cert_file_env())
-    if ofile_env is None:
-        return None
+    odir_env = _cstr_decode_fs(lib.X509_get_default_cert_dir_env())
+
+    # Platform depenedent
     ofile = _cstr_decode_fs(lib.X509_get_default_cert_file())
-    if ofile is None:
-        return None
-    odir_env = _cstr_decode_fs(lib.X509_get_default_cert_dir_env())
-    if odir_env is None:
-        return None
     odir = _cstr_decode_fs(lib.X509_get_default_cert_dir())
-    if odir is None:
-        return odir
-    return (ofile_env, ofile, odir_env, odir);
+
+    if os.path.exists(ofile) and os.path.exists(odir):
+        get_default_verify_paths.retval = (ofile_env, ofile, odir_env, odir)
+        return get_default_verify_paths.retval
+
+    # OpenSSL didn't supply the goods. Try some other options
+    for f in certFiles:
+        if os.path.exists(f):
+            ofile = f 
+    for f in certDirectories:
+        if os.path.exists(f):
+            odir = f 
+    get_default_verify_paths.retval = (ofile_env, ofile, odir_env, odir)
+    return get_default_verify_paths.retval
+
 
 @ffi.callback("int(SSL*,unsigned char **,unsigned char *,const unsigned char 
*,unsigned int,void *)")
 def select_alpn_callback(ssl, out, outlen, client_protocols, 
client_protocols_len, args):
diff --git a/pypy/config/test/test_pypyoption.py 
b/pypy/config/test/test_pypyoption.py
--- a/pypy/config/test/test_pypyoption.py
+++ b/pypy/config/test/test_pypyoption.py
@@ -14,7 +14,7 @@
     conf = get_pypy_config()
     conf.translation.gc = "boehm"
     with py.test.raises(ConfigError):
-        conf.translation.gcrootfinder = 'asmgcc'
+        conf.translation.gcrootfinder = 'shadowstack'
 
 def test_frameworkgc():
     for name in ["minimark", "semispace"]:
diff --git a/pypy/doc/config/translation.gcrootfinder.txt 
b/pypy/doc/config/translation.gcrootfinder.txt
--- a/pypy/doc/config/translation.gcrootfinder.txt
+++ b/pypy/doc/config/translation.gcrootfinder.txt
@@ -1,16 +1,7 @@
 Choose the method used to find the roots in the GC.  This only
-applies to our framework GCs.  You have a choice of two
-alternatives:
+applies to our framework GCs.
 
 - ``--gcrootfinder=shadowstack``: use a so-called "shadow
   stack", which is an explicitly maintained custom stack of
-  root pointers.  This is the most portable solution.
-
-- ``--gcrootfinder=asmgcc``: use assembler hackery to find the
-  roots directly from the normal stack.  This is a bit faster,
-  but platform specific.  It works so far with GCC or MSVC,
-  on i386 and x86-64.  It is tested only on Linux 
-  so other platforms (as well as MSVC) may need
-  various fixes before they can be used. Note asmgcc will be deprecated
-  at some future date, and does not work with clang.
-
+  root pointers.  This is the most portable solution, and also
+  the only one available now.
diff --git a/pypy/doc/release-v7.3.0.rst b/pypy/doc/release-v7.3.0.rst
--- a/pypy/doc/release-v7.3.0.rst
+++ b/pypy/doc/release-v7.3.0.rst
@@ -177,6 +177,8 @@
 * Adds encoding, decoding codepages on win32
 * Remove socket error attributes from ``_ssl`` (`issue 3119`_)
 * Add missing ``os.getgrouplist`` (part of `issue 2375`_)
+* Back-port the tentative fix from cpython: "Import deadlock detection causes
+  deadlock" (part of `issue 3111`_)
 
 Python 3.6 C-API
 ~~~~~~~~~~~~~~~~
@@ -210,6 +212,7 @@
 .. _`issue 3100`: https://bitbucket.com/pypy/pypy/issues/3100
 .. _`issue 3108`: https://bitbucket.com/pypy/pypy/issues/3108
 .. _`issue 3109`: https://bitbucket.com/pypy/pypy/issues/3109
+.. _`issue 3111`: https://bitbucket.com/pypy/pypy/issues/3111
 .. _`issue 3112`: https://bitbucket.com/pypy/pypy/issues/3112
 .. _`issue 3114`: https://bitbucket.com/pypy/pypy/issues/3114
 .. _`issue 3117`: https://bitbucket.com/pypy/pypy/issues/3117
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -8,3 +8,8 @@
 .. branch: backport-decode_timeval_ns-py3.7
 
 Backport ``rtime.decode_timeval_ns`` from py3.7 to rpython
+
+.. branch: kill-asmgcc
+
+Completely remove the deprecated translation option ``--gcrootfinder=asmgcc``
+because it no longer works with a recent enough ``gcc``.
diff --git a/pypy/module/_cffi_backend/call_python.py 
b/pypy/module/_cffi_backend/call_python.py
--- a/pypy/module/_cffi_backend/call_python.py
+++ b/pypy/module/_cffi_backend/call_python.py
@@ -43,8 +43,7 @@
     from rpython.rlib import rgil
 
     rgil.acquire()
-    rffi.stackcounter.stacks_counter += 1
-    llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
+    llop.gc_stack_bottom(lltype.Void)   # marker to enter RPython from C
 
     cerrno._errno_after(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
 
@@ -69,7 +68,6 @@
 
     cerrno._errno_before(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
 
-    rffi.stackcounter.stacks_counter -= 1
     rgil.release()
 
 
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1046,8 +1046,7 @@
         else:
             gilstate = pystate.PyGILState_IGNORE
 
-        rffi.stackcounter.stacks_counter += 1
-        llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
+        llop.gc_stack_bottom(lltype.Void)   # marker to enter RPython from C
         retval = fatal_value
         boxed_args = ()
         tb = None
@@ -1124,7 +1123,6 @@
             return fatal_value
 
         assert lltype.typeOf(retval) == restype
-        rffi.stackcounter.stacks_counter -= 1
 
         _restore_gil_state(pygilstate_release, gilstate, gil_release, 
_gil_auto, tid)
         return retval
diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py
--- a/pypy/module/thread/os_thread.py
+++ b/pypy/module/thread/os_thread.py
@@ -30,7 +30,7 @@
 #   called from the rffi-generated wrapper).  The gc_thread_run()
 #   operation will automatically notice that the current thread id was
 #   not seen before, and (in shadowstack) it will allocate and use a
-#   fresh new stack.  Again, this has no effect in asmgcc.
+#   fresh new stack.
 #
 # * Only then does bootstrap() really run.  The first thing it does
 #   is grab the start-up information (app-level callable and args)
@@ -43,7 +43,7 @@
 #   thread.
 #
 # * Just before a thread finishes, gc_thread_die() is called to free
-#   its shadow stack.  This has no effect in asmgcc.
+#   its shadow stack.
 
 
 class Bootstrapper(object):
diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh
--- a/pypy/tool/release/repackage.sh
+++ b/pypy/tool/release/repackage.sh
@@ -2,8 +2,8 @@
 pmaj=2  # python main version: 2 or 3
 pmin=7  # python minor version
 maj=7
-min=2
-rev=0rc2
+min=3
+rev=0rc1
 
 case $pmaj in
     "2") exe=pypy;;
diff --git a/rpython/config/test/test_translationoption.py 
b/rpython/config/test/test_translationoption.py
--- a/rpython/config/test/test_translationoption.py
+++ b/rpython/config/test/test_translationoption.py
@@ -13,13 +13,6 @@
     config.translation.gcrootfinder = "shadowstack"
     py.test.raises(ConflictConfigError, set_opt_level, config, '0')
 
-if compiler.name == 'msvc' or sys.platform == 'darwin':
-    def test_no_asmgcrot_on_msvc():
-        config = get_combined_translation_config()
-        config.translation.gcrootfinder = "asmgcc"
-        py.test.raises(ConfigError, set_opt_level, config, 'jit') 
-
-
 def test_get_translation_config():
     from rpython.translator.interactive import Translation
     from rpython.config import config
diff --git a/rpython/config/translationoption.py 
b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -18,10 +18,6 @@
 DEFL_GC = "incminimark"   # XXX
 
 DEFL_ROOTFINDER_WITHJIT = "shadowstack"
-## if sys.platform.startswith("linux"):
-##     _mach = os.popen('uname -m', 'r').read().strip()
-##     if _mach.startswith('x86') or _mach in ['i386', 'i486', 'i586', 'i686']:
-##         DEFL_ROOTFINDER_WITHJIT = "asmgcc"   # only for Linux on x86 / 
x86-64
 
 IS_64_BITS = sys.maxint > 2147483647
 
@@ -100,13 +96,11 @@
                default=IS_64_BITS, cmdline="--gcremovetypeptr"),
     ChoiceOption("gcrootfinder",
                  "Strategy for finding GC Roots (framework GCs only)",
-                 ["n/a", "shadowstack", "asmgcc"],
+                 ["n/a", "shadowstack"],
                  "shadowstack",
                  cmdline="--gcrootfinder",
                  requires={
                      "shadowstack": [("translation.gctransformer", 
"framework")],
-                     "asmgcc": [("translation.gctransformer", "framework"),
-                                ("translation.backend", "c")],
                     }),
 
     # other noticeable options
@@ -402,10 +396,6 @@
     # if we have specified strange inconsistent settings.
     config.translation.gc = config.translation.gc
 
-    # disallow asmgcc on OS/X and on Win32
-    if config.translation.gcrootfinder == "asmgcc":
-        if sys.platform == "darwin" or sys.platform =="win32":
-            raise ConfigError("'asmgcc' not supported on this platform")
 
 # ----------------------------------------------------------------
 
diff --git a/rpython/jit/backend/llsupport/assembler.py 
b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -438,51 +438,8 @@
 
     @staticmethod
     @rgc.no_collect
-    def _reacquire_gil_asmgcc(css, old_rpy_fastgil):
-        # Before doing an external call, 'rpy_fastgil' is initialized to
-        # be equal to css.  This function is called if we find out after
-        # the call that it is no longer equal to css.  See description
-        # in translator/c/src/thread_pthread.c.
-
-        # XXX some duplicated logic here, but note that rgil.acquire()
-        # does more than just RPyGilAcquire()
-        if old_rpy_fastgil == 0:
-            # this case occurs if some other thread stole the GIL but
-            # released it again.  What occurred here is that we changed
-            # 'rpy_fastgil' from 0 to 1, thus successfully reaquiring the
-            # GIL.
-            pass
-
-        elif old_rpy_fastgil == 1:
-            # 'rpy_fastgil' was (and still is) locked by someone else.
-            # We need to wait for the regular mutex.
-            from rpython.rlib import rgil
-            rgil.acquire()
-        else:
-            # stole the GIL from a different thread that is also
-            # currently in an external call from the jit.  Attach
-            # the 'old_rpy_fastgil' into the chained list.
-            from rpython.memory.gctransform import asmgcroot
-            oth = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, old_rpy_fastgil)
-            next = asmgcroot.gcrootanchor.next
-            oth.next = next
-            oth.prev = asmgcroot.gcrootanchor
-            asmgcroot.gcrootanchor.next = oth
-            next.prev = oth
-
-        # similar to trackgcroot.py:pypy_asm_stackwalk, second part:
-        # detach the 'css' from the chained list
-        from rpython.memory.gctransform import asmgcroot
-        old = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css)
-        prev = old.prev
-        next = old.next
-        prev.next = next
-        next.prev = prev
-
-    @staticmethod
-    @rgc.no_collect
     def _reacquire_gil_shadowstack():
-        # Simplified version of _reacquire_gil_asmgcc(): in shadowstack mode,
+        # This used to be more complex for asmgcc.  In shadowstack mode,
         # 'rpy_fastgil' contains only zero or non-zero, and this is only
         # called when the old value stored in 'rpy_fastgil' was non-zero
         # (i.e. still locked, must wait with the regular mutex)
@@ -499,13 +456,10 @@
                                      self._reacquire_gil_shadowstack)
             self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func)
         else:
-            reacqgil_func = llhelper(self._REACQGIL2_FUNC,
-                                     self._reacquire_gil_asmgcc)
-            self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func)
+            raise AssertionError("!is_shadow_stack")
 
     def _is_asmgcc(self):
-        gcrootmap = self.cpu.gc_ll_descr.gcrootmap
-        return bool(gcrootmap) and not gcrootmap.is_shadow_stack
+        return False        # legacy
 
 
 def debug_bridge(descr_number, rawstart, codeendpos):
diff --git a/rpython/jit/backend/llsupport/gc.py 
b/rpython/jit/backend/llsupport/gc.py
--- a/rpython/jit/backend/llsupport/gc.py
+++ b/rpython/jit/backend/llsupport/gc.py
@@ -21,7 +21,6 @@
 from rpython.jit.backend.llsupport.descr import get_call_descr
 from rpython.jit.backend.llsupport.descr import unpack_arraydescr
 from rpython.jit.backend.llsupport.rewrite import GcRewriterAssembler
-from rpython.memory.gctransform import asmgcroot
 from rpython.jit.codewriter.effectinfo import EffectInfo
 
 # ____________________________________________________________
@@ -117,7 +116,7 @@
         descrs = JitFrameDescrs()
         descrs.arraydescr = cpu.arraydescrof(jitframe.JITFRAME)
         for name in ['jf_descr', 'jf_guard_exc', 'jf_force_descr',
-                     'jf_frame_info', 'jf_gcmap', 'jf_extra_stack_depth',
+                     'jf_frame_info', 'jf_gcmap',
                      'jf_savedata', 'jf_forward']:
             setattr(descrs, name, cpu.fielddescrof(jitframe.JITFRAME, name))
         descrs.jfi_frame_size = cpu.fielddescrof(jitframe.JITFRAMEINFO,
@@ -244,15 +243,6 @@
 # ____________________________________________________________
 # All code below is for the hybrid or minimark GC
 
-class GcRootMap_asmgcc(object):
-    is_shadow_stack = False
-
-    def __init__(self, gcdescr):
-        pass
-
-    def register_asm_addr(self, start, mark):
-        pass
-
 class GcRootMap_shadowstack(object):
     is_shadow_stack = True
 
diff --git a/rpython/jit/backend/llsupport/jitframe.py 
b/rpython/jit/backend/llsupport/jitframe.py
--- a/rpython/jit/backend/llsupport/jitframe.py
+++ b/rpython/jit/backend/llsupport/jitframe.py
@@ -49,7 +49,6 @@
     rgc.register_custom_trace_hook(JITFRAME, lambda_jitframe_trace)
     frame = lltype.malloc(JITFRAME, frame_info.jfi_frame_depth)
     frame.jf_frame_info = frame_info
-    frame.jf_extra_stack_depth = 0
     return frame
 
 def jitframe_resolve(frame):
@@ -71,8 +70,6 @@
     ('jf_force_descr', llmemory.GCREF),
     # a map of GC pointers
     ('jf_gcmap', lltype.Ptr(GCMAP)),
-    # how much we decrease stack pointer. Used around calls and malloc slowpath
-    ('jf_extra_stack_depth', lltype.Signed),
     # For the front-end: a GCREF for the savedata
     ('jf_savedata', llmemory.GCREF),
     # For GUARD_(NO)_EXCEPTION and GUARD_NOT_FORCED: the exception we
@@ -103,7 +100,6 @@
 LENGTHOFS = llmemory.arraylengthoffset(JITFRAME.jf_frame)
 SIGN_SIZE = llmemory.sizeof(lltype.Signed)
 UNSIGN_SIZE = llmemory.sizeof(lltype.Unsigned)
-STACK_DEPTH_OFS = getofs('jf_extra_stack_depth')
 
 def jitframe_trace(gc, obj_addr, callback, arg):
     gc._trace_callback(callback, arg, obj_addr + getofs('jf_descr'))
diff --git a/rpython/jit/backend/llsupport/rewrite.py 
b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -584,8 +584,6 @@
 
             length = self.emit_getfield(ConstInt(frame_info),
                                         descr=descrs.jfi_frame_depth, raw=True)
-            self.emit_setfield(frame, self.c_zero,
-                               descr=descrs.jf_extra_stack_depth)
             self.emit_setfield(frame, self.c_null,
                                descr=descrs.jf_savedata)
             self.emit_setfield(frame, self.c_null,
diff --git a/rpython/jit/backend/llsupport/test/test_gc.py 
b/rpython/jit/backend/llsupport/test/test_gc.py
--- a/rpython/jit/backend/llsupport/test/test_gc.py
+++ b/rpython/jit/backend/llsupport/test/test_gc.py
@@ -110,7 +110,7 @@
         class config_(object):
             class translation(object):
                 gc = self.gc
-                gcrootfinder = 'asmgcc'
+                gcrootfinder = 'shadowstack'
                 gctransformer = 'framework'
                 gcremovetypeptr = False
         class FakeTranslator(object):
diff --git a/rpython/jit/backend/llsupport/test/test_gc_integration.py 
b/rpython/jit/backend/llsupport/test/test_gc_integration.py
--- a/rpython/jit/backend/llsupport/test/test_gc_integration.py
+++ b/rpython/jit/backend/llsupport/test/test_gc_integration.py
@@ -507,7 +507,6 @@
     ('jf_frame_info', lltype.Ptr(jitframe.JITFRAMEINFO)),
     ('jf_descr', llmemory.GCREF),
     ('jf_force_descr', llmemory.GCREF),
-    ('jf_extra_stack_depth', lltype.Signed),
     ('jf_guard_exc', llmemory.GCREF),
     ('jf_gcmap', lltype.Ptr(jitframe.GCMAP)),
     ('jf_gc_trace_state', lltype.Signed),
@@ -594,7 +593,7 @@
         descrs = JitFrameDescrs()
         descrs.arraydescr = cpu.arraydescrof(JITFRAME)
         for name in ['jf_descr', 'jf_guard_exc', 'jf_force_descr',
-                     'jf_frame_info', 'jf_gcmap', 'jf_extra_stack_depth']:
+                     'jf_frame_info', 'jf_gcmap']:
             setattr(descrs, name, cpu.fielddescrof(JITFRAME, name))
         descrs.jfi_frame_depth = cpu.fielddescrof(jitframe.JITFRAMEINFO,
                                                   'jfi_frame_depth')
diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py 
b/rpython/jit/backend/llsupport/test/test_rewrite.py
--- a/rpython/jit/backend/llsupport/test/test_rewrite.py
+++ b/rpython/jit/backend/llsupport/test/test_rewrite.py
@@ -170,7 +170,6 @@
         jf_descr = framedescrs.jf_descr
         jf_guard_exc = framedescrs.jf_guard_exc
         jf_forward = framedescrs.jf_forward
-        jf_extra_stack_depth = framedescrs.jf_extra_stack_depth
         signedframedescr = self.cpu.signedframedescr
         floatframedescr = self.cpu.floatframedescr
         casmdescr.compiled_loop_token = clt
@@ -386,7 +385,7 @@
         class config_(object):
             class translation(object):
                 gc = 'minimark'
-                gcrootfinder = 'asmgcc'
+                gcrootfinder = 'shadowstack'
                 gctransformer = 'framework'
                 gcremovetypeptr = False
         gcdescr = get_description(config_)
@@ -1102,7 +1101,6 @@
         p1 = call_malloc_nursery_varsize_frame(i1)
         gc_store(p1, 0,  0, %(tiddescr.field_size)s)
         i2 = gc_load_i(ConstClass(frame_info), %(jfi_frame_depth.offset)s, 
%(jfi_frame_depth.field_size)s)
-        %(setfield('p1', 0, jf_extra_stack_depth))s
         %(setfield('p1', 'NULL', jf_savedata))s
         %(setfield('p1', 'NULL', jf_force_descr))s
         %(setfield('p1', 'NULL', jf_descr))s
diff --git a/rpython/jit/backend/llsupport/test/zrpy_gc_test.py 
b/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
--- a/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
+++ b/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
@@ -176,9 +176,6 @@
             cls.cbuilder = compile(get_entry(allfuncs), cls.gc,
                                    gcrootfinder=cls.gcrootfinder, jit=True,
                                    thread=True)
-        except ConfigError as e:        
-            assert str(e).startswith('invalid value asmgcc')
-            py.test.skip('asmgcc not supported')
         finally:
             GcLLDescr_framework.DEBUG = OLD_DEBUG
 
diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py 
b/rpython/jit/backend/llsupport/test/ztranslation_test.py
--- a/rpython/jit/backend/llsupport/test/ztranslation_test.py
+++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py
@@ -331,9 +331,6 @@
         try:
             res = self.meta_interp(main, [400])
             assert res == main(400)
-        except ConfigError as e:
-            assert str(e).startswith('invalid value asmgcc')
-            py.test.skip('asmgcc not supported')
         finally:
             del os.environ['PYPYLOG']
 
diff --git a/rpython/jit/backend/x86/arch.py b/rpython/jit/backend/x86/arch.py
--- a/rpython/jit/backend/x86/arch.py
+++ b/rpython/jit/backend/x86/arch.py
@@ -35,9 +35,7 @@
     PASS_ON_MY_FRAME = 15
     JITFRAME_FIXED_SIZE = 6 + 8 * 2 # 6 GPR + 8 XMM * 2 WORDS/float
     # 'threadlocal_addr' is passed as 2nd argument on the stack,
-    # and it can be left here for when it is needed.  As an additional hack,
-    # with asmgcc, it is made odd-valued to mean "already seen this frame
-    # during the previous minor collection".
+    # and it can be left here for when it is needed.
     THREADLOCAL_OFS = (FRAME_FIXED_SIZE + 2) * WORD
 else:
     # rbp + rbx + r12 + r13 + r14 + r15 + threadlocal + 12 extra words = 19
@@ -45,12 +43,10 @@
     PASS_ON_MY_FRAME = 12
     JITFRAME_FIXED_SIZE = 28 # 13 GPR + 15 XMM
     # 'threadlocal_addr' is passed as 2nd argument in %esi,
-    # and is moved into this frame location.  As an additional hack,
-    # with asmgcc, it is made odd-valued to mean "already seen this frame
-    # during the previous minor collection".
+    # and is moved into this frame location.
     THREADLOCAL_OFS = (FRAME_FIXED_SIZE - 1) * WORD
 
-assert PASS_ON_MY_FRAME >= 12       # asmgcc needs at least JIT_USE_WORDS + 3
+assert PASS_ON_MY_FRAME >= 12
 
 # return address, followed by FRAME_FIXED_SIZE words
 DEFAULT_FRAME_BYTES = (1 + FRAME_FIXED_SIZE) * WORD
diff --git a/rpython/jit/backend/x86/assembler.py 
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -137,11 +137,6 @@
         self.expand_byte_mask_addr = float_constants + 64
         self.element_ones = [float_constants + 80 + 16*i for i in range(4)]
 
-    def set_extra_stack_depth(self, mc, value):
-        if self._is_asmgcc():
-            extra_ofs = self.cpu.get_ofs_of_frame_field('jf_extra_stack_depth')
-            mc.MOV_bi(extra_ofs, value)
-
     def build_frame_realloc_slowpath(self):
         mc = codebuf.MachineCodeBlockWrapper()
         self._push_all_regs_to_frame(mc, [], self.cpu.supports_floats)
@@ -161,14 +156,20 @@
             mc.MOV_sr(0, ebp.value)
         # align
 
-        self.set_extra_stack_depth(mc, align * WORD)
+        #
+        # * Note: these commented-out pieces of code about 'extra_stack_depth'
+        # * are not necessary any more, but they are kept around in case we
+        # * need in the future again to track the exact stack depth.
+        #
+        #self.set_extra_stack_depth(mc, align * WORD)
+
         self._store_and_reset_exception(mc, None, ebx, ecx)
 
         mc.CALL(imm(self.cpu.realloc_frame))
         mc.MOV_rr(ebp.value, eax.value)
         self._restore_exception(mc, None, ebx, ecx)
         mc.ADD_ri(esp.value, (align - 1) * WORD)
-        self.set_extra_stack_depth(mc, 0)
+        #self.set_extra_stack_depth(mc, 0)
 
         gcrootmap = self.cpu.gc_ll_descr.gcrootmap
         if gcrootmap and gcrootmap.is_shadow_stack:
@@ -196,12 +197,12 @@
         # the caller already did push_gcmap(store=True)
         if IS_X86_64:
             mc.SUB(esp, imm(WORD))     # alignment
-            self.set_extra_stack_depth(mc, 2 * WORD)
+            #self.set_extra_stack_depth(mc, 2 * WORD)
             # the arguments are already in the correct registers
         else:
             # we want space for 4 arguments + call + alignment
             mc.SUB(esp, imm(WORD * 7))
-            self.set_extra_stack_depth(mc, 8 * WORD)
+            #self.set_extra_stack_depth(mc, 8 * WORD)
             # store the arguments at the correct place in the stack
             for i in range(4):
                 mc.MOV_sr(i * WORD, cond_call_register_arguments[i].value)
@@ -211,7 +212,7 @@
             mc.ADD(esp, imm(WORD))
         else:
             mc.ADD(esp, imm(WORD * 7))
-        self.set_extra_stack_depth(mc, 0)
+        #self.set_extra_stack_depth(mc, 0)
         self.pop_gcmap(mc)   # cancel the push_gcmap(store=True) in the caller
         self._pop_all_regs_from_frame(mc, [eax], supports_floats, callee_only)
         mc.RET()
@@ -275,11 +276,11 @@
                 # (already in edx)              # length
                 mc.MOV_rr(esi.value, ecx.value) # tid
                 mc.MOV_rs(edi.value, WORD * 3)  # load the itemsize
-        self.set_extra_stack_depth(mc, 16)
+        #self.set_extra_stack_depth(mc, 16)
         mc.CALL(imm(follow_jump(addr)))
         self._reload_frame_if_necessary(mc)
         mc.ADD_ri(esp.value, 16 - WORD)
-        self.set_extra_stack_depth(mc, 0)
+        #self.set_extra_stack_depth(mc, 0)
         #
         mc.TEST_rr(eax.value, eax.value)
         # common case: not taken
@@ -1018,8 +1019,6 @@
         from rpython.rlib.rvmprof.rvmprof import cintf
         # edx = address of pypy_threadlocal_s
         self.mc.MOV_rs(edx.value, THREADLOCAL_OFS)
-        if self._is_asmgcc():
-            self.mc.AND_ri(edx.value, ~1)
         # eax = (our local vmprof_tl_stack).next
         self.mc.MOV_rs(eax.value, (FRAME_FIXED_SIZE - 4 + 0) * WORD)
         # save in vmprof_tl_stack the value eax
@@ -2236,25 +2235,6 @@
 
     def _call_assembler_emit_call(self, addr, argloc, _):
         threadlocal_loc = RawEspLoc(THREADLOCAL_OFS, INT)
-        if self._is_asmgcc():
-            # We need to remove the bit "already seen during the
-            # previous minor collection" instead of passing this
-            # value directly.
-            if IS_X86_64:
-                tmploc = esi    # already the correct place
-                if argloc is tmploc:
-                    # this case is theoretical only so far: in practice,
-                    # argloc is always eax, never esi
-                    self.mc.MOV_rr(edi.value, esi.value)
-                    argloc = edi
-            else:
-                tmploc = eax
-                if tmploc is argloc:
-                    tmploc = edx
-            self.mc.MOV(tmploc, threadlocal_loc)
-            self.mc.AND_ri(tmploc.value, ~1)
-            threadlocal_loc = tmploc
-        #
         self.simple_call(addr, [argloc, threadlocal_loc])
 
     def _call_assembler_emit_helper_call(self, addr, arglocs, result_loc):
@@ -2672,8 +2652,6 @@
         assert self.cpu.translate_support_code
         assert isinstance(resloc, RegLoc)
         self.mc.MOV_rs(resloc.value, THREADLOCAL_OFS)
-        if self._is_asmgcc():
-            self.mc.AND_ri(resloc.value, ~1)
         self.load_from_mem(resloc, addr_add_const(resloc, offset),
                            imm(size), imm(sign))
 
diff --git a/rpython/jit/backend/x86/callbuilder.py 
b/rpython/jit/backend/x86/callbuilder.py
--- a/rpython/jit/backend/x86/callbuilder.py
+++ b/rpython/jit/backend/x86/callbuilder.py
@@ -61,13 +61,6 @@
             self.arglocs = arglocs + [fnloc]
         self.start_frame_size = self.mc._frame_size
 
-    def select_call_release_gil_mode(self):
-        AbstractCallBuilder.select_call_release_gil_mode(self)
-        if self.asm._is_asmgcc():
-            from rpython.memory.gctransform import asmgcroot
-            self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS
-            assert self.stack_max >= 3
-
     def subtract_esp_aligned(self, count):
         if count > 0:
             align = align_stack_words(count)
@@ -103,9 +96,14 @@
         # value eax, if necessary
         assert not self.is_call_release_gil
         current_esp = self.get_current_esp()
-        self.change_extra_stack_depth = (current_esp != 0)
-        if self.change_extra_stack_depth:
-            self.asm.set_extra_stack_depth(self.mc, -current_esp)
+        #
+        # * Note: these commented-out pieces of code about 'extra_stack_depth'
+        # * are not necessary any more, but they are kept around in case we
+        # * need in the future again to track the exact stack depth.
+        #
+        #self.change_extra_stack_depth = (current_esp != 0)
+        #if self.change_extra_stack_depth:
+        #    self.asm.set_extra_stack_depth(self.mc, -current_esp)
         noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack()
         gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs)
         self.asm.push_gcmap(self.mc, gcmap, store=True)
@@ -119,13 +117,14 @@
                 # top at this point, so reuse it instead of loading it again
                 ssreg = ebx
         self.asm._reload_frame_if_necessary(self.mc, shadowstack_reg=ssreg)
-        if self.change_extra_stack_depth:
-            self.asm.set_extra_stack_depth(self.mc, 0)
+        #if self.change_extra_stack_depth:
+        #    self.asm.set_extra_stack_depth(self.mc, 0)
         self.asm.pop_gcmap(self.mc)
 
     def call_releasegil_addr_and_move_real_arguments(self, fastgil):
         from rpython.jit.backend.x86.assembler import heap
         assert self.is_call_release_gil
+        assert not self.asm._is_asmgcc()
         #
         # Save this thread's shadowstack pointer into 'ebx',
         # for later comparison
@@ -135,38 +134,12 @@
                 rst = gcrootmap.get_root_stack_top_addr()
                 self.mc.MOV(ebx, heap(rst))
         #
-        if not self.asm._is_asmgcc():
-            # shadowstack: change 'rpy_fastgil' to 0 (it should be
-            # non-zero right now).
-            self.change_extra_stack_depth = False
-            # ^^ note that set_extra_stack_depth() in this case is a no-op
-            css_value = imm(0)
-        else:
-            from rpython.memory.gctransform import asmgcroot
-            # build a 'css' structure on the stack: 2 words for the linkage,
-            # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a
-            # total size of JIT_USE_WORDS.  This structure is found at
-            # [ESP+css].
-            css = -self.get_current_esp() + (
-                WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS))
-            assert css >= 2 * WORD
-            # Save ebp
-            index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP)
-            self.mc.MOV_sr(index_of_ebp, ebp.value)  # MOV [css.ebp], EBP
-            # Save the "return address": we pretend that it's css
-            self.mc.LEA_rs(eax.value, css)           # LEA eax, [css]
-            frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR)
-            self.mc.MOV_sr(frame_ptr, eax.value)     # MOV [css.frame], eax
-            # Set up jf_extra_stack_depth to pretend that the return address
-            # was at css, and so our stack frame is supposedly shorter by
-            # (PASS_ON_MY_FRAME-JIT_USE_WORDS+1) words
-            delta = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + 1
-            self.change_extra_stack_depth = True
-            self.asm.set_extra_stack_depth(self.mc, -delta * WORD)
-            css_value = eax
+        # shadowstack: change 'rpy_fastgil' to 0 (it should be
+        # non-zero right now).
+        #self.change_extra_stack_depth = False
         #
         # <--here--> would come a memory fence, if the CPU needed one.
-        self.mc.MOV(heap(fastgil), css_value)
+        self.mc.MOV(heap(fastgil), imm(0))
         #
         if not we_are_translated():        # for testing: we should not access
             self.mc.ADD(ebp, imm(1))       # ebp any more
@@ -184,8 +157,6 @@
                 self.tlofs_reg = r12
             self.mc.MOV_rs(self.tlofs_reg.value,
                            THREADLOCAL_OFS - self.get_current_esp())
-            if self.asm._is_asmgcc():
-                self.mc.AND_ri(self.tlofs_reg.value, ~1)
         return self.tlofs_reg
 
     def save_stack_position(self):
@@ -318,13 +289,6 @@
             cb = self.callbuilder
             if not cb.result_value_saved_early:
                 cb.save_result_value(save_edx=False)
-            if assembler._is_asmgcc():
-                if IS_X86_32:
-                    css_value = edx
-                    old_value = ecx
-                    mc.MOV_sr(4, old_value.value)
-                    mc.MOV_sr(0, css_value.value)
-                # on X86_64, they are already in the right registers
             mc.CALL(imm(follow_jump(assembler.reacqgil_addr)))
             if not cb.result_value_saved_early:
                 cb.restore_result_value(save_edx=False)
@@ -333,29 +297,10 @@
         from rpython.jit.backend.x86 import rx86
         #
         # check if we need to call the reacqgil() function or not
-        # (to acquiring the GIL, remove the asmgcc head from
-        # the chained list, etc.)
+        # (to acquiring the GIL)
         mc = self.mc
         restore_edx = False
-        if not self.asm._is_asmgcc():
-            css = 0
-            css_value = imm(0)
-            old_value = ecx
-        else:
-            from rpython.memory.gctransform import asmgcroot
-            css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS)
-            if IS_X86_32:
-                assert css >= 16
-                if self.restype == 'L':    # long long result: eax/edx
-                    if not self.result_value_saved_early:
-                        mc.MOV_sr(12, edx.value)
-                        restore_edx = True
-                css_value = edx    # note: duplicated in ReacqGilSlowPath
-                old_value = ecx    #
-            elif IS_X86_64:
-                css_value = edi
-                old_value = esi
-            mc.LEA_rs(css_value.value, css)
+        old_value = ecx
         #
         # Use XCHG as an atomic test-and-set-lock.  It also implicitly
         # does a memory barrier.
@@ -365,11 +310,12 @@
         else:
             mc.MOV_ri(X86_64_SCRATCH_REG.value, fastgil)
             mc.XCHG_rm(old_value.value, (X86_64_SCRATCH_REG.value, 0))
-        mc.CMP(old_value, css_value)
+        mc.CMP(old_value, imm(0))
         #
         gcrootmap = self.asm.cpu.gc_ll_descr.gcrootmap
-        if bool(gcrootmap) and gcrootmap.is_shadow_stack:
+        if bool(gcrootmap):
             from rpython.jit.backend.x86.assembler import heap
+            assert gcrootmap.is_shadow_stack
             #
             # When doing a call_release_gil with shadowstack, there
             # is the risk that the 'rpy_fastgil' was free but the
@@ -406,14 +352,8 @@
         if not we_are_translated():    # for testing: now we can accesss
             mc.SUB(ebp, imm(1))        # ebp again
         #
-        # Now that we required the GIL, we can reload a possibly modified ebp
-        if self.asm._is_asmgcc():
-            # special-case: reload ebp from the css
-            from rpython.memory.gctransform import asmgcroot
-            index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP)
-            mc.MOV_rs(ebp.value, index_of_ebp)  # MOV EBP, [css.ebp]
-        #else:
-        #   for shadowstack, done for us by _reload_frame_if_necessary()
+        # Now that we required the GIL, we will reload a possibly modified ebp:
+        # this done for us by _reload_frame_if_necessary()
 
     def save_result_value(self, save_edx):
         """Overridden in CallBuilder32 and CallBuilder64"""
diff --git a/rpython/jit/backend/x86/regalloc.py 
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -829,10 +829,7 @@
         self.xrm.before_call(save_all_regs=save_all_regs)
         if gc_level == SAVE_GCREF_REGS:
             gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap
-            # we save all the GCREF registers for shadowstack and asmgcc for 
now
-            # --- for asmgcc too: we can't say "register x is a gc ref"
-            # without distinguishing call sites, which we don't do any
-            # more for now.
+            # we save all the GCREF registers for shadowstack
             if gcrootmap: # and gcrootmap.is_shadow_stack:
                 save_all_regs = SAVE_GCREF_REGS
         self.rm.before_call(save_all_regs=save_all_regs)
@@ -940,15 +937,6 @@
     consider_cond_call_gc_wb_array = consider_cond_call_gc_wb
 
     def consider_cond_call(self, op):
-        # A 32-bit-only, asmgcc-only issue: 'cond_call_register_arguments'
-        # contains edi and esi, which are also in asmgcroot.py:ASM_FRAMEDATA.
-        # We must make sure that edi and esi do not contain GC pointers.
-        if IS_X86_32 and self.assembler._is_asmgcc():
-            for box, loc in self.rm.reg_bindings.items():
-                if (loc == edi or loc == esi) and box.type == REF:
-                    self.rm.force_spill_var(box)
-                    assert box not in self.rm.reg_bindings
-        #
         args = op.getarglist()
         assert 2 <= len(args) <= 4 + 2     # maximum 4 arguments
         v_func = args[1]
diff --git a/rpython/jit/backend/x86/test/test_zrpy_gcasmgcc.py 
b/rpython/jit/backend/x86/test/test_zrpy_gcasmgcc.py
deleted file mode 100644
--- a/rpython/jit/backend/x86/test/test_zrpy_gcasmgcc.py
+++ /dev/null
@@ -1,9 +0,0 @@
-import py
-from rpython.jit.backend.llsupport.test.zrpy_gc_test import 
CompileFrameworkTests
-from rpython.translator.platform import platform as compiler
-
-if compiler.name == 'msvc':
-    py.test.skip('asmgcc buggy on msvc')
-
-class TestAsmGcc(CompileFrameworkTests):
-    gcrootfinder = "asmgcc"
diff --git a/rpython/jit/backend/x86/test/test_zrpy_releasegil.py 
b/rpython/jit/backend/x86/test/test_zrpy_releasegil.py
--- a/rpython/jit/backend/x86/test/test_zrpy_releasegil.py
+++ b/rpython/jit/backend/x86/test/test_zrpy_releasegil.py
@@ -1,11 +1,5 @@
 from rpython.jit.backend.llsupport.test.zrpy_releasegil_test import 
ReleaseGILTests
-from rpython.translator.platform import platform as compiler
 
 
 class TestShadowStack(ReleaseGILTests):
     gcrootfinder = "shadowstack"
-
-
-if compiler.name != 'msvc':
-    class TestAsmGcc(ReleaseGILTests):
-        gcrootfinder = "asmgcc"
diff --git 
a/rpython/jit/backend/x86/test/test_ztranslation_external_exception.py 
b/rpython/jit/backend/x86/test/test_ztranslation_external_exception.py
--- a/rpython/jit/backend/x86/test/test_ztranslation_external_exception.py
+++ b/rpython/jit/backend/x86/test/test_ztranslation_external_exception.py
@@ -1,19 +1,12 @@
 from rpython.jit.backend.llsupport.test.ztranslation_test import 
TranslationRemoveTypePtrTest
 from rpython.translator.translator import TranslationContext
 from rpython.config.translationoption import DEFL_GC
-from rpython.translator.platform import platform as compiler
 
-if compiler.name == 'msvc':
-    _MSVC = True
-else:
-    _MSVC = False
 
 class TestTranslationRemoveTypePtrX86(TranslationRemoveTypePtrTest):
     def _get_TranslationContext(self):
         t = TranslationContext()
         t.config.translation.gc = DEFL_GC   # 'hybrid' or 'minimark'
-        if not _MSVC:
-            t.config.translation.gcrootfinder = 'asmgcc'
         t.config.translation.list_comprehension_operations = True
         t.config.translation.gcremovetypeptr = True
         return t
diff --git a/rpython/jit/metainterp/resoperation.py 
b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -1156,8 +1156,7 @@
     'CALL_ASSEMBLER/*d/rfin',  # call already compiled assembler
     'CALL_MAY_FORCE/*d/rfin',
     'CALL_LOOPINVARIANT/*d/rfin',
-    'CALL_RELEASE_GIL/*d/fin',
-    # release the GIL and "close the stack" for asmgcc
+    'CALL_RELEASE_GIL/*d/fin',  # release the GIL around the call
     'CALL_PURE/*d/rfin',             # removed before it's passed to the 
backend
     'CHECK_MEMORY_ERROR/1/n',   # after a CALL: NULL => propagate MemoryError
     'CALL_MALLOC_NURSERY/1/r',  # nursery malloc, const number of bytes, zeroed
diff --git a/rpython/memory/gctransform/asmgcroot.py 
b/rpython/memory/gctransform/asmgcroot.py
deleted file mode 100644
--- a/rpython/memory/gctransform/asmgcroot.py
+++ /dev/null
@@ -1,870 +0,0 @@
-from rpython.flowspace.model import (Constant, Variable, Block, Link,
-     copygraph, SpaceOperation, checkgraph)
-from rpython.rlib.debug import ll_assert
-from rpython.rlib.nonconst import NonConstant
-from rpython.rlib import rgil
-from rpython.rtyper.annlowlevel import llhelper
-from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
-from rpython.rtyper.lltypesystem.lloperation import llop
-from rpython.memory.gctransform.framework import (
-     BaseFrameworkGCTransformer, BaseRootWalker)
-from rpython.rtyper.llannotation import SomeAddress
-from rpython.rtyper.rbuiltin import gen_cast
-from rpython.translator.unsimplify import varoftype
-from rpython.translator.tool.cbuild import ExternalCompilationInfo
-import sys
-
-
-#
-#  This transformer avoids the use of a shadow stack in a completely
-#  platform-specific way, by directing genc to insert asm() special
-#  instructions in the C source, which are recognized by GCC.
-#  The .s file produced by GCC is then parsed by trackgcroot.py.
-#
-
-IS_64_BITS = sys.maxint > 2147483647
-
-class AsmGcRootFrameworkGCTransformer(BaseFrameworkGCTransformer):
-    _asmgcc_save_restore_arguments = None
-
-    def push_roots(self, hop, keep_current_args=False):
-        livevars = self.get_livevars_for_roots(hop, keep_current_args)
-        self.num_pushs += len(livevars)
-        return livevars
-
-    def pop_roots(self, hop, livevars):
-        if not livevars:
-            return
-        # mark the values as gc roots
-        for var in livevars:
-            v_adr = gen_cast(hop.llops, llmemory.Address, var)
-            v_newaddr = hop.genop("direct_call", [c_asm_gcroot, v_adr],
-                                  resulttype=llmemory.Address)
-            hop.genop("gc_reload_possibly_moved", [v_newaddr, var])
-
-    def build_root_walker(self):
-        return AsmStackRootWalker(self)
-
-    def mark_call_cannotcollect(self, hop, name):
-        hop.genop("direct_call", [c_asm_nocollect, name])
-
-    def gct_direct_call(self, hop):
-        # just a sanity check: if we find a fnptr with the hint on the
-        # _callable, then we'd also find the hint by looking only at the
-        # graph.  We'll actually change this graph only later, in
-        # start_transforming_graph().
-        fnptr = hop.spaceop.args[0].value
-        try:
-            close_stack = fnptr._obj._callable._gctransformer_hint_close_stack_
-        except AttributeError:
-            pass
-        else:
-            assert fnptr._obj.graph.func is fnptr._obj._callable
-        BaseFrameworkGCTransformer.gct_direct_call(self, hop)
-
-    def start_transforming_graph(self, graph):
-        try:
-            close_stack = graph.func._gctransformer_hint_close_stack_
-        except AttributeError:
-            close_stack = False
-        if close_stack:
-            self._transform_hint_close_stack(graph)
-
-    def _transform_hint_close_stack(self, graph):
-        # We cannot easily pass variable amount of arguments of the call
-        # across the call to the pypy_asm_stackwalk helper.  So we store
-        # them away and restore them.  More precisely, we need to
-        # replace 'graph' with code that saves the arguments, and make
-        # a new graph that starts with restoring the arguments.
-        if self._asmgcc_save_restore_arguments is None:
-            self._asmgcc_save_restore_arguments = {}
-        sradict = self._asmgcc_save_restore_arguments
-        sra = []     # list of pointers to raw-malloced containers for args
-        seen = {}
-        ARGS = [v.concretetype for v in graph.getargs()]
-        for TYPE in ARGS:
-            if isinstance(TYPE, lltype.Ptr):
-                TYPE = llmemory.Address
-            num = seen.get(TYPE, 0)
-            seen[TYPE] = num + 1
-            key = (TYPE, num)
-            if key not in sradict:
-                CONTAINER = lltype.FixedSizeArray(TYPE, 1)
-                p = lltype.malloc(CONTAINER, flavor='raw', zero=True,
-                                  immortal=True)
-                sradict[key] = Constant(p, lltype.Ptr(CONTAINER))
-            sra.append(sradict[key])
-        #
-        # make a copy of the graph that will reload the values
-        graph2 = copygraph(graph)
-        del graph2.func   # otherwise, start_transforming_graph() will
-                          # again transform graph2, and we get an
-                          # infinite loop
-        #
-        # edit the original graph to only store the value of the arguments
-        block = Block(graph.startblock.inputargs)
-        c_item0 = Constant('item0', lltype.Void)
-        assert len(block.inputargs) == len(sra)
-        for v_arg, c_p in zip(block.inputargs, sra):
-            if isinstance(v_arg.concretetype, lltype.Ptr):
-                v_adr = varoftype(llmemory.Address)
-                block.operations.append(
-                    SpaceOperation("cast_ptr_to_adr", [v_arg], v_adr))
-                v_arg = v_adr
-            v_void = varoftype(lltype.Void)
-            block.operations.append(
-                SpaceOperation("bare_setfield", [c_p, c_item0, v_arg], v_void))
-        #
-        # call asm_stackwalk(graph2)
-        RESULT = graph.getreturnvar().concretetype
-        FUNC2 = lltype.FuncType([], RESULT)
-        fnptr2 = lltype.functionptr(FUNC2,
-                                    graph.name + '_reload',
-                                    graph=graph2)
-        c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2))
-        HELPERFUNC = lltype.FuncType([lltype.Ptr(FUNC2),
-                                      ASM_FRAMEDATA_HEAD_PTR], RESULT)
-        v_asm_stackwalk = varoftype(lltype.Ptr(HELPERFUNC), "asm_stackwalk")
-        block.operations.append(
-            SpaceOperation("cast_pointer", [c_asm_stackwalk], v_asm_stackwalk))
-        v_result = varoftype(RESULT)
-        block.operations.append(
-            SpaceOperation("indirect_call", [v_asm_stackwalk, c_fnptr2,
-                                             c_gcrootanchor,
-                                             Constant(None, lltype.Void)],
-                           v_result))
-        block.closeblock(Link([v_result], graph.returnblock))
-        graph.startblock = block
-        #
-        # edit the copy of the graph to reload the values
-        block2 = graph2.startblock
-        block1 = Block([])
-        reloadedvars = []
-        for v, c_p in zip(block2.inputargs, sra):
-            v = v.copy()
-            if isinstance(v.concretetype, lltype.Ptr):
-                w = varoftype(llmemory.Address)
-            else:
-                w = v
-            block1.operations.append(SpaceOperation('getfield',
-                                                    [c_p, c_item0], w))
-            if w is not v:
-                block1.operations.append(SpaceOperation('cast_adr_to_ptr',
-                                                        [w], v))
-            reloadedvars.append(v)
-        block1.closeblock(Link(reloadedvars, block2))
-        graph2.startblock = block1
-        #
-        checkgraph(graph)
-        checkgraph(graph2)
-
-
-class AsmStackRootWalker(BaseRootWalker):
-
-    def __init__(self, gctransformer):
-        BaseRootWalker.__init__(self, gctransformer)
-
-        def _asm_callback():
-            self.walk_stack_from()
-        self._asm_callback = _asm_callback
-        self._shape_decompressor = ShapeDecompressor()
-        self._with_jit = hasattr(gctransformer.translator, '_jit2gc')
-        if self._with_jit:
-            jit2gc = gctransformer.translator._jit2gc
-            self.frame_tid = jit2gc['frame_tid']
-        self.gctransformer = gctransformer
-        #
-        # unless overridden in need_thread_support():
-        self.belongs_to_current_thread = lambda framedata: True
-
-    def need_stacklet_support(self, gctransformer, getfn):
-        from rpython.annotator import model as annmodel
-        from rpython.rlib import _stacklet_asmgcc
-        # stacklet support: BIG HACK for rlib.rstacklet
-        _stacklet_asmgcc._asmstackrootwalker = self     # as a global! argh
-        _stacklet_asmgcc.complete_destrptr(gctransformer)
-        #
-        def gc_detach_callback_pieces():
-            anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
-            result = llmemory.NULL
-            framedata = anchor.address[1]
-            while framedata != anchor:
-                next = framedata.address[1]
-                if self.belongs_to_current_thread(framedata):
-                    # detach it
-                    prev = framedata.address[0]
-                    prev.address[1] = next
-                    next.address[0] = prev
-                    # update the global stack counter
-                    rffi.stackcounter.stacks_counter -= 1
-                    # reattach framedata into the singly-linked list 'result'
-                    framedata.address[0] = rffi.cast(llmemory.Address, -1)
-                    framedata.address[1] = result
-                    result = framedata
-                framedata = next
-            return result
-        #
-        def gc_reattach_callback_pieces(pieces):
-            anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
-            while pieces != llmemory.NULL:
-                framedata = pieces
-                pieces = pieces.address[1]
-                # attach 'framedata' into the normal doubly-linked list
-                following = anchor.address[1]
-                following.address[0] = framedata
-                framedata.address[1] = following
-                anchor.address[1] = framedata
-                framedata.address[0] = anchor
-                # update the global stack counter
-                rffi.stackcounter.stacks_counter += 1
-        #
-        s_addr = SomeAddress()
-        s_None = annmodel.s_None
-        self.gc_detach_callback_pieces_ptr = getfn(gc_detach_callback_pieces,
-                                                   [], s_addr)
-        self.gc_reattach_callback_pieces_ptr=getfn(gc_reattach_callback_pieces,
-                                                   [s_addr], s_None)
-
-    def need_thread_support(self, gctransformer, getfn):
-        # Threads supported "out of the box" by the rest of the code.
-        # The whole code in this function is only there to support
-        # fork()ing in a multithreaded process :-(
-        # For this, we need to handle gc_thread_start and gc_thread_die
-        # to record the mapping {thread_id: stack_start}, and
-        # gc_thread_before_fork and gc_thread_after_fork to get rid of
-        # all ASM_FRAMEDATA structures that do no belong to the current
-        # thread after a fork().
-        from rpython.rlib import rthread
-        from rpython.memory.support import AddressDict
-        from rpython.memory.support import copy_without_null_values
-        from rpython.annotator import model as annmodel
-        gcdata = self.gcdata
-
-        def get_aid():
-            """Return the thread identifier, cast to an (opaque) address."""
-            return llmemory.cast_int_to_adr(rthread.get_ident())
-
-        def thread_start():
-            value = llmemory.cast_int_to_adr(llop.stack_current(lltype.Signed))
-            gcdata.aid2stack.setitem(get_aid(), value)
-        thread_start._always_inline_ = True
-
-        def thread_setup():
-            gcdata.aid2stack = AddressDict()
-            gcdata.dead_threads_count = 0
-            # to also register the main thread's stack
-            thread_start()
-        thread_setup._always_inline_ = True
-
-        def thread_die():
-            gcdata.aid2stack.setitem(get_aid(), llmemory.NULL)
-            # from time to time, rehash the dictionary to remove
-            # old NULL entries
-            gcdata.dead_threads_count += 1
-            if (gcdata.dead_threads_count & 511) == 0:
-                copy = copy_without_null_values(gcdata.aid2stack)
-                gcdata.aid2stack.delete()
-                gcdata.aid2stack = copy
-
-        def belongs_to_current_thread(framedata):
-            # xxx obscure: the answer is Yes if, as a pointer, framedata
-            # lies between the start of the current stack and the top of it.
-            stack_start = gcdata.aid2stack.get(get_aid(), llmemory.NULL)
-            ll_assert(stack_start != llmemory.NULL,
-                      "current thread not found in gcdata.aid2stack!")
-            stack_stop = llmemory.cast_int_to_adr(
-                             llop.stack_current(lltype.Signed))
-            return (stack_start <= framedata <= stack_stop or
-                    stack_start >= framedata >= stack_stop)
-        self.belongs_to_current_thread = belongs_to_current_thread
-
-        def thread_before_fork():
-            # before fork(): collect all ASM_FRAMEDATA structures that do
-            # not belong to the current thread, and move them out of the
-            # way, i.e. out of the main circular doubly linked list.
-            detached_pieces = llmemory.NULL
-            anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
-            initialframedata = anchor.address[1]
-            while initialframedata != anchor:   # while we have not looped back
-                if not belongs_to_current_thread(initialframedata):
-                    # Unlink it
-                    prev = initialframedata.address[0]
-                    next = initialframedata.address[1]
-                    prev.address[1] = next
-                    next.address[0] = prev
-                    # Link it to the singly linked list 'detached_pieces'
-                    initialframedata.address[0] = detached_pieces
-                    detached_pieces = initialframedata
-                    rffi.stackcounter.stacks_counter -= 1
-                # Then proceed to the next piece of stack
-                initialframedata = initialframedata.address[1]
-            return detached_pieces
-
-        def thread_after_fork(result_of_fork, detached_pieces):
-            if result_of_fork == 0:
-                # We are in the child process.  Assumes that only the
-                # current thread survived.  All the detached_pieces
-                # are pointers in other stacks, so have likely been
-                # freed already by the multithreaded library.
-                # Nothing more for us to do.
-                pass
-            else:
-                # We are still in the parent process.  The fork() may
-                # have succeeded or not, but that's irrelevant here.
-                # We need to reattach the detached_pieces now, to the
-                # circular doubly linked list at 'gcrootanchor'.  The
-                # order is not important.
-                anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
-                while detached_pieces != llmemory.NULL:
-                    reattach = detached_pieces
-                    detached_pieces = detached_pieces.address[0]
-                    a_next = anchor.address[1]
-                    reattach.address[0] = anchor
-                    reattach.address[1] = a_next
-                    anchor.address[1] = reattach
-                    a_next.address[0] = reattach
-                    rffi.stackcounter.stacks_counter += 1
-
-        self.thread_setup = thread_setup
-        self.thread_start_ptr = getfn(thread_start, [], annmodel.s_None,
-                                      inline=True)
-        self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None)
-        self.thread_before_fork_ptr = getfn(thread_before_fork, [],
-                                            SomeAddress())
-        self.thread_after_fork_ptr = getfn(thread_after_fork,
-                                           [annmodel.SomeInteger(),
-                                            SomeAddress()],
-                                           annmodel.s_None)
-        #
-        # check that the order of the need_*() is correct for us: if we
-        # need both threads and stacklets, need_thread_support() must be
-        # called first, to initialize self.belongs_to_current_thread.
-        assert not hasattr(self, 'gc_detach_callback_pieces_ptr')
-
-    def postprocess_graph(self, gct, graph, any_inlining):
-        pass
-
-    def walk_stack_roots(self, collect_stack_root, is_minor=False):
-        gcdata = self.gcdata
-        gcdata._gc_collect_stack_root = collect_stack_root
-        gcdata._gc_collect_is_minor = is_minor
-        pypy_asm_stackwalk(llhelper(ASM_CALLBACK_PTR, self._asm_callback),
-                           gcrootanchor)
-
-    def walk_stack_from(self):
-        curframe = lltype.malloc(WALKFRAME, flavor='raw')
-        otherframe = lltype.malloc(WALKFRAME, flavor='raw')
-
-        # Walk over all the pieces of stack.  They are in a circular linked
-        # list of structures of 7 words, the 2 first words being prev/next.
-        # The anchor of this linked list is:
-        anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
-        initialframedata = anchor.address[1]
-        stackscount = 0
-        while initialframedata != anchor:     # while we have not looped back
-            self.walk_frames(curframe, otherframe, initialframedata)
-            # Then proceed to the next piece of stack
-            initialframedata = initialframedata.address[1]
-            stackscount += 1
-        #
-        # for the JIT: rpy_fastgil may contain an extra framedata
-        rpy_fastgil = rgil.gil_fetch_fastgil().signed[0]
-        if rpy_fastgil != 1:
-            ll_assert(rpy_fastgil != 0, "walk_stack_from doesn't have the GIL")
-            initialframedata = rffi.cast(llmemory.Address, rpy_fastgil)
-            #
-            # very rare issue: initialframedata.address[0] is uninitialized
-            # in this case, but "retaddr = callee.frame_address.address[0]"
-            # reads it.  If it happens to be exactly a valid return address
-            # inside the C code, then bad things occur.
-            initialframedata.address[0] = llmemory.NULL
-            #
-            self.walk_frames(curframe, otherframe, initialframedata)
-            stackscount += 1
-        #
-        expected = rffi.stackcounter.stacks_counter
-        if NonConstant(0):
-            rffi.stackcounter.stacks_counter += 42    # hack to force it
-        ll_assert(not (stackscount < expected), "non-closed stacks around")
-        ll_assert(not (stackscount > expected), "stacks counter corruption?")
-        lltype.free(otherframe, flavor='raw')
-        lltype.free(curframe, flavor='raw')
-
-    def walk_frames(self, curframe, otherframe, initialframedata):
-        self.fill_initial_frame(curframe, initialframedata)
-        # Loop over all the frames in the stack
-        while self.walk_to_parent_frame(curframe, otherframe):
-            swap = curframe
-            curframe = otherframe    # caller becomes callee
-            otherframe = swap
-
-    def fill_initial_frame(self, curframe, initialframedata):
-        # Read the information provided by initialframedata
-        initialframedata += 2*sizeofaddr #skip the prev/next words at the start
-        reg = 0
-        while reg < CALLEE_SAVED_REGS:
-            # NB. 'initialframedata' stores the actual values of the
-            # registers %ebx etc., and if these values are modified
-            # they are reloaded by pypy_asm_stackwalk().  By contrast,
-            # 'regs_stored_at' merely points to the actual values
-            # from the 'initialframedata'.
-            curframe.regs_stored_at[reg] = initialframedata + reg*sizeofaddr
-            reg += 1
-        curframe.frame_address = initialframedata.address[CALLEE_SAVED_REGS]
-
-    def walk_to_parent_frame(self, callee, caller):
-        """Starting from 'callee', walk the next older frame on the stack
-        and fill 'caller' accordingly.  Also invokes the collect_stack_root()
-        callback from the GC code for each GC root found in 'caller'.
-        """
-        #
-        # The gcmap table is a list of entries, two machine words each:
-        #     void *SafePointAddress;
-        #     int Shape;
-        #
-        # A "safe point" is the return address of a call.
-        # The "shape" of a safe point is a list of integers
-        # that represent "locations".  A "location" can be
-        # either in the stack or in a register.  See
-        # getlocation() for the decoding of this integer.
-        # The locations stored in a "shape" are as follows:
-        #
-        #   * The "location" of the return address.  This is just
-        #     after the end of the frame of 'callee'; it is the
-        #     first word of the frame of 'caller' (see picture
-        #     below).
-        #
-        #   * Four "locations" that specify where the function saves
-        #     each of the four callee-saved registers (%ebx, %esi,
-        #     %edi, %ebp).
-        #
-        #   * The number of live GC roots around the call.
-        #
-        #   * For each GC root, an integer that specify where the
-        #     GC pointer is stored.  This is a "location" too.
-        #
-        # XXX the details are completely specific to X86!!!
-        # a picture of the stack may help:
-        #                                           ^ ^ ^
-        #     |     ...      |                 to older frames
-        #     +--------------+
-        #     |   ret addr   |  <------ caller_frame (addr of retaddr)
-        #     |     ...      |
-        #     | caller frame |
-        #     |     ...      |
-        #     +--------------+
-        #     |   ret addr   |  <------ callee_frame (addr of retaddr)
-        #     |     ...      |
-        #     | callee frame |
-        #     |     ...      |                 lower addresses
-        #     +--------------+                      v v v
-        #
-
-        retaddr = callee.frame_address.address[0]
-        #
-        # try to locate the caller function based on retaddr.
-        # set up self._shape_decompressor.
-        #
-        ebp_in_caller = callee.regs_stored_at[INDEX_OF_EBP].address[0]
-        self.locate_caller_based_on_retaddr(retaddr, ebp_in_caller)
-        #
-        # found!  Enumerate the GC roots in the caller frame
-        #
-        collect_stack_root = self.gcdata._gc_collect_stack_root
-        gc = self.gc
-        while True:
-            location = self._shape_decompressor.next()
-            if location == 0:
-                break
-            addr = self.getlocation(callee, ebp_in_caller, location)
-            if gc.points_to_valid_gc_object(addr):
-                collect_stack_root(gc, addr)
-        #
-        # small hack: the JIT reserves THREADLOCAL_OFS's last bit for
-        # us.  We use it to store an "already traced past this frame"
-        # flag.
-        if self._with_jit and self.gcdata._gc_collect_is_minor:
-            if self.mark_jit_frame_can_stop(callee):
-                return False
-        #
-        # track where the caller_frame saved the registers from its own
-        # caller
-        #
-        reg = CALLEE_SAVED_REGS - 1
-        while reg >= 0:
-            location = self._shape_decompressor.next()
-            addr = self.getlocation(callee, ebp_in_caller, location)
-            caller.regs_stored_at[reg] = addr
-            reg -= 1
-
-        location = self._shape_decompressor.next()
-        caller.frame_address = self.getlocation(callee, ebp_in_caller,
-                                                location)
-        # we get a NULL marker to mean "I'm the frame
-        # of the entry point, stop walking"
-        return caller.frame_address != llmemory.NULL
-
-    def locate_caller_based_on_retaddr(self, retaddr, ebp_in_caller):
-        gcmapstart = llop.gc_asmgcroot_static(llmemory.Address, 0)
-        gcmapend   = llop.gc_asmgcroot_static(llmemory.Address, 1)
-        item = search_in_gcmap(gcmapstart, gcmapend, retaddr)
-        if item:
-            self._shape_decompressor.setpos(item.signed[1])
-            return
-
-        if not self._shape_decompressor.sorted:
-            # the item may have been not found because the main array was
-            # not sorted.  Sort it and try again.
-            win32_follow_gcmap_jmp(gcmapstart, gcmapend)
-            sort_gcmap(gcmapstart, gcmapend)
-            self._shape_decompressor.sorted = True
-            item = search_in_gcmap(gcmapstart, gcmapend, retaddr)
-            if item:
-                self._shape_decompressor.setpos(item.signed[1])
-                return
-
-        if self._with_jit:
-            # item not found.  We assume that it's a JIT-generated
-            # location -- but we check for consistency that ebp points
-            # to a JITFRAME object.
-            from rpython.jit.backend.llsupport.jitframe import STACK_DEPTH_OFS
-
-            tid = self.gc.get_possibly_forwarded_type_id(ebp_in_caller)
-            if (rffi.cast(lltype.Signed, tid) ==
-                    rffi.cast(lltype.Signed, self.frame_tid)):
-                # fish the depth
-                extra_stack_depth = (ebp_in_caller + STACK_DEPTH_OFS).signed[0]
-                ll_assert((extra_stack_depth & (rffi.sizeof(lltype.Signed) - 
1))
-                           == 0, "asmgcc: misaligned extra_stack_depth")
-                extra_stack_depth //= rffi.sizeof(lltype.Signed)
-                self._shape_decompressor.setjitframe(extra_stack_depth)
-                return
-        llop.debug_fatalerror(lltype.Void, "cannot find gc roots!")
-
-    def getlocation(self, callee, ebp_in_caller, location):
-        """Get the location in the 'caller' frame of a variable, based
-        on the integer 'location' that describes it.  All locations are
-        computed based on information saved by the 'callee'.
-        """
-        ll_assert(location >= 0, "negative location")
-        kind = location & LOC_MASK
-        offset = location & ~ LOC_MASK
-        if IS_64_BITS:
-            offset <<= 1
-        if kind == LOC_REG:   # register
-            if location == LOC_NOWHERE:
-                return llmemory.NULL
-            reg = (location >> 2) - 1
-            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 + sizeofaddr
-            return esp_in_caller + offset
-        elif kind == LOC_EBP_PLUS:    # in the caller stack frame at N(%ebp)
-            return ebp_in_caller + offset
-        else:  # kind == LOC_EBP_MINUS:   at -N(%ebp)
-            return ebp_in_caller - offset
-
-    def mark_jit_frame_can_stop(self, callee):
-        location = self._shape_decompressor.get_threadlocal_loc()
-        if location == LOC_NOWHERE:
-            return False
-        addr = self.getlocation(callee, llmemory.NULL, location)
-        #
-        x = addr.signed[0]
-        if x & 1:
-            return True            # this JIT stack frame is already marked!
-        else:
-            addr.signed[0] = x | 1    # otherwise, mark it but don't stop
-            return False
-
-
-LOC_REG       = 0
-LOC_ESP_PLUS  = 1
-LOC_EBP_PLUS  = 2
-LOC_EBP_MINUS = 3
-LOC_MASK      = 0x03
-LOC_NOWHERE   = LOC_REG | 0
-
-# ____________________________________________________________
-
-sizeofaddr = llmemory.sizeof(llmemory.Address)
-arrayitemsize = 2 * sizeofaddr
-
-
-def binary_search(start, end, addr1):
-    """Search for an element in a sorted array.
-
-    The interval from the start address (included) to the end address
-    (excluded) is assumed to be a sorted arrays of pairs (addr1, addr2).
-    This searches for the item with a given addr1 and returns its
-    address.  If not found exactly, it tries to return the address
-    of the item left of addr1 (i.e. such that result.address[0] < addr1).
-    """
-    count = (end - start) // arrayitemsize
-    while count > 1:
-        middleindex = count // 2
-        middle = start + middleindex * arrayitemsize
-        if addr1 < middle.address[0]:
-            count = middleindex
-        else:
-            start = middle
-            count -= middleindex
-    return start
-
-def search_in_gcmap(gcmapstart, gcmapend, retaddr):
-    item = binary_search(gcmapstart, gcmapend, retaddr)
-    if item.address[0] == retaddr:
-        return item     # found
-    # 'retaddr' not exactly found.  Check that 'item' is the start of a
-    # compressed range that includes 'retaddr'.
-    if retaddr > item.address[0] and item.signed[1] < 0:
-        return item     # ok
-    else:
-        return llmemory.NULL    # failed
-
-def search_in_gcmap2(gcmapstart, gcmapend, retaddr):
-    # same as 'search_in_gcmap', but without range checking support
-    # (item.signed[1] is an address in this case, not a signed at all!)
-    item = binary_search(gcmapstart, gcmapend, retaddr)
-    if item.address[0] == retaddr:
-        return item.address[1]     # found
-    else:
-        return llmemory.NULL    # failed
-
-def sort_gcmap(gcmapstart, gcmapend):
-    count = (gcmapend - gcmapstart) // arrayitemsize
-    qsort(gcmapstart,
-          rffi.cast(rffi.SIZE_T, count),
-          rffi.cast(rffi.SIZE_T, arrayitemsize),
-          c_compare_gcmap_entries)
-
-def replace_dead_entries_with_nulls(start, end):
-    # replace the dead entries (null value) with a null key.
-    count = (end - start) // arrayitemsize - 1
-    while count >= 0:
-        item = start + count * arrayitemsize
-        if item.address[1] == llmemory.NULL:
-            item.address[0] = llmemory.NULL
-        count -= 1
-
-if sys.platform == 'win32':
-    def win32_follow_gcmap_jmp(start, end):
-        # The initial gcmap table contains addresses to a JMP
-        # instruction that jumps indirectly to the real code.
-        # Replace them with the target addresses.
-        assert rffi.SIGNEDP is rffi.LONGP, "win64 support missing"
-        while start < end:
-            code = rffi.cast(rffi.CCHARP, start.address[0])[0]
-            if code == '\xe9': # jmp
-                rel32 = rffi.cast(rffi.SIGNEDP, start.address[0]+1)[0]
-                target = start.address[0] + (rel32 + 5)
-                start.address[0] = target
-            start += arrayitemsize
-else:
-    def win32_follow_gcmap_jmp(start, end):
-        pass
-
-# ____________________________________________________________
-
-class ShapeDecompressor:
-    _alloc_flavor_ = "raw"
-
-    sorted = False
-
-    def setpos(self, pos):
-        if pos < 0:
-            pos = ~ pos     # can ignore this "range" marker here
-        gccallshapes = llop.gc_asmgcroot_static(llmemory.Address, 2)
-        self.addr = gccallshapes + pos
-        self.jit_index = -1
-
-    def setjitframe(self, extra_stack_depth):
-        self.jit_index = 0
-        self.extra_stack_depth = extra_stack_depth
-
-    def next(self):
-        index = self.jit_index
-        if index < 0:
-            # case "outside the jit"
-            addr = self.addr
-            value = 0
-            while True:
-                b = ord(addr.char[0])
-                addr += 1
-                value += b
-                if b < 0x80:
-                    break
-                value = (value - 0x80) << 7
-            self.addr = addr
-            return value
-        else:
-            # case "in the jit"
-            from rpython.jit.backend.x86.arch import FRAME_FIXED_SIZE
-            from rpython.jit.backend.x86.arch import PASS_ON_MY_FRAME
-            self.jit_index = index + 1
-            if index == 0:
-                # the jitframe is an object in EBP
-                return LOC_REG | ((INDEX_OF_EBP + 1) << 2)
-            if index == 1:
-                return 0
-            # the remaining returned values should be:
-            #      saved %rbp
-            #      saved %r15           or on 32bit:
-            #      saved %r14             saved %ebp
-            #      saved %r13             saved %edi
-            #      saved %r12             saved %esi
-            #      saved %rbx             saved %ebx
-            #      return addr            return addr
-            stack_depth = PASS_ON_MY_FRAME + self.extra_stack_depth
-            if IS_64_BITS:
-                if index == 2:   # rbp
-                    return LOC_ESP_PLUS | (stack_depth << 2)
-                if index == 3:   # r15
-                    return LOC_ESP_PLUS | ((stack_depth + 5) << 2)
-                if index == 4:   # r14
-                    return LOC_ESP_PLUS | ((stack_depth + 4) << 2)
-                if index == 5:   # r13
-                    return LOC_ESP_PLUS | ((stack_depth + 3) << 2)
-                if index == 6:   # r12
-                    return LOC_ESP_PLUS | ((stack_depth + 2) << 2)
-                if index == 7:   # rbx
-                    return LOC_ESP_PLUS | ((stack_depth + 1) << 2)
-                if index == 8:   # return addr
-                    return (LOC_ESP_PLUS |
-                        ((FRAME_FIXED_SIZE + self.extra_stack_depth) << 2))
-            else:
-                if index == 2:   # ebp
-                    return LOC_ESP_PLUS | (stack_depth << 2)
-                if index == 3:   # edi
-                    return LOC_ESP_PLUS | ((stack_depth + 3) << 2)
-                if index == 4:   # esi
-                    return LOC_ESP_PLUS | ((stack_depth + 2) << 2)
-                if index == 5:   # ebx
-                    return LOC_ESP_PLUS | ((stack_depth + 1) << 2)
-                if index == 6:   # return addr
-                    return (LOC_ESP_PLUS |
-                        ((FRAME_FIXED_SIZE + self.extra_stack_depth) << 2))
-            llop.debug_fatalerror(lltype.Void, "asmgcroot: invalid index")
-            return 0   # annotator fix
-
-    def get_threadlocal_loc(self):
-        index = self.jit_index
-        if index < 0:
-            return LOC_NOWHERE     # case "outside the jit"
-        else:
-            # case "in the jit"
-            from rpython.jit.backend.x86.arch import THREADLOCAL_OFS, WORD
-            return (LOC_ESP_PLUS |
-                    ((THREADLOCAL_OFS // WORD + self.extra_stack_depth) << 2))
-
-
-# ____________________________________________________________
-
-#
-# The special pypy_asm_stackwalk(), implemented directly in
-# assembler, fills information about the current stack top in an
-# ASM_FRAMEDATA array and invokes an RPython callback with it.
-# An ASM_FRAMEDATA is an array of 5 values that describe everything
-# we need to know about a stack frame:
-#
-#   - the value that %ebx had when the current function started
-#   - the value that %esi had when the current function started
-#   - the value that %edi had when the current function started
-#   - the value that %ebp had when the current function started
-#   - frame address (actually the addr of the retaddr of the current function;
-#                    that's the last word of the frame in memory)
-#
-# On 64 bits, it is an array of 7 values instead of 5:
-#
-#   - %rbx, %r12, %r13, %r14, %r15, %rbp; and the frame address
-#
-
-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
-
-JIT_USE_WORDS = 2 + FRAME_PTR + 1
-
-ASM_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([], lltype.Void))
-
-# used internally by walk_stack_from()
-WALKFRAME = lltype.Struct('WALKFRAME',
-        ('regs_stored_at',    # address of where the registers have been saved
-             lltype.FixedSizeArray(llmemory.Address, CALLEE_SAVED_REGS)),
-        ('frame_address',
-             llmemory.Address),
-    )
-
-# We have a circular doubly-linked list of all the ASM_FRAMEDATAs currently
-# alive.  The list's starting point is given by 'gcrootanchor', which is not
-# a full ASM_FRAMEDATA but only contains the prev/next pointers:
-ASM_FRAMEDATA_HEAD_PTR = lltype.Ptr(lltype.ForwardReference())
-ASM_FRAMEDATA_HEAD_PTR.TO.become(lltype.Struct('ASM_FRAMEDATA_HEAD',
-        ('prev', ASM_FRAMEDATA_HEAD_PTR),
-        ('next', ASM_FRAMEDATA_HEAD_PTR)
-    ))
-gcrootanchor = lltype.malloc(ASM_FRAMEDATA_HEAD_PTR.TO, immortal=True)
-gcrootanchor.prev = gcrootanchor
-gcrootanchor.next = gcrootanchor
-c_gcrootanchor = Constant(gcrootanchor, ASM_FRAMEDATA_HEAD_PTR)
-
-eci = ExternalCompilationInfo(compile_extra=['-DPYPY_USE_ASMGCC'],
-                              post_include_bits=["""
-static int pypy_compare_gcmap_entries(const void *addr1, const void *addr2)
-{
-    char *key1 = * (char * const *) addr1;
-    char *key2 = * (char * const *) addr2;
-    if (key1 < key2)
-        return -1;
-    else if (key1 == key2)
-        return 0;
-    else
-        return 1;
-}
-"""])
-
-pypy_asm_stackwalk = rffi.llexternal('pypy_asm_stackwalk',
-                                     [ASM_CALLBACK_PTR,
-                                      ASM_FRAMEDATA_HEAD_PTR],
-                                     lltype.Signed,
-                                     sandboxsafe=True,
-                                     _nowrapper=True,
-                                     random_effects_on_gcobjs=True,
-                                     compilation_info=eci)
-c_asm_stackwalk = Constant(pypy_asm_stackwalk,
-                           lltype.typeOf(pypy_asm_stackwalk))
-
-pypy_asm_gcroot = rffi.llexternal('pypy_asm_gcroot',
-                                  [llmemory.Address],
-                                  llmemory.Address,
-                                  sandboxsafe=True,
-                                  _nowrapper=True)
-c_asm_gcroot = Constant(pypy_asm_gcroot, lltype.typeOf(pypy_asm_gcroot))
-
-pypy_asm_nocollect = rffi.llexternal('pypy_asm_gc_nocollect',
-                                     [rffi.CCHARP], lltype.Void,
-                                     sandboxsafe=True,
-                                     _nowrapper=True)
-c_asm_nocollect = Constant(pypy_asm_nocollect, 
lltype.typeOf(pypy_asm_nocollect))
-
-QSORT_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([llmemory.Address,
-                                                 llmemory.Address], rffi.INT))
-c_compare_gcmap_entries = rffi.llexternal('pypy_compare_gcmap_entries',
-                                          [llmemory.Address, llmemory.Address],
-                                          rffi.INT, compilation_info=eci,
-                                          _nowrapper=True, sandboxsafe=True)
-qsort = rffi.llexternal('qsort',
-                        [llmemory.Address,
-                         rffi.SIZE_T,
-                         rffi.SIZE_T,
-                         QSORT_CALLBACK_PTR],
-                        lltype.Void,
-                        sandboxsafe=True,
-                        random_effects_on_gcobjs=False,  # but has a callback
-                        _nowrapper=True)
diff --git a/rpython/memory/gctransform/framework.py 
b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -1003,21 +1003,6 @@
         # for stacklet
         hop.genop("direct_call", 
[self.root_walker.gc_modified_shadowstack_ptr])
 
-    def gct_gc_detach_callback_pieces(self, hop):
-        op = hop.spaceop
-        assert len(op.args) == 0
-        hop.genop("direct_call",
-                  [self.root_walker.gc_detach_callback_pieces_ptr],
-                  resultvar=op.result)
-
-    def gct_gc_reattach_callback_pieces(self, hop):
-        op = hop.spaceop
-        assert len(op.args) == 1
-        hop.genop("direct_call",
-                  [self.root_walker.gc_reattach_callback_pieces_ptr,
-                   op.args[0]],
-                  resultvar=op.result)
-
     def gct_do_malloc_fixedsize(self, hop):
         # used by the JIT (see rpython.jit.backend.llsupport.gc)
         op = hop.spaceop
@@ -1244,8 +1229,10 @@
 
     def gct_gc_thread_start(self, hop):
         assert self.translator.config.translation.thread
+        # There is no 'thread_start_ptr' any more for now, so the following
+        # line is always false.
         if hasattr(self.root_walker, 'thread_start_ptr'):
-            # only with asmgcc.  Note that this is actually called after
+            # Note that this is actually called after
             # the first gc_thread_run() in the new thread.
             hop.genop("direct_call", [self.root_walker.thread_start_ptr])
 
diff --git a/rpython/memory/gctransform/transform.py 
b/rpython/memory/gctransform/transform.py
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -217,9 +217,6 @@
         self.var_last_needed_in = None
         self.curr_block = None
 
-    def start_transforming_graph(self, graph):
-        pass    # for asmgcc.py
-
     def transform_graph(self, graph):
         if graph in self.minimal_transform:
             if self.minimalgctransformer:
@@ -229,7 +226,6 @@
         if graph in self.seen_graphs:
             return
         self.seen_graphs.add(graph)
-        self.start_transforming_graph(graph)
 
         self.links_to_split = {} # link -> vars to pop_alive across the link
 
diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py
deleted file mode 100644
--- a/rpython/rlib/_stacklet_asmgcc.py
+++ /dev/null
@@ -1,325 +0,0 @@
-from rpython.rlib.debug import ll_assert
-from rpython.rlib import rgc
-from rpython.rlib.objectmodel import specialize
-from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
-from rpython.rtyper.lltypesystem.lloperation import llop
-from rpython.rtyper.annlowlevel import llhelper, MixLevelHelperAnnotator
-from rpython.annotator import model as annmodel
-from rpython.rtyper.llannotation import lltype_to_annotation
-from rpython.rlib import _rffi_stacklet as _c
-
-
-_asmstackrootwalker = None    # BIG HACK: monkey-patched by asmgcroot.py
-_stackletrootwalker = None
-
-def get_stackletrootwalker():
-    # XXX this is too complicated now; we don't need a StackletRootWalker
-    # instance to store global state.  We could rewrite it all in one big
-    # function.  We don't care enough for now.
-
-    # lazily called, to make the following imports lazy
-    global _stackletrootwalker
-    if _stackletrootwalker is not None:
-        return _stackletrootwalker
-
-    from rpython.memory.gctransform.asmgcroot import (
-        WALKFRAME, CALLEE_SAVED_REGS, INDEX_OF_EBP, sizeofaddr)
-
-    assert _asmstackrootwalker is not None, "should have been monkey-patched"
-    basewalker = _asmstackrootwalker
-
-    class StackletRootWalker(object):
-        _alloc_flavor_ = "raw"
-
-        def setup(self, obj):
-            # initialization: read the SUSPSTACK object
-            p = llmemory.cast_adr_to_ptr(obj, lltype.Ptr(SUSPSTACK))
-            if not p.handle:
-                return False
-            self.context = llmemory.cast_ptr_to_adr(p.handle)
-            self.next_callback_piece = p.callback_pieces
-            anchor = p.anchor
-            del p
-            self.curframe = lltype.malloc(WALKFRAME, flavor='raw')
-            self.otherframe = lltype.malloc(WALKFRAME, flavor='raw')
-            self.fill_initial_frame(self.curframe, anchor)
-            return True
-
-        def fill_initial_frame(self, curframe, initialframedata):
-            # Copy&paste :-(
-            initialframedata += 2*sizeofaddr
-            reg = 0
-            while reg < CALLEE_SAVED_REGS:
-                curframe.regs_stored_at[reg] = initialframedata+reg*sizeofaddr
-                reg += 1
-            retaddraddr = initialframedata + CALLEE_SAVED_REGS * sizeofaddr
-            retaddraddr = self.translateptr(retaddraddr)
-            curframe.frame_address = retaddraddr.address[0]
-
-        def fetch_next_stack_piece(self):
-            if self.next_callback_piece == llmemory.NULL:
-                lltype.free(self.curframe, flavor='raw')
-                lltype.free(self.otherframe, flavor='raw')
-                self.context = llmemory.NULL
-                return False
-            else:
-                anchor = self.next_callback_piece
-                nextaddr = anchor + sizeofaddr
-                nextaddr = self.translateptr(nextaddr)
-                self.next_callback_piece = nextaddr.address[0]
-                self.fill_initial_frame(self.curframe, anchor)
-                return True
-
-        @specialize.arg(3)
-        def customtrace(self, gc, obj, callback, arg):
-            #
-            # Pointers to the stack can be "translated" or not:
-            #
-            #   * Non-translated pointers point to where the data would be
-            #     if the stack was installed and running.
-            #
-            #   * Translated pointers correspond to where the data
-            #     is now really in memory.
-            #
-            # Note that 'curframe' contains non-translated pointers, and
-            # of course the stack itself is full of non-translated pointers.
-            #
-            if not self.setup(obj):
-                return
-
-            while True:
-                callee = self.curframe
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to