Commit ca2ed310 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add some lifetime information to temporaries in the cfg

By adding a 'is_kill' flag to AST_Name nodes, which say that
this is the last use of this name.  This handles some common cases
of keeping temporaries alive for too long.

For some rare cases, there is no AST_Name that is a last use:
for example, the iterator object of a for loop is live after
every time it is used, but dies when exiting the loop.

For those, we insert a `del #foo` instead.

The interpreter and bjit use these flags to remove temporaries
from the vregs.

The LLVM jit ignores them since it has its own way of handling
lifetime.  It ignores any `del` statements on temporary names
as an optimization.

This does not handle decref'ing temporaries on an exception.
parent ae919c9f
...@@ -136,8 +136,13 @@ public: ...@@ -136,8 +136,13 @@ public:
bool visit_name(AST_Name* node) { bool visit_name(AST_Name* node) {
if (node->ctx_type == AST_TYPE::Load) if (node->ctx_type == AST_TYPE::Load)
_doLoad(node->id, node); _doLoad(node->id, node);
else if (node->ctx_type == AST_TYPE::Store || node->ctx_type == AST_TYPE::Del else if (node->ctx_type == AST_TYPE::Del) {
|| node->ctx_type == AST_TYPE::Param) // Hack: we don't have a bytecode for temporary-kills:
if (node->id.s()[0] == '#')
return true;
_doLoad(node->id, node);
_doStore(node->id);
} else if (node->ctx_type == AST_TYPE::Store || node->ctx_type == AST_TYPE::Param)
_doStore(node->id); _doStore(node->id);
else { else {
ASSERT(0, "%d", node->ctx_type); ASSERT(0, "%d", node->ctx_type);
...@@ -145,6 +150,7 @@ public: ...@@ -145,6 +150,7 @@ public:
} }
return true; return true;
} }
bool visit_alias(AST_alias* node) { bool visit_alias(AST_alias* node) {
InternedString name = node->name; InternedString name = node->name;
if (node->asname.s().size()) if (node->asname.s().size())
......
...@@ -1080,6 +1080,24 @@ Value ASTInterpreter::visit_return(AST_Return* node) { ...@@ -1080,6 +1080,24 @@ Value ASTInterpreter::visit_return(AST_Return* node) {
finishJITing(); finishJITing();
} }
// Some day, we should make sure that all temporaries got deleted (and decrefed) at the right time:
#if 0
bool temporaries_alive = false;
#ifndef NDEBUG
for (auto&& v : getSymVRegMap()) {
if (v.first.s()[0] == '#' && vregs[v.second]) {
fprintf(stderr, "%s still alive\n", v.first.c_str());
temporaries_alive = true;
}
}
if (temporaries_alive)
source_info->cfg->print();
assert(!temporaries_alive);
#endif
#endif
next_block = 0; next_block = 0;
return s; return s;
} }
...@@ -1332,15 +1350,22 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) { ...@@ -1332,15 +1350,22 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
jit->emitDelName(target->id); jit->emitDelName(target->id);
ASTInterpreterJitInterface::delNameHelper(this, target->id); ASTInterpreterJitInterface::delNameHelper(this, target->id);
} else { } else {
abortJITing();
assert(vst == ScopeInfo::VarScopeType::FAST); assert(vst == ScopeInfo::VarScopeType::FAST);
assert(getSymVRegMap().count(target->id)); assert(getSymVRegMap().count(target->id));
assert(getSymVRegMap()[target->id] == target->vreg); assert(getSymVRegMap()[target->id] == target->vreg);
if (target->id.s()[0] == '#') {
assert(vregs[target->vreg] != NULL);
if (jit)
jit->emitKillTemporary(target->id, target->vreg);
} else {
abortJITing();
if (vregs[target->vreg] == 0) { if (vregs[target->vreg] == 0) {
assertNameDefined(0, target->id.c_str(), NameError, true /* local_var_msg */); assertNameDefined(0, target->id.c_str(), NameError, true /* local_var_msg */);
return Value(); return Value();
} }
}
Py_DECREF(vregs[target->vreg]); Py_DECREF(vregs[target->vreg]);
vregs[target->vreg] = NULL; vregs[target->vreg] = NULL;
...@@ -1635,6 +1660,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) { ...@@ -1635,6 +1660,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
switch (node->lookup_type) { switch (node->lookup_type) {
case ScopeInfo::VarScopeType::GLOBAL: { case ScopeInfo::VarScopeType::GLOBAL: {
assert(!node->is_kill);
Value v; Value v;
if (jit) if (jit)
v.var = jit->emitGetGlobal(frame_info.globals, node->id.getBox()); v.var = jit->emitGetGlobal(frame_info.globals, node->id.getBox());
...@@ -1643,6 +1669,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) { ...@@ -1643,6 +1669,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
return v; return v;
} }
case ScopeInfo::VarScopeType::DEREF: { case ScopeInfo::VarScopeType::DEREF: {
assert(!node->is_kill);
return Value(ASTInterpreterJitInterface::derefHelper(this, node->id), return Value(ASTInterpreterJitInterface::derefHelper(this, node->id),
jit ? jit->emitDeref(node->id) : NULL); jit ? jit->emitDeref(node->id) : NULL);
} }
...@@ -1651,22 +1678,35 @@ Value ASTInterpreter::visit_name(AST_Name* node) { ...@@ -1651,22 +1678,35 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
Value v; Value v;
if (jit) { if (jit) {
bool is_live = true; bool is_live = true;
if (node->lookup_type == ScopeInfo::VarScopeType::FAST) if (node->is_kill) {
is_live = false;
assert(!source_info->getLiveness()->isLiveAtEnd(node->id, current_block));
} else if (node->lookup_type == ScopeInfo::VarScopeType::FAST)
is_live = source_info->getLiveness()->isLiveAtEnd(node->id, current_block); is_live = source_info->getLiveness()->isLiveAtEnd(node->id, current_block);
if (is_live) if (is_live) {
assert(!node->is_kill);
v.var = jit->emitGetLocal(node->id, node->vreg); v.var = jit->emitGetLocal(node->id, node->vreg);
else } else {
v.var = jit->emitGetBlockLocal(node->id, node->vreg); v.var = jit->emitGetBlockLocal(node->id, node->vreg);
if (node->is_kill) {
assert(node->id.s()[0] == '#');
jit->emitKillTemporary(node->id, node->vreg);
}
}
} }
assert(node->vreg >= 0); assert(node->vreg >= 0);
assert(getSymVRegMap().count(node->id)); assert(getSymVRegMap().count(node->id));
assert(getSymVRegMap()[node->id] == node->vreg); assert(getSymVRegMap()[node->id] == node->vreg);
Box* val = vregs[node->vreg]; Box* val = vregs[node->vreg];
if (val) { if (val) {
Py_INCREF(val);
v.o = val; v.o = val;
if (node->is_kill)
vregs[node->vreg] = NULL;
else
Py_INCREF(val);
return v; return v;
} }
...@@ -1674,6 +1714,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) { ...@@ -1674,6 +1714,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
RELEASE_ASSERT(0, "should be unreachable"); RELEASE_ASSERT(0, "should be unreachable");
} }
case ScopeInfo::VarScopeType::NAME: { case ScopeInfo::VarScopeType::NAME: {
assert(!node->is_kill && "we might need to support this");
Value v; Value v;
if (jit) if (jit)
v.var = jit->emitGetBoxedLocal(node->id.getBox()); v.var = jit->emitGetBoxedLocal(node->id.getBox());
......
...@@ -379,6 +379,10 @@ RewriterVar* JitFragmentWriter::emitGetBlockLocal(InternedString s, int vreg) { ...@@ -379,6 +379,10 @@ RewriterVar* JitFragmentWriter::emitGetBlockLocal(InternedString s, int vreg) {
return it->second; return it->second;
} }
void JitFragmentWriter::emitKillTemporary(InternedString s, int vreg) {
emitSetLocal(s, vreg, false, imm(nullptr));
}
RewriterVar* JitFragmentWriter::emitGetBoxedLocal(BoxedString* s) { RewriterVar* JitFragmentWriter::emitGetBoxedLocal(BoxedString* s) {
RewriterVar* boxed_locals = emitGetBoxedLocals(); RewriterVar* boxed_locals = emitGetBoxedLocals();
RewriterVar* globals = getInterp()->getAttr(ASTInterpreterJitInterface::getGlobalsOffset()); RewriterVar* globals = getInterp()->getAttr(ASTInterpreterJitInterface::getGlobalsOffset());
......
...@@ -230,6 +230,7 @@ public: ...@@ -230,6 +230,7 @@ public:
RewriterVar* emitExceptionMatches(RewriterVar* v, RewriterVar* cls); RewriterVar* emitExceptionMatches(RewriterVar* v, RewriterVar* cls);
RewriterVar* emitGetAttr(RewriterVar* obj, BoxedString* s, AST_expr* node); RewriterVar* emitGetAttr(RewriterVar* obj, BoxedString* s, AST_expr* node);
RewriterVar* emitGetBlockLocal(InternedString s, int vreg); RewriterVar* emitGetBlockLocal(InternedString s, int vreg);
void emitKillTemporary(InternedString s, int vreg);
RewriterVar* emitGetBoxedLocal(BoxedString* s); RewriterVar* emitGetBoxedLocal(BoxedString* s);
RewriterVar* emitGetBoxedLocals(); RewriterVar* emitGetBoxedLocals();
RewriterVar* emitGetClsAttr(RewriterVar* obj, BoxedString* s); RewriterVar* emitGetClsAttr(RewriterVar* obj, BoxedString* s);
......
...@@ -2123,6 +2123,12 @@ private: ...@@ -2123,6 +2123,12 @@ private:
} }
void _doDelName(AST_Name* target, const UnwindInfo& unw_info) { void _doDelName(AST_Name* target, const UnwindInfo& unw_info) {
// Hack: we don't have a bytecode for temporary-kills:
if (target->id.s()[0] == '#') {
// The refcounter will automatically delete this object.
return;
}
auto scope_info = irstate->getScopeInfo(); auto scope_info = irstate->getScopeInfo();
ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(target->id); ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(target->id);
if (vst == ScopeInfo::VarScopeType::GLOBAL) { if (vst == ScopeInfo::VarScopeType::GLOBAL) {
......
...@@ -1630,7 +1630,8 @@ bool PrintVisitor::visit_suite(AST_Suite* node) { ...@@ -1630,7 +1630,8 @@ bool PrintVisitor::visit_suite(AST_Suite* node) {
bool PrintVisitor::visit_name(AST_Name* node) { bool PrintVisitor::visit_name(AST_Name* node) {
stream << node->id.s(); stream << node->id.s();
// printf("%s(%d)", node->id.c_str(), node->ctx_type); // Uncomment this line to see which names are kills:
// if (node->is_kill) stream << "<k>";
return false; return false;
} }
......
...@@ -735,6 +735,8 @@ public: ...@@ -735,6 +735,8 @@ public:
// the zero based index of this variable inside the vregs array. If uninitialized it's value is -1. // the zero based index of this variable inside the vregs array. If uninitialized it's value is -1.
int vreg; int vreg;
bool is_kill = false;
virtual void accept(ASTVisitor* v); virtual void accept(ASTVisitor* v);
virtual void* accept_expr(ExprVisitor* v); virtual void* accept_expr(ExprVisitor* v);
......
...@@ -213,12 +213,16 @@ private: ...@@ -213,12 +213,16 @@ private:
return source->getInternedStrings().get(std::move(name)); return source->getInternedStrings().get(std::move(name));
} }
AST_Name* makeName(InternedString id, AST_TYPE::AST_TYPE ctx_type, int lineno, int col_offset = 0) { AST_Name* makeName(InternedString id, AST_TYPE::AST_TYPE ctx_type, int lineno, int col_offset = 0,
bool is_kill = false) {
AST_Name* name = new AST_Name(id, ctx_type, lineno, col_offset); AST_Name* name = new AST_Name(id, ctx_type, lineno, col_offset);
name->is_kill = is_kill;
return name; return name;
} }
AST_Name* makeLoad(InternedString id, AST* node) { return makeName(id, AST_TYPE::Load, node->lineno); } AST_Name* makeLoad(InternedString id, AST* node, bool is_kill = false) {
return makeName(id, AST_TYPE::Load, node->lineno, 0, is_kill);
}
void pushLoopContinuation(CFGBlock* continue_dest, CFGBlock* break_dest) { void pushLoopContinuation(CFGBlock* continue_dest, CFGBlock* break_dest) {
assert(continue_dest assert(continue_dest
...@@ -370,7 +374,7 @@ private: ...@@ -370,7 +374,7 @@ private:
curblock = body_block; curblock = body_block;
InternedString next_name(nodeName()); InternedString next_name(nodeName());
pushAssign(next_name, makeCall(next_attr)); pushAssign(next_name, makeCall(next_attr));
pushAssign(c->target, makeLoad(next_name, node)); pushAssign(c->target, makeLoad(next_name, node, true));
for (AST_expr* if_condition : c->ifs) { for (AST_expr* if_condition : c->ifs) {
AST_expr* remapped = callNonzero(remapExpr(if_condition)); AST_expr* remapped = callNonzero(remapExpr(if_condition));
...@@ -402,6 +406,7 @@ private: ...@@ -402,6 +406,7 @@ private:
assert((finished_block != NULL) == (i != 0)); assert((finished_block != NULL) == (i != 0));
if (finished_block) { if (finished_block) {
curblock = exit_block; curblock = exit_block;
push_back(makeKill(iter_name));
pushJump(finished_block, true); pushJump(finished_block, true);
} }
finished_block = test_block; finished_block = test_block;
...@@ -733,10 +738,10 @@ private: ...@@ -733,10 +738,10 @@ private:
for (int i = 0; i < node->values.size() - 1; i++) { for (int i = 0; i < node->values.size() - 1; i++) {
AST_expr* val = remapExpr(node->values[i]); AST_expr* val = remapExpr(node->values[i]);
pushAssign(name, val); pushAssign(name, _dup(val));
AST_Branch* br = new AST_Branch(); AST_Branch* br = new AST_Branch();
br->test = callNonzero(_dup(val)); br->test = callNonzero(val);
push_back(br); push_back(br);
CFGBlock* was_block = curblock; CFGBlock* was_block = curblock;
...@@ -844,7 +849,7 @@ private: ...@@ -844,7 +849,7 @@ private:
val->col_offset = node->col_offset; val->col_offset = node->col_offset;
val->lineno = node->lineno; val->lineno = node->lineno;
val->left = left; val->left = left;
val->comparators.push_back(right); val->comparators.push_back(_dup(right));
val->ops.push_back(node->ops[i]); val->ops.push_back(node->ops[i]);
pushAssign(name, val); pushAssign(name, val);
...@@ -867,7 +872,7 @@ private: ...@@ -867,7 +872,7 @@ private:
curblock = next_block; curblock = next_block;
left = _dup(right); left = right;
} }
pushJump(exit_block); pushJump(exit_block);
...@@ -1303,7 +1308,7 @@ private: ...@@ -1303,7 +1308,7 @@ private:
if (wrap_with_assign && (rtn->type != AST_TYPE::Name || ast_cast<AST_Name>(rtn)->id.s()[0] != '#')) { if (wrap_with_assign && (rtn->type != AST_TYPE::Name || ast_cast<AST_Name>(rtn)->id.s()[0] != '#')) {
InternedString name = nodeName(); InternedString name = nodeName();
pushAssign(name, rtn); pushAssign(name, rtn);
return makeLoad(name, node); return makeLoad(name, node, true);
} else { } else {
return rtn; return rtn;
} }
...@@ -1452,6 +1457,7 @@ public: ...@@ -1452,6 +1457,7 @@ public:
ExcBlockInfo& exc_info = exc_handlers.back(); ExcBlockInfo& exc_info = exc_handlers.back();
curblock = exc_dest; curblock = exc_dest;
// TODO: need to clear some temporaries here
AST_Assign* exc_asgn = new AST_Assign(); AST_Assign* exc_asgn = new AST_Assign();
AST_Tuple* target = new AST_Tuple(); AST_Tuple* target = new AST_Tuple();
target->elts.push_back(makeName(exc_info.exc_type_name, AST_TYPE::Store, node->lineno)); target->elts.push_back(makeName(exc_info.exc_type_name, AST_TYPE::Store, node->lineno));
...@@ -1489,7 +1495,7 @@ public: ...@@ -1489,7 +1495,7 @@ public:
auto tmp = nodeName(); auto tmp = nodeName();
pushAssign(tmp, new AST_MakeClass(def)); pushAssign(tmp, new AST_MakeClass(def));
// is this name mangling correct? // is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno)); pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno, 0, true));
return true; return true;
} }
...@@ -1511,7 +1517,7 @@ public: ...@@ -1511,7 +1517,7 @@ public:
auto tmp = nodeName(); auto tmp = nodeName();
pushAssign(tmp, new AST_MakeFunction(def)); pushAssign(tmp, new AST_MakeFunction(def));
// is this name mangling correct? // is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno)); pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno, node->col_offset, true));
return true; return true;
} }
...@@ -1557,7 +1563,7 @@ public: ...@@ -1557,7 +1563,7 @@ public:
if (a->asname.s().size() == 0) { if (a->asname.s().size() == 0) {
// No asname, so load the top-level module into the name // No asname, so load the top-level module into the name
// (e.g., for `import os.path`, loads the os module into `os`) // (e.g., for `import os.path`, loads the os module into `os`)
pushAssign(internString(getTopModule(a->name.s())), makeLoad(tmpname, node)); pushAssign(internString(getTopModule(a->name.s())), makeLoad(tmpname, node, /* is_kill */ true));
} else { } else {
// If there is an asname, get the bottom-level module by // If there is an asname, get the bottom-level module by
// getting the attributes and load it into asname. // getting the attributes and load it into asname.
...@@ -1571,11 +1577,11 @@ public: ...@@ -1571,11 +1577,11 @@ public:
l = r + 1; l = r + 1;
continue; continue;
} }
pushAssign(tmpname, new AST_Attribute(makeLoad(tmpname, node), AST_TYPE::Load, pushAssign(tmpname, new AST_Attribute(makeLoad(tmpname, node, true), AST_TYPE::Load,
internString(a->name.s().substr(l, r - l)))); internString(a->name.s().substr(l, r - l))));
l = r + 1; l = r + 1;
} while (l < a->name.s().size()); } while (l < a->name.s().size());
pushAssign(a->asname, makeLoad(tmpname, node)); pushAssign(a->asname, makeLoad(tmpname, node, true));
} }
} }
...@@ -1610,13 +1616,16 @@ public: ...@@ -1610,13 +1616,16 @@ public:
InternedString tmp_module_name = nodeName(); InternedString tmp_module_name = nodeName();
pushAssign(tmp_module_name, import); pushAssign(tmp_module_name, import);
int i = 0;
for (AST_alias* a : node->names) { for (AST_alias* a : node->names) {
i++;
bool is_kill = (i == node->names.size());
if (a->name.s() == "*") { if (a->name.s() == "*") {
AST_LangPrimitive* import_star = new AST_LangPrimitive(AST_LangPrimitive::IMPORT_STAR); AST_LangPrimitive* import_star = new AST_LangPrimitive(AST_LangPrimitive::IMPORT_STAR);
import_star->lineno = node->lineno; import_star->lineno = node->lineno;
import_star->col_offset = node->col_offset; import_star->col_offset = node->col_offset;
import_star->args.push_back(makeLoad(tmp_module_name, node)); import_star->args.push_back(makeLoad(tmp_module_name, node, is_kill));
AST_Expr* import_star_expr = new AST_Expr(); AST_Expr* import_star_expr = new AST_Expr();
import_star_expr->value = import_star; import_star_expr->value = import_star;
...@@ -1628,12 +1637,12 @@ public: ...@@ -1628,12 +1637,12 @@ public:
AST_LangPrimitive* import_from = new AST_LangPrimitive(AST_LangPrimitive::IMPORT_FROM); AST_LangPrimitive* import_from = new AST_LangPrimitive(AST_LangPrimitive::IMPORT_FROM);
import_from->lineno = node->lineno; import_from->lineno = node->lineno;
import_from->col_offset = node->col_offset; import_from->col_offset = node->col_offset;
import_from->args.push_back(makeLoad(tmp_module_name, node)); import_from->args.push_back(makeLoad(tmp_module_name, node, is_kill));
import_from->args.push_back(new AST_Str(a->name.s())); import_from->args.push_back(new AST_Str(a->name.s()));
InternedString tmp_import_name = nodeName(); InternedString tmp_import_name = nodeName();
pushAssign(tmp_import_name, import_from); pushAssign(tmp_import_name, import_from);
pushAssign(a->asname.s().size() ? a->asname : a->name, makeLoad(tmp_import_name, node)); pushAssign(a->asname.s().size() ? a->asname : a->name, makeLoad(tmp_import_name, node, true));
} }
} }
...@@ -1681,8 +1690,13 @@ public: ...@@ -1681,8 +1690,13 @@ public:
bool visit_assign(AST_Assign* node) override { bool visit_assign(AST_Assign* node) override {
AST_expr* remapped_value = remapExpr(node->value); AST_expr* remapped_value = remapExpr(node->value);
for (AST_expr* target : node->targets) { for (int i = 0; i < node->targets.size(); i++) {
pushAssign(target, _dup(remapped_value)); AST_expr* val;
if (i == node->targets.size() - 1)
val = remapped_value;
else
val = _dup(remapped_value);
pushAssign(node->targets[i], val);
} }
return true; return true;
} }
...@@ -1776,7 +1790,7 @@ public: ...@@ -1776,7 +1790,7 @@ public:
InternedString node_name(nodeName()); InternedString node_name(nodeName());
pushAssign(node_name, binop); pushAssign(node_name, binop);
pushAssign(remapped_target, makeLoad(node_name, node)); pushAssign(remapped_target, makeLoad(node_name, node, true));
return true; return true;
} }
...@@ -2050,6 +2064,13 @@ public: ...@@ -2050,6 +2064,13 @@ public:
return true; return true;
} }
AST_stmt* makeKill(InternedString name) {
// There might be a better way to represent this, maybe with a dedicated AST_Kill bytecode?
auto del = new AST_Delete();
del->targets.push_back(makeName(name, AST_TYPE::Del, 0, 0, false));
return del;
}
bool visit_for(AST_For* node) override { bool visit_for(AST_For* node) override {
assert(curblock); assert(curblock);
...@@ -2093,12 +2114,13 @@ public: ...@@ -2093,12 +2114,13 @@ public:
curblock = test_false; curblock = test_false;
pushJump(else_block); pushJump(else_block);
// TODO: need to del the iter_name when break'ing out of the loop
pushLoopContinuation(test_block, end_block); pushLoopContinuation(test_block, end_block);
curblock = loop_block; curblock = loop_block;
InternedString next_name(nodeName()); InternedString next_name(nodeName());
pushAssign(next_name, makeCall(next_attr)); pushAssign(next_name, makeCall(next_attr));
pushAssign(node->target, makeLoad(next_name, node)); pushAssign(node->target, makeLoad(next_name, node, true));
for (int i = 0; i < node->body.size(); i++) { for (int i = 0; i < node->body.size(); i++) {
node->body[i]->accept(this); node->body[i]->accept(this);
...@@ -2130,6 +2152,7 @@ public: ...@@ -2130,6 +2152,7 @@ public:
cfg->placeBlock(else_block); cfg->placeBlock(else_block);
curblock = else_block; curblock = else_block;
push_back(makeKill(itername));
for (int i = 0; i < node->orelse.size(); i++) { for (int i = 0; i < node->orelse.size(); i++) {
node->orelse[i]->accept(this); node->orelse[i]->accept(this);
if (!curblock) if (!curblock)
...@@ -2254,16 +2277,16 @@ public: ...@@ -2254,16 +2277,16 @@ public:
caught_all = true; caught_all = true;
} }
AST_LangPrimitive* set_exc_info = new AST_LangPrimitive(AST_LangPrimitive::SET_EXC_INFO);
set_exc_info->args.push_back(makeLoad(exc_type_name, node));
set_exc_info->args.push_back(makeLoad(exc_value_name, node));
set_exc_info->args.push_back(makeLoad(exc_traceback_name, node));
push_back(makeExpr(set_exc_info));
if (exc_handler->name) { if (exc_handler->name) {
pushAssign(exc_handler->name, _dup(exc_obj)); pushAssign(exc_handler->name, _dup(exc_obj));
} }
AST_LangPrimitive* set_exc_info = new AST_LangPrimitive(AST_LangPrimitive::SET_EXC_INFO);
set_exc_info->args.push_back(makeLoad(exc_type_name, node, true));
set_exc_info->args.push_back(makeLoad(exc_value_name, node, true));
set_exc_info->args.push_back(makeLoad(exc_traceback_name, node, true));
push_back(makeExpr(set_exc_info));
for (AST_stmt* subnode : exc_handler->body) { for (AST_stmt* subnode : exc_handler->body) {
subnode->accept(this); subnode->accept(this);
if (!curblock) if (!curblock)
...@@ -2284,9 +2307,9 @@ public: ...@@ -2284,9 +2307,9 @@ public:
if (!caught_all) { if (!caught_all) {
AST_Raise* raise = new AST_Raise(); AST_Raise* raise = new AST_Raise();
raise->arg0 = makeLoad(exc_type_name, node); raise->arg0 = makeLoad(exc_type_name, node, true);
raise->arg1 = makeLoad(exc_value_name, node); raise->arg1 = makeLoad(exc_value_name, node, true);
raise->arg2 = makeLoad(exc_traceback_name, node); raise->arg2 = makeLoad(exc_traceback_name, node, true);
push_back(raise); push_back(raise);
curblock = NULL; curblock = NULL;
} }
......
from _weakref import ref
# Test to make sure that we clear local variables at the right time:
def f1():
def f():
pass
r = ref(f)
print type(r())
# del f
f = 1
assert not r()
for i in xrange(40):
f1()
def f3():
class MyIter(object):
def __init__(self):
self.n = 5
def __del__(self):
print "deleting iter"
def next(self):
if self.n:
self.n -= 1
return self.n
raise StopIteration()
class MyIterable(object):
def __iter__(self):
return MyIter()
for i in MyIterable():
print i
else:
print -1
f3()
# expected: fail # expected: fail
# - finalization (let alone resurrection) not implemented yet
# Objects are allowed to resurrect themselves in their __del__ methods... # Objects are allowed to resurrect themselves in their __del__ methods...
# Note: the behavior here will differ from cPython and maybe PyPy
x = None x = None
running = True running = True
......
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