[pypy-svn] r50290 - in pypy/branch/asmgcroot/pypy: rpython/memory/gctransform translator/c
arigo at codespeak.net
arigo at codespeak.net
Thu Jan 3 17:36:57 CET 2008
Author: arigo
Date: Thu Jan 3 17:36:56 2008
New Revision: 50290
Modified:
pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/asmgcroot.py
pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/framework.py
pypy/branch/asmgcroot/pypy/translator/c/trackgcroot.py
Log:
Invoke the GC root walking via a callback. This allows us to
save and restore all the callee-saved registers into the stack
at a single clear place: pypy_asm_stackwalk().
Modified: pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/asmgcroot.py
==============================================================================
--- pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/asmgcroot.py (original)
+++ pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/asmgcroot.py Thu Jan 3 17:36:56 2008
@@ -1,8 +1,8 @@
from pypy.rpython.memory.gctransform.framework import FrameworkGCTransformer
+from pypy.rpython.memory.gctransform.framework import BaseRootWalker
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython import rmodel
-from pypy.rpython.rbuiltin import gen_cast
+from pypy.rpython.annlowlevel import llhelper
from pypy.rlib.debug import ll_assert
@@ -29,170 +29,174 @@
hop.genop("asm_gcroot", [var])
def build_root_walker(self):
- gcdata = self.gcdata
- gc = gcdata.gc
+ return AsmStackRootWalker(self)
+
+
+class AsmStackRootWalker(BaseRootWalker):
+
+ def __init__(self, gctransformer):
+ BaseRootWalker.__init__(self, gctransformer)
+
+ def _asm_callback(initialframedata):
+ self.walk_stack_from(initialframedata)
+ self._asm_callback = _asm_callback
+
+ def setup_root_walker(self):
+ # The gcmap table is a list of pairs of pointers:
+ # void *SafePointAddress;
+ # void *Shape;
+ # Here, i.e. when the program starts, we sort it
+ # in-place on the SafePointAddress to allow for more
+ # efficient searches.
+ gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
+ gcmapend = llop.llvm_gcmapend(llmemory.Address)
+ insertion_sort(gcmapstart, gcmapend)
- class RootWalker:
- _alloc_flavor_ = 'raw'
+ def walk_stack_roots(self, collect_stack_root):
+ gcdata = self.gcdata
+ gcdata._gc_collect_stack_root = collect_stack_root
+ pypy_asm_stackwalk(llhelper(ASM_CALLBACK_PTR, self._asm_callback))
- def setup_root_stack(self):
- # The gcmap table is a list of pairs of pointers:
- # void *SafePointAddress;
- # void *Shape;
- # Here, i.e. when the program starts, we sort it
- # in-place on the SafePointAddress to allow for more
- # efficient searches.
- gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
- gcmapend = llop.llvm_gcmapend(llmemory.Address)
- insertion_sort(gcmapstart, gcmapend)
-
- need_root_stack = False
-
- def append_static_root(adr):
- gcdata.static_root_end.address[0] = adr
- gcdata.static_root_end += sizeofaddr
- append_static_root = staticmethod(append_static_root)
-
- def walk_roots(self, collect_stack_root,
- collect_static_in_prebuilt_nongc,
- collect_static_in_prebuilt_gc,
- collect_finished):
- ...
- self.callee_data = lltype.malloc(ASM_STACKWALK, flavor="raw")
- self.caller_data = lltype.malloc(ASM_STACKWALK, flavor="raw")
- pypy_asm_stackwalk_init(self.caller_data)
- self.remaining_roots_in_current_frame = 0
- # We must walk at least a couple of frames up the stack
- # *now*, i.e. before we leave __init__, otherwise
- # the caller_data ends up pointing to a dead frame.
- # We can walk until we find a real GC root; then we're
- # definitely out of the GC code itself.
- while self.remaining_roots_in_current_frame == 0:
- if not self.walk_to_parent_frame():
- break # not a single GC root? unlikely but not
- # impossible I guess
- if with_static:
- self.static_current = gcdata.static_root_end
- else:
- self.static_current = gcdata.static_root_nongcend
-
- def pop(self):
- while self.static_current != gcdata.static_root_start:
- self.static_current -= sizeofaddr
- result = self.static_current.address[0]
- if result.address[0] != llmemory.NULL:
- return result
-
- while True:
- while self.remaining_roots_in_current_frame == 0:
- if not self.walk_to_parent_frame():
- return llmemory.NULL
- result = self.next_gcroot_from_current_frame()
- if result.address[0] != llmemory.NULL:
- return result
-
- def walk_to_parent_frame(self):
- if not self.caller_data:
- return False
- #
- # The gcmap table is a list of pairs of pointers:
- # void *SafePointAddress;
- # void *Shape;
- #
- # A "safe point" is the return address of a call.
- # The "shape" of a safe point is a list of integers
- # as follows:
- #
- # * The size of the frame of the function containing the
- # call (in theory it can be different from call to call).
- # This size includes the return address (see picture
- # below).
- #
- # * Four integers that specify where the function saves
- # each of the four callee-saved registers (%ebx, %esi,
- # %edi, %ebp). This is a "location", see below.
- #
- # * 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", see below.
- #
- # A "location" can be either in the stack or in a register.
- # If it is in the stack, it is specified as an integer offset
- # from the current frame (so it is typically < 0, as seen
- # in the picture below, though it can also be > 0 if the
- # location is an input argument to the current function and
- # thus lives at the bottom of the caller's frame).
- # A "location" can also be in a register; in our context it
- # can only be a callee-saved register. This is specified
- # as a small odd-valued integer (1=%ebx, 3=%esi, etc.)
-
- # In the code below, we walk the next older frame on the stack.
- # The caller becomes the callee; we swap the two buffers and
- # fill in the new caller's data.
- callee = self.caller_data
- caller = self.callee_data
- self.caller_data = caller
- self.callee_data = callee
- #
- # 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
- #
- callee_frame = callee[FRAME_PTR]
- retaddr = callee[RET_ADDR]
- #
- # try to locate the caller function based on retaddr.
- #
- gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
- gcmapend = llop.llvm_gcmapend(llmemory.Address)
- item = binary_search(gcmapstart, gcmapend, retaddr)
- if item.address[0] != retaddr:
- # retaddr not found!
- llop.debug_fatalerror(lltype.Void, "cannot find gc roots!")
- return False
-
- # found! Now we can fill in 'caller'.
- shape = item.address[1]
- framesize = shape.signed[0]
- caller[FRAME_PTR] = callee_frame + framesize
- caller[RET_ADDR] = caller[FRAME_PTR].address[0]
- reg = 0
- while reg < CALLEE_SAVED_REGS:
- caller[reg] = self.read_from_location(shape.signed[1+reg])
- reg += 1
- livecount = shape.signed[1+CALLEE_SAVED_REGS]
- self.remaining_roots_in_current_frame = livecount
- self.liveoffsets = shape + 4 * (1+CALLEE_SAVED_REGS+1)
- return True
-
- def finished(self):
- lltype.free(self.stackwalkcur, flavor='raw')
- self.stackwalkcur = lltype.nullptr(ASM_STACKWALK)
- lltype.free(self.stackwalknext, flavor='raw')
- self.stackwalknext = lltype.nullptr(ASM_STACKWALK)
-
- def next_gcroot_from_current_frame(self):
- i = self.remaining_roots_in_current_frame - 1
- self.remaining_roots_in_current_frame = i
- ll_assert(i >= 0, "bad call to next_gcroot_from_current_frame")
- liveoffset = self.liveoffsets.signed[i]
- return self.callee_data[FRAME_PTR] + liveoffset
+ def walk_stack_from(self, initialframedata):
+ curframe = lltype.malloc(WALKFRAME, flavor='raw')
+ otherframe = lltype.malloc(WALKFRAME, flavor='raw')
+ 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
+ lltype.free(otherframe, flavor='raw')
+ lltype.free(curframe, flavor='raw')
+
+ def fill_initial_frame(self, curframe, initialframedata):
+ # Read the information provided by initialframedata
+ 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 pairs of pointers:
+ # void *SafePointAddress;
+ # void *Shape;
+ #
+ # A "safe point" is the return address of a call.
+ # The "shape" of a safe point is a list of integers
+ # as follows:
+ #
+ # * The size of the frame of the function containing the
+ # call (in theory it can be different from call to call).
+ # This size includes the return address (see picture
+ # below).
+ #
+ # * Four integers that specify where the function saves
+ # each of the four callee-saved registers (%ebx, %esi,
+ # %edi, %ebp). This is a "location", see below.
+ #
+ # * 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", see below.
+ #
+ # A "location" can be either in the stack or in a register.
+ # If it is in the stack, it is specified as an integer offset
+ # from the current frame (so it is typically < 0, as seen
+ # in the picture below, though it can also be > 0 if the
+ # location is an input argument to the current function and
+ # thus lives at the bottom of the caller's frame).
+ # A "location" can also be in a register; in our context it
+ # can only be a callee-saved register. This is specified
+ # as a small odd-valued integer (1=%ebx, 3=%esi, etc.)
+ #
+ # 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.
+ #
+ gcmapstart = llop.llvm_gcmapstart(llmemory.Address)
+ gcmapend = llop.llvm_gcmapend(llmemory.Address)
+ item = binary_search(gcmapstart, gcmapend, retaddr)
+ if item.address[0] != retaddr:
+ # retaddr not found!
+ llop.debug_fatalerror(lltype.Void, "cannot find gc roots!")
+ return False
+ #
+ # found! Now we can go to the caller_frame.
+ #
+ shape = item.address[1]
+ framesize = shape.signed[0]
+ caller.frame_address = callee.frame_address + framesize
+ #
+ # enumerate the GC roots in the caller frame
+ #
+ collect_stack_root = self.gcdata._gc_collect_stack_root
+ gc = self.gc
+ LIVELOCS = 1 + CALLEE_SAVED_REGS + 1 # index of the first gc root loc
+ livecount = shape.signed[LIVELOCS-1]
+ while livecount > 0:
+ livecount -= 1
+ location = shape.signed[LIVELOCS + livecount]
+ addr = self.getlocation(callee, caller, location)
+ if addr.address[0] != llmemory.NULL:
+ collect_stack_root(gc, addr)
+ #
+ # track where the caller_frame saved the registers from its own
+ # caller
+ #
+ if shape.signed[1] == -1: # a marker that means "I'm the frame
+ return False # of the entry point, stop walking"
+ reg = 0
+ while reg < CALLEE_SAVED_REGS:
+ location = shape.signed[1+reg]
+ addr = self.getlocation(callee, caller, location)
+ caller.regs_stored_at[reg] = addr
+ reg += 1
+ return True
+
+ def getlocation(self, callee, caller, location):
+ """Get the location in the 'caller' frame of a variable, based
+ on the integer 'location' that describes it. The 'callee' is
+ only used if the location is in a register that was saved in the
+ callee.
+ """
+ if location & 1: # register
+ reg = location >> 1
+ ll_assert(0 <= reg < CALLEE_SAVED_REGS, "bad register location")
+ return callee.regs_stored_at[reg]
+ else:
+ # in the stack frame
+ return caller.frame_address + location
- return RootWalker()
+# ____________________________________________________________
sizeofaddr = llmemory.sizeof(llmemory.Address)
arrayitemsize = 2 * sizeofaddr
@@ -239,11 +243,14 @@
scan.address[1] = addr2
next += arrayitemsize
+# ____________________________________________________________
+
#
-# The special pypy_asm_stackwalk_init(), implemented directly in
-# assembler, initializes an ASM_STACKWALK array in order to bootstrap
-# the stack walking code. An ASM_STACKWALK is an array of 6 values
-# that describe everything we need to know about a stack frame:
+# 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
@@ -251,16 +258,23 @@
# - 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)
-# - the return address for when the current function finishes
-# (which is usually just the word at "frame address")
#
CALLEE_SAVED_REGS = 4 # there are 4 callee-saved registers
-FRAME_PTR = CALLEE_SAVED_REGS
-RET_ADDR = CALLEE_SAVED_REGS + 1
-ASM_STACKWALK = lltype.FixedSizeArray(llmemory.Address, CALLEE_SAVED_REGS + 2)
-
-pypy_asm_stackwalk_init = rffi.llexternal('pypy_asm_stackwalk_init',
- [lltype.Ptr(ASM_STACKWALK)],
- lltype.Void,
- sandboxsafe=True,
- _nowrapper=True)
+FRAME_PTR = CALLEE_SAVED_REGS # the frame is at index 4 in the array
+
+ASM_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([llmemory.Address],
+ 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),
+ )
+
+pypy_asm_stackwalk = rffi.llexternal('pypy_asm_stackwalk',
+ [ASM_CALLBACK_PTR],
+ lltype.Void,
+ sandboxsafe=True,
+ _nowrapper=True)
Modified: pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/branch/asmgcroot/pypy/rpython/memory/gctransform/framework.py Thu Jan 3 17:36:56 2008
@@ -131,18 +131,16 @@
self.gcdata = gcdata
self.malloc_fnptr_cache = {}
- sizeofaddr = llmemory.sizeof(llmemory.Address)
-
gcdata.gc = GCClass(AddressLinkedList, **GC_PARAMS)
root_walker = self.build_root_walker()
gcdata.set_query_functions(gcdata.gc)
- gcdata.set_root_walker(gcdata.gc, root_walker)
+ gcdata.gc.set_root_walker(root_walker)
self.num_pushs = 0
self.write_barrier_calls = 0
def frameworkgc_setup():
# run-time initialization code
- root_walker.setup_root_stack()
+ root_walker.setup_root_walker()
gcdata.gc.setup()
bk = self.translator.annotator.bookkeeper
@@ -173,25 +171,16 @@
self.frameworkgc_setup_ptr = getfn(frameworkgc_setup, [],
annmodel.s_None)
- if RootWalker.need_root_stack:
- #self.pop_root_ptr = getfn(RootWalker.pop_root, [],
- # annmodel.SomeAddress(),
- # inline = True)
- #self.push_root_ptr = getfn(RootWalker.push_root,
- # [annmodel.SomeAddress()],
- # annmodel.s_None,
- # inline = True)
- self.incr_stack_ptr = getfn(RootWalker.incr_stack,
+ if root_walker.need_root_stack:
+ self.incr_stack_ptr = getfn(root_walker.incr_stack,
[annmodel.SomeInteger()],
annmodel.SomeAddress(),
inline = True)
- self.decr_stack_ptr = getfn(RootWalker.decr_stack,
+ self.decr_stack_ptr = getfn(root_walker.decr_stack,
[annmodel.SomeInteger()],
annmodel.SomeAddress(),
inline = True)
else:
- #self.push_root_ptr = None
- #self.pop_root_ptr = None
self.incr_stack_ptr = None
self.decr_stack_ptr = None
self.weakref_deref_ptr = self.inittime_helper(
@@ -352,71 +341,7 @@
fields.append(('_' + fldname, FLDTYPE))
def build_root_walker(self):
- gcdata = self.gcdata
- sizeofaddr = llmemory.sizeof(llmemory.Address)
- rootstacksize = sizeofaddr * self.root_stack_depth
-
- class RootWalker:
- _alloc_flavor_ = 'raw'
- def setup_root_stack():
- stackbase = llmemory.raw_malloc(rootstacksize)
- ll_assert(bool(stackbase), "could not allocate root stack")
- llmemory.raw_memclear(stackbase, rootstacksize)
- gcdata.root_stack_top = stackbase
- gcdata.root_stack_base = stackbase
- setup_root_stack = staticmethod(setup_root_stack)
-
- need_root_stack = True
-
- def incr_stack(n):
- top = gcdata.root_stack_top
- gcdata.root_stack_top = top + n*sizeofaddr
- return top
- incr_stack = staticmethod(incr_stack)
-
- def append_static_root(adr):
- gcdata.static_root_end.address[0] = adr
- gcdata.static_root_end += sizeofaddr
- append_static_root = staticmethod(append_static_root)
-
- def decr_stack(n):
- top = gcdata.root_stack_top - n*sizeofaddr
- gcdata.root_stack_top = top
- return top
- decr_stack = staticmethod(decr_stack)
-
- def push_root(addr):
- top = gcdata.root_stack_top
- top.address[0] = addr
- gcdata.root_stack_top = top + sizeofaddr
- push_root = staticmethod(push_root)
-
- def pop_root():
- top = gcdata.root_stack_top - sizeofaddr
- gcdata.root_stack_top = top
- return top.address[0]
- pop_root = staticmethod(pop_root)
-
- def __init__(self, with_static=True):
- self.stack_current = gcdata.root_stack_top
- if with_static:
- self.static_current = gcdata.static_root_end
- else:
- self.static_current = gcdata.static_root_nongcend
-
- def pop(self):
- while self.static_current != gcdata.static_root_start:
- self.static_current -= sizeofaddr
- result = self.static_current.address[0]
- if result.address[0] != llmemory.NULL:
- return result
- while self.stack_current != gcdata.root_stack_base:
- self.stack_current -= sizeofaddr
- if self.stack_current.address[0] != llmemory.NULL:
- return self.stack_current
- return llmemory.NULL
-
- return StackRootIterator
+ return ShadowStackRootWalker(self)
def consider_constant(self, TYPE, value):
self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc)
@@ -830,3 +755,87 @@
[v] + previous_steps + [c_name, c_null])
elif isinstance(FIELD, lltype.Struct):
gen_zero_gc_pointers(FIELD, v, llops, previous_steps + [c_name])
+
+# ____________________________________________________________
+
+
+sizeofaddr = llmemory.sizeof(llmemory.Address)
+
+
+class BaseRootWalker:
+ need_root_stack = False
+
+ def __init__(self, gctransformer):
+ self.gcdata = gctransformer.gcdata
+ self.gc = self.gcdata.gc
+
+ def _freeze_(self):
+ return True
+
+ def setup_root_walker(self):
+ pass
+
+ def append_static_root(self, adr):
+ self.gcdata.static_root_end.address[0] = adr
+ self.gcdata.static_root_end += sizeofaddr
+
+ def walk_roots(self, collect_stack_root,
+ collect_static_in_prebuilt_nongc,
+ collect_static_in_prebuilt_gc):
+ gcdata = self.gcdata
+ gc = self.gc
+ if collect_static_in_prebuilt_nongc:
+ addr = gcdata.static_root_start
+ end = gcdata.static_root_nongcend
+ while addr != end:
+ if addr.address[0] != llmemory.NULL:
+ collect_static_in_prebuilt_nongc(gc, addr)
+ addr += sizeofaddr
+ if collect_static_in_prebuilt_gc:
+ addr = gcdata.static_root_nongcend
+ end = gcdata.static_root_end
+ while addr != end:
+ if addr.address[0] != llmemory.NULL:
+ collect_static_in_prebuilt_gc(gc, addr)
+ addr += sizeofaddr
+ if collect_stack_root:
+ self.walk_stack_roots(collect_stack_root) # abstract
+
+
+class ShadowStackRootWalker(BaseRootWalker):
+ need_root_stack = True
+
+ def __init__(self, gctransformer):
+ BaseRootWalker.__init__(self, gctransformer)
+ self.rootstacksize = sizeofaddr * gctransformer.root_stack_depth
+ # NB. 'self' is frozen, but we can use self.gcdata to store state
+ gcdata = self.gcdata
+
+ def incr_stack(n):
+ top = gcdata.root_stack_top
+ gcdata.root_stack_top = top + n*sizeofaddr
+ return top
+ self.incr_stack = incr_stack
+
+ def decr_stack(n):
+ top = gcdata.root_stack_top - n*sizeofaddr
+ gcdata.root_stack_top = top
+ return top
+ self.decr_stack = decr_stack
+
+ def setup_root_walker(self):
+ stackbase = llmemory.raw_malloc(self.rootstacksize)
+ ll_assert(bool(stackbase), "could not allocate root stack")
+ llmemory.raw_memclear(stackbase, self.rootstacksize)
+ self.gcdata.root_stack_top = stackbase
+ self.gcdata.root_stack_base = stackbase
+
+ def walk_stack_roots(self, collect_stack_root):
+ gcdata = self.gcdata
+ gc = self.gc
+ addr = gcdata.root_stack_base
+ end = gcdata.root_stack_top
+ while addr != end:
+ if addr.address[0] != llmemory.NULL:
+ collect_stack_root(gc, addr)
+ addr += sizeofaddr
Modified: pypy/branch/asmgcroot/pypy/translator/c/trackgcroot.py
==============================================================================
--- pypy/branch/asmgcroot/pypy/translator/c/trackgcroot.py (original)
+++ pypy/branch/asmgcroot/pypy/translator/c/trackgcroot.py Thu Jan 3 17:36:56 2008
@@ -35,18 +35,26 @@
assert self.seen_main
shapes = {}
print >> output, """\t.text
- .globl pypy_asm_stackwalk_init
- .type pypy_asm_stackwalk_init, @function
- pypy_asm_stackwalk_init:
+ .globl pypy_asm_stackwalk
+ .type pypy_asm_stackwalk, @function
+ pypy_asm_stackwalk:
/* See description in asmgcroot.py */
- movl 4(%esp), %edx /* argument */
- movl %ebx, (%edx)
- movl %esi, 4(%edx)
- movl %edi, 8(%edx)
- movl %ebp, 12(%edx)
- movl %esp, 16(%edx)
- movl (%esp), %eax
- movl %eax, 20(%edx)
+ movl 4(%esp), %edx /* my argument, which is the callback */
+ movl (%esp), %eax /* my return address */
+ pushl %eax /* ASM_FRAMEDATA[4] */
+ pushl %ebp /* ASM_FRAMEDATA[3] */
+ pushl %edi /* ASM_FRAMEDATA[2] */
+ pushl %esi /* ASM_FRAMEDATA[1] */
+ pushl %ebx /* ASM_FRAMEDATA[0] */
+ movl %esp, %eax /* address of ASM_FRAMEDATA */
+ pushl %eax
+ call *%edx /* invoke the callback */
+ popl %eax
+ popl %ebx /* restore from ASM_FRAMEDATA[0] */
+ popl %esi /* restore from ASM_FRAMEDATA[1] */
+ popl %edi /* restore from ASM_FRAMEDATA[2] */
+ popl %ebp /* restore from ASM_FRAMEDATA[3] */
+ popl %eax
ret
.size pypy_asm_stackwalk_init, .-pypy_asm_stackwalk_init
"""
More information about the Pypy-commit
mailing list