Commit 1b3bcf5e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Handle statically-allocated PyTypeObjects by having the collector keep a list of them.

Even with some optimizations it seems to hurt perf a little bit...
we'll have to see if it's worth it.

Also, rename "static roots" to "permanent roots", since it's
slightly different than the "static allocation" problem we're
tackling here.
parent 7be0644b
......@@ -37,31 +37,46 @@ namespace pyston {
namespace gc {
static TraceStack roots;
void registerStaticRootObj(void* obj) {
void registerPermanentRoot(void* obj) {
assert(global_heap.getAllocationFromInteriorPointer(obj));
roots.push(obj);
#ifndef NDEBUG
// Check for double-registers. Wouldn't cause any problems, but we probably shouldn't be doing them.
static std::unordered_set<void*> roots;
ASSERT(roots.count(obj) == 0, "Please only register roots once");
roots.insert(obj);
#endif
}
std::vector<std::pair<void*, void*> > static_root_memory;
void registerStaticRootMemory(void* start, void* end) {
assert(start < end);
static std::unordered_set<void*> nonheap_roots;
// Track the highest-addressed nonheap root; the assumption is that the nonheap roots will
// typically all have lower addresses than the heap roots, so this can serve as a cheap
// way to verify it's not a nonheap root (the full check requires a hashtable lookup).
static void* max_nonheap_root = 0;
void registerNonheapRootObject(void* obj) {
// I suppose that things could work fine even if this were true, but why would it happen?
assert(global_heap.getAllocationFromInteriorPointer(obj) == NULL);
assert(nonheap_roots.count(obj) == 0);
// While these aren't necessary to work correctly, they are the anticipated use case:
assert(global_heap.getAllocationFromInteriorPointer(start) == NULL);
assert(global_heap.getAllocationFromInteriorPointer(end) == NULL);
nonheap_roots.insert(obj);
max_nonheap_root = std::max(obj, max_nonheap_root);
}
static_root_memory.push_back(std::make_pair(start, end));
static bool isNonheapRoot(void* p) {
return p <= max_nonheap_root && nonheap_roots.count(p) != 0;
}
static std::unordered_set<StaticRootHandle*>* getRootHandles() {
static std::unordered_set<StaticRootHandle*> root_handles;
static std::unordered_set<GCRootHandle*>* getRootHandles() {
static std::unordered_set<GCRootHandle*> root_handles;
return &root_handles;
}
StaticRootHandle::StaticRootHandle() {
GCRootHandle::GCRootHandle() {
getRootHandles()->insert(this);
}
StaticRootHandle::~StaticRootHandle() {
GCRootHandle::~GCRootHandle() {
getRootHandles()->erase(this);
}
......@@ -72,19 +87,19 @@ bool TraceStackGCVisitor::isValid(void* p) {
}
void TraceStackGCVisitor::visit(void* p) {
if (isNonheapRoot(p)) {
return;
} else {
assert(global_heap.getAllocationFromInteriorPointer(p)->user_data == p);
stack->push(p);
}
}
void TraceStackGCVisitor::visitRange(void* const* start, void* const* end) {
#ifndef NDEBUG
void* const* cur = start;
while (cur < end) {
assert(isValid(*cur));
cur++;
while (start < end) {
visit(*start);
start++;
}
#endif
stack->pushall(start, end);
}
void TraceStackGCVisitor::visitPotential(void* p) {
......@@ -113,8 +128,14 @@ static void markPhase() {
TraceStackGCVisitor visitor(&stack);
for (const auto& p : static_root_memory) {
visitor.visitPotentialRange((void**)p.first, (void**)p.second);
for (void* p : nonheap_roots) {
Box* b = reinterpret_cast<Box*>(p);
BoxedClass* cls = b->cls;
if (cls) {
ASSERT(cls->gc_visit, "%s", getTypeName(b)->c_str());
cls->gc_visit(&visitor, b);
}
}
for (auto h : *getRootHandles()) {
......
......@@ -27,7 +27,7 @@ private:
std::vector<void*> v;
public:
void pushall(void* const* start, void* const* end) { v.insert(v.end(), start, end); }
template <typename T> void pushall(T start, T end) { v.insert(v.end(), start, end); }
void push(void* p) { v.push_back(p); }
......@@ -62,25 +62,27 @@ public:
// Mark this gc-allocated object as being a root, even if there are no visible references to it.
// (Note: this marks the gc allocation itself, not the pointer that points to one. For that, use
// a StaticRootHandle or registerStaticRootMemory)
void registerStaticRootObj(void* root_obj);
// Register a non-gc region of memory (such as statically-allocated memory) as a source of potential
// GC roots.
void registerStaticRootMemory(void* start, void* end);
void runCollection();
// a GCRootHandle)
void registerPermanentRoot(void* root_obj);
// Register an object that was not allocated through this collector, as a root for this collector.
// The motivating usecase is statically-allocated PyTypeObject objects, which are full Python objects
// even if they are not heap allocated.
void registerNonheapRootObject(void* obj);
// If you want to have a static root "location" where multiple values could be stored, use this:
class StaticRootHandle {
class GCRootHandle {
public:
Box* value;
StaticRootHandle();
~StaticRootHandle();
GCRootHandle();
~GCRootHandle();
void operator=(Box* b) { value = b; }
operator Box*() { return value; }
};
void runCollection();
}
}
......
......@@ -71,8 +71,8 @@ void setupBool() {
True = new BoxedBool(true);
False = new BoxedBool(false);
gc::registerStaticRootObj(True);
gc::registerStaticRootObj(False);
gc::registerPermanentRoot(True);
gc::registerPermanentRoot(False);
}
void teardownBool() {
......
......@@ -528,7 +528,7 @@ void setupBuiltins() {
notimplemented_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)notimplementedRepr, STR, 1)));
notimplemented_cls->freeze();
NotImplemented = new Box(notimplemented_cls);
gc::registerStaticRootObj(NotImplemented);
gc::registerPermanentRoot(NotImplemented);
builtins_module->giveAttr("NotImplemented", NotImplemented);
builtins_module->giveAttr("NotImplementedType", notimplemented_cls);
......
......@@ -101,7 +101,7 @@ public:
void setupSys() {
sys_modules_dict = new BoxedDict();
gc::registerStaticRootObj(sys_modules_dict);
gc::registerPermanentRoot(sys_modules_dict);
// This is ok to call here because we've already created the sys_modules_dict
sys_module = createModule("sys", "__builtin__");
......
......@@ -201,7 +201,7 @@ extern "C" void conservativeGCHandler(GCVisitor* v, Box* b) {
}
extern "C" int PyType_Ready(PyTypeObject* cls) {
gc::registerStaticRootMemory(cls, cls + 1);
gc::registerNonheapRootObject(cls);
// unhandled fields:
RELEASE_ASSERT(cls->tp_print == NULL, "");
......
......@@ -263,7 +263,6 @@ void setupDict() {
dict_cls->freeze();
gc::registerStaticRootObj(dict_iterator_cls);
dict_iterator_cls->giveAttr("__name__", boxStrConstant("dictiterator"));
CLFunction* hasnext = boxRTFunction((void*)dictIterHasnextUnboxed, BOOL, 1);
......
......@@ -190,7 +190,6 @@ void setupGenerator() {
generator_cls->giveAttr("send", new BoxedFunction(boxRTFunction((void*)generatorSend, UNKNOWN, 2)));
generator_cls->giveAttr("throw", new BoxedFunction(boxRTFunction((void*)generatorThrow, UNKNOWN, 2)));
gc::registerStaticRootObj(generator_cls);
generator_cls->freeze();
}
}
......@@ -659,7 +659,7 @@ static void _addFuncIntUnknown(const char* name, ConcreteCompilerType* rtn_type,
void setupInt() {
for (int i = 0; i < NUM_INTERNED_INTS; i++) {
interned_ints[i] = new BoxedInt(int_cls, i);
gc::registerStaticRootObj(interned_ints[i]);
gc::registerPermanentRoot(interned_ints[i]);
}
int_cls->giveAttr("__name__", boxStrConstant("int"));
......
......@@ -575,7 +575,6 @@ void setupList() {
list_cls->freeze();
gc::registerStaticRootObj(list_iterator_cls);
list_iterator_cls->giveAttr("__name__", boxStrConstant("listiterator"));
CLFunction* hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1);
......
......@@ -413,7 +413,7 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
}
if (!is_user_defined)
gc::registerStaticRootObj(this);
gc::registerPermanentRoot(this);
}
extern "C" const std::string* getNameOfClass(BoxedClass* cls) {
......@@ -696,7 +696,7 @@ static Box* _handleClsAttr(Box* obj, Box* attr) {
return boxBool(rtn);
}
case BoxedMemberDescriptor::INT: {
int rtn = reinterpret_cast<int*>(obj)[member_desc->offset/sizeof(int)];
int rtn = reinterpret_cast<int*>(obj)[member_desc->offset / sizeof(int)];
return boxInt(rtn);
}
default:
......
......@@ -213,7 +213,6 @@ void setupSet() {
new BoxedFunction(boxRTFunction((void*)setiteratorHasnext, BOXED_BOOL, 1)));
set_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)setiteratorNext, UNKNOWN, 1)));
set_iterator_cls->freeze();
gc::registerStaticRootObj(set_iterator_cls);
set_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)setNew, UNKNOWN, 2, 1, false, false), { None }));
......
......@@ -102,7 +102,7 @@ void unwindExc(Box* exc_obj) {
}
static std::vector<const LineInfo*> getTracebackEntries();
static gc::StaticRootHandle last_exc;
static gc::GCRootHandle last_exc;
static std::vector<const LineInfo*> last_tb;
void raiseRaw(Box* exc_obj) __attribute__((__noreturn__));
......
......@@ -784,7 +784,6 @@ Box* strCount2(BoxedString* self, Box* elt) {
void setupStr() {
str_iterator_cls = new BoxedClass(object_cls, &strIteratorGCHandler, 0, sizeof(BoxedString), false);
gc::registerStaticRootObj(str_iterator_cls);
str_iterator_cls->giveAttr("__name__", boxStrConstant("striterator"));
str_iterator_cls->giveAttr("__hasnext__",
new BoxedFunction(boxRTFunction((void*)BoxedStringIterator::hasnext, BOXED_BOOL, 1)));
......
......@@ -329,7 +329,6 @@ void setupTuple() {
tuple_cls->freeze();
gc::registerStaticRootObj(tuple_iterator_cls);
tuple_iterator_cls->giveAttr("__name__", boxStrConstant("tupleiterator"));
CLFunction* hasnext = boxRTFunction((void*)tupleiterHasnextUnboxed, BOOL, 1);
......
......@@ -183,7 +183,7 @@ extern "C" void boxGCHandler(GCVisitor* v, Box* b) {
HCAttrs::AttrList* attr_list = attrs->attr_list;
assert(attr_list);
v->visit(attr_list);
v->visitPotentialRange((void**)&attr_list->attrs[0], (void**)&attr_list->attrs[nattrs]);
v->visitRange((void**)&attr_list->attrs[0], (void**)&attr_list->attrs[nattrs]);
}
}
} else {
......@@ -584,7 +584,7 @@ Box* objectStr(Box* obj) {
bool TRACK_ALLOCATIONS = false;
void setupRuntime() {
root_hcls = HiddenClass::makeRoot();
gc::registerStaticRootObj(root_hcls);
gc::registerPermanentRoot(root_hcls);
object_cls = new BoxedClass(NULL, &boxGCHandler, 0, sizeof(Box), false);
type_cls = new BoxedClass(object_cls, &typeGCHandler, offsetof(BoxedClass, attrs), sizeof(BoxedClass), false);
......@@ -593,7 +593,7 @@ void setupRuntime() {
none_cls = new BoxedClass(object_cls, NULL, 0, sizeof(Box), false);
None = new Box(none_cls);
gc::registerStaticRootObj(None);
gc::registerPermanentRoot(None);
// TODO we leak all the string data!
str_cls = new BoxedClass(object_cls, NULL, 0, sizeof(BoxedString), false);
......@@ -607,7 +607,7 @@ void setupRuntime() {
tuple_cls = new BoxedClass(object_cls, &tupleGCHandler, 0, sizeof(BoxedTuple), false);
EmptyTuple = new BoxedTuple({});
gc::registerStaticRootObj(EmptyTuple);
gc::registerPermanentRoot(EmptyTuple);
module_cls = new BoxedClass(object_cls, NULL, offsetof(BoxedModule, attrs), sizeof(BoxedModule), false);
......
......@@ -331,7 +331,8 @@ public:
int offset;
BoxedMemberDescriptor(MemberType type, int offset) : Box(member_cls), type(type), offset(offset) {}
BoxedMemberDescriptor(PyMemberDef* member) : Box(member_cls), type((MemberType)member->type), offset(member->offset) {}
BoxedMemberDescriptor(PyMemberDef* member)
: Box(member_cls), type((MemberType)member->type), offset(member->offset) {}
};
// TODO is there any particular reason to make this a Box, ie a python-level object?
......
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