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