Skip to content
Browse files

A slew of GC fixes

* When we fill up the young object space, we spill right away to the
  mature space and set a flag that we need to collect the young space.
* GC is only done currently when a task completes
  • Loading branch information...
1 parent 8543558 commit 8906a3fb12ce37ca6ad11813c4b572675ea292df Evan Phoenix committed Sep 11, 2008
View
4 .gdbinit
@@ -9,3 +9,7 @@ end
define rps
p __show_simple__($arg0)
end
+
+define validate
+p rubinius::VM::current_state()->om->validate_object($arg0)
+end
View
5 kernel/bootstrap/class.rb
@@ -80,11 +80,6 @@ def self.set_ivar(name)
# of load order mattering)
class IncludedModule < Module
- self.instance_fields = 8
-
- # HACK: make this a VM exported constant
- self.object_type = 7
-
def superclass; @superclass ; end
def module ; @module ; end
View
5 vm/builtin/contexts.cpp
@@ -113,6 +113,11 @@ namespace rubinius {
return -1;
}
+ void MethodContext::post_copy(MethodContext* old) {
+ this->position_stack(old->calculate_sp());
+ this->js.stack_top = this->stk + this->stack_size;
+ }
+
/* Attempt to recycle +this+ context into the context cache, based
* on it's size. Returns true if the context was recycled, otherwise
* false. */
View
4 vm/builtin/contexts.hpp
@@ -107,6 +107,10 @@ namespace rubinius {
return js.stack - stk;
}
+ /* Run after a context is copied, allowing it to fix up
+ * it's internal pointers */
+ void post_copy(MethodContext* old);
+
class Info : public TypeInfo {
public:
BASIC_TYPEINFO(TypeInfo)
View
6 vm/builtin/object.cpp
@@ -333,7 +333,9 @@ namespace rubinius {
// between all duplicates made from this object
// TODO - Verify this statement
dup = state->om->new_object(lookup_begin(state), field_count);
+ gc_zone zone = dup->zone;
dup->all_flags = all_flags;
+ dup->zone = zone;
if(stores_bytes_p()) {
std::memcpy(dup->bytes, bytes, field_count * sizeof(OBJECT));
@@ -352,11 +354,13 @@ namespace rubinius {
LookupTable* source_constants = this->metaclass(state)->constants->dup(state);
OBJECT new_object = this->dup(state);
+ // TODO why can't we use new_object->metaclass(state) here? Why are
+ // we creating a metaclass by hand?
// Clone gets a new MetaClass
SET(new_object, klass, (MetaClass*)state->new_object(G(metaclass)));
// Set the clone's method and constants tables to those
// of the receiver's metaclass
- SET(new_object->klass, method_table, source_methods);
+ SET(new_object->metaclass(state), method_table, source_methods);
SET(new_object->klass, constants, source_constants);
return new_object;
View
1 vm/builtin/sendsite.cpp
@@ -20,6 +20,7 @@ namespace rubinius {
SET(ss, sender, Qnil);
SET(ss, selector, Selector::lookup(state, name));
ss->hits = ss->misses = 0;
+ ss->resolver = NULL;
ss->initialize(state);
ss->selector->associate(state, ss);
View
14 vm/builtin/task.cpp
@@ -49,7 +49,7 @@ namespace rubinius {
Task* Task::create(STATE, size_t stack_size) {
Task* task = (Task*)state->new_struct(G(task), sizeof(Task));
task->state = state;
- task->probe = state->probe;
+ SET(task, probe, state->probe.get());
task->msg = new Message(state);
SET(task, control_channel, Qnil);
SET(task, debug_channel, Qnil);
@@ -619,11 +619,13 @@ namespace rubinius {
if(state->om->collect_young_now) {
state->om->collect_young_now = false;
state->om->collect_young(state->globals.roots);
+ state->global_cache->clear();
}
if(state->om->collect_mature_now) {
state->om->collect_mature_now = false;
state->om->collect_mature(state->globals.roots);
+ state->global_cache->clear();
}
}
@@ -640,8 +642,9 @@ namespace rubinius {
// If we're switching tasks, return to the task monitor
if(state->interrupts.switch_task) {
state->interrupts.switch_task = false;
- return;
}
+
+ return;
}
}
}
@@ -674,7 +677,12 @@ namespace rubinius {
}
}
- std::cout << ":" << ctx->line() << " in " << ctx->cm->file->to_str(state)->byte_address();
+ std::cout << ":" << ctx->line() << " in ";
+ if(SYMBOL file_sym = try_as<Symbol>(ctx->cm->file)) {
+ std::cout << file_sym->c_str(state);
+ } else {
+ std::cout << "<unknown>";
+ }
std::cout << "\n";
ctx = ctx->sender;
View
9 vm/builtin/tuple.cpp
@@ -2,11 +2,20 @@
#include "vm.hpp"
#include "objectmemory.hpp"
#include "builtin/fixnum.hpp"
+#include "builtin/compactlookuptable.hpp"
#include <cstdarg>
#include <iostream>
namespace rubinius {
+
+ template <>
+ bool kind_of<Tuple>(OBJECT obj) {
+ return obj->reference_p() && (
+ obj->obj_type == Tuple::type ||
+ obj->obj_type == CompactLookupTable::type);
+ }
+
OBJECT Tuple::at(size_t index) {
if(field_count <= index) {
ObjectBoundsExceeded::raise(this, index);
View
2 vm/environment.cpp
@@ -21,7 +21,7 @@ namespace rubinius {
Environment::Environment() {
state = new VM();
TaskProbe* probe = TaskProbe::create(state);
- state->probe = probe->parse_env(NULL) ? probe : (TaskProbe*)Qnil;
+ state->probe.set(probe->parse_env(NULL) ? probe : (TaskProbe*)Qnil);
}
Environment::~Environment() {
View
8 vm/gc.cpp
@@ -55,6 +55,14 @@ namespace rubinius {
if(slot) object_memory->set_class(obj, slot);
}
+ if(obj->ivars && obj->ivars->reference_p()) {
+ slot = saw_object(obj->ivars);
+ if(slot) {
+ obj->ivars = slot;
+ object_memory->write_barrier(obj, slot);
+ }
+ }
+
TypeInfo* ti = object_memory->type_info[obj->obj_type];
if(ti) {
ObjectMark mark(this);
View
43 vm/gc_baker.cpp
@@ -4,6 +4,7 @@
#include "gc_baker.hpp"
#include "objectmemory.hpp"
#include "builtin/tuple.hpp"
+#include "builtin/contexts.hpp"
namespace rubinius {
@@ -40,6 +41,8 @@ namespace rubinius {
tmp->all_flags = orig->all_flags;
tmp->field_count = orig->field_count;
tmp->klass = orig->klass;
+ tmp->ivars = orig->ivars;
+ tmp->Forwarded = 0;
for(size_t i = 0; i < orig->field_count; i++) {
tmp->field[i] = orig->field[i];
@@ -64,13 +67,33 @@ namespace rubinius {
if(obj->forwarded_p()) return obj->forward();
+ // This object is already in the next space, we don't want to
+ // copy it again!
+ // TODO test this!
+ if(next->contains_p(obj)) return obj;
+
if(obj->age++ >= lifetime) {
copy = object_memory->promote_object(obj);
+
+ // We promoted it, so our scan pointer loop wont see it to walk
+ // it's references. Instead we scan in manually here.
+ // HACK TODO this can cause a cascading C stack as a lot of
+ // objects are promoted at once and cause a stack overflow.
+ //
+ // We should keep track of all the promoted objects and walk
+ // them at the end.
+ scan_object(copy);
} else if(next->enough_space_p(obj->size_in_bytes())) {
copy = next->copy_object(obj);
total_objects++;
} else {
copy = object_memory->promote_object(obj);
+ // See note above concerning promoted objects.
+ scan_object(copy);
+ }
+
+ if(MethodContext* ctx = try_as<MethodContext>(copy)) {
+ ctx->post_copy(as<MethodContext>(obj));
}
obj->set_forward(copy);
@@ -97,9 +120,13 @@ namespace rubinius {
ObjectArray::iterator oi;
for(oi = current_rs->begin(); oi != current_rs->end(); oi++) {
- assert((*oi)->zone == MatureObjectZone);
- assert(!(*oi)->forwarded_p());
- scan_object(*oi);
+ tmp = *oi;
+ assert(tmp->zone == MatureObjectZone);
+ assert(!tmp->forwarded_p());
+
+ /* Remove the Remember bit, since we're clearing the set. */
+ tmp->Remember = 0;
+ scan_object(tmp);
}
delete current_rs;
@@ -196,4 +223,14 @@ namespace rubinius {
}
}
}
+
+ ObjectPosition BakerGC::validate_object(OBJECT obj) {
+ if(current->contains_p(obj)) {
+ return cValid;
+ } else if(next->contains_p(obj)) {
+ return cInWrongYoungHalf;
+ } else {
+ return cUnknown;
+ }
+ }
}
View
18 vm/gc_baker.hpp
@@ -3,6 +3,8 @@
#include "gc.hpp"
#include "gc_root.hpp"
+#include "object_position.hpp"
+
#include <iostream>
namespace rubinius {
@@ -45,14 +47,14 @@ namespace rubinius {
}
bool contains_p(address addr) {
- if(addr < start) return FALSE;
- if(addr >= last) return FALSE;
- return TRUE;
+ if(addr < start) return false;
+ if(addr >= last) return false;
+ return true;
}
bool enough_space_p(size_t size) {
- if((uintptr_t)current + size > (uintptr_t)last) return FALSE;
- return TRUE;
+ if((uintptr_t)current + size > (uintptr_t)last) return false;
+ return true;
}
bool fully_scanned_p() {
@@ -95,14 +97,16 @@ namespace rubinius {
OBJECT obj;
if(!current->enough_space_p(bytes)) {
+#if 0
if(!next->enough_space_p(bytes)) {
return NULL;
} else {
total_objects++;
obj = (OBJECT)next->allocate(bytes);
}
-
+#endif
*collect_now = true;
+ return NULL;
} else {
total_objects++;
obj = (OBJECT)current->allocate(bytes);
@@ -122,6 +126,8 @@ namespace rubinius {
OBJECT next_object(OBJECT obj);
void find_lost_souls();
void clean_weakrefs();
+
+ ObjectPosition validate_object(OBJECT obj);
};
};
View
16 vm/gc_marksweep.cpp
@@ -82,10 +82,13 @@ namespace rubinius {
bool collect;
OBJECT obj = allocate(orig->field_count, &collect);
+ // HACK this code is exactly duplicated from BakerGC
+
obj->all_flags = orig->all_flags;
obj->field_count = orig->field_count;
obj->klass = orig->klass;
obj->age = 0;
+ obj->ivars = orig->ivars;
for(size_t i = 0; i < orig->field_count; i++) {
obj->field[i] = orig->field[i];
@@ -149,6 +152,19 @@ namespace rubinius {
}
}
+ ObjectPosition MarkSweepGC::validate_object(OBJECT obj) {
+ std::list<Entry*>::iterator i;
+
+ for(i = entries.begin(); i != entries.end(); i++) {
+ Entry* entry = *i;
+ if(entry->header->to_object() == obj) {
+ return cMatureObject;
+ }
+ }
+
+ return cUnknown;
+ }
+
// HACK todo test this!
void MarkSweepGC::clean_weakrefs() {
if(!weak_refs) return;
View
3 vm/gc_marksweep.hpp
@@ -4,6 +4,7 @@
#include "object.hpp"
#include "gc.hpp"
#include "gc_root.hpp"
+#include "object_position.hpp"
#include <list>
@@ -82,6 +83,8 @@ namespace rubinius {
void free_object(Entry *entry);
virtual OBJECT saw_object(OBJECT obj);
void collect(Roots &roots);
+
+ ObjectPosition validate_object(OBJECT obj);
};
};
View
5 vm/gc_root.cpp
@@ -3,5 +3,8 @@
namespace rubinius {
Root::Root(STATE) : object(NULL), roots(&state->globals.roots) { }
- Root::Root(STATE, OBJECT obj) : object(obj), roots(&state->globals.roots) { }
+
+ Root::Root(STATE, OBJECT obj) : object(obj), roots(&state->globals.roots) {
+ roots->push_back(this);
+ }
}
View
6 vm/global_cache.hpp
@@ -21,7 +21,7 @@ namespace rubinius {
struct cache_entry entries[CPU_CACHE_SIZE];
- GlobalCache() {
+ void clear() {
for(size_t i = 0; i < CPU_CACHE_SIZE; i++) {
entries[i].klass = 0;
entries[i].name = 0;
@@ -31,6 +31,10 @@ namespace rubinius {
}
}
+ GlobalCache() {
+ clear();
+ }
+
struct cache_entry* lookup(Module* cls, SYMBOL name) {
struct cache_entry* entry;
View
25 vm/objectmemory.cpp
@@ -94,6 +94,7 @@ namespace rubinius {
/* Store an object into the remember set. Called when we've calculated
* externally that the object in question needs to be remembered */
void ObjectMemory::remember_object(OBJECT target) {
+ assert(target->zone == MatureObjectZone);
/* If it's already remembered, ignore this request */
if(target->Remember) return;
target->Remember = 1;
@@ -219,21 +220,8 @@ namespace rubinius {
OBJECT ObjectMemory::create_object(Class* cls, size_t fields) {
OBJECT obj;
- gc_zone loc;
-
- if(fields > large_object_threshold) {
- obj = mature.allocate(fields, &collect_mature_now);
- loc = MatureObjectZone;
- } else {
- if((obj = young.allocate(fields, &collect_young_now))) {
- loc = YoungObjectZone;
- } else {
- obj = mature.allocate(fields, &collect_mature_now);
- loc = MatureObjectZone;
- }
- }
- obj->init(loc, fields);
+ obj = allocate_object(fields);
set_class(obj, cls);
obj->obj_type = (object_type)cls->instance_type->to_native();
@@ -245,6 +233,15 @@ namespace rubinius {
TypeInfo* ObjectMemory::find_type_info(OBJECT obj) {
return type_info[obj->obj_type];
}
+
+ ObjectPosition ObjectMemory::validate_object(OBJECT obj) {
+ ObjectPosition pos;
+
+ pos = young.validate_object(obj);
+ if(pos != cUnknown) return pos;
+
+ return mature.validate_object(obj);
+ }
};
void* XMALLOC(size_t bytes) {
View
4 vm/objectmemory.hpp
@@ -6,6 +6,8 @@
#include "gc_baker.hpp"
#include "type_info.hpp"
+#include "object_position.hpp"
+
namespace rubinius {
/* ObjectMemory is the primary API that the rest of the VM uses to interact
@@ -64,6 +66,8 @@ namespace rubinius {
bool valid_object_p(OBJECT obj);
void debug_marksweep(bool val);
void add_type_info(TypeInfo* ti);
+
+ ObjectPosition validate_object(OBJECT obj);
};
// Type-safe, write-barrier-enabled version of 'SET'
View
6 vm/vm.cpp
@@ -25,15 +25,14 @@
#define GO(whatever) globals.whatever
namespace rubinius {
- VM::VM(size_t bytes) : probe(NULL), wait_events(false) {
+ VM::VM(size_t bytes) : wait_events(false) {
config.compile_up_front = false;
context_cache = NULL;
- probe = (TaskProbe*)Qnil;
-
user_config = new ConfigParser();
om = new ObjectMemory(bytes);
+ probe.set(Qnil, &globals.roots);
MethodContext::initialize_cache(this);
TypeInfo::init(this);
@@ -247,6 +246,7 @@ namespace rubinius {
void VM::run_and_monitor() {
for(;;) {
+ G(current_task)->check_interrupts();
G(current_task)->execute();
}
}
View
2 vm/vm.hpp
@@ -48,7 +48,7 @@ namespace rubinius {
event::Loop* events;
event::Loop* signal_events;
GlobalCache* global_cache;
- TaskProbe* probe;
+ TypedRoot<TaskProbe*> probe;
Primitives* primitives;
Configuration config;
Interrupts interrupts;

0 comments on commit 8906a3f

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