update GC pseudocode
parent
613f848ce1
commit
61a7bf871c
|
@ -89,9 +89,6 @@ def gc_collect(): # implemented by ports
|
|||
# add root pointers (platform-dependent)
|
||||
gc_collect_root(roots)
|
||||
|
||||
# mark all reachable blocks
|
||||
gc_mark()
|
||||
|
||||
# if there was a stack overflow, scan all memory for reachable blocks
|
||||
gc_deal_with_stack_overflow()
|
||||
|
||||
|
@ -100,20 +97,33 @@ def gc_collect(): # implemented by ports
|
|||
|
||||
def gc_collect_root(roots):
|
||||
for root in roots:
|
||||
# Add this root to the (empty) stack. len(gc.stack) will be 1.
|
||||
may_add_to_stack(root)
|
||||
|
||||
# Shrink the stack to zero, hopefully without GC stack overflow.
|
||||
gc_drain_stack()
|
||||
|
||||
def may_add_to_stack(pointer): # VERIFY_MARK_AND_PUSH
|
||||
# If this is a pointer and points to an unmarked block, mark it and try to
|
||||
# push it on the stack.
|
||||
if is_heap_pointer(pointer):
|
||||
# Get the block number this pointer points to.
|
||||
block = BLOCK_FROM_PTR(pointer)
|
||||
# Test whether this could be a pointer.
|
||||
if looks_like_pointer(root):
|
||||
block = block_from_ptr(root)
|
||||
if block.state == HEAD:
|
||||
# Set the mark bit on this block.
|
||||
block.state = MARK
|
||||
|
||||
# Mark all descendants of this root.
|
||||
gc_mark_subtree(block)
|
||||
|
||||
def gc_mark_subtree(block):
|
||||
# The passed in block must already been marked.
|
||||
|
||||
# Try to reduce the stack, and don't return until it's empty. But with every
|
||||
# reduction, multiple blocks may be added to the stack so this function may
|
||||
# actually hit a stack overflow.
|
||||
while True:
|
||||
# Check this block's children.
|
||||
# Each block contains 4 memory words (on a 32-bit system with 16-byte
|
||||
# blocks). These words may be pointers to blocks on the heap, but may also
|
||||
# be other things like integers, parts of raw data (strings, bytecode, etc.)
|
||||
# or pointers to memory outside of the heap.
|
||||
for pointer in reversed(block.all_pointers_in_chain()[1:]):
|
||||
if looks_like_pointer(pointer):
|
||||
childblock = block_from_ptr(pointer)
|
||||
if childblock.state == HEAD:
|
||||
childblock.state = MARK
|
||||
# Is there space left on the GC stack?
|
||||
if len(gc.stack) < MICROPY_ALLOC_GC_STACK_SIZE:
|
||||
# Yes, add this block to the stack.
|
||||
|
@ -123,18 +133,12 @@ def may_add_to_stack(pointer): # VERIFY_MARK_AND_PUSH
|
|||
# to be scanned again (some marked blocks may have unmarked children).
|
||||
gc.stack_overflow = True
|
||||
|
||||
def gc_drain_stack():
|
||||
# Try to reduce the stack, and don't return until it's empty. But with every
|
||||
# reduction, multiple blocks may be added to the stack so this function may
|
||||
# actually hit a stack overflow.
|
||||
while len(gc.stack) > 0:
|
||||
# Are there any blocks on the stack?
|
||||
if len(gc.stack) == 0:
|
||||
break # No, stack is empty, we're done.
|
||||
|
||||
# pop the next block off the stack
|
||||
block = gc.stack.pop()
|
||||
# Each block contains 4 memory words (on a 32-bit system with 16-byte
|
||||
# blocks). These words may be pointers to blocks on the heap, but may also
|
||||
# be other things like integers, parts of raw data (strings, bytecode, etc.)
|
||||
# or pointers to memory outside of the heap.
|
||||
for pointer in block:
|
||||
may_add_to_stack(pointer)
|
||||
|
||||
def gc_deal_with_stack_overflow():
|
||||
# Keep scanning the whole memory until all marked blocks don't have unmarked
|
||||
|
@ -143,16 +147,13 @@ def gc_deal_with_stack_overflow():
|
|||
# The stack is there to make the mark phase more efficient, i.e. it avoids
|
||||
# having to scan the whole memory too often. But sometimes, the stack is too
|
||||
# small and requires a full scan (like at the beginning of the mark phase).
|
||||
gc.stack_overflow = True # indicates the whole memory needs to be scanned
|
||||
while gc.stack_overflow:
|
||||
gc.stack_overflow = False
|
||||
gc.stack = []
|
||||
for block in gc.memory:
|
||||
# A block can have the states FREE, HEAD, TAIL or MARK, as set in the
|
||||
# allocation table.
|
||||
if block.state == MARK:
|
||||
gc.stack.append(block)
|
||||
gc_drain_stack()
|
||||
gc_mark_subtree(block)
|
||||
|
||||
def gc_sweep():
|
||||
# Free unmarked blocks and unmark marked blocks.
|
||||
|
|
Loading…
Reference in New Issue