Commit 5de3104a authored by Rudi Chen's avatar Rudi Chen

Make GC handling of HiddenClass more general, support other runtime objects.

Instead of GCKind::HIDDEN_CLASS, use GCKind::RUNTIME and require that
the runtime objects have a gc_visit functions by inheriting from
GCAllocatedRuntime.
parent ae12787c
......@@ -466,26 +466,35 @@ enum class GCKind : uint8_t {
CONSERVATIVE = 2,
PRECISE = 3,
UNTRACKED = 4,
HIDDEN_CLASS = 5,
RUNTIME = 5,
CONSERVATIVE_PYTHON = 6,
};
extern "C" void* gc_alloc(size_t nbytes, GCKind kind);
extern "C" void* gc_realloc(void* ptr, size_t bytes);
extern "C" void gc_free(void* ptr);
}
template <gc::GCKind gc_kind> class GCAllocated {
class GCAllocatedRuntime {
public:
void* operator new(size_t size) __attribute__((visibility("default"))) { return gc::gc_alloc(size, gc_kind); }
virtual ~GCAllocatedRuntime() {}
void* operator new(size_t size) __attribute__((visibility("default"))) {
return gc::gc_alloc(size, gc::GCKind::RUNTIME);
}
void operator delete(void* ptr) __attribute__((visibility("default"))) { gc::gc_free(ptr); }
virtual void gc_visit(GCVisitor* visitor) = 0;
};
class BoxIteratorImpl : public GCAllocated<gc::GCKind::CONSERVATIVE> {
class BoxIteratorImpl : public GCAllocatedRuntime {
public:
virtual ~BoxIteratorImpl() = default;
virtual void next() = 0;
virtual Box* getValue() = 0;
virtual bool isSame(const BoxIteratorImpl* rhs) = 0;
virtual void gc_visit(GCVisitor* v) = 0;
};
class BoxIterator {
......
......@@ -404,9 +404,9 @@ static __attribute__((always_inline)) void visitByGCKind(void* p, GCVisitor& vis
ASSERT(cls->gc_visit, "%s", getTypeName(b));
cls->gc_visit(&visitor, b);
}
} else if (kind_id == GCKind::HIDDEN_CLASS) {
HiddenClass* hcls = reinterpret_cast<HiddenClass*>(p);
hcls->gc_visit(&visitor);
} else if (kind_id == GCKind::RUNTIME) {
GCAllocatedRuntime* runtime_obj = reinterpret_cast<GCAllocatedRuntime*>(p);
runtime_obj->gc_visit(&visitor);
} else {
RELEASE_ASSERT(0, "Unhandled kind: %d", (int)kind_id);
}
......
......@@ -234,7 +234,7 @@ struct HeapStatistics {
int num_hcls_by_attrs[HCLS_ATTRS_STAT_MAX + 1];
int num_hcls_by_attrs_exceed;
TypeStats python, conservative, conservative_python, untracked, hcls, precise;
TypeStats python, conservative, conservative_python, untracked, runtime, precise;
TypeStats total;
HeapStatistics(bool collect_cls_stats, bool collect_hcls_stats)
......@@ -287,18 +287,9 @@ void addStatistic(HeapStatistics* stats, GCAllocation* al, int nbytes) {
} else if (al->kind_id == GCKind::UNTRACKED) {
stats->untracked.nallocs++;
stats->untracked.nbytes += nbytes;
} else if (al->kind_id == GCKind::HIDDEN_CLASS) {
stats->hcls.nallocs++;
stats->hcls.nbytes += nbytes;
if (stats->collect_hcls_stats) {
HiddenClass* hcls = (HiddenClass*)al->user_data;
int numattrs = hcls->attributeArraySize();
if (numattrs <= HCLS_ATTRS_STAT_MAX)
stats->num_hcls_by_attrs[numattrs]++;
else
stats->num_hcls_by_attrs_exceed++;
}
} else if (al->kind_id == GCKind::RUNTIME) {
stats->runtime.nallocs++;
stats->runtime.nbytes += nbytes;
} else if (al->kind_id == GCKind::PRECISE) {
stats->precise.nallocs++;
stats->precise.nbytes += nbytes;
......@@ -327,7 +318,7 @@ void Heap::dumpHeapStatistics(int level) {
stats.conservative.print("conservative");
stats.conservative_python.print("conservative_python");
stats.untracked.print("untracked");
stats.hcls.print("hcls");
stats.runtime.print("runtime");
stats.precise.print("precise");
if (collect_cls_stats) {
......@@ -338,16 +329,6 @@ void Heap::dumpHeapStatistics(int level) {
stats.total.print("Total");
if (collect_hcls_stats) {
fprintf(stderr, "%ld hidden classes currently alive\n", stats.hcls.nallocs);
fprintf(stderr, "%ld have at least one Box that uses them\n", stats.hcls_uses.size());
for (int i = 0; i <= HCLS_ATTRS_STAT_MAX; i++) {
fprintf(stderr, "With % 3d attributes: %d\n", i, stats.num_hcls_by_attrs[i]);
}
fprintf(stderr, "With >% 2d attributes: %d\n", HCLS_ATTRS_STAT_MAX, stats.num_hcls_by_attrs_exceed);
}
fprintf(stderr, "\n");
}
......
......@@ -27,6 +27,20 @@
namespace pyston {
void HiddenClass::gc_visit(GCVisitor* visitor) {
// Visit children even for the dict-backed case, since children will just be empty
visitor->visitRange((void* const*)&children.vector()[0], (void* const*)&children.vector()[children.size()]);
visitor->visit(attrwrapper_child);
// We don't need to visit the keys of the 'children' map, since the children should have those as entries
// in the attr_offssets map.
// Also, if we have any children, we can skip scanning our attr_offsets map, since it will be a subset
// of our child's map.
if (children.empty())
for (auto p : attr_offsets)
visitor->visit(p.first);
}
void HiddenClass::appendAttribute(BoxedString* attr) {
assert(attr->interned_state != SSTATE_NOT_INTERNED);
assert(type == SINGLETON);
......
......@@ -25,7 +25,7 @@
namespace pyston {
class HiddenClass : public GCAllocated<gc::GCKind::HIDDEN_CLASS> {
class HiddenClass : public GCAllocatedRuntime {
public:
// We have a couple different storage strategies for attributes, which
// are distinguished by having a different hidden class type.
......@@ -76,19 +76,7 @@ public:
return new HiddenClass(DICT_BACKED);
}
void gc_visit(GCVisitor* visitor) {
// Visit children even for the dict-backed case, since children will just be empty
visitor->visitRange((void* const*)&children.vector()[0], (void* const*)&children.vector()[children.size()]);
visitor->visit(attrwrapper_child);
// We don't need to visit the keys of the 'children' map, since the children should have those as entries
// in the attr_offssets map.
// Also, if we have any children, we can skip scanning our attr_offsets map, since it will be a subset
// of our child's map.
if (children.empty())
for (auto p : attr_offsets)
visitor->visit(p.first);
}
void gc_visit(GCVisitor* visitor);
// The total size of the attribute array. The slots in the attribute array may not correspond 1:1 to Python
// attributes.
......
......@@ -62,6 +62,13 @@ public:
static BoxIteratorGeneric _end(nullptr);
return &_end;
}
void gc_visit(GCVisitor* v) {
if (iterator)
v->visit(iterator);
if (value)
v->visit(value);
}
};
template <typename T> class BoxIteratorIndex : public BoxIteratorImpl {
......@@ -107,6 +114,11 @@ public:
static BoxIteratorIndex _end(nullptr);
return &_end;
}
void gc_visit(GCVisitor* v) {
if (obj)
v->visit(obj);
}
};
}
......
......@@ -154,7 +154,12 @@ extern "C" void dumpEx(void* p, int levels) {
}
if (al->kind_id == gc::GCKind::PRECISE) {
printf("precise gc array\n");
printf("pyston precise object\n");
return;
}
if (al->kind_id == gc::GCKind::RUNTIME) {
printf("pyston runtime object\n");
return;
}
......@@ -291,11 +296,6 @@ extern "C" void dumpEx(void* p, int levels) {
return;
}
if (al->kind_id == gc::GCKind::HIDDEN_CLASS) {
printf("Hidden class object\n");
return;
}
RELEASE_ASSERT(0, "%d", (int)al->kind_id);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment