The ConcurrentMark instance keeps track of the heap start and end in its own instance variables _heap_start and _heap_end.
When the heap is expanded (at allocations or at the end of a GC) we call ConcurrentMark::update_g1_committed() to reset the _heap_end to reflect the new heap end.
When we expand the heap we only add new regions. These should have TAMS set to bottom to make sure that all objects in them are considered live as by the SATB assumption. That means that there is really no need for the concurrent mark thread to visit them. Thus, we don't really have to update the _heap_end when we expand the heap.
Also note that we don't shrink the heap during a concurrent mark. So, no need to update the _heap_end for that reason.
This means that ConcurrentMark::update_g1_committed() and the calls to it can be removed.
However, currently the initial setting of the _heap_end variable is done in ConcurrentMark::reset(), which is called in the beginning of an initial mark GC. If that GC decides to expand the heap at the end of the GC we need to update the _heap_end value. Rather than updating it I would propose to separate out the setting of _heap_start and _heap_end to a method called ConcurrentMark::reset_heap_boundaries():
void ConcurrentMark::reset_heap_boundaries() {
MemRegion committed = _g1h->g1_committed();
_heap_start = committed.start();
_heap_end = committed.end();
assert(_heap_start != NULL, "heap bounds should look ok");
assert(_heap_end != NULL, "heap bounds should look ok");
assert(_heap_start < _heap_end, "heap bounds should look ok");
}
And then call reset_heap_boundaries() after the initial mark GC has done its expansion.