hotspot full gc擬似コード

5430 ワード


class Object {
  bool _gc_mark = false;
  Object* _forwardee; // null for normal objects non-null for forwarded objects

  void forward_to(address new_addr) {
    _forwardee = new_addr;
  }

  Object* forwardee() {
    return _forwardee;
  }

  bool forwarded() {
    return _forwardee != null;
  }

  void copy_to_forwardee() {
    // copy current obj to the forwardee address and clear its forwardee
  }

  void set_gc_mark() {
    _gc_mark = true;
  }

  bool gc_marked() {
    return _gc_mark;
  }

  void clear_gc_mark() {
    _gc_mark = false;
  }

  size_t size();

  void adjust_object_fields() {
    foreach(Object** p : this->object_fiels()) {
      *p = (*p)->forwardee();
    }
  }

  Iterator<Object**> object_fields();
};

class Heap {
  ContigCompatibleSpace* _the_space;

  Heap(address bottom, address end);

  address allocate(size_t size);
  void collect();
  void process_root(Object** slot);
  void mark_compact_phase1();
  void mark_compact_phase2();
  void mark_compact_phase3();
  void mark_compact_phase4();
};

class ContigCompatibleSpace {
  address _bottom;
  address _top;
  address _end;
  Object* _first_dead;

public:
  ContigCompatibleSpace(address bottom, address end);

  address bottom() {
    return _bottom;
  }

  address top() {
    return _top;
  }

  address end() {
    return _end;
  }

  bool contains(address obj);
  address allocate(size_t size);
  void reset();

  void scan_and_forward();
  void adjust_pointers();
  void compact();
};

Heap::Heap(address bottom, address end) {
  _the_space = new ContigCompatibleSpace(bottom, end);
}

address Heap::allocate(size_t size) {
  return _the_space->allocate();
}

void Heap::collect() {
  mark_compact_phase1();
  mark_compact_phase2();
  mark_compact_phase3();
  mark_compact_phase4();
}

void Heap::mark_compact_phase1() {
  foreach(Object** slot : ROOTS) {
    process_root(slot);
  }
}

void Heap::process_root(Object** slot) {
  Stack s;

  Object* oop = *slot;
  oop->set_gc_mark();
  s.push(oop);
  while (!s.empty()) {
    oop = s.pop();

    foreach(Object** obj_field : oop->object_fields()) {
      if (!(*obj_field)->gc_marked()) {
        (*obj_field)->set_gc_mark();
        s.push(*obj_filed);
      }
    }
  }
}

void Heap::mark_compact_phase2() {
  _the_space->scan_and_forward();
}

void Heap::mark_compact_phase3() {
  foreach(Object** slot : ROOTS) {
    *slot = (*slot)->forwardee();
  }

  _the_space->adjust_pointers();
}

void Heap::mark_compact_phase4() {
  _the_space->compact();
}

ContigCompatibleSpace::ContigCompatibleSpace(address bottom, address end) {
  _bottom = bottom;
  _top = bottom;
  _end = end;
}

address ContigCompatibleSpace::contains(address obj) {
  return _bottom <= obj && obj < _top;
}

address ContigCompatibleSpace::allocate(size_t size) {
  if (_top + size <= _end) {
    Object* obj = _top;
    _top += size;
    return obj;
  } else {
    return null;
  }
}

void ContigCompatibleSpace::reset() {
  _top = _bottom;
}

void ContigCompatibleSpace::scan_and_forward() {
  Object* q = _bottom;
  address compacting_top = _bottom;
  _first_dead = _end;
  while (q < _end) {
    if (q->gc_marked()) {
      if (compacting_top == q) {
        q->clear_gc_mark();
        q->forward_to(null);
      } else
        q->forward_to(compacting_top);
      compacting_top += q->size();
      q += q->size();
    } else {
      if (_first_dead == _end)
        _first_dead = q;
      Object* p = q;
      do {
        p += p->size();
      } while (!p->gc_marked());
      q->forward_to(p);
      q = p;
    }
  }
}

void ContigCompatibleSpace::adjust_pointers() {
  Object* q = _bottom;
  while (q < _first_dead) {
    q->adjust_object_fields();
    q += q->size();
  }
  q = _first_dead->forwardee();
  while (q < _end) {
    if (q->gc_marked()) {
      q->adjust_object_fields();
      q += q->size();
    } else {
      q = q->forwardee();
    }
  }
}

void ContigCompatibleSpace::compact() {
  Object* q = _first_dead->forwardee();
  while (q < _end) {
    if (q->gc_marked()) {
      q->clear_gc_mark();
      q->copy_to_forwardee();
      q += q->size();
    } else {
      q = q->forwardee();
    }
  }
}