require 'baker_gc'
require 'mark_sweepgc'
class HybridGC < GarbageCollector
def initialize(eden_size, mature_size)
super()
# Where all objects begin...
@eden = BakerGC.new(eden_size)
@eden.stack = @stack
# if they live long enough, they are moved here. Objects
# here are still young, but have a higher probability of living
# on.
@survivor = BakerGC.new(eden_size)
@survivor.stack = @stack
# If life has treated an object well, it is promoted to the mature
# space, where it lives out it's life.
@mature = MarkSweepGC.new(mature_size)
@mature.stack = @stack
# Controls how many times @eden is swept before
# moving an object to survivor.
@compacts_before_survivor = 2
# Counter tracking how many compacts for survivor.
@compacts_til_survivor = @compacts_before_survivor
# Controls how many times @survivor is swept before
# promotion is run again.
@compacts_before_mature = 5
# Counter tracking how many compacts need to be done.
@compacts_til_mature = @compacts_before_mature
end
attr_reader :compacts_til_mature, :compacts_til_survivor
attr_accessor :compacts_before_mature, :compacts_before_survivor
def allocate(size)
@eden.allocate(size)
end
def clean_eden(roots)
@eden.collect roots
end
def clean_survivor(roots)
@survivor.collect roots
end
def promote(obj, where)
size = obj.memory_size
addr = where.allocate(size)
Memory.transfer_memory obj.address, size, addr
nw = RObject.new(addr)
update_stack obj, nw
return nw
end
def promote_to_mature(obj)
promote obj, @mature
end
def promote_to_survivor(obj)
promote obj, @survivor
end
def promote_between(from, to)
# A hash of all objects promoted in this go around.
promoted = {}
# Go through eden and promote all objects that are marked.
from.each_object do |obj|
if object_marked?(obj)
# puts "unmarking: #{obj.address}"
unmark_object(obj)
promoted[obj.address] = promote(obj, to)
else
# Otherwise mark it so that the next time around we promote
# it.
mark_object(obj)
end
end
# For all objects in +from+...
from.each_object do |obj|
# look at all references
obj.references.each do |ref, idx|
# and if +ref+ was promoted, update the reference
if promo = promoted[ref.address]
obj.put idx, promo
end
end
end
from.remember_set.each do |obj|
obj.references.each do |ref, idx|
if promo = promoted[ref.address]
obj.put idx, promo
# migrate remember set objects to the to space too.
to.remember_set << obj
end
end
end
# puts "promoted #{promoted.size} from #{from} to #{to}"
end
def update_remember_sets(obj, ref)
if immature?(ref)
unless immature? obj
@eden.remember_set << obj
end
elsif survivor?(ref)
end
end
def compact(roots)
clean_eden roots
# Order here is important. We have to move from survivor to mature
# before we move from eden to survivor so that objects we JUST moved
# from eden don't get picked up in the sweep of mature.
if @compacts_til_mature == 0
promote_between @survivor, @mature
@compacts_til_mature = @compacts_before_mature
else
@compacts_til_mature -= 1
end
if @compacts_til_survivor == 0
clean_survivor roots
promote_between @eden, @survivor
@compacts_til_survivor = @compacts_before_survivor
else
@compacts_til_survivor -= 1
end
end
def mature?(obj)
@mature.contains?(obj)
end
def survivor?(obj)
@survivor.contains?(obj)
end
def immature?(obj)
@eden.contains?(obj)
end
end