Commit 38388e1b authored by Marius Wachtler's avatar Marius Wachtler

Free generator even if the don't exit

parent 3a5b3e50
...@@ -53,6 +53,31 @@ namespace pyston { ...@@ -53,6 +53,31 @@ namespace pyston {
namespace { namespace {
static BoxedClass* astinterpreter_cls;
class ASTInterpreter;
// Map from stack frame pointers for frames corresponding to ASTInterpreter::execute() to the ASTInterpreter handling
// them. Used to look up information about that frame. This is used for getting tracebacks, for CPython introspection
// (sys._getframe & co), and for GC scanning.
static std::unordered_map<void*, ASTInterpreter*> s_interpreterMap;
static_assert(THREADING_USE_GIL, "have to make the interpreter map thread safe!");
class RegisterHelper {
private:
void* frame_addr;
ASTInterpreter* interpreter;
public:
RegisterHelper(ASTInterpreter* interpreter, void* frame_addr);
~RegisterHelper();
static void deregister(void* frame_addr) {
assert(s_interpreterMap.count(frame_addr));
s_interpreterMap.erase(frame_addr);
}
};
union Value { union Value {
bool b; bool b;
int64_t n; int64_t n;
...@@ -68,7 +93,7 @@ union Value { ...@@ -68,7 +93,7 @@ union Value {
} }
}; };
class ASTInterpreter { class ASTInterpreter : public Box {
public: public:
typedef ContiguousMap<InternedString, Box*> SymMap; typedef ContiguousMap<InternedString, Box*> SymMap;
...@@ -149,8 +174,11 @@ private: ...@@ -149,8 +174,11 @@ private:
// This is either a module or a dict // This is either a module or a dict
Box* globals; Box* globals;
void* frame_addr; // used to clear entry inside the s_interpreterMap on destruction
public: public:
DEFAULT_CLASS_SIMPLE(astinterpreter_cls);
AST_stmt* getCurrentStatement() { AST_stmt* getCurrentStatement() {
assert(current_inst); assert(current_inst);
return current_inst; return current_inst;
...@@ -175,7 +203,16 @@ public: ...@@ -175,7 +203,16 @@ public:
void setFrameInfo(const FrameInfo* frame_info); void setFrameInfo(const FrameInfo* frame_info);
void setGlobals(Box* globals); void setGlobals(Box* globals);
void gcVisit(GCVisitor* visitor); static void gcHandler(GCVisitor* visitor, Box* box);
static void simpleDestructor(Box* box) {
ASTInterpreter* inter = (ASTInterpreter*)box;
assert(inter->cls == astinterpreter_cls);
if (inter->frame_addr)
RegisterHelper::deregister(inter->frame_addr);
inter->~ASTInterpreter();
}
friend class RegisterHelper;
}; };
void ASTInterpreter::addSymbol(InternedString name, Box* value, bool allow_duplicates) { void ASTInterpreter::addSymbol(InternedString name, Box* value, bool allow_duplicates) {
...@@ -215,17 +252,17 @@ void ASTInterpreter::setGlobals(Box* globals) { ...@@ -215,17 +252,17 @@ void ASTInterpreter::setGlobals(Box* globals) {
this->globals = globals; this->globals = globals;
} }
void ASTInterpreter::gcVisit(GCVisitor* visitor) { void ASTInterpreter::gcHandler(GCVisitor* visitor, Box* box) {
visitor->visitRange((void* const*)&sym_table.vector()[0], (void* const*)&sym_table.vector()[sym_table.size()]); boxGCHandler(visitor, box);
if (passed_closure)
visitor->visit(passed_closure); ASTInterpreter* interp = (ASTInterpreter*)box;
if (created_closure) auto&& vec = interp->sym_table.vector();
visitor->visit(created_closure); visitor->visitRange((void* const*)&vec[0], (void* const*)&vec[interp->sym_table.size()]);
if (generator) visitor->visit(interp->passed_closure);
visitor->visit(generator); visitor->visit(interp->created_closure);
if (frame_info.boxedLocals) visitor->visit(interp->generator);
visitor->visit(frame_info.boxedLocals); visitor->visit(interp->globals);
visitor->visit(globals); interp->frame_info.gcVisit(visitor);
} }
ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function) ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function)
...@@ -240,7 +277,8 @@ ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function) ...@@ -240,7 +277,8 @@ ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function)
created_closure(0), created_closure(0),
generator(0), generator(0),
edgecount(0), edgecount(0),
frame_info(ExcInfo(NULL, NULL, NULL)) { frame_info(ExcInfo(NULL, NULL, NULL)),
frame_addr(0) {
CLFunction* f = compiled_function->clfunc; CLFunction* f = compiled_function->clfunc;
if (!source_info->cfg) if (!source_info->cfg)
...@@ -279,25 +317,16 @@ void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGener ...@@ -279,25 +317,16 @@ void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGener
} }
} }
// Map from stack frame pointers for frames corresponding to ASTInterpreter::execute() to the ASTInterpreter handling RegisterHelper::RegisterHelper(ASTInterpreter* interpreter, void* frame_addr)
// them. Used to look up information about that frame. This is used for getting tracebacks, for CPython introspection : frame_addr(frame_addr), interpreter(interpreter) {
// (sys._getframe & co), and for GC scanning. interpreter->frame_addr = frame_addr;
static std::unordered_map<void*, ASTInterpreter*> s_interpreterMap;
static_assert(THREADING_USE_GIL, "have to make the interpreter map thread safe!");
class RegisterHelper {
private:
void* frame_addr;
public:
RegisterHelper(ASTInterpreter* interpreter, void* frame_addr) : frame_addr(frame_addr) {
s_interpreterMap[frame_addr] = interpreter; s_interpreterMap[frame_addr] = interpreter;
} }
~RegisterHelper() {
assert(s_interpreterMap.count(frame_addr)); RegisterHelper::~RegisterHelper() {
s_interpreterMap.erase(frame_addr); interpreter->frame_addr = nullptr;
} deregister(frame_addr);
}; }
Value ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block, AST_stmt* start_at) { Value ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block, AST_stmt* start_at) {
STAT_TIMER(t0, "us_timer_astinterpreter_execute"); STAT_TIMER(t0, "us_timer_astinterpreter_execute");
...@@ -382,7 +411,7 @@ void ASTInterpreter::doStore(AST_expr* node, Value value) { ...@@ -382,7 +411,7 @@ void ASTInterpreter::doStore(AST_expr* node, Value value) {
doStore(name->id, value); doStore(name->id, value);
} else if (node->type == AST_TYPE::Attribute) { } else if (node->type == AST_TYPE::Attribute) {
AST_Attribute* attr = (AST_Attribute*)node; AST_Attribute* attr = (AST_Attribute*)node;
setattr(visit_expr(attr->value).o, attr->attr.c_str(), value.o); pyston::setattr(visit_expr(attr->value).o, attr->attr.c_str(), value.o);
} else if (node->type == AST_TYPE::Tuple) { } else if (node->type == AST_TYPE::Tuple) {
AST_Tuple* tuple = (AST_Tuple*)node; AST_Tuple* tuple = (AST_Tuple*)node;
Box** array = unpackIntoArray(value.o, tuple->elts.size()); Box** array = unpackIntoArray(value.o, tuple->elts.size());
...@@ -897,7 +926,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) { ...@@ -897,7 +926,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
} }
case AST_TYPE::Attribute: { case AST_TYPE::Attribute: {
AST_Attribute* attr = (AST_Attribute*)target_; AST_Attribute* attr = (AST_Attribute*)target_;
delattr(visit_expr(attr->value).o, attr->attr.c_str()); pyston::delattr(visit_expr(attr->value).o, attr->attr.c_str());
break; break;
} }
case AST_TYPE::Name: { case AST_TYPE::Name: {
...@@ -1237,7 +1266,7 @@ Value ASTInterpreter::visit_tuple(AST_Tuple* node) { ...@@ -1237,7 +1266,7 @@ Value ASTInterpreter::visit_tuple(AST_Tuple* node) {
} }
Value ASTInterpreter::visit_attribute(AST_Attribute* node) { Value ASTInterpreter::visit_attribute(AST_Attribute* node) {
return getattr(visit_expr(node->value).o, node->attr.c_str()); return pyston::getattr(visit_expr(node->value).o, node->attr.c_str());
} }
} }
...@@ -1261,23 +1290,23 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge ...@@ -1261,23 +1290,23 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge
} }
++cf->times_called; ++cf->times_called;
ASTInterpreter interpreter(cf); ASTInterpreter* interpreter = new ASTInterpreter(cf);
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo(); ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source.get(); SourceInfo* source_info = cf->clfunc->source.get();
if (unlikely(scope_info->usesNameLookup())) { if (unlikely(scope_info->usesNameLookup())) {
interpreter.setBoxedLocals(new BoxedDict()); interpreter->setBoxedLocals(new BoxedDict());
} }
assert((!globals) == cf->clfunc->source->scoping->areGlobalsFromModule()); assert((!globals) == cf->clfunc->source->scoping->areGlobalsFromModule());
if (globals) { if (globals) {
interpreter.setGlobals(globals); interpreter->setGlobals(globals);
} else { } else {
interpreter.setGlobals(source_info->parent_module); interpreter->setGlobals(source_info->parent_module);
} }
interpreter.initArguments(nargs, (BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, arg3, args); interpreter->initArguments(nargs, (BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, arg3, args);
Value v = ASTInterpreter::execute(interpreter); Value v = ASTInterpreter::execute(*interpreter);
return v.o ? v.o : None; return v.o ? v.o : None;
} }
...@@ -1285,18 +1314,18 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge ...@@ -1285,18 +1314,18 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge
Box* astInterpretFunctionEval(CompiledFunction* cf, Box* globals, Box* boxedLocals) { Box* astInterpretFunctionEval(CompiledFunction* cf, Box* globals, Box* boxedLocals) {
++cf->times_called; ++cf->times_called;
ASTInterpreter interpreter(cf); ASTInterpreter* interpreter = new ASTInterpreter(cf);
interpreter.initArguments(0, NULL, NULL, NULL, NULL, NULL, NULL); interpreter->initArguments(0, NULL, NULL, NULL, NULL, NULL, NULL);
interpreter.setBoxedLocals(boxedLocals); interpreter->setBoxedLocals(boxedLocals);
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo(); ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source.get(); SourceInfo* source_info = cf->clfunc->source.get();
assert(!cf->clfunc->source->scoping->areGlobalsFromModule()); assert(!cf->clfunc->source->scoping->areGlobalsFromModule());
assert(globals); assert(globals);
interpreter.setGlobals(globals); interpreter->setGlobals(globals);
Value v = ASTInterpreter::execute(interpreter); Value v = ASTInterpreter::execute(*interpreter);
return v.o ? v.o : None; return v.o ? v.o : None;
} }
...@@ -1309,29 +1338,29 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl ...@@ -1309,29 +1338,29 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
assert(after_expr); assert(after_expr);
assert(expr_val); assert(expr_val);
ASTInterpreter interpreter(cf); ASTInterpreter* interpreter = new ASTInterpreter(cf);
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo(); ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source.get(); SourceInfo* source_info = cf->clfunc->source.get();
assert(cf->clfunc->source->scoping->areGlobalsFromModule()); assert(cf->clfunc->source->scoping->areGlobalsFromModule());
interpreter.setGlobals(source_info->parent_module); interpreter->setGlobals(source_info->parent_module);
for (const auto& p : frame_state.locals->d) { for (const auto& p : frame_state.locals->d) {
assert(p.first->cls == str_cls); assert(p.first->cls == str_cls);
auto name = static_cast<BoxedString*>(p.first)->s(); auto name = static_cast<BoxedString*>(p.first)->s();
if (name == PASSED_GENERATOR_NAME) { if (name == PASSED_GENERATOR_NAME) {
interpreter.setGenerator(p.second); interpreter->setGenerator(p.second);
} else if (name == PASSED_CLOSURE_NAME) { } else if (name == PASSED_CLOSURE_NAME) {
interpreter.setPassedClosure(p.second); interpreter->setPassedClosure(p.second);
} else if (name == CREATED_CLOSURE_NAME) { } else if (name == CREATED_CLOSURE_NAME) {
interpreter.setCreatedClosure(p.second); interpreter->setCreatedClosure(p.second);
} else { } else {
InternedString interned = cf->clfunc->source->getInternedStrings().get(name); InternedString interned = cf->clfunc->source->getInternedStrings().get(name);
interpreter.addSymbol(interned, p.second, false); interpreter->addSymbol(interned, p.second, false);
} }
} }
interpreter.setFrameInfo(frame_state.frame_info); interpreter->setFrameInfo(frame_state.frame_info);
CFGBlock* start_block = NULL; CFGBlock* start_block = NULL;
AST_stmt* starting_statement = NULL; AST_stmt* starting_statement = NULL;
...@@ -1343,7 +1372,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl ...@@ -1343,7 +1372,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
assert(asgn->targets[0]->type == AST_TYPE::Name); assert(asgn->targets[0]->type == AST_TYPE::Name);
auto name = ast_cast<AST_Name>(asgn->targets[0]); auto name = ast_cast<AST_Name>(asgn->targets[0]);
assert(name->id.str()[0] == '#'); assert(name->id.str()[0] == '#');
interpreter.addSymbol(name->id, expr_val, true); interpreter->addSymbol(name->id, expr_val, true);
break; break;
} else if (enclosing_stmt->type == AST_TYPE::Expr) { } else if (enclosing_stmt->type == AST_TYPE::Expr) {
auto expr = ast_cast<AST_Expr>(enclosing_stmt); auto expr = ast_cast<AST_Expr>(enclosing_stmt);
...@@ -1381,7 +1410,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl ...@@ -1381,7 +1410,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
assert(starting_statement); assert(starting_statement);
} }
Value v = ASTInterpreter::execute(interpreter, start_block, starting_statement); Value v = ASTInterpreter::execute(*interpreter, start_block, starting_statement);
return v.o ? v.o : None; return v.o ? v.o : None;
} }
...@@ -1430,9 +1459,10 @@ BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr) { ...@@ -1430,9 +1459,10 @@ BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr) {
return interpreter->getPassedClosure(); return interpreter->getPassedClosure();
} }
void gatherInterpreterRoots(GCVisitor* visitor) { void setupInterpreter() {
for (const auto& p : s_interpreterMap) { astinterpreter_cls = BoxedHeapClass::create(type_cls, object_cls, ASTInterpreter::gcHandler, 0, 0,
p.second->gcVisit(visitor); sizeof(ASTInterpreter), false, "astinterpreter");
} astinterpreter_cls->simple_destructor = ASTInterpreter::simpleDestructor;
astinterpreter_cls->freeze();
} }
} }
...@@ -33,6 +33,7 @@ struct LineInfo; ...@@ -33,6 +33,7 @@ struct LineInfo;
extern const void* interpreter_instr_addr; extern const void* interpreter_instr_addr;
void setupInterpreter();
Box* astInterpretFunction(CompiledFunction* f, int nargs, Box* closure, Box* generator, Box* globals, Box* arg1, Box* astInterpretFunction(CompiledFunction* f, int nargs, Box* closure, Box* generator, Box* globals, Box* arg1,
Box* arg2, Box* arg3, Box** args); Box* arg2, Box* arg3, Box** args);
Box* astInterpretFunctionEval(CompiledFunction* cf, Box* globals, Box* boxedLocals); Box* astInterpretFunctionEval(CompiledFunction* cf, Box* globals, Box* boxedLocals);
...@@ -46,7 +47,6 @@ struct FrameInfo; ...@@ -46,7 +47,6 @@ struct FrameInfo;
FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr); FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr);
BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr); BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr);
void gatherInterpreterRoots(gc::GCVisitor* visitor);
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible); BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible);
} }
......
...@@ -117,8 +117,7 @@ static llvm::Value* getBoxedLocalsGep(llvm::IRBuilder<true>& builder, llvm::Valu ...@@ -117,8 +117,7 @@ static llvm::Value* getBoxedLocalsGep(llvm::IRBuilder<true>& builder, llvm::Valu
static llvm::Value* getExcinfoGep(llvm::IRBuilder<true>& builder, llvm::Value* v) { static llvm::Value* getExcinfoGep(llvm::IRBuilder<true>& builder, llvm::Value* v) {
static_assert(offsetof(FrameInfo, exc) == 0, ""); static_assert(offsetof(FrameInfo, exc) == 0, "");
static_assert(offsetof(ExcInfo, type) == 0, ""); return builder.CreateConstInBoundsGEP2_32(v, 0, 0);
return builder.CreateConstInBoundsGEP2_32(builder.CreateConstInBoundsGEP2_32(v, 0, 0), 0, 0);
} }
static llvm::Value* getFrameObjGep(llvm::IRBuilder<true>& builder, llvm::Value* v) { static llvm::Value* getFrameObjGep(llvm::IRBuilder<true>& builder, llvm::Value* v) {
...@@ -180,8 +179,16 @@ llvm::Value* IRGenState::getFrameInfoVar() { ...@@ -180,8 +179,16 @@ llvm::Value* IRGenState::getFrameInfoVar() {
// The "normal" case // The "normal" case
// frame_info.exc.type = NULL // frame_info.exc.type = NULL
builder.CreateStore(getNullPtr(g.llvm_value_type_ptr), getExcinfoGep(builder, al)); // frame_info.exc.value = NULL
// frame_info.exc.traceback = NULL
llvm::Constant* null_value = getNullPtr(g.llvm_value_type_ptr);
llvm::Value* exc_info = getExcinfoGep(builder, al);
builder.CreateStore(
null_value, builder.CreateConstInBoundsGEP2_32(exc_info, 0, offsetof(ExcInfo, type) / sizeof(Box*)));
builder.CreateStore(
null_value, builder.CreateConstInBoundsGEP2_32(exc_info, 0, offsetof(ExcInfo, value) / sizeof(Box*)));
builder.CreateStore(null_value, builder.CreateConstInBoundsGEP2_32(exc_info, 0, offsetof(ExcInfo, traceback)
/ sizeof(Box*)));
// frame_info.boxedLocals = NULL // frame_info.boxedLocals = NULL
llvm::Value* boxed_locals_gep = getBoxedLocalsGep(builder, al); llvm::Value* boxed_locals_gep = getBoxedLocalsGep(builder, al);
builder.CreateStore(getNullPtr(g.llvm_value_type_ptr), boxed_locals_gep); builder.CreateStore(getNullPtr(g.llvm_value_type_ptr), boxed_locals_gep);
......
...@@ -706,6 +706,8 @@ struct FrameInfo { ...@@ -706,6 +706,8 @@ struct FrameInfo {
BoxedFrame* frame_obj; BoxedFrame* frame_obj;
FrameInfo(ExcInfo exc) : exc(exc), boxedLocals(NULL), frame_obj(0) {} FrameInfo(ExcInfo exc) : exc(exc), boxedLocals(NULL), frame_obj(0) {}
void gcVisit(GCVisitor* visitor);
}; };
struct CallattrFlags { struct CallattrFlags {
......
...@@ -277,7 +277,6 @@ void markPhase() { ...@@ -277,7 +277,6 @@ void markPhase() {
GCVisitor visitor(&stack); GCVisitor visitor(&stack);
threading::visitAllStacks(&visitor); threading::visitAllStacks(&visitor);
gatherInterpreterRoots(&visitor);
for (auto h : *getRootHandles()) { for (auto h : *getRootHandles()) {
visitor.visit(h->value); visitor.visit(h->value);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "capi/typeobject.h" #include "capi/typeobject.h"
#include "capi/types.h" #include "capi/types.h"
#include "codegen/ast_interpreter.h"
#include "codegen/unwinding.h" #include "codegen/unwinding.h"
#include "core/options.h" #include "core/options.h"
#include "core/stats.h" #include "core/stats.h"
...@@ -91,6 +92,14 @@ bool IN_SHUTDOWN = false; ...@@ -91,6 +92,14 @@ bool IN_SHUTDOWN = false;
#define SLICE_STOP_OFFSET ((char*)&(((BoxedSlice*)0x01)->stop) - (char*)0x1) #define SLICE_STOP_OFFSET ((char*)&(((BoxedSlice*)0x01)->stop) - (char*)0x1)
#define SLICE_STEP_OFFSET ((char*)&(((BoxedSlice*)0x01)->step) - (char*)0x1) #define SLICE_STEP_OFFSET ((char*)&(((BoxedSlice*)0x01)->step) - (char*)0x1)
void FrameInfo::gcVisit(GCVisitor* visitor) {
visitor->visit(boxedLocals);
visitor->visit(exc.traceback);
visitor->visit(exc.type);
visitor->visit(exc.value);
visitor->visit(frame_obj);
}
// Analogue of PyType_GenericAlloc (default tp_alloc), but should only be used for Pyston classes! // Analogue of PyType_GenericAlloc (default tp_alloc), but should only be used for Pyston classes!
extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems) noexcept { extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems) noexcept {
assert(cls); assert(cls);
...@@ -2637,6 +2646,7 @@ void setupRuntime() { ...@@ -2637,6 +2646,7 @@ void setupRuntime() {
closure_cls->freeze(); closure_cls->freeze();
setupInterpreter();
setupCAPI(); setupCAPI();
// Can't set up object methods until we set up CAPI support: // Can't set up object methods until we set up CAPI support:
......
# expected: fail
# We currently don't call finalizers when destroying a generator.
def G():
try:
yield 0
yield 1
print "end"
except Exception as e:
print e
finally:
print "finally"
def foo():
g = G()
print g.next()
print g.next()
foo()
# This test checks if generators which get started but haven't yet stopped (=not raisen a StopIteration exc, etc)
# get freed when there aren't any references to the generators left.
import gc
import weakref
class C(object):
val = 42
def G():
l = range(100)
yield weakref.ref(C())
while True:
yield 1
def get_weakrefs(num=5):
wr = []
for i in range(num):
g = G()
w = g.next()
wr.append(w)
return wr
def recurse(f, n):
if n:
return recurse(f, n-1)
return f()
wr = recurse(get_weakrefs, 100)
gc.collect()
for w in wr:
try:
print w.__hash__()
print w().val
except TypeError as e:
print e
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