Skip to content
Browse files

Introduce explicit scanned state for mature GC

This uses an additional bit for the mark field, which now has a separate
flag to indicate that the object has been completely scanned. This will
be used in the write barrier for concurrent collection. This is needed
for the case where we store an unmarked object into an already scanned
object so we don't accidentally free the unmarked object.

This makes the black state of the tri color GC invariant explicit.
Before this was implicit by it being black when it was marked and not
anymore in the mark stack. For concurrent GC we want this explicit so we
don't have to check the mark stack in each write barrier.
  • Loading branch information...
1 parent df7e4de commit d1d99d6048a01f1687080f98baa904d4562ed920 @dbussink dbussink committed May 24, 2013
Showing with 47 additions and 16 deletions.
  1. +3 −0 vm/gc/baker.hpp
  2. +1 −0 vm/gc/debug.hpp
  3. +5 −1 vm/gc/gc.cpp
  4. +1 −0 vm/gc/gc.hpp
  5. +4 −0 vm/gc/immix.cpp
  6. +1 −0 vm/gc/immix.hpp
  7. +1 −0 vm/gc/marksweep.hpp
  8. +1 −0 vm/gc/walker.hpp
  9. +1 −3 vm/objectmemory.cpp
  10. +1 −1 vm/objectmemory.hpp
  11. +12 −0 vm/oop.cpp
  12. +16 −11 vm/oop.hpp
View
3 vm/gc/baker.hpp
@@ -283,6 +283,9 @@ namespace rubinius {
/// generation.
virtual Object* saw_object(Object* obj);
+ /// Called for each object after the object is scanned
+ virtual void scanned_object(Object* obj) {}
+
/// Scans the remaining unscanned portion of what was the Current space.
void copy_unscanned();
View
1 vm/gc/debug.hpp
@@ -17,6 +17,7 @@ namespace rubinius {
virtual ~HeapDebug() { }
virtual Object* saw_object(Object* obj);
+ virtual void scanned_object(Object* obj) {}
void walk(Roots &roots);
};
}
View
6 vm/gc/gc.cpp
@@ -83,6 +83,11 @@ namespace rubinius {
std::cout << "detected " << obj << " during scan_object.\n";
}
#endif
+ // We set scanned here before we finish scanning the object.
+ // This is done so we don't have a race condition while we're
+ // scanning the object and another thread updates a field during
+ // the phase where the object is partially scanned.
+ scanned_object(obj);
slot = saw_object(obj->klass());
if(slot && slot != obj->klass()) {
@@ -118,7 +123,6 @@ namespace rubinius {
}
}
-
/**
* Removes a mature object from the remembered set, ensuring it will not keep
* alive any young objects if no other live references to those objects exist.
View
1 vm/gc/gc.hpp
@@ -148,6 +148,7 @@ namespace rubinius {
* encountered during garbage collection.
*/
virtual Object* saw_object(Object*) = 0;
+ virtual void scanned_object(Object*) = 0;
// Scans the specified Object for references to other Objects.
void scan_object(Object* obj);
void delete_object(Object* obj);
View
4 vm/gc/immix.cpp
@@ -117,6 +117,10 @@ namespace rubinius {
return copy;
}
+ void ImmixGC::scanned_object(Object* obj) {
+ obj->scanned();
+ }
+
ObjectPosition ImmixGC::validate_object(Object* obj) {
if(gc_.allocated_address(memory::Address(obj))) {
if(obj->in_immix_p()) {
View
1 vm/gc/immix.hpp
@@ -126,6 +126,7 @@ namespace rubinius {
Object* move_object(Object* orig, int bytes);
virtual Object* saw_object(Object*);
+ virtual void scanned_object(Object*);
void collect(GCData* data);
void walk_finalizers();
View
1 vm/gc/marksweep.hpp
@@ -43,6 +43,7 @@ namespace rubinius {
void sweep_objects();
void free_object(Object* obj, bool fast = false);
virtual Object* saw_object(Object* obj);
+ virtual void scanned_object(Object* obj) {}
void after_marked();
void profile(STATE);
View
1 vm/gc/walker.hpp
@@ -18,6 +18,7 @@ namespace rubinius {
virtual ~ObjectWalker();
virtual Object* saw_object(Object*);
+ virtual void scanned_object(Object*) {}
void seed(GCData& data);
Object* next();
View
4 vm/objectmemory.cpp
@@ -55,7 +55,7 @@ namespace rubinius {
, inflated_headers_(new InflatedHeaders(state))
, capi_handles_(new capi::Handles)
, code_manager_(&state->shared)
- , mark_(1)
+ , mark_(2)
, allow_gc_(true)
, slab_size_(4096)
, shared_(state->shared)
@@ -1063,10 +1063,8 @@ namespace rubinius {
std::cout << " total allocated: " << code_manager_.total_allocated() << "\n";
std::cout << " total freed: " << code_manager_.total_freed() << "\n";
}
-
};
-
// The following memory functions are defined in ruby.h for use by C-API
// extensions, and also used by library code lifted from MRI (e.g. Oniguruma).
// They provide some book-keeping around memory usage for non-VM code, so that
View
2 vm/objectmemory.hpp
@@ -211,7 +211,7 @@ namespace rubinius {
}
void rotate_mark() {
- mark_ = (mark_ == 1 ? 2 : 1);
+ mark_ = (mark_ == 2 ? 4 : 2);
}
bool can_gc() const {
View
12 vm/oop.cpp
@@ -218,6 +218,18 @@ namespace rubinius {
}
}
+ void ObjectHeader::scanned() {
+ for(;;) {
+ HeaderWord orig = header;
+ HeaderWord new_val = orig;
+ new_val.f.Marked |= 1;
+
+ if(header.atomic_set(orig, new_val)) {
+ return;
+ }
+ }
+ }
+
void ObjectHeader::clear_mark() {
for(;;) {
HeaderWord orig = header;
View
27 vm/oop.hpp
@@ -142,13 +142,13 @@ Object* const cUndef = reinterpret_cast<Object*>(0x22L);
#define OBJECT_FLAGS_MEANING 16
#define OBJECT_FLAGS_FORWARDED 17
#define OBJECT_FLAGS_REMEMBER 18
-#define OBJECT_FLAGS_MARKED 20
-#define OBJECT_FLAGS_INIMMIX 21
-#define OBJECT_FLAGS_PINNED 22
-#define OBJECT_FLAGS_FROZEN 23
-#define OBJECT_FLAGS_TAINTED 24
-#define OBJECT_FLAGS_UNTRUSTED 25
-#define OBJECT_FLAGS_LOCK_CONTENDED 26
+#define OBJECT_FLAGS_MARKED 21
+#define OBJECT_FLAGS_INIMMIX 22
+#define OBJECT_FLAGS_PINNED 23
+#define OBJECT_FLAGS_FROZEN 24
+#define OBJECT_FLAGS_TAINTED 25
+#define OBJECT_FLAGS_UNTRUSTED 26
+#define OBJECT_FLAGS_LOCK_CONTENDED 27
struct ObjectFlags {
object_type obj_type : 8;
@@ -158,7 +158,7 @@ Object* const cUndef = reinterpret_cast<Object*>(0x22L);
unsigned int Forwarded : 1;
unsigned int Remember : 1;
- unsigned int Marked : 2;
+ unsigned int Marked : 3;
unsigned int InImmix : 1;
unsigned int Pinned : 1;
@@ -167,7 +167,7 @@ Object* const cUndef = reinterpret_cast<Object*>(0x22L);
unsigned int Tainted : 1;
unsigned int Untrusted : 1;
unsigned int LockContended : 1;
- unsigned int unused : 5;
+ unsigned int unused : 4;
uint32_t aux_word;
};
@@ -256,7 +256,7 @@ Object* const cUndef = reinterpret_cast<Object*>(0x22L);
}
bool marked_p(unsigned int which) const {
- return mark_ == (int)which;
+ return (mark_ & which) == (int)which;
}
void mark(ObjectMemory* om, unsigned int which) {
@@ -481,10 +481,15 @@ Object* const cUndef = reinterpret_cast<Object*>(0x22L);
}
bool marked_p(unsigned int which) const {
- return flags().Marked == which;
+ return (flags().Marked & which) == which;
+ }
+
+ bool scanned_p(unsigned int which) const {
+ return flags().Marked == which + 1;
}
void mark(ObjectMemory* om, unsigned int which);
+ void scanned();
int which_mark() const {
return flags().Marked;

0 comments on commit d1d99d6

Please sign in to comment.
Something went wrong with that request. Please try again.