[pypy-commit] pypy default: Fix for 'rpy_fastgil' on shadowstack: see comments
arigo
noreply at buildbot.pypy.org
Sat Aug 23 22:18:29 CEST 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r73015:8357f0cf25ea
Date: 2014-08-23 22:18 +0200
http://bitbucket.org/pypy/pypy/changeset/8357f0cf25ea/
Log: Fix for 'rpy_fastgil' on shadowstack: see comments
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
@@ -1066,13 +1066,16 @@
cb = callbuilder.CallBuilder(self, fnloc, arglocs)
cb.emit_no_collect()
- def _reload_frame_if_necessary(self, mc, align_stack=False):
+ def _reload_frame_if_necessary(self, mc, align_stack=False,
+ shadowstack_reg=None):
gcrootmap = self.cpu.gc_ll_descr.gcrootmap
if gcrootmap:
if gcrootmap.is_shadow_stack:
- rst = gcrootmap.get_root_stack_top_addr()
- mc.MOV(ecx, heap(rst))
- mc.MOV(ebp, mem(ecx, -WORD))
+ if shadowstack_reg is None:
+ rst = gcrootmap.get_root_stack_top_addr()
+ mc.MOV(ecx, heap(rst))
+ shadowstack_reg = ecx
+ mc.MOV(ebp, mem(shadowstack_reg, -WORD))
wbdescr = self.cpu.gc_ll_descr.write_barrier_descr
if gcrootmap and wbdescr:
# frame never uses card marking, so we enforce this is not
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
@@ -1,6 +1,7 @@
import sys
from rpython.rlib.clibffi import FFI_DEFAULT_ABI
from rpython.rlib.objectmodel import we_are_translated
+from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.jit.metainterp.history import INT, FLOAT
from rpython.jit.backend.x86.arch import (WORD, IS_X86_64, IS_X86_32,
PASS_ON_MY_FRAME, FRAME_FIXED_SIZE)
@@ -21,6 +22,8 @@
def align_stack_words(words):
return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1)
+NO_ARG_FUNC_PTR = lltype.Ptr(lltype.FuncType([], lltype.Void))
+
class CallBuilderX86(AbstractCallBuilder):
@@ -87,13 +90,50 @@
self.asm.push_gcmap(self.mc, gcmap, store=True)
def pop_gcmap(self):
- self.asm._reload_frame_if_necessary(self.mc)
+ ssreg = None
+ gcrootmap = self.asm.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap:
+ if gcrootmap.is_shadow_stack and self.is_call_release_gil:
+ from rpython.jit.backend.x86.assembler import heap
+ from rpython.jit.backend.x86 import rx86
+ from rpython.rtyper.lltypesystem.lloperation import llop
+ #
+ # When doing a call_release_gil with shadowstack, there
+ # is the risk that the 'rpy_fastgil' was free but the
+ # current shadowstack can be the one of a different
+ # thread. So here we check if the shadowstack pointer
+ # is still the same as before we released the GIL (saved
+ # in 'ebx'), and if not, we call 'thread_run'.
+ rst = gcrootmap.get_root_stack_top_addr()
+ mc = self.mc
+ mc.CMP(ebx, heap(rst))
+ mc.J_il8(rx86.Conditions['E'], 0)
+ je_location = mc.get_relative_pos()
+ # call 'thread_run'
+ t_run = llop.gc_thread_run_ptr(NO_ARG_FUNC_PTR)
+ mc.CALL(imm(rffi.cast(lltype.Signed, t_run)))
+ # patch the JE above
+ offset = mc.get_relative_pos() - je_location
+ assert 0 < offset <= 127
+ mc.overwrite(je_location-1, chr(offset))
+ 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)
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
+ #
+ # Save this thread's shadowstack pointer into 'ebx',
+ # for later comparison
+ gcrootmap = self.asm.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap:
+ if gcrootmap.is_shadow_stack:
+ 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
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
@@ -977,6 +977,12 @@
hop.genop("direct_call", [self.root_walker.thread_run_ptr])
self.pop_roots(hop, livevars)
+ def gct_gc_thread_run_ptr(self, hop):
+ assert self.translator.config.translation.thread
+ assert hasattr(self.root_walker, 'thread_run_ptr')
+ hop.genop("same_as", [self.root_walker.thread_run_ptr],
+ resultvar=hop.spaceop.result)
+
def gct_gc_thread_start(self, hop):
assert self.translator.config.translation.thread
if hasattr(self.root_walker, 'thread_start_ptr'):
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -473,6 +473,7 @@
'gc_set_max_heap_size': LLOp(),
'gc_can_move' : LLOp(sideeffects=False),
'gc_thread_run' : LLOp(),
+ 'gc_thread_run_ptr' : LLOp(sideeffects=False),
'gc_thread_start' : LLOp(),
'gc_thread_die' : LLOp(),
'gc_thread_before_fork':LLOp(), # returns an opaque address
More information about the pypy-commit
mailing list