Commit ed5f850c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #425 from toshok/generator-gc-fix

free generator stacks both in the destructor and when a generator exits.
parents 473e11eb 143aeb15
...@@ -60,6 +60,22 @@ public: ...@@ -60,6 +60,22 @@ public:
} }
}; };
static void freeGeneratorStack(BoxedGenerator* g) {
if (g->stack_begin == NULL)
return;
available_addrs.push_back((uint64_t)g->stack_begin);
// Limit the number of generator stacks we keep around:
if (available_addrs.size() > 5) {
uint64_t addr = available_addrs.front();
available_addrs.pop_front();
int r = munmap((void*)(addr - MAX_STACK_SIZE), MAX_STACK_SIZE);
assert(r == 0);
}
g->stack_begin = NULL;
}
Context* getReturnContextForGeneratorFrame(void* frame_addr) { Context* getReturnContextForGeneratorFrame(void* frame_addr) {
BoxedGenerator* generator = s_generator_map[frame_addr]; BoxedGenerator* generator = s_generator_map[frame_addr];
assert(generator); assert(generator);
...@@ -103,8 +119,10 @@ Box* generatorSend(Box* s, Box* v) { ...@@ -103,8 +119,10 @@ Box* generatorSend(Box* s, Box* v) {
raiseExcHelper(ValueError, "generator already executing"); raiseExcHelper(ValueError, "generator already executing");
// check if the generator already exited // check if the generator already exited
if (self->entryExited) if (self->entryExited) {
freeGeneratorStack(self);
raiseExcHelper(StopIteration, ""); raiseExcHelper(StopIteration, "");
}
self->returnValue = v; self->returnValue = v;
self->running = true; self->running = true;
...@@ -112,12 +130,16 @@ Box* generatorSend(Box* s, Box* v) { ...@@ -112,12 +130,16 @@ Box* generatorSend(Box* s, Box* v) {
self->running = false; self->running = false;
// propagate exception to the caller // propagate exception to the caller
if (self->exception.type) if (self->exception.type) {
freeGeneratorStack(self);
raiseRaw(self->exception); raiseRaw(self->exception);
}
// throw StopIteration if the generator exited // throw StopIteration if the generator exited
if (self->entryExited) if (self->entryExited) {
freeGeneratorStack(self);
raiseExcHelper(StopIteration, ""); raiseExcHelper(StopIteration, "");
}
return self->returnValue; return self->returnValue;
} }
...@@ -220,7 +242,12 @@ extern "C" BoxedGenerator::BoxedGenerator(BoxedFunctionBase* function, Box* arg1 ...@@ -220,7 +242,12 @@ extern "C" BoxedGenerator::BoxedGenerator(BoxedFunctionBase* function, Box* arg1
#error "implement me" #error "implement me"
#endif #endif
gc::registerGCManagedBytes(MAX_STACK_SIZE); // we're registering memory that isn't in the gc heap here,
// which may sound wrong. Generators, however, can represent
// a larger tax on system resources than just their GC
// allocation, so we try to encode that here as additional gc
// heap pressure.
gc::registerGCManagedBytes(INITIAL_STACK_SIZE);
} else { } else {
generator_stack_reused.log(); generator_stack_reused.log();
...@@ -290,18 +317,7 @@ Box* generatorName(Box* _self, void* context) { ...@@ -290,18 +317,7 @@ Box* generatorName(Box* _self, void* context) {
void generatorDestructor(Box* b) { void generatorDestructor(Box* b) {
assert(isSubclass(b->cls, generator_cls)); assert(isSubclass(b->cls, generator_cls));
BoxedGenerator* self = static_cast<BoxedGenerator*>(b); BoxedGenerator* self = static_cast<BoxedGenerator*>(b);
freeGeneratorStack(self);
if (self->stack_begin) {
available_addrs.push_back((uint64_t)self->stack_begin);
// Limit the number of generator stacks we keep around:
if (available_addrs.size() > 5) {
uint64_t addr = available_addrs.front();
available_addrs.pop_front();
int r = munmap((void*)(addr - MAX_STACK_SIZE), MAX_STACK_SIZE);
assert(r == 0);
}
}
self->stack_begin = NULL;
} }
void setupGenerator() { void setupGenerator() {
......
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