public
Description: Rubinius, the Ruby VM
Homepage: http://rubini.us
Clone URL: git://github.com/evanphx/rubinius.git
rubinius / lib / hybridgc.rb
100644 155 lines (126 sloc) 3.905 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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