Permalink
Browse files

GC performance tweeks

  • Loading branch information...
1 parent 48fa88d commit baf87dc49e7d59272c7379b9b2d6c908edd54a84 Evan Phoenix committed Oct 22, 2009
View
2 vm/builtin/compiledmethod.cpp
@@ -1,3 +1,5 @@
+#include "gc/gc.hpp"
+
#include "builtin/compiledmethod.hpp"
#include "builtin/class.hpp"
#include "builtin/fixnum.hpp"
View
8 vm/builtin/packed_object.cpp
@@ -1,3 +1,5 @@
+#include "gc/gc.hpp"
+
#include "builtin/packed_object.hpp"
#include "builtin/object.hpp"
#include "builtin/lookuptable.hpp"
@@ -85,8 +87,10 @@ namespace rubinius {
return const_cast<ObjectHeader*>(obj)->reference_class()->packed_size();
}
- static size_t to_fields(size_t total) {
- return (total - sizeof(ObjectHeader)) / sizeof(Object*);
+ namespace {
+ inline size_t to_fields(size_t total) {
+ return (total - sizeof(ObjectHeader)) / sizeof(Object*);
+ }
}
void PackedObject::Info::mark(Object* obj, ObjectMark& mark) {
View
2 vm/builtin/sendsite.cpp
@@ -1,3 +1,5 @@
+#include "gc/gc.hpp"
+
#include "builtin/sendsite.hpp"
#include "builtin/class.hpp"
#include "builtin/lookuptable.hpp"
View
2 vm/builtin/time.hpp
@@ -4,6 +4,8 @@
#include "builtin/object.hpp"
#include "type_info.hpp"
+#include "builtin/tuple.hpp"
+
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
# define HAVE_STRUCT_TM_TM_GMTOFF
# define HAVE_STRUCT_TM_TM_ZONE
View
7 vm/builtin/tuple.cpp
@@ -1,3 +1,5 @@
+#include "gc/gc.hpp"
+
#include "builtin/tuple.hpp"
#include "vm.hpp"
#include "vm/object_utils.hpp"
@@ -193,10 +195,7 @@ namespace rubinius {
}
size_t Tuple::Info::object_size(const ObjectHeader* obj) {
- const Tuple *tup = reinterpret_cast<const Tuple*>(obj);
- assert(tup);
-
- return tup->full_size_;
+ return force_as<Tuple>(obj)->full_size_;
}
View
2 vm/builtin/variable_scope.cpp
@@ -1,11 +1,13 @@
#include "vm.hpp"
#include "objectmemory.hpp"
#include "call_frame.hpp"
+#include "gc/gc.hpp"
#include "builtin/object.hpp"
#include "builtin/variable_scope.hpp"
#include "builtin/class.hpp"
#include "builtin/system.hpp"
+#include "builtin/tuple.hpp"
namespace rubinius {
void VariableScope::init(STATE) {
View
10 vm/builtin/weakref.cpp
@@ -1,6 +1,9 @@
#include "builtin/weakref.hpp"
#include "builtin/class.hpp"
+#include "object_utils.hpp"
+#include "gc/gc.hpp"
+
namespace rubinius {
void WeakRef::init(STATE) {
GO(cls_weakref).set(state->new_class("WeakRef", G(object)));
@@ -13,4 +16,11 @@ namespace rubinius {
return ref;
}
+
+ void WeakRef::Info::mark(Object* obj, ObjectMark& mark) {
+ WeakRef* ref = as<WeakRef>(obj);
+ if(ref->alive_p()) {
+ mark.gc->add_weak_ref(obj);
+ }
+ }
}
View
7 vm/builtin/weakref.hpp
@@ -32,6 +32,13 @@ namespace rubinius {
bool alive_p() {
return object_->reference_p();
}
+
+ class Info : public TypeInfo {
+ public:
+ Info(object_type type, bool cleanup = false) : TypeInfo(type, cleanup) { }
+ virtual void mark(Object* obj, ObjectMark& mark);
+ virtual void auto_mark(Object* obj, ObjectMark& mark) {}
+ };
};
}
View
5 vm/gc/baker.cpp
@@ -6,6 +6,7 @@
#include "object_utils.hpp"
#include "builtin/tuple.hpp"
+#include "builtin/class.hpp"
#include "instruments/stats.hpp"
@@ -122,10 +123,6 @@ namespace rubinius {
for(Roots::Iterator i(data.roots()); i.more(); i.advance()) {
i->set(saw_object(i->get()));
- //tmp = i->get();
- //if(tmp->reference_p() && tmp->young_object_p()) {
- // i->set(saw_object(tmp));
- //}
}
for(capi::Handles::Iterator i(*data.handles()); i.more(); i.advance()) {
View
2 vm/gc/debug.cpp
@@ -35,11 +35,13 @@ namespace rubinius {
seen[obj] = 1;
+ /*
if(obj->young_object_p()) {
if(!object_memory_->young.current->contains_p(obj)) {
throw std::runtime_error("Invalid young object detected.");
}
}
+ */
scan_object(obj);
View
26 vm/gc/gc.cpp
@@ -17,6 +17,8 @@
#include "builtin/staticscope.hpp"
#include "capi/handle.hpp"
+#include "object_watch.hpp"
+
namespace rubinius {
GCData::GCData(STATE)
@@ -45,33 +47,15 @@ namespace rubinius {
std::cout << "detected " << obj << " during scan_object.\n";
}
- if(obj->klass() && obj->klass()->reference_p()) {
- slot = saw_object(obj->klass());
- // casting to Class* is ok here because we're in the GC, and the movement
- // of slot MUST return the same type as obj->klass()
- if(slot) obj->klass(object_memory_, reinterpret_cast<Class*>(slot));
- }
+ slot = saw_object(obj->klass());
+ if(slot) obj->klass(object_memory_, force_as<Class>(slot));
- if(obj->ivars() && obj->ivars()->reference_p()) {
+ if(obj->ivars()->reference_p()) {
slot = saw_object(obj->ivars());
if(slot) obj->ivars(object_memory_, slot);
}
- // If this object's refs are weak, then add it to the weak_refs
- // vector and don't look at it otherwise.
- if(WeakRef* ref = try_as<WeakRef>(obj)) {
- if(ref->alive_p()) {
- if(!weak_refs_) {
- weak_refs_ = new ObjectArray(0);
- }
-
- weak_refs_->push_back(obj);
- }
- return;
- }
-
TypeInfo* ti = object_memory_->type_info[obj->type_id()];
- assert(ti);
ObjectMark mark(this);
ti->mark(obj, mark);
View
8 vm/gc/gc.hpp
@@ -106,6 +106,14 @@ namespace rubinius {
VM* state();
+ void add_weak_ref(Object* obj) {
+ if(!weak_refs_) {
+ weak_refs_ = new ObjectArray;
+ }
+
+ weak_refs_->push_back(obj);
+ }
+
friend class ObjectMark;
};
View
5 vm/gc/immix.cpp
@@ -4,6 +4,7 @@
#include "instruments/stats.hpp"
#include "capi/handle.hpp"
+#include "object_watch.hpp"
namespace rubinius {
void ImmixGC::ObjectDescriber::added_chunk(int count) {
@@ -103,9 +104,7 @@ namespace rubinius {
for(Roots::Iterator i(data.roots()); i.more(); i.advance()) {
tmp = i->get();
- if(tmp->reference_p()) {
- saw_object(tmp);
- }
+ if(tmp->reference_p()) saw_object(tmp);
}
for(capi::Handles::Iterator i(*data.handles()); i.more(); i.advance()) {
View
2 vm/gc/object_mark.cpp
@@ -6,8 +6,6 @@
#include "vm.hpp"
namespace rubinius {
- ObjectMark::ObjectMark(GarbageCollector* gc) : gc(gc) { }
-
VM* ObjectMark::state() {
return gc->state();
}
View
6 vm/gc/object_mark.hpp
@@ -14,9 +14,13 @@ namespace rubinius {
public:
GarbageCollector* gc;
+ public:
+ ObjectMark(GarbageCollector* gc)
+ : gc(gc)
+ {}
+
VM* state();
- ObjectMark(GarbageCollector* gc);
Object* call(Object*);
void set(Object* target, Object** pos, Object* val);
void just_set(Object* target, Object* val);
View
2 vm/llvm/jit_operations.hpp
@@ -236,7 +236,7 @@ namespace rubinius {
}
Value* get_class_id(Value* cls) {
- Value* idx[] = { zero_, cint(3) };
+ Value* idx[] = { zero_, cint(4) };
Value* gep = create_gep(cls, idx, 2, "class_id_pos");
return create_load(gep, "class_id");
}
View
2 vm/llvm/types.cpp.gen
@@ -54,13 +54,15 @@ mod->addTypeName("struct.rubinius::Fixnum", OpaqueTy_struct_rubinius__Fixnum);
PointerType* PointerTy_7 = PointerType::get(OpaqueTy_struct_rubinius__Fixnum, 0);
StructTy_struct_rubinius__Class_fields.push_back(PointerTy_7);
+StructTy_struct_rubinius__Class_fields.push_back(PointerTy_5);
OpaqueType* OpaqueTy_struct_rubinius__TypeInfo = OpaqueType::get(getGlobalContext());
mod->addTypeName("struct.rubinius::TypeInfo", OpaqueTy_struct_rubinius__TypeInfo);
PointerType* PointerTy_8 = PointerType::get(OpaqueTy_struct_rubinius__TypeInfo, 0);
StructTy_struct_rubinius__Class_fields.push_back(PointerTy_8);
StructTy_struct_rubinius__Class_fields.push_back(IntegerType::get(getGlobalContext(), 32));
+StructTy_struct_rubinius__Class_fields.push_back(IntegerType::get(getGlobalContext(), 64));
StructType* StructTy_struct_rubinius__Class = StructType::get(mod->getContext(), StructTy_struct_rubinius__Class_fields, /*isPacked=*/false);
mod->addTypeName("struct.rubinius::Class", StructTy_struct_rubinius__Class);
View
1 vm/marshal.cpp
@@ -21,6 +21,7 @@
#include "builtin/symbol.hpp"
#include "builtin/tuple.hpp"
+#include "detection.hpp"
namespace rubinius {
View
15 vm/object_utils.hpp
@@ -164,6 +164,21 @@ namespace rubinius {
return static_cast<const T*>(obj);
}
+ /**
+ * Converts one type into another without a type check. This is
+ * like reinterprete_cast<>(), but we use it so we can easily
+ * find where we're doing explicit force casts.
+ */
+ template <class T>
+ static inline T* force_as(ObjectHeader* obj) {
+ return reinterpret_cast<T*>(obj);
+ }
+
+ template <class T>
+ static inline const T* force_as(const ObjectHeader* obj) {
+ return reinterpret_cast<const T*>(obj);
+ }
+
void type_assert(STATE, Object* obj, object_type type, const char* reason);
View
76 vm/objectmemory.cpp
@@ -4,6 +4,9 @@
#include "vm.hpp"
#include "objectmemory.hpp"
#include "gc/marksweep.hpp"
+#include "gc/baker.hpp"
+#include "gc/immix.hpp"
+
#include "config_parser.hpp"
#include "builtin/class.hpp"
@@ -21,12 +24,11 @@ namespace rubinius {
/* ObjectMemory methods */
ObjectMemory::ObjectMemory(STATE, Configuration& config)
- : state(state)
- , young(this, config.gc_bytes)
- , mark_sweep_(this)
- , immix_(this)
+ : young_(new BakerGC(this, config.gc_bytes))
+ , mark_sweep_(new MarkSweepGC(this))
+ , immix_(new ImmixGC(this))
+ , state(state)
{
-
// TODO Not sure where this code should be...
if(char* num = getenv("RBX_WATCH")) {
object_watch = (Object*)strtol(num, NULL, 10);
@@ -39,7 +41,7 @@ namespace rubinius {
last_object_id = 0;
large_object_threshold = config.gc_large_object;
- young.lifetime = config.gc_lifetime;
+ young_->lifetime = config.gc_lifetime;
for(size_t i = 0; i < LastObjectType; i++) {
type_info[i] = NULL;
@@ -50,8 +52,8 @@ namespace rubinius {
ObjectMemory::~ObjectMemory() {
- young.free_objects();
- mark_sweep_.free_objects();
+ young_->free_objects();
+ mark_sweep_->free_objects();
// TODO free immix data
@@ -60,23 +62,39 @@ namespace rubinius {
for(size_t i = 0; i < LastObjectType; i++) {
if(type_info[i]) delete type_info[i];
}
+
+ delete immix_;
+ delete mark_sweep_;
+ delete young_;
+ }
+
+ Object* ObjectMemory::new_object_fast(Class* cls, size_t bytes, object_type type) {
+ if(Object* obj = young_->raw_allocate(bytes, &collect_young_now)) {
+ if(collect_young_now) state->interrupts.set_perform_gc();
+ obj->init_header(cls, YoungObjectZone, type);
+ obj->clear_fields(bytes);
+ return obj;
+ } else {
+ return new_object_typed(cls, bytes, type);
+ }
}
+
void ObjectMemory::set_young_lifetime(size_t age) {
- young.lifetime = age;
+ young_->lifetime = age;
}
void ObjectMemory::debug_marksweep(bool val) {
if(val) {
- mark_sweep_.free_entries = false;
+ mark_sweep_->free_entries = false;
} else {
- mark_sweep_.free_entries = true;
+ mark_sweep_->free_entries = true;
}
}
bool ObjectMemory::valid_object_p(Object* obj) {
if(obj->young_object_p()) {
- return young.current->contains_p(obj);
+ return young_->current->contains_p(obj);
} else if(obj->mature_object_p()) {
return true;
} else {
@@ -91,7 +109,7 @@ namespace rubinius {
stats::GCStats::get()->objects_promoted++;
#endif
- Object* copy = immix_.allocate(obj->size_in_bytes(state));
+ Object* copy = immix_->allocate(obj->size_in_bytes(state));
copy->obj_type_ = obj->type_id();
copy->initialize_copy(obj, 0);
@@ -106,7 +124,7 @@ namespace rubinius {
void ObjectMemory::collect_young(GCData& data) {
static int collect_times = 0;
- young.collect(data);
+ young_->collect(data);
prune_handles(data.handles(), true);
prune_handles(data.cached_handles(), true);
collect_times++;
@@ -120,19 +138,19 @@ namespace rubinius {
stats::GCStats::get()->collect_mature.start();
#endif
- immix_.collect(data);
+ immix_->collect(data);
data.global_cache()->prune_unmarked();
- immix_.clean_weakrefs();
+ immix_->clean_weakrefs();
prune_handles(data.handles(), false);
prune_handles(data.cached_handles(), false);
// Have to do this after all things that check for mark bits is
// done, as it free()s objects, invalidating mark bits.
- mark_sweep_.after_marked();
+ mark_sweep_->after_marked();
- immix_.unmark_all(data);
+ immix_->unmark_all(data);
#ifdef RBX_GC_STATS
stats::GCStats::get()->collect_mature.stop();
@@ -161,7 +179,7 @@ namespace rubinius {
if(obj->young_object_p()) {
// A weakref pointing to a valid young object
- if(young.validate_object(obj) == cValid) {
+ if(young_->validate_object(obj) == cValid) {
continue;
// A weakref pointing to a forwarded young object
@@ -216,7 +234,7 @@ namespace rubinius {
Object* obj;
if(unlikely(bytes > large_object_threshold)) {
- obj = mark_sweep_.allocate(bytes, &collect_mature_now);
+ obj = mark_sweep_->allocate(bytes, &collect_mature_now);
if(collect_mature_now) {
state->interrupts.set_perform_gc();
}
@@ -226,12 +244,12 @@ namespace rubinius {
#endif
} else {
- obj = young.allocate(bytes);
+ obj = young_->allocate(bytes);
if(unlikely(obj == NULL)) {
collect_young_now = true;
state->interrupts.set_perform_gc();
- obj = immix_.allocate(bytes);
+ obj = immix_->allocate(bytes);
if(collect_mature_now) {
state->interrupts.set_perform_gc();
}
@@ -252,7 +270,7 @@ namespace rubinius {
Object* obj;
if(bytes > large_object_threshold) {
- obj = mark_sweep_.allocate(bytes, &collect_mature_now);
+ obj = mark_sweep_->allocate(bytes, &collect_mature_now);
if(collect_mature_now) {
state->interrupts.set_perform_gc();
}
@@ -262,7 +280,7 @@ namespace rubinius {
#endif
} else {
- obj = immix_.allocate(bytes);
+ obj = immix_->allocate(bytes);
if(collect_mature_now) {
state->interrupts.set_perform_gc();
}
@@ -312,7 +330,7 @@ namespace rubinius {
/* ONLY use to create Class, the first object. */
Object* ObjectMemory::allocate_object_raw(size_t bytes) {
- Object* obj = mark_sweep_.allocate(bytes, &collect_mature_now);
+ Object* obj = mark_sweep_->allocate(bytes, &collect_mature_now);
obj->clear_fields(bytes);
return obj;
}
@@ -322,7 +340,7 @@ namespace rubinius {
stats::GCStats::get()->mature_object_types[type]++;
#endif
- Object* obj = mark_sweep_.allocate(bytes, &collect_mature_now);
+ Object* obj = mark_sweep_->allocate(bytes, &collect_mature_now);
if(collect_mature_now) {
state->interrupts.set_perform_gc();
}
@@ -354,13 +372,13 @@ namespace rubinius {
ObjectPosition ObjectMemory::validate_object(Object* obj) {
ObjectPosition pos;
- pos = young.validate_object(obj);
+ pos = young_->validate_object(obj);
if(pos != cUnknown) return pos;
- pos = immix_.validate_object(obj);
+ pos = immix_->validate_object(obj);
if(pos != cUnknown) return pos;
- return mark_sweep_.validate_object(obj);
+ return mark_sweep_->validate_object(obj);
}
};
View
40 vm/objectmemory.hpp
@@ -1,9 +1,9 @@
#ifndef RBX_OBJECTMEMORY_H
#define RBX_OBJECTMEMORY_H
-#include "gc/marksweep.hpp"
-#include "gc/baker.hpp"
-#include "gc/immix.hpp"
+// #include "gc/marksweep.hpp"
+// #include "gc/baker.hpp"
+// #include "gc/immix.hpp"
#include "prelude.hpp"
#include "type_info.hpp"
@@ -12,6 +12,10 @@
#include "call_frame_list.hpp"
+#include "builtin/object.hpp"
+
+class TestObjectMemory; // So we can friend it properly
+
namespace rubinius {
class Object;
@@ -37,19 +41,24 @@ namespace rubinius {
class CallFrame;
class GCData;
class Configuration;
+ class BakerGC;
+ class MarkSweepGC;
+ class ImmixGC;
+
+ typedef std::vector<Object*> ObjectArray;
class ObjectMemory {
- public:
+ BakerGC* young_;
+ MarkSweepGC* mark_sweep_;
+ ImmixGC* immix_;
+
+ public:
bool collect_young_now;
bool collect_mature_now;
STATE;
ObjectArray *remember_set;
- BakerGC young;
- MarkSweepGC mark_sweep_;
-
- ImmixGC immix_;
size_t last_object_id;
TypeInfo* type_info[(int)LastObjectType];
@@ -67,16 +76,7 @@ namespace rubinius {
Object* new_object_typed_mature(Class* cls, size_t bytes, object_type type);
Object* new_object_typed_enduring(Class* cls, size_t bytes, object_type type);
- Object* new_object_fast(Class* cls, size_t bytes, object_type type) {
- if(Object* obj = young.raw_allocate(bytes, &collect_young_now)) {
- if(collect_young_now) state->interrupts.set_perform_gc();
- obj->init_header(cls, YoungObjectZone, type);
- obj->clear_fields(bytes);
- return obj;
- } else {
- return new_object_typed(cls, bytes, type);
- }
- }
+ Object* new_object_fast(Class* cls, size_t bytes, object_type type);
template <class T>
T* new_object_bytes(Class* cls, size_t& bytes) {
@@ -134,6 +134,9 @@ namespace rubinius {
private:
Object* allocate_object(size_t bytes);
Object* allocate_object_mature(size_t bytes);
+
+ public:
+ friend class ::TestObjectMemory;
};
#define FREE(obj) free(obj)
@@ -143,7 +146,6 @@ namespace rubinius {
#define ALLOCA_N(type, size) ((type*)alloca(sizeof(type) * (size)))
#define ALLOCA(type) ((type*)alloca(sizeof(type)))
-
};
View
1 vm/stack_variables.hpp
@@ -7,6 +7,7 @@ namespace rubinius {
class VariableScope;
class StackVariables {
+ public: // Treat these like private!
VariableScope* on_heap_;
VariableScope* parent_;
Object* self_;
View
27 vm/test/test_objectmemory.hpp
@@ -4,6 +4,9 @@
#include "gc/gc.hpp"
#include "gc/root.hpp"
+#include "gc/baker.hpp"
+#include "gc/marksweep.hpp"
+
#include "object_utils.hpp"
#include "builtin/array.hpp"
@@ -43,15 +46,15 @@ class TestObjectMemory : public CxxTest::TestSuite, public VMTest {
Tuple* obj;
- int start = om.young.current->used();
+ int start = om.young_->current->used();
obj = util_new_object(om);
TS_ASSERT_EQUALS(obj->num_fields(), 3U);
TS_ASSERT_EQUALS(obj->zone, YoungObjectZone);
- TS_ASSERT(om.young.current->used() == start + obj->size_in_bytes(state));
- TS_ASSERT(om.young.heap_a.used() == start + obj->size_in_bytes(state));
+ TS_ASSERT(om.young_->current->used() == start + obj->size_in_bytes(state));
+ TS_ASSERT(om.young_->heap_a.used() == start + obj->size_in_bytes(state));
}
void test_write_barrier() {
@@ -93,21 +96,21 @@ class TestObjectMemory : public CxxTest::TestSuite, public VMTest {
void test_collect_young() {
ObjectMemory& om = *state->om;
Object* obj;
- size_t start = om.young.current->used();
+ size_t start = om.young_->current->used();
util_new_object(om);
util_new_object(om);
util_new_object(om);
util_new_object(om);
obj = util_new_object(om);
- Heap *cur = om.young.next;
- TS_ASSERT_EQUALS(om.young.current->used(), start + obj->size_in_bytes(state) * 5);
+ Heap *cur = om.young_->next;
+ TS_ASSERT_EQUALS(om.young_->current->used(), start + obj->size_in_bytes(state) * 5);
om.collect_young(*gc_data);
- TS_ASSERT(om.young.current->used() <= start);
- TS_ASSERT_EQUALS((void*)cur, (void*)om.young.current);
+ TS_ASSERT(om.young_->current->used() <= start);
+ TS_ASSERT_EQUALS((void*)cur, (void*)om.young_->current);
obj = util_new_object(om);
TS_ASSERT_EQUALS(obj->age, 0U);
@@ -140,7 +143,7 @@ class TestObjectMemory : public CxxTest::TestSuite, public VMTest {
TS_ASSERT(obj != new_obj);
obj = (Tuple*)new_obj;
- TS_ASSERT(om.young.current->contains_p(obj));
+ TS_ASSERT(om.young_->current->contains_p(obj));
obj3 = (Tuple*)obj->field[0];
TS_ASSERT(obj2 != obj3);
@@ -175,13 +178,13 @@ class TestObjectMemory : public CxxTest::TestSuite, public VMTest {
om.large_object_threshold = 10;
- size_t start = om.young.current->used();
+ size_t start = om.young_->current->used();
obj = util_new_object(om,20);
TS_ASSERT_EQUALS(obj->num_fields(), 20U);
TS_ASSERT_EQUALS(obj->zone, MatureObjectZone);
- TS_ASSERT_EQUALS(om.young.current->used(), start);
+ TS_ASSERT_EQUALS(om.young_->current->used(), start);
}
void test_collect_young_doesnt_move_mature_objects() {
@@ -453,7 +456,7 @@ class TestObjectMemory : public CxxTest::TestSuite, public VMTest {
TS_ASSERT_EQUALS(obj->requires_cleanup_p(), true);
- state->om->mark_sweep_.delete_object(obj);
+ state->om->mark_sweep_->delete_object(obj);
TS_ASSERT_EQUALS(c->squeaky, obj);
View
2 vm/type_info.cpp
@@ -6,6 +6,8 @@
#include "builtin/symbol.hpp"
#include "field_offset.hpp"
+#include "gc/gc.hpp"
+
#include <iostream>
#include <iomanip>
View
4 vm/util/immix.hpp
@@ -282,7 +282,7 @@ namespace immix {
if(base_.as_int() == -1) {
perror("mmap");
- abort();
+ ::abort();
}
// Best case scenario
@@ -305,7 +305,7 @@ namespace immix {
void free() {
if(munmap(system_base_, system_size_) != 0) {
perror("munmap");
- abort();
+ ::abort();
}
}
View
1 vm/vm.cpp
@@ -2,6 +2,7 @@
#include "objectmemory.hpp"
#include "event.hpp"
#include "global_cache.hpp"
+#include "gc/gc.hpp"
#include "vm/object_utils.hpp"

0 comments on commit baf87dc

Please sign in to comment.