Commit c9598857 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Different approach for tracking ic gc references

1) instead of hooking loadConst to automatically find GC references,
   add an API for specifically saying that a reference needs to be tracked
   (I think/hope there aren't more that do this)
2) change the way we store the gc references so that it's O(#references) to
   scan them instead of O(#ics).
parent adb9ad0c
...@@ -84,6 +84,9 @@ uint8_t* ICSlotRewrite::getSlotStart() { ...@@ -84,6 +84,9 @@ uint8_t* ICSlotRewrite::getSlotStart() {
return (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize(); return (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize();
} }
// Map of gc pointers -> number of ics that point tot hem.
static llvm::DenseMap<void*, int> ic_gc_references;
void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references) { void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references) {
bool still_valid = true; bool still_valid = true;
for (int i = 0; i < dependencies.size(); i++) { for (int i = 0; i < dependencies.size(); i++) {
...@@ -120,7 +123,16 @@ void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references) { ...@@ -120,7 +123,16 @@ void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references) {
// if (VERBOSITY()) printf("Commiting to %p-%p\n", start, start + ic->slot_size); // if (VERBOSITY()) printf("Commiting to %p-%p\n", start, start + ic->slot_size);
memcpy(slot_start, buf, ic->getSlotSize()); memcpy(slot_start, buf, ic->getSlotSize());
for (auto p : ic_entry->gc_references) {
int& i = ic_gc_references[p];
if (i == 1)
ic_gc_references.erase(p);
else
--i;
}
ic_entry->gc_references = std::move(gc_references); ic_entry->gc_references = std::move(gc_references);
for (auto p : ic_entry->gc_references)
ic_gc_references[p]++;
ic->times_rewritten++; ic->times_rewritten++;
...@@ -344,10 +356,15 @@ bool ICInfo::isMegamorphic() { ...@@ -344,10 +356,15 @@ bool ICInfo::isMegamorphic() {
} }
void ICInfo::visitGCReferences(gc::GCVisitor* v) { void ICInfo::visitGCReferences(gc::GCVisitor* v) {
for (auto&& p : ic_gc_references) {
v->visitNonRelocatable(p.first);
}
#if MOVING_GC
for (const auto& p : ics_list) { for (const auto& p : ics_list) {
for (auto& slot : p->slots) { for (auto& slot : p->slots) {
v->visitNonRelocatableRange(&slot.gc_references[0], &slot.gc_references[slot.gc_references.size()]); v->visitNonRelocatableRange(&slot.gc_references[0], &slot.gc_references[slot.gc_references.size()]);
} }
} }
#endif
} }
} }
...@@ -716,6 +716,11 @@ void Rewriter::_trap() { ...@@ -716,6 +716,11 @@ void Rewriter::_trap() {
assembler->trap(); assembler->trap();
} }
void Rewriter::addGCReference(void* obj) {
assert(gc::isValidGCObject(obj));
gc_references.push_back(obj);
}
RewriterVar* Rewriter::loadConst(int64_t val, Location dest) { RewriterVar* Rewriter::loadConst(int64_t val, Location dest) {
STAT_TIMER(t0, "us_timer_rewriter", 10); STAT_TIMER(t0, "us_timer_rewriter", 10);
......
...@@ -554,6 +554,11 @@ public: ...@@ -554,6 +554,11 @@ public:
const char* debugName() { return rewrite->debugName(); } const char* debugName() { return rewrite->debugName(); }
// Register that this rewrite will embed a reference to a particular gc object.
// TODO: come up with an implementation that is performant enough that we can automatically
// infer these from loadConst calls.
void addGCReference(void* obj);
void trap(); void trap();
RewriterVar* loadConst(int64_t val, Location loc = Location::any()); RewriterVar* loadConst(int64_t val, Location loc = Location::any());
// has_side_effects: whether this call could have "side effects". the exact side effects we've // has_side_effects: whether this call could have "side effects". the exact side effects we've
......
...@@ -546,8 +546,8 @@ static void visitRoots(GCVisitor& visitor) { ...@@ -546,8 +546,8 @@ static void visitRoots(GCVisitor& visitor) {
} }
GC_TRACE_LOG("Looking at generated code pointers\n"); GC_TRACE_LOG("Looking at generated code pointers\n");
#if MOVING_GC
ICInfo::visitGCReferences(&visitor); ICInfo::visitGCReferences(&visitor);
#if MOVING_GC
CompiledFunction::visitAllCompiledFunctions(&visitor); CompiledFunction::visitAllCompiledFunctions(&visitor);
#endif #endif
} }
......
...@@ -532,8 +532,15 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -532,8 +532,15 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
// value is fixed. // value is fixed.
if (!PyString_CheckExact(_str) && !PyUnicode_CheckExact(_str)) if (!PyString_CheckExact(_str) && !PyUnicode_CheckExact(_str))
rewrite_args = NULL; rewrite_args = NULL;
else else {
if (PyString_CheckExact(_str) && PyString_CHECK_INTERNED(_str) == SSTATE_INTERNED_IMMORTAL) {
// can avoid keeping the extra gc reference
} else {
rewrite_args->rewriter->addGCReference(_str);
}
rewrite_args->arg2->addGuard((intptr_t)arg2); rewrite_args->arg2->addGuard((intptr_t)arg2);
}
} }
try { try {
......
# Regression test: make sure we guard / invalidate our getattr() rewrites:
class C(object):
pass
c = C()
for i in xrange(100):
setattr(c, "attr%d" % i, i)
def f():
for j in xrange(2, 10):
t = 0
for i in xrange(2000):
for k in xrange(j):
t += getattr(c, "attr%d" % k)
print t
f()
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