def setup_root_stack(): # 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)
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. # gcmapstart = llop.llvm_gcmapstart(llmemory.Address) gcmapend = llop.llvm_gcmapend(llmemory.Address) item = search_in_gcmap(gcmapstart, gcmapend, retaddr) if not item: # the item may have been not found because the array was # not sorted. Sort it and try again. sort_gcmap(gcmapstart, gcmapend) item = search_in_gcmap(gcmapstart, gcmapend, retaddr) if not item: llop.debug_fatalerror(lltype.Void, "cannot find gc roots!") return False # # found! Enumerate the GC roots in the caller frame # shape = item.signed[1] if shape < 0: shape = ~ shape # can ignore this "range" marker here self._shape_decompressor.setpos(shape) 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, location) if addr.address[0] != llmemory.NULL: collect_stack_root(gc, addr) # # 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, location) caller.regs_stored_at[reg] = addr reg -= 1 location = self._shape_decompressor.next() caller.frame_address = self.getlocation(callee, 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 walk_to_parent_frame(self): # # 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 records the size of the # frame of the function containing it, as well as a # list of the variables that contain gc roots at that # time. Each variable is described by its offset in # the frame. # callee_frame = self.stack_current if llmemory.cast_adr_to_int(callee_frame) & 1: return False # odd bit set here when the callee_frame # is the frame of main(), i.e. when there # is nothing more for us in the stack. # # XXX the details are completely specific to X86!!! # a picture of the stack may help: # ^ ^ ^ # | ... | to older frames # +--------------+ # | first word | <------ caller_frame (addr of 1st word) # + + # | caller frame | # | ... | # | frame data | <------ frame_data_base # +--------------+ # | ret addr | # +--------------+ # | first word | <------ callee_frame (addr of 1st word) # + + # | callee frame | # | ... | # | frame data | lower addresses # +--------------+ v v v # retaddr = callee_frame.address[1] # # 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: # # found! Setup pointers allowing us to # parse the caller's frame structure... # shape = item.address[1] # XXX assumes that .signed is 32-bit framesize = shape.signed[0] # odd if it's main() livecount = shape.signed[1] caller_frame = callee_frame + 4 + framesize self.stack_current = caller_frame self.frame_data_base = callee_frame + 8 self.remaining_roots_in_current_frame = livecount self.liveoffsets = shape + 8 return True # retaddr not found! llop.debug_fatalerror(lltype.Void, "cannot find gc roots!") return False
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. # gcmapstart = llop.llvm_gcmapstart(llmemory.Address) gcmapend = llop.llvm_gcmapend(llmemory.Address) item = search_in_gcmap(gcmapstart, gcmapend, retaddr) if not item: # the item may have been not found because the array was # not sorted. Sort it and try again. sort_gcmap(gcmapstart, gcmapend) item = search_in_gcmap(gcmapstart, gcmapend, retaddr) if not item: llop.debug_fatalerror(lltype.Void, "cannot find gc roots!") return False # # found! Enumerate the GC roots in the caller frame # shape = item.signed[1] if shape < 0: shape = ~shape # can ignore this "range" marker here self._shape_decompressor.setpos(shape) 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, location) if addr.address[0] != llmemory.NULL: collect_stack_root(gc, addr) # # 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, location) caller.regs_stored_at[reg] = addr reg -= 1 location = self._shape_decompressor.next() caller.frame_address = self.getlocation(callee, location) # we get a NULL marker to mean "I'm the frame # of the entry point, stop walking" return caller.frame_address != llmemory.NULL