Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Clean up young generation debris.
Browse files Browse the repository at this point in the history
brixen committed Jul 4, 2016
1 parent f412225 commit d653ec8
Showing 21 changed files with 41 additions and 599 deletions.
2 changes: 2 additions & 0 deletions machine/builtin/string.hpp
Original file line number Diff line number Diff line change
@@ -187,6 +187,7 @@ namespace rubinius {
* allocate a new object in the young space, we can copy it directly
* without needing a write barrier.
*/
/* TODO: young gen removal
String* so = state->memory()->new_object<String>(state, G(string));
if(likely(so->young_object_p())) {
so->copy_body(state, this);
@@ -195,6 +196,7 @@ namespace rubinius {
infect(state, so);
return so;
}
*/
}
return string_dup_slow(state);
}
34 changes: 2 additions & 32 deletions machine/capi/handles.cpp
Original file line number Diff line number Diff line change
@@ -70,9 +70,7 @@ namespace rubinius {
if(diagnostics()) delete diagnostics();
}

void Handles::deallocate_handles(std::list<Handle*>* cached,
unsigned int mark, /* BakerGC */ void* young)
{
void Handles::deallocate_handles(std::list<Handle*>* cached, unsigned int mark) {
std::vector<bool> chunk_marks(allocator_->chunks_.size(), false);

diagnostics()->objects_ = 0;
@@ -96,35 +94,7 @@ namespace rubinius {
continue;
}

if(young) {
/*
if(obj->young_object_p()) {
// A weakref pointing to a valid young object
//
// TODO this only works because we run prune_handles right after
// a collection. In this state, valid objects are only in current.
if(young->in_current_p(obj)) {
chunk_marks[i] = true;
diagnostics()->objects_++;
// A weakref pointing to a forwarded young object
} else if(obj->forwarded_p()) {
handle->set_object(obj->forward());
chunk_marks[i] = true;
diagnostics()->objects_++;
// A weakref pointing to a dead young object
} else {
handle->clear();
}
} else {
// Not a young object, so won't be GC'd so mark
// chunk as still active
chunk_marks[i] = true;
diagnostics()->objects_++;
}
*/

// A weakref pointing to a dead mature object
} else if(!obj->marked_p(mark)) {
if(!obj->marked_p(mark)) {
handle->clear();
} else {
chunk_marks[i] = true;
2 changes: 1 addition & 1 deletion machine/capi/handles.hpp
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ namespace rubinius {

bool validate(Handle* handle);

void deallocate_handles(std::list<Handle*>* cached, unsigned int mark, /* BakerGC */ void* young);
void deallocate_handles(std::list<Handle*>* cached, unsigned int mark);

void flush_all(NativeMethodEnvironment* env);

27 changes: 0 additions & 27 deletions machine/global_cache.cpp
Original file line number Diff line number Diff line change
@@ -193,33 +193,6 @@ namespace rubinius {
Object* klass = entry->klass;
if(!klass) continue;

if(klass->young_object_p()) {
if(klass->forwarded_p()) {
Module* fwd = force_as<Module>(klass->forward());
entry->klass = fwd;
} else {
clear = true;
}
}

Object* mod = entry->module;
if(mod->young_object_p()) {
if(mod->forwarded_p()) {
entry->module = force_as<Module>(mod->forward());
} else {
clear = true;
}
}

Object* exec = entry->method;
if(exec->young_object_p()) {
if(exec->forwarded_p()) {
entry->method = force_as<Executable>(exec->forward());
} else {
clear = true;
}
}

if(clear) {
entry_names[i] = NULL;
entry->clear();
93 changes: 6 additions & 87 deletions machine/memory.cpp
Original file line number Diff line number Diff line change
@@ -68,7 +68,6 @@ namespace rubinius {
, mature_gc_in_progress_(false)
, slab_size_(4096)
, interrupt_flag_(false)
, collect_young_flag_(false)
, collect_full_flag_(false)
, last_object_id(1)
, last_snapshot_id(0)
@@ -82,6 +81,8 @@ namespace rubinius {
}
#endif

state->shared().set_memory(this);

for(size_t i = 0; i < LastObjectType; i++) {
type_info[i] = NULL;
}
@@ -100,7 +101,6 @@ namespace rubinius {

delete immix_;
delete mark_sweep_;
/* delete young_; */

for(std::list<capi::GlobalHandle*>::iterator i = global_capi_handle_locations_.begin();
i != global_capi_handle_locations_.end(); ++i) {
@@ -421,26 +421,6 @@ namespace rubinius {
}
}

bool Memory::refill_slab(STATE, memory::Slab& slab) {
utilities::thread::SpinLock::LockGuard guard(allocation_lock_);

memory::Address addr = memory::Address::null(); /* young_->allocate_for_slab(slab_size_); */

metrics::MetricsData& metrics = state->vm()->metrics();
metrics.memory.young_objects += slab.allocations();
metrics.memory.young_bytes += slab.bytes_used();

if(addr) {
slab.refill(addr, slab_size_);
metrics.memory.slab_refills++;
return true;
} else {
slab.refill(0, 0);
metrics.memory.slab_refills_fails++;
return false;
}
}

bool Memory::valid_object_p(STATE, Object* obj) {
if(obj->true_p()) {
return true;
@@ -454,8 +434,6 @@ namespace rubinius {
return true;
} else if(obj->symbol_p()) {
return true;
} else if(obj->young_object_p()) {
return false; /* young_->validate_object(obj) == cValid; */
} else if(obj->mature_object_p()) {
if(obj->in_immix_p()) {
if(immix_->validate_object(state, obj) == cInImmix) {
@@ -511,76 +489,24 @@ namespace rubinius {
* prohibition lifts, a GC will eventually be triggered again.
*/
if(!can_gc()) {
collect_young_flag_ = false;
collect_full_flag_ = false;
interrupt_flag_ = false;
return;
}

if(!collect_young_flag_ && !collect_full_flag_) return;
if(!collect_full_flag_) return;

if(cDebugThreading) {
std::cerr << std::endl << "[" << state
<< " WORLD beginning GC.]" << std::endl;
}

if(collect_young_flag_) {
memory::GCData gc_data(state);

RUBINIUS_GC_BEGIN(0);
collect_young(state, &gc_data);

if(!collect_full_flag_) interrupt_flag_ = false;

RUBINIUS_GC_END(0);
}

if(collect_full_flag_) {
RUBINIUS_GC_BEGIN(1);
collect_full(state);
}
}

void Memory::collect_young(STATE, memory::GCData* data) {
timer::StopWatch<timer::milliseconds> timerx(
state->vm()->metrics().gc.young_ms);

/*
young_->collect(data);
prune_handles(state, data->handles(), data->cached_handles(), young_);
metrics::MetricsData& metrics = state->vm()->metrics();
metrics.gc.young_count++;
data->global_cache()->prune_young();
{
std::lock_guard<std::mutex> guard(data->thread_nexus()->threads_mutex());
for(ThreadList::iterator i = data->thread_nexus()->threads()->begin();
i != data->thread_nexus()->threads()->end();
++i)
{
memory::Slab& slab = (*i)->local_slab();
// Reset the slab to a size of 0 so that the thread has to do
// an allocation to get a proper refill. This keeps the number
// of threads in the system from starving the available
// number of slabs.
slab.refill(0, 0);
}
}
young_->reset();
#ifdef RBX_GC_DEBUG
young_->verify(data);
#endif
*/

collect_young_flag_ = false;
}

void Memory::collect_full(STATE) {
// If we're already collecting, ignore this request
if(mature_gc_in_progress_) return;
@@ -634,7 +560,7 @@ namespace rubinius {

data->global_cache()->prune_unmarked(mark());

prune_handles(state, data->handles(), data->cached_handles(), NULL);
prune_handles(state, data->handles(), data->cached_handles());

// Have to do this after all things that check for mark bits is
// done, as it free()s objects, invalidating mark bits.
@@ -723,10 +649,8 @@ namespace rubinius {

}

void Memory::prune_handles(STATE, capi::Handles* handles,
std::list<capi::Handle*>* cached, /* BakerGC */ void* young)
{
handles->deallocate_handles(cached, mark(), young);
void Memory::prune_handles(STATE, capi::Handles* handles, std::list<capi::Handle*>* cached) {
handles->deallocate_handles(cached, mark());
}

void Memory::add_type_info(STATE, TypeInfo* ti) {
@@ -793,11 +717,6 @@ namespace rubinius {
ObjectPosition Memory::validate_object(STATE, Object* obj) {
ObjectPosition pos;

/*
pos = young_->validate_object(obj);
if(pos != cUnknown) return pos;
*/

pos = immix_->validate_object(state, obj);
if(pos != cUnknown) return pos;

43 changes: 2 additions & 41 deletions machine/memory.hpp
Original file line number Diff line number Diff line change
@@ -115,9 +115,6 @@ namespace rubinius {
/// Flag indicating that a Memory condition exists
bool interrupt_flag_;

/// Flag indicating whether a young collection should be performed soon
bool collect_young_flag_;

/// Flag indicating whether a full collection should be performed soon
bool collect_full_flag_;

@@ -172,16 +169,6 @@ namespace rubinius {
allow_gc_ = false;
}

void schedule_young_collection(STATE, metrics::metric& counter) {
counter++;

// Don't trigger GC if currently prohibited so we don't thrash checking.
if(can_gc()) {
interrupt_flag_ = collect_young_flag_ = true;
state->vm()->thread_nexus()->set_stop();
}
}

void schedule_full_collection(STATE, const char* trigger, metrics::metric& counter) {
counter++;
schedule_full_collection(state, trigger);
@@ -277,25 +264,7 @@ namespace rubinius {
Object* new_object(STATE, Class* klass, native_int bytes, object_type type) {
// TODO: GC
// allocate:
Object* obj = 0; /* state->vm()->local_slab().allocate(bytes).as<Object>();
if(likely(obj)) {
state->vm()->metrics().memory.young_objects++;
state->vm()->metrics().memory.young_bytes += bytes;
obj->init_header(YoungObjectZone, type);
goto set_klass;
}
if(state->vm()->local_slab().empty_p()) {
if(refill_slab(state, state->vm()->local_slab())) {
goto allocate;
} else {
schedule_young_collection(state->vm(), state->vm()->metrics().gc.young_set);
}
}
*/
Object* obj = 0;

if(likely(obj = new_object(state, bytes))) goto set_type;

@@ -510,8 +479,6 @@ namespace rubinius {
TypeInfo* find_type_info(STATE, Object* obj);
Object* promote_object(STATE, Object* obj);

bool refill_slab(STATE, memory::Slab& slab);

void assign_object_id(STATE, Object* obj);
bool inflate_lock_count_overflow(STATE, ObjectHeader* obj, int count);
LockStatus contend_for_lock(STATE, ObjectHeader* obj, size_t us, bool interrupt);
@@ -525,14 +492,12 @@ namespace rubinius {
void add_code_resource(STATE, memory::CodeResource* cr);

void validate_handles(STATE, capi::Handles* handles);
void prune_handles(STATE, capi::Handles* handles,
std::list<capi::Handle*>* cached, /* BakerGC */ void* young);
void prune_handles(STATE, capi::Handles* handles, std::list<capi::Handle*>* cached);

ObjectPosition validate_object(STATE, Object* obj);

void collect(STATE) {
if(can_gc()) {
collect_young_flag_ = true;
collect_full_flag_ = true;
interrupt_flag_ = true;
state->vm()->thread_nexus()->set_stop();
@@ -590,10 +555,6 @@ namespace rubinius {
return interrupt_flag_;
}

bool& collect_young_p() {
return collect_young_flag_;
}

bool& collect_full_p() {
return collect_full_flag_;
}
8 changes: 0 additions & 8 deletions machine/memory/debug.cpp
Original file line number Diff line number Diff line change
@@ -34,14 +34,6 @@ namespace memory {

seen[obj] = 1;

/*
if(obj->young_object_p()) {
if(!memory_->young.current->contains_p(obj)) {
throw std::runtime_error("Invalid young object detected.");
}
}
*/

scan_object(state, obj);

return NULL;
37 changes: 13 additions & 24 deletions machine/memory/gc.cpp
Original file line number Diff line number Diff line change
@@ -296,15 +296,15 @@ namespace memory {
}


void GarbageCollector::scan(STATE, ManagedThread* thr, bool young_only) {
void GarbageCollector::scan(STATE, ManagedThread* thr) {
for(Roots::Iterator ri(thr->roots()); ri.more(); ri.advance()) {
if(Object* fwd = saw_object(state, ri->get())) {
ri->set(fwd);
}
}

scan(state, thr->variable_root_buffers(), young_only);
scan(state, thr->root_buffers(), young_only);
scan(state, thr->variable_root_buffers());
scan(state, thr->root_buffers());

if(VM* vm = thr->as_vm()) {
vm->gc_scan(state, this);
@@ -330,7 +330,7 @@ namespace memory {
}

void GarbageCollector::scan(STATE, VariableRootBuffers& buffers,
bool young_only, AddressDisplacement* offset)
AddressDisplacement* offset)
{
VariableRootBuffer* vrb = displace(buffers.front(), offset);

@@ -340,7 +340,7 @@ namespace memory {
Object** var = displace(buffer[idx], offset);
Object* cur = *var;

if(cur && cur->reference_p() && (!young_only || cur->young_object_p())) {
if(cur && cur->reference_p()) {
if(Object* tmp = saw_object(state, cur)) {
*var = tmp;
}
@@ -351,7 +351,7 @@ namespace memory {
}
}

void GarbageCollector::scan(STATE, RootBuffers& buffers, bool young_only) {
void GarbageCollector::scan(STATE, RootBuffers& buffers) {
for(RootBuffers::Iterator i(buffers);
i.more();
i.advance())
@@ -360,7 +360,7 @@ namespace memory {
for(int idx = 0; idx < i->size(); idx++) {
Object* cur = buffer[idx];

if(cur->reference_p() && (!young_only || cur->young_object_p())) {
if(cur->reference_p()) {
if(Object* tmp = saw_object(state, cur)) {
buffer[idx] = tmp;
}
@@ -383,13 +383,15 @@ namespace memory {
if(!obj->reference_p()) continue;

if(check_forwards) {
/* TODO: young gen removal
if(obj->young_object_p()) {
if(!obj->forwarded_p()) {
ref->set_object(memory_, cNil);
} else {
ref->set_object(memory_, obj->forward());
}
}
*/
} else if(!obj->marked_p(memory_->mark())) {
ref->set_object(memory_, cNil);
}
@@ -399,28 +401,15 @@ namespace memory {
weak_refs_ = NULL;
}

void GarbageCollector::clean_locked_objects(STATE, ManagedThread* thr, bool young_only) {
void GarbageCollector::clean_locked_objects(STATE, ManagedThread* thr) {
LockedObjects& los = thr->locked_objects();
for(LockedObjects::iterator i = los.begin();
i != los.end();) {
Object* obj = static_cast<Object*>(*i);
if(young_only) {
if(obj->young_object_p()) {
if(obj->forwarded_p()) {
*i = obj->forward();
++i;
} else {
i = los.erase(i);
}
} else {
++i;
}
if(!obj->marked_p(memory_->mark())) {
i = los.erase(i);
} else {
if(!obj->marked_p(memory_->mark())) {
i = los.erase(i);
} else {
++i;
}
++i;
}
}
}
8 changes: 4 additions & 4 deletions machine/memory/gc.hpp
Original file line number Diff line number Diff line change
@@ -142,12 +142,12 @@ namespace memory {
}

void clean_weakrefs(STATE, bool check_forwards=false);
void clean_locked_objects(STATE, ManagedThread* thr, bool young_only);
void clean_locked_objects(STATE, ManagedThread* thr);

// Scans the thread for object references
void scan(STATE, ManagedThread* thr, bool young_only);
void scan(STATE, VariableRootBuffers& buffers, bool young_only, AddressDisplacement* offset=0);
void scan(STATE, RootBuffers& rb, bool young_only);
void scan(STATE, ManagedThread* thr);
void scan(STATE, VariableRootBuffers& buffers, AddressDisplacement* offset=0);
void scan(STATE, RootBuffers& rb);

void verify(STATE, GCData* data);

16 changes: 6 additions & 10 deletions machine/memory/immix_collector.cpp
Original file line number Diff line number Diff line change
@@ -64,6 +64,7 @@ namespace memory {
, diagnostics_(new Diagnostics())
{
gc_.describer().set_object_memory(om, this);
allocator_.get_new_block(state);
reset_chunks_left();
}

@@ -103,14 +104,9 @@ namespace memory {
Address ImmixGC::ObjectDescriber::update_pointer(STATE, Address addr) {
Object* obj = addr.as<Object>();
if(!obj) return Address::null();
if(obj->young_object_p()) {
if(obj->forwarded_p()) return obj->forward();
return Address::null();
} else {
// we must remember this because it might
// contain references to young gen objects
memory_->remember_object(obj);
}
// we must remember this because it might
// contain references to young gen objects
memory_->remember_object(obj);
return addr;
}

@@ -221,7 +217,7 @@ namespace memory {
i != state->vm()->thread_nexus()->threads()->end();
++i)
{
scan(state, *i, false);
scan(state, *i);
}
}

@@ -323,7 +319,7 @@ namespace memory {
i != state->vm()->thread_nexus()->threads()->end();
++i)
{
clean_locked_objects(state, *i, false);
clean_locked_objects(state, *i);
}
}

2 changes: 0 additions & 2 deletions machine/memory/immix_marker.cpp
Original file line number Diff line number Diff line change
@@ -72,8 +72,6 @@ namespace memory {
while(immix_->process_mark_stack(state, immix_->memory()->interrupt_p())) {
if(thread_exit_ || immix_->memory()->collect_full_p()) {
break;
} else if(immix_->memory()->collect_young_p()) {
state->vm()->checkpoint(state);
} else if(immix_->memory()->interrupt_p()) {
// We may be trying to fork or otherwise checkpoint
state->vm()->checkpoint(state);
1 change: 0 additions & 1 deletion machine/memory/immix_region.hpp
Original file line number Diff line number Diff line change
@@ -936,7 +936,6 @@ namespace memory {
, declines_(0)
, collection_pending_(false)
{
get_new_block(state);
}

/**
2 changes: 1 addition & 1 deletion machine/memory/walker.cpp
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ namespace memory {
i != state->vm()->thread_nexus()->threads()->end();
++i)
{
scan(state, *i, false);
scan(state, *i);
}
}

2 changes: 0 additions & 2 deletions machine/memory/write_barrier.hpp
Original file line number Diff line number Diff line change
@@ -88,8 +88,6 @@ namespace memory {
mark_object(reinterpret_cast<Object*>(val));
}
if(target->remembered_p()) return;
if(target->young_object_p()) return;
if(!val->young_object_p()) return;
}

remember_object(reinterpret_cast<Object*>(target));
10 changes: 0 additions & 10 deletions machine/metrics.cpp
Original file line number Diff line number Diff line change
@@ -283,12 +283,6 @@ namespace rubinius {
"console.responses.sent", metrics_data_.console.responses_sent));

// GC metrics
metrics_map_.push_back(new MetricsItem(
"gc.young.set", metrics_data_.gc.young_set));
metrics_map_.push_back(new MetricsItem(
"gc.young.count", metrics_data_.gc.young_count));
metrics_map_.push_back(new MetricsItem(
"gc.young.ms", metrics_data_.gc.young_ms));
metrics_map_.push_back(new MetricsItem(
"gc.immix.set", metrics_data_.gc.immix_set));
metrics_map_.push_back(new MetricsItem(
@@ -399,10 +393,6 @@ namespace rubinius {
"machine.profile.ns", metrics_data_.machine.profile_ns));

// Memory metrics
metrics_map_.push_back(new MetricsItem(
"memory.young.bytes", metrics_data_.memory.young_bytes));
metrics_map_.push_back(new MetricsItem(
"memory.young.objects", metrics_data_.memory.young_objects));
metrics_map_.push_back(new MetricsItem(
"memory.immix.bytes", metrics_data_.memory.immix_bytes));
metrics_map_.push_back(new MetricsItem(
15 changes: 0 additions & 15 deletions machine/metrics.hpp
Original file line number Diff line number Diff line change
@@ -49,9 +49,6 @@ namespace rubinius {
};

struct GCMetrics {
metric young_set;
metric young_count;
metric young_ms;
metric immix_set;
metric immix_count;
metric immix_stop_ms;
@@ -68,9 +65,6 @@ namespace rubinius {
metric resource_set;

GCMetrics() {
young_set = 0;
young_count = 0;
young_ms = 0;
immix_set = 0;
immix_count = 0;
immix_stop_ms = 0;
@@ -88,9 +82,6 @@ namespace rubinius {
}

void add(GCMetrics& data) {
young_set += data.young_set;
young_count += data.young_count;
young_ms += data.young_ms;
immix_set += data.immix_set;
immix_count += data.immix_count;
immix_stop_ms += data.immix_stop_ms;
@@ -247,8 +238,6 @@ namespace rubinius {
};

struct MemoryMetrics {
metric young_bytes;
metric young_objects;
metric immix_bytes;
metric immix_objects;
metric immix_chunks;
@@ -268,8 +257,6 @@ namespace rubinius {
metric suspend_ms;

MemoryMetrics() {
young_bytes = 0;
young_objects = 0;
immix_bytes = 0;
immix_objects = 0;
immix_chunks = 0;
@@ -290,8 +277,6 @@ namespace rubinius {
}

void add(MemoryMetrics& data) {
young_bytes += data.young_bytes;
young_objects += data.young_objects;
immix_bytes += data.immix_bytes;
immix_objects += data.immix_objects;
immix_chunks += data.immix_chunks;
3 changes: 0 additions & 3 deletions machine/oop.cpp
Original file line number Diff line number Diff line change
@@ -224,9 +224,6 @@ namespace rubinius {
}

bool ObjectHeader::pin() {
// Can't pin young objects!
if(young_object_p()) return false;

for(;;) {
HeaderWord orig = header;
HeaderWord new_val = orig;
5 changes: 0 additions & 5 deletions machine/oop.hpp
Original file line number Diff line number Diff line change
@@ -108,7 +108,6 @@ Object* const cUndef = reinterpret_cast<Object*>(0x22L);
{
UnspecifiedZone = 0,
MatureObjectZone = 1,
YoungObjectZone = 2,
} gc_zone;

class Class;
@@ -447,10 +446,6 @@ Object* const cUndef = reinterpret_cast<Object*>(0x22L);
return __REFERENCE_P__(this);
}

bool young_object_p() const {
return zone() == YoungObjectZone;
}

bool mature_object_p() const {
return zone() == MatureObjectZone;
}
4 changes: 4 additions & 0 deletions machine/shared_state.hpp
Original file line number Diff line number Diff line change
@@ -296,6 +296,10 @@ namespace rubinius {
return root_vm_;
}

void set_memory(Memory* memory) {
om = memory;
}

Memory* memory() const {
return om;
}
287 changes: 0 additions & 287 deletions machine/test/test_object_memory.hpp
Original file line number Diff line number Diff line change
@@ -43,46 +43,6 @@ class TestMemory : public CxxTest::TestSuite, public VMTest {
return Tuple::create(state, count);
}

/* TODO: young gen
void xtest_new_object() {
Memory& om = *state->memory();
om.collect_young(state, gc_data);
Tuple* obj = util_new_object(om);
TS_ASSERT_EQUALS(obj->num_fields(), 3);
TS_ASSERT_EQUALS(obj->zone(), YoungObjectZone);
}
*/

/* TODO: young gen
void xtest_write_barrier() {
Memory& om = *state->memory();
Object* obj;
Object* obj2;
om.collect_young(state, gc_data);
obj = util_new_object(om);
obj2 = util_new_object(om);
TS_ASSERT_EQUALS(obj->remembered_p(), 0U);
TS_ASSERT_EQUALS(obj2->remembered_p(), 0U);
size_t start = om.remember_set()->size();
obj->set_zone(MatureObjectZone);
TS_ASSERT(obj2->young_object_p());
om.write_barrier(obj, obj2);
TS_ASSERT_EQUALS(om.remember_set()->size(), start + 1);
TS_ASSERT_EQUALS(obj->remembered_p(), 1U);
om.write_barrier(obj, obj2);
TS_ASSERT_EQUALS(om.remember_set()->size(), start + 1);
}
*/

/* Causes a segfault when fails. */
void test_write_barrier_not_called_for_immediates() {
Memory& om = *state->memory();
@@ -98,216 +58,16 @@ class TestMemory : public CxxTest::TestSuite, public VMTest {
TS_ASSERT_EQUALS(obj->remembered_p(), 0U);
}

/* TODO: young gen
void xtest_collect_young() {
Memory& om = *state->memory();
Object* obj;
size_t start = om.young_->bytes_used();
util_new_object(om);
util_new_object(om);
util_new_object(om);
util_new_object(om);
util_new_object(om);
om.collect_young(state, gc_data);
TS_ASSERT(om.young_->bytes_used() <= start);
obj = util_new_object(om);
TS_ASSERT_EQUALS(obj->age(), 0U);
memory::Root r(roots, obj);
om.collect_young(state, gc_data);
TS_ASSERT(obj->forwarded_p());
}
*/

/* TODO: young gen
void xtest_collect_young_through_references() {
Memory& om = *state->memory();
Tuple *obj, *obj2, *obj3;
om.collect_young(state, gc_data);
obj = as<Tuple>(util_new_object(om));
obj2 = as<Tuple>(util_new_object(om));
obj->field[0] = obj2;
obj2->field[0] = cTrue;
TS_ASSERT(obj->young_object_p());
TS_ASSERT(obj2->young_object_p());
memory::Root r(roots, obj);
om.collect_young(state, gc_data);
TS_ASSERT(obj->forwarded_p());
TS_ASSERT(obj2->forwarded_p());
Object* new_obj = roots->front()->get();
TS_ASSERT(obj != new_obj);
obj = as<Tuple>(new_obj);
TS_ASSERT(om.young_->in_current_p(obj));
obj3 = as<Tuple>(obj->field[0]);
TS_ASSERT(obj2 != obj3);
TS_ASSERT_EQUALS(obj2->field[0], cTrue);
}
*/

#define LARGE_OBJECT_BYTE_SIZE 30 * 1024 * 1024

void test_new_large_object() {
Memory& om = *state->memory();
Tuple* obj;

/* TODO: young gen
size_t start = om.young_->bytes_used();
*/

obj = util_new_object(om, LARGE_OBJECT_BYTE_SIZE);
TS_ASSERT_EQUALS(obj->num_fields(), LARGE_OBJECT_BYTE_SIZE);
TS_ASSERT_EQUALS(obj->zone(), MatureObjectZone);

/* TODO: young gen
TS_ASSERT_EQUALS(om.young_->bytes_used(), start);
*/
}

void test_collect_young_doesnt_move_mature_objects() {
Memory& om = *state->memory();
Object* obj;

obj = util_new_object(om, LARGE_OBJECT_BYTE_SIZE);

memory::Root r(roots, obj);

om.collect_young(state, gc_data);

TS_ASSERT_EQUALS(obj, roots->front()->get());
}

/* TODO: young gen
void xtest_collect_young_uses_remember_set() {
Memory& om = *state->memory();
Tuple *young, *mature;
om.collect_young(state, gc_data);
young = as<Tuple>(util_new_object(om));
TS_ASSERT_EQUALS(young->zone(), YoungObjectZone);
mature = as<Tuple>(util_new_object(om, LARGE_OBJECT_BYTE_SIZE));
TS_ASSERT_EQUALS(mature->zone(), MatureObjectZone);
young->field[0] = cTrue;
mature->field[0] = young;
om.write_barrier(mature, young);
TS_ASSERT_EQUALS(mature->remembered_p(), 1U);
om.collect_young(state, gc_data);
TS_ASSERT(mature->field[0] != young);
TS_ASSERT_EQUALS((as<Tuple>(mature->field[0])->field[0]), cTrue);
}
*/

/* TODO: young gen
void xtest_collect_young_promotes_objects() {
Memory& om = *state->memory();
Object* young;
om.collect_young(state, gc_data);
young = util_new_object(om);
memory::Root r(roots, young);
TS_ASSERT_EQUALS(young->age(), 0U);
om.collect_young(state, gc_data);
TS_ASSERT_EQUALS(roots->front()->get()->age(), 1U);
om.collect_young(state, gc_data);
TS_ASSERT_EQUALS(roots->front()->get()->age(), 2U);
om.collect_young(state, gc_data);
TS_ASSERT(roots->front()->get()->mature_object_p());
}
*/

/* TODO: young gen
void xtest_collect_young_resets_remember_set() {
Memory& om = *state->memory();
Tuple *young, *mature;
om.collect_young(state, gc_data);
young = as<Tuple>(util_new_object(om));
mature = as<Tuple>(util_new_object(om, LARGE_OBJECT_BYTE_SIZE));
TS_ASSERT(mature->mature_object_p());
TS_ASSERT(young->young_object_p());
mature->field[0] = young;
om.write_barrier(mature, young);
TS_ASSERT_EQUALS(mature->remembered_p(), 1U);
TS_ASSERT_EQUALS(young->age(), 0U);
om.collect_young(state, gc_data);
TS_ASSERT_EQUALS(mature->field[0]->age(), 1U);
om.collect_young(state, gc_data);
TS_ASSERT_EQUALS(mature->field[0]->age(), 2U);
om.collect_young(state, gc_data);
}
*/

/* TODO: young gen
void xtest_collect_young_uses_forwarding_pointers() {
Memory& om = *state->memory();
Tuple *obj, *obj2;
obj = as<Tuple>(util_new_object(om));
obj2 = as<Tuple>(util_new_object(om));
obj->field[0] = obj2;
obj->field[1] = obj2;
obj->field[2] = obj2;
om.write_barrier(obj, obj2);
memory::Root r(roots, obj);
om.collect_young(state, gc_data);
obj = as<Tuple>(roots->front()->get());
obj2 = as<Tuple>(obj->field[0]);
TS_ASSERT_EQUALS(obj2, obj->field[1]);
TS_ASSERT_EQUALS(obj2, obj->field[2]);
}
*/

/* TODO: young gen
void xtest_collect_young_copies_byte_bodies() {
Memory& om = *state->memory();
ByteArray* obj;
obj = ByteArray::create(state, 3);
obj->raw_bytes()[0] = 47;
memory::Root r(roots, obj);
om.collect_young(state, gc_data);
obj = as<ByteArray>(roots->front()->get());
TS_ASSERT_EQUALS(obj->raw_bytes()[0], static_cast<char>(47));
}
*/

void test_collect_full() {
Memory& om = *state->memory();
@@ -329,26 +89,6 @@ class TestMemory : public CxxTest::TestSuite, public VMTest {
TS_ASSERT(mature->marked_p(mark));
}

void test_collect_full_marks_young_objects() {
Memory& om = *state->memory();
Tuple* young;
Object* mature;

young = util_new_object(om);
mature = util_new_object(om, LARGE_OBJECT_BYTE_SIZE);

young->field[0] = mature; // dangerous, but ok in tests

unsigned int mark = om.mark();
TS_ASSERT(!young->marked_p(mark));
memory::Root r(roots, young);

om.collect_full(state);
gc_data = NULL;

TS_ASSERT(young->marked_p(mark));
}

/* Could segfault on failure due to infinite loop. */
void test_collect_full_stops_at_already_marked_objects() {
Memory& om = *state->memory();
@@ -375,33 +115,6 @@ class TestMemory : public CxxTest::TestSuite, public VMTest {
TS_ASSERT_EQUALS(mature->field[0], young);
}

/* TODO: young gen
void xtest_collect_young_stops_at_already_marked_objects() {
Memory& om = *state->memory();
Tuple *obj, *obj2;
obj = as<Tuple>(util_new_object(om));
obj2 = as<Tuple>(util_new_object(om));
obj2->field[1] = cTrue;
obj->field[0] = obj2;
obj2->field[0] = obj;
om.write_barrier(obj, obj2);
om.write_barrier(obj2, obj);
memory::Root r(roots, obj);
om.collect_young(state, gc_data);
obj = as<Tuple>(roots->front()->get());
obj2 = as<Tuple>(obj->field[0]);
TS_ASSERT_EQUALS(obj2->field[0], obj);
TS_ASSERT_EQUALS(obj2->field[1], cTrue);
}
*/

void test_valid_object_p() {
Memory& om = *state->memory();
Object* obj;
39 changes: 0 additions & 39 deletions machine/test/test_vm.hpp
Original file line number Diff line number Diff line change
@@ -39,43 +39,4 @@ class TestVM : public CxxTest::TestSuite, public VMTest {

TS_ASSERT_EQUALS(sym1, sym2);
}

void test_collection() {
std::map<int, Object*> objs;

int index = 0;
memory::Root* root = static_cast<memory::Root*>(state->globals().roots.head());
while(root) {
Object* tmp = root->get();
if(tmp->reference_p() && tmp->young_object_p()) {
objs[index] = tmp;
}
index++;

root = static_cast<memory::Root*>(root->next());
}

//std::cout << "young: " << index << " (" <<
// state->om->young.total_objects << ")" << std::endl;

memory::GCData gc_data(state->vm());
state->memory()->collect_young(state, &gc_data);

index = 0;
root = static_cast<memory::Root*>(state->globals().roots.head());
while(root) {
if(Object* tmp = objs[index]) {
TS_ASSERT(root->get() != tmp);
}
index++;

root = static_cast<memory::Root*>(root->next());
}

memory::HeapDebug hd(state->memory());
hd.walk(state->globals().roots);

//std::cout << "total: " << hd.seen_objects << " (" <<
// state->om->young.total_objects << ")" << std::endl;
}
};

0 comments on commit d653ec8

Please sign in to comment.