Commit a68bb9e6 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Basic auto-refcounter for the rewriter

parent 6d12a868
This diff is collapsed.
...@@ -201,7 +201,12 @@ class RewriterVar; ...@@ -201,7 +201,12 @@ class RewriterVar;
class RewriterAction; class RewriterAction;
enum class RefType { enum class RefType {
UNKNOWN, UNKNOWN
#ifndef NDEBUG
// Set this to non-zero to make it possible for the debugger to
= 0
#endif
,
OWNED, OWNED,
BORROWED, BORROWED,
}; };
...@@ -209,10 +214,13 @@ enum class RefType { ...@@ -209,10 +214,13 @@ enum class RefType {
// This might make more sense as an inner class of Rewriter, but // This might make more sense as an inner class of Rewriter, but
// you can't forward-declare that :/ // you can't forward-declare that :/
class RewriterVar { class RewriterVar {
#ifndef NDEBUG // Fields for automatic refcounting:
private: int num_refs_consumed = 0; // The number of "refConsumed()" calls on this RewriterVar
int skip_assert_last_action = 0; int last_refconsumed_numuses = 0; // The number of uses in the `uses` array when the last refConsumed() call was made.
#endif RefType reftype = RefType::UNKNOWN;
// Helper function: whether there is a ref that got consumed but came from the consumption of the
// initial (owned) reference.
bool refHandedOff();
public: public:
typedef llvm::SmallVector<RewriterVar*, 8> SmallVector; typedef llvm::SmallVector<RewriterVar*, 8> SmallVector;
...@@ -228,109 +236,31 @@ public: ...@@ -228,109 +236,31 @@ public:
RewriterVar* cmp(AST_TYPE::AST_TYPE cmp_type, RewriterVar* other, Location loc = Location::any()); RewriterVar* cmp(AST_TYPE::AST_TYPE cmp_type, RewriterVar* other, Location loc = Location::any());
RewriterVar* toBool(Location loc = Location::any()); RewriterVar* toBool(Location loc = Location::any());
RewriterVar* setType(RefType type) { RewriterVar* setType(RefType type);
assert(this->reftype == RefType::UNKNOWN);
assert(type != RefType::UNKNOWN);
this->reftype = type;
this->vrefcount = 1;
return this;
}
// Due to optimizations, there are some functions that sometimes return a new RewriterVar and // XXX convert callers back to setType
// sometimes return an existing one (specifically, loadConst() does this).
// asBorrowed() is meant for that kind of case.
// I think its presence indicates something fishy about the API though.
RewriterVar* asBorrowed() { RewriterVar* asBorrowed() {
if (this->reftype == RefType::UNKNOWN) return setType(RefType::BORROWED);
return setType(RefType::BORROWED);
assert(this->reftype == RefType::BORROWED);
// Special case: the rewriter can "resurrect" constants, and produce an existing
// RewriterVar even though at the bjit / IC level it's a new variable.
if (this->vrefcount == 0) {
#ifndef NDEBUG
skip_assert_last_action++;
#endif
vrefcount++;
return this;
} else {
return this->incvref();
}
} }
RewriterVar* incvref() { RewriterVar* incvref() {
assert(reftype == RefType::OWNED || reftype == RefType::BORROWED); assert(0 && "don't call incvref anymore");
//assert(vrefcount > 0 || (reftype == RefType::BORROWED && vrefcount >= 0));
assert(vrefcount > 0);
vrefcount++;
return this;
} }
#ifndef NDEBUG
// Assert that there are exactly num_left actions get added after this call.
// Meant for debugging. It's a way to cross between the two rewriter phases.
void addAssertLastActionAction(int num_left=0);
#endif
RewriterVar* decvref() { RewriterVar* decvref() {
assert(reftype == RefType::OWNED || reftype == RefType::BORROWED); assert(0 && "don't call decvref anymore");
assert(vrefcount > 0);
vrefcount--;
if (vrefcount == 0) {
if (reftype == RefType::OWNED)
decref();
// Assert that there are no more uses of the this at the machine-code level.
// This is kind of weird to cross this abstraction boundary like this, but
// I think it's a good safety net.
#ifndef NDEBUG
addAssertLastActionAction();
#endif
}
return this;
} }
// Steal a ref (not a vref) from this object. // Call this to let the automatic refcount machinery know that a refcount
// If there aren't any owned refs available, one will be created. // got "consumed", ie passed off. Such as to a function that steals a reference,
// Doesn't change the vrefcount, but the vref that stealRef acts on // or when stored into a memory location that is an owned reference, etc.
// becomes a borrowed vref. One can not use this RewriterVar after stealRef // This should get called *after* the ref got consumed, ie something like
// except for the operation that will actually steal the ref. // r_array->setAttr(0, r_val);
// If that is necessary, an extra vref should be taken out beforehand. // r_val->refConsumed()
// void refConsumed();
// Typical usage should look like:
// var->stealRef();
// functionThatStealsRef(var);
// var->decvref();
//
// If you need to use var after functionThatStealsRef, the whole snippet
// needs to be surrounded in an incvref/decvref.
//
// TODO: I still think I can find a better API for this. Maybe something like
// var->materializeRefFor([&](){ functionThatStealsRef(var); });
//
RewriterVar* stealRef() {
assert(reftype == RefType::OWNED || reftype == RefType::BORROWED);
assert(vrefcount > 0);
if (reftype == RefType::OWNED && vrefcount == 1) {
// handoff, do nothing;
reftype = RefType::BORROWED;
} else {
incref();
}
if (vrefcount == 1) { RewriterVar* stealRef() {
// See the comment in decvref. assert(0 && "don't call stealref anymore");
// This is similar, except that we want there to be exactly one more use of this variable:
// whatever consumes the vref. We want that to happen after the materializeVref call.
#ifndef NDEBUG
addAssertLastActionAction(1);
#endif
}
return this;
} }
...@@ -360,7 +290,12 @@ private: ...@@ -360,7 +290,12 @@ private:
llvm::SmallVector<int, 32> uses; llvm::SmallVector<int, 32> uses;
int next_use; int next_use;
void bumpUse(); void bumpUse();
// Call this on the result at the end of the action in which it's created
// TODO we should have a better way of dealing with variables that have 0 uses
void releaseIfNoUses(); void releaseIfNoUses();
// Helper funciton to release all the resources that this var is using.
// Don't call it directly: call bumpUse and releaseIfNoUses instead.
void _release();
bool isDoneUsing() { return next_use == uses.size(); } bool isDoneUsing() { return next_use == uses.size(); }
bool hasScratchAllocation() const { return scratch_allocation.second > 0; } bool hasScratchAllocation() const { return scratch_allocation.second > 0; }
void resetHasScratchAllocation() { scratch_allocation = std::make_pair(0, 0); } void resetHasScratchAllocation() { scratch_allocation = std::make_pair(0, 0); }
...@@ -369,9 +304,6 @@ private: ...@@ -369,9 +304,6 @@ private:
bool is_arg; bool is_arg;
bool is_constant; bool is_constant;
RefType reftype = RefType::UNKNOWN;
int vrefcount;
uint64_t constant_value; uint64_t constant_value;
Location arg_loc; Location arg_loc;
std::pair<int /*offset*/, int /*size*/> scratch_allocation; std::pair<int /*offset*/, int /*size*/> scratch_allocation;
...@@ -397,12 +329,7 @@ private: ...@@ -397,12 +329,7 @@ private:
RewriterVar& operator=(const RewriterVar&) = delete; RewriterVar& operator=(const RewriterVar&) = delete;
public: public:
RewriterVar(Rewriter* rewriter) RewriterVar(Rewriter* rewriter) : rewriter(rewriter), next_use(0), is_arg(false), is_constant(false) {
: rewriter(rewriter),
next_use(0),
is_arg(false),
is_constant(false),
vrefcount(0) {
assert(rewriter); assert(rewriter);
} }
...@@ -410,7 +337,7 @@ public: ...@@ -410,7 +337,7 @@ public:
// XXX: for testing, reset these on deallocation so that we will see the next time they get set. // XXX: for testing, reset these on deallocation so that we will see the next time they get set.
~RewriterVar() { ~RewriterVar() {
reftype = (RefType)-1; reftype = (RefType)-1;
vrefcount = -11; num_refs_consumed = -11;
} }
#endif #endif
......
...@@ -418,8 +418,6 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b ...@@ -418,8 +418,6 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
interpreter.jit->emitSetCurrentInst(s); interpreter.jit->emitSetCurrentInst(s);
if (v.o) { if (v.o) {
Py_DECREF(v.o); Py_DECREF(v.o);
if (v.var)
v.var->decvref();
} }
v = interpreter.visit_stmt(s); v = interpreter.visit_stmt(s);
} }
...@@ -509,7 +507,6 @@ void ASTInterpreter::doStore(AST_expr* node, STOLEN(Value) value) { ...@@ -509,7 +507,6 @@ void ASTInterpreter::doStore(AST_expr* node, STOLEN(Value) value) {
Value o = visit_expr(attr->value); Value o = visit_expr(attr->value);
if (jit) { if (jit) {
jit->emitSetAttr(node, o, attr->attr.getBox(), value); jit->emitSetAttr(node, o, attr->attr.getBox(), value);
o.var->decvref();
} }
pyston::setattr(o.o, attr->attr.getBox(), value.o); pyston::setattr(o.o, attr->attr.getBox(), value.o);
Py_DECREF(o.o); Py_DECREF(o.o);
...@@ -578,10 +575,6 @@ Value ASTInterpreter::visit_binop(AST_BinOp* node) { ...@@ -578,10 +575,6 @@ Value ASTInterpreter::visit_binop(AST_BinOp* node) {
AUTO_DECREF(left.o); AUTO_DECREF(left.o);
AUTO_DECREF(right.o); AUTO_DECREF(right.o);
Value r = doBinOp(node, left, right, node->op_type, BinExpType::BinOp); Value r = doBinOp(node, left, right, node->op_type, BinExpType::BinOp);
if (jit) {
left.var->decvref();
right.var->decvref();
}
return r; return r;
} }
...@@ -869,10 +862,6 @@ Value ASTInterpreter::visit_augBinOp(AST_AugBinOp* node) { ...@@ -869,10 +862,6 @@ Value ASTInterpreter::visit_augBinOp(AST_AugBinOp* node) {
Py_DECREF(left.o); Py_DECREF(left.o);
Py_DECREF(right.o); Py_DECREF(right.o);
if (jit) {
left.var->decvref();
right.var->decvref();
}
return r; return r;
} }
...@@ -883,8 +872,6 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) { ...@@ -883,8 +872,6 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
Value val = visit_expr(node->args[0]); Value val = visit_expr(node->args[0]);
v = Value(getPystonIter(val.o), jit ? jit->emitGetPystonIter(val) : NULL); v = Value(getPystonIter(val.o), jit ? jit->emitGetPystonIter(val) : NULL);
Py_DECREF(val.o); Py_DECREF(val.o);
if (jit)
val.var->decvref();
} else if (node->opcode == AST_LangPrimitive::IMPORT_FROM) { } else if (node->opcode == AST_LangPrimitive::IMPORT_FROM) {
assert(node->args.size() == 2); assert(node->args.size() == 2);
assert(node->args[0]->type == AST_TYPE::Name); assert(node->args[0]->type == AST_TYPE::Name);
...@@ -946,8 +933,6 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) { ...@@ -946,8 +933,6 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
Value obj = visit_expr(node->args[0]); Value obj = visit_expr(node->args[0]);
v = Value(boxBool(nonzero(obj.o)), jit ? jit->emitNonzero(obj) : NULL); v = Value(boxBool(nonzero(obj.o)), jit ? jit->emitNonzero(obj) : NULL);
Py_DECREF(obj.o); Py_DECREF(obj.o);
if (jit)
obj.var->decvref();
} else if (node->opcode == AST_LangPrimitive::SET_EXC_INFO) { } else if (node->opcode == AST_LangPrimitive::SET_EXC_INFO) {
assert(node->args.size() == 3); assert(node->args.size() == 3);
...@@ -976,8 +961,6 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) { ...@@ -976,8 +961,6 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
Value obj = visit_expr(node->args[0]); Value obj = visit_expr(node->args[0]);
v = Value(boxBool(hasnext(obj.o)), jit ? jit->emitHasnext(obj) : NULL); v = Value(boxBool(hasnext(obj.o)), jit ? jit->emitHasnext(obj) : NULL);
Py_DECREF(obj.o); Py_DECREF(obj.o);
if (jit)
obj.var->decvref();
} else if (node->opcode == AST_LangPrimitive::PRINT_EXPR) { } else if (node->opcode == AST_LangPrimitive::PRINT_EXPR) {
abortJITing(); abortJITing();
Value obj = visit_expr(node->args[0]); Value obj = visit_expr(node->args[0]);
...@@ -1157,8 +1140,6 @@ Value ASTInterpreter::visit_makeFunction(AST_MakeFunction* mkfn) { ...@@ -1157,8 +1140,6 @@ Value ASTInterpreter::visit_makeFunction(AST_MakeFunction* mkfn) {
if (jit) { if (jit) {
auto prev_func_var = func.var; auto prev_func_var = func.var;
func.var = jit->emitRuntimeCall(NULL, decorators[i], ArgPassSpec(1), { func }, NULL); func.var = jit->emitRuntimeCall(NULL, decorators[i], ArgPassSpec(1), { func }, NULL);
decorators[i].var->decvref();
prev_func_var->decvref();
} }
} }
return func; return func;
...@@ -1333,12 +1314,6 @@ Value ASTInterpreter::visit_print(AST_Print* node) { ...@@ -1333,12 +1314,6 @@ Value ASTInterpreter::visit_print(AST_Print* node) {
else else
printHelper(getSysStdout(), autoXDecref(var.o), node->nl); printHelper(getSysStdout(), autoXDecref(var.o), node->nl);
if (jit) {
if (node->dest)
dest.var->decvref();
var.var->decvref();
}
return Value(); return Value();
} }
...@@ -1362,10 +1337,6 @@ Value ASTInterpreter::visit_compare(AST_Compare* node) { ...@@ -1362,10 +1337,6 @@ Value ASTInterpreter::visit_compare(AST_Compare* node) {
Value r = doBinOp(node, left, right, node->ops[0], BinExpType::Compare); Value r = doBinOp(node, left, right, node->ops[0], BinExpType::Compare);
Py_DECREF(left.o); Py_DECREF(left.o);
Py_DECREF(right.o); Py_DECREF(right.o);
if (jit) {
left.var->decvref();
right.var->decvref();
}
return r; return r;
} }
...@@ -1499,12 +1470,6 @@ Value ASTInterpreter::visit_call(AST_Call* node) { ...@@ -1499,12 +1470,6 @@ Value ASTInterpreter::visit_call(AST_Call* node) {
for (auto e : args) for (auto e : args)
Py_DECREF(e); Py_DECREF(e);
if (jit) {
func.var->decvref();
for (auto e : args_vars)
e->decvref();
}
return v; return v;
} }
...@@ -1693,8 +1658,6 @@ Value ASTInterpreter::visit_attribute(AST_Attribute* node) { ...@@ -1693,8 +1658,6 @@ Value ASTInterpreter::visit_attribute(AST_Attribute* node) {
Value v = visit_expr(node->value); Value v = visit_expr(node->value);
Value r(pyston::getattr(v.o, node->attr.getBox()), jit ? jit->emitGetAttr(v, node->attr.getBox(), node) : NULL); Value r(pyston::getattr(v.o, node->attr.getBox()), jit ? jit->emitGetAttr(v, node->attr.getBox(), node) : NULL);
Py_DECREF(v.o); Py_DECREF(v.o);
if (jit)
v.var->decvref();
return r; return r;
} }
} }
......
...@@ -278,9 +278,6 @@ RewriterVar* JitFragmentWriter::emitCreateTuple(const llvm::ArrayRef<RewriterVar ...@@ -278,9 +278,6 @@ RewriterVar* JitFragmentWriter::emitCreateTuple(const llvm::ArrayRef<RewriterVar
else else
r = call(false, (void*)createTupleHelper, imm(num), allocArgs(values)); r = call(false, (void*)createTupleHelper, imm(num), allocArgs(values));
for (auto v : values)
v->decvref();
return r; return r;
} }
...@@ -305,7 +302,6 @@ RewriterVar* JitFragmentWriter::emitGetBlockLocal(InternedString s, int vreg) { ...@@ -305,7 +302,6 @@ RewriterVar* JitFragmentWriter::emitGetBlockLocal(InternedString s, int vreg) {
auto it = local_syms.find(s); auto it = local_syms.find(s);
if (it == local_syms.end()) if (it == local_syms.end())
return emitGetLocal(s, vreg); return emitGetLocal(s, vreg);
it->second->incvref();
return it->second; return it->second;
} }
...@@ -378,7 +374,7 @@ RewriterVar* JitFragmentWriter::emitLandingpad() { ...@@ -378,7 +374,7 @@ RewriterVar* JitFragmentWriter::emitLandingpad() {
RewriterVar* JitFragmentWriter::emitNonzero(RewriterVar* v) { RewriterVar* JitFragmentWriter::emitNonzero(RewriterVar* v) {
// nonzeroHelper returns bool // nonzeroHelper returns bool
return call(false, (void*)nonzeroHelper, v); return call(false, (void*)nonzeroHelper, v)->setType(RefType::OWNED);
} }
RewriterVar* JitFragmentWriter::emitNotNonzero(RewriterVar* v) { RewriterVar* JitFragmentWriter::emitNotNonzero(RewriterVar* v) {
...@@ -498,11 +494,13 @@ void JitFragmentWriter::emitOSRPoint(AST_Jump* node) { ...@@ -498,11 +494,13 @@ void JitFragmentWriter::emitOSRPoint(AST_Jump* node) {
} }
void JitFragmentWriter::emitPrint(RewriterVar* dest, RewriterVar* var, bool nl) { void JitFragmentWriter::emitPrint(RewriterVar* dest, RewriterVar* var, bool nl) {
if (LOG_BJIT_ASSEMBLY) comment("BJIT: emitPrint() start");
if (!dest) if (!dest)
dest = call(false, (void*)getSysStdout); dest = call(false, (void*)getSysStdout);
if (!var) if (!var)
var = imm(0ul); var = imm(0ul);
call(false, (void*)printHelper, dest, var, imm(nl)); call(false, (void*)printHelper, dest, var, imm(nl));
if (LOG_BJIT_ASSEMBLY) comment("BJIT: emitPrint() end");
} }
void JitFragmentWriter::emitRaise0() { void JitFragmentWriter::emitRaise0() {
...@@ -514,38 +512,23 @@ void JitFragmentWriter::emitRaise3(RewriterVar* arg0, RewriterVar* arg1, Rewrite ...@@ -514,38 +512,23 @@ void JitFragmentWriter::emitRaise3(RewriterVar* arg0, RewriterVar* arg1, Rewrite
} }
void JitFragmentWriter::emitEndBlock() { void JitFragmentWriter::emitEndBlock() {
for (auto v : local_syms) { // XXX remove
if (v.second) {
if (LOG_BJIT_ASSEMBLY) {
// XXX silly but we need to keep this alive
std::string s = std::string("BJIT: decvref(") + v.first.c_str() + ")";
comment(*new std::string(s));
}
v.second->decvref(); // xdecref?
}
}
} }
void JitFragmentWriter::emitReturn(RewriterVar* v) { void JitFragmentWriter::emitReturn(RewriterVar* v) {
v->stealRef();
addAction([=]() { _emitReturn(v); }, { v }, ActionType::NORMAL); addAction([=]() { _emitReturn(v); }, { v }, ActionType::NORMAL);
v->decvref(); v->refConsumed();
} }
void JitFragmentWriter::emitSetAttr(AST_expr* node, RewriterVar* obj, BoxedString* s, STOLEN(RewriterVar*) attr) { void JitFragmentWriter::emitSetAttr(AST_expr* node, RewriterVar* obj, BoxedString* s, STOLEN(RewriterVar*) attr) {
attr->stealRef(); attr->stealRef();
emitPPCall((void*)setattr, { obj, imm(s), attr }, 2, 512, node); emitPPCall((void*)setattr, { obj, imm(s), attr }, 2, 512, node);
attr->decvref();
} }
void JitFragmentWriter::emitSetBlockLocal(InternedString s, STOLEN(RewriterVar*) v) { void JitFragmentWriter::emitSetBlockLocal(InternedString s, STOLEN(RewriterVar*) v) {
if (LOG_BJIT_ASSEMBLY) comment("BJIT: emitSetBlockLocal() start"); if (LOG_BJIT_ASSEMBLY) comment("BJIT: emitSetBlockLocal() start");
RewriterVar* prev = local_syms[s]; RewriterVar* prev = local_syms[s];
local_syms[s] = v; local_syms[s] = v;
if (prev) {
// TODO: xdecref?
prev->decvref();
}
if (LOG_BJIT_ASSEMBLY) comment("BJIT: emitSetBlockLocal() end"); if (LOG_BJIT_ASSEMBLY) comment("BJIT: emitSetBlockLocal() end");
} }
...@@ -558,9 +541,8 @@ void JitFragmentWriter::emitSetExcInfo(RewriterVar* type, RewriterVar* value, Re ...@@ -558,9 +541,8 @@ void JitFragmentWriter::emitSetExcInfo(RewriterVar* type, RewriterVar* value, Re
} }
void JitFragmentWriter::emitSetGlobal(Box* global, BoxedString* s, STOLEN(RewriterVar*) v) { void JitFragmentWriter::emitSetGlobal(Box* global, BoxedString* s, STOLEN(RewriterVar*) v) {
v->stealRef();
emitPPCall((void*)setGlobal, { imm(global), imm(s), v }, 2, 512); emitPPCall((void*)setGlobal, { imm(global), imm(s), v }, 2, 512);
v->decvref(); v->refConsumed();
} }
void JitFragmentWriter::emitSetItem(RewriterVar* target, RewriterVar* slice, RewriterVar* value) { void JitFragmentWriter::emitSetItem(RewriterVar* target, RewriterVar* slice, RewriterVar* value) {
...@@ -585,9 +567,8 @@ void JitFragmentWriter::emitSetLocal(InternedString s, int vreg, bool set_closur ...@@ -585,9 +567,8 @@ void JitFragmentWriter::emitSetLocal(InternedString s, int vreg, bool set_closur
v); v);
} else { } else {
RewriterVar* prev = vregs_array->getAttr(8 * vreg); RewriterVar* prev = vregs_array->getAttr(8 * vreg);
v->stealRef();
vregs_array->setAttr(8 * vreg, v); vregs_array->setAttr(8 * vreg, v);
v->decvref(); v->refConsumed();
// TODO With definedness analysis, we could know whether we can skip this check (definitely defined) // TODO With definedness analysis, we could know whether we can skip this check (definitely defined)
// or not even load the previous value (definitely undefined). // or not even load the previous value (definitely undefined).
...@@ -973,10 +954,6 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm:: ...@@ -973,10 +954,6 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm::
pp_scratch_location -= 8; pp_scratch_location -= 8;
} }
for (RewriterVar* arg : args) {
arg->bumpUse();
}
assertConsistent(); assertConsistent();
StackInfo stack_info(pp_scratch_size, pp_scratch_location); StackInfo stack_info(pp_scratch_size, pp_scratch_location);
...@@ -987,6 +964,17 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm:: ...@@ -987,6 +964,17 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm::
assertConsistent(); assertConsistent();
result->releaseIfNoUses(); result->releaseIfNoUses();
// TODO: it would be nice to be able to bumpUse on these earlier so that we could potentially avoid spilling
// the args across the call if we don't need to.
// This had to get moved to the very end of this function due to the fact that bumpUse can cause refcounting
// operations to happen.
// I'm not sure though that just moving this earlier is good enough though -- we also might need to teach setupCall
// that the args might not be needed afterwards?
// Anyway this feels like micro-optimizations at the moment and we can figure it out later.
for (RewriterVar* arg : args) {
arg->bumpUse();
}
} }
void JitFragmentWriter::_emitRecordType(RewriterVar* type_recorder_var, RewriterVar* obj_cls_var) { void JitFragmentWriter::_emitRecordType(RewriterVar* type_recorder_var, RewriterVar* obj_cls_var) {
...@@ -1025,6 +1013,20 @@ void JitFragmentWriter::_emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val ...@@ -1025,6 +1013,20 @@ void JitFragmentWriter::_emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val
assert(next_block_var->is_constant); assert(next_block_var->is_constant);
uint64_t val = val_constant->constant_value; uint64_t val = val_constant->constant_value;
assert(val == (uint64_t)True || val == (uint64_t)False);
// HAXX ahead:
// Override the automatic refcounting system, to force a decref to happen before the jump.
// Really, we should probably do a decref on either side post-jump.
// But the automatic refcounter doesn't support that, and since the value is either True or False,
// we can get away with doing the decref early.
// TODO: better solution is to just make NONZERO return a borrowed ref, so we don't have to decref at all.
_decref(var);
// Hax: override the automatic refcount system
assert(var->reftype == RefType::OWNED);
assert(var->num_refs_consumed == 0);
var->reftype = RefType::BORROWED;
assembler::Register var_reg = var->getInReg(); assembler::Register var_reg = var->getInReg();
if (isLargeConstant(val)) { if (isLargeConstant(val)) {
assembler::Register reg = val_constant->getInReg(Location::any(), true, /* otherThan */ var_reg); assembler::Register reg = val_constant->getInReg(Location::any(), true, /* otherThan */ var_reg);
...@@ -1034,10 +1036,7 @@ void JitFragmentWriter::_emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val ...@@ -1034,10 +1036,7 @@ void JitFragmentWriter::_emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val
} }
{ {
// TODO: Figure out if we need a large/small forward based on the number of local syms we will have to decref? assembler::ForwardJump jne(*assembler, assembler::COND_EQUAL);
assembler::LargeForwardJump jne(*assembler, assembler::COND_EQUAL);
_decref(var);
ExitInfo exit_info; ExitInfo exit_info;
_emitJump(next_block, next_block_var, exit_info); _emitJump(next_block, next_block_var, exit_info);
...@@ -1049,11 +1048,6 @@ void JitFragmentWriter::_emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val ...@@ -1049,11 +1048,6 @@ void JitFragmentWriter::_emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val
} }
} }
if (LOG_BJIT_ASSEMBLY) assembler->comment("BJIT: decreffing emitSideExit var");
_decref(var);
if (LOG_BJIT_ASSEMBLY) assembler->comment("BJIT: decreffing emitSideExit var end");
var->bumpUse(); var->bumpUse();
val_constant->bumpUse(); val_constant->bumpUse();
......
...@@ -24,8 +24,8 @@ int PYSTON_VERSION_MICRO = 0; ...@@ -24,8 +24,8 @@ int PYSTON_VERSION_MICRO = 0;
int MAX_OPT_ITERATIONS = 1; int MAX_OPT_ITERATIONS = 1;
bool LOG_IC_ASSEMBLY = false; bool LOG_IC_ASSEMBLY = 0;
bool LOG_BJIT_ASSEMBLY = false; bool LOG_BJIT_ASSEMBLY = 0;
bool CONTINUE_AFTER_FATAL = false; bool CONTINUE_AFTER_FATAL = false;
bool FORCE_INTERPRETER = true; bool FORCE_INTERPRETER = true;
...@@ -49,7 +49,7 @@ bool FORCE_LLVM_CAPI_CALLS = false; ...@@ -49,7 +49,7 @@ bool FORCE_LLVM_CAPI_CALLS = false;
bool FORCE_LLVM_CAPI_THROWS = false; bool FORCE_LLVM_CAPI_THROWS = false;
int OSR_THRESHOLD_INTERPRETER = 5; // XXX int OSR_THRESHOLD_INTERPRETER = 5; // XXX
int REOPT_THRESHOLD_INTERPRETER = 5; // XXX int REOPT_THRESHOLD_INTERPRETER = 1; // XXX
int OSR_THRESHOLD_BASELINE = 2500; int OSR_THRESHOLD_BASELINE = 2500;
int REOPT_THRESHOLD_BASELINE = 1500; int REOPT_THRESHOLD_BASELINE = 1500;
int OSR_THRESHOLD_T2 = 10000; int OSR_THRESHOLD_T2 = 10000;
......
...@@ -1023,15 +1023,13 @@ void Box::setattr(BoxedString* attr, Box* val, SetattrRewriteArgs* rewrite_args) ...@@ -1023,15 +1023,13 @@ void Box::setattr(BoxedString* attr, Box* val, SetattrRewriteArgs* rewrite_args)
RewriterVar* r_hattrs RewriterVar* r_hattrs
= rewrite_args->obj->getAttr(cls->attrs_offset + offsetof(HCAttrs, attr_list), Location::any()); = rewrite_args->obj->getAttr(cls->attrs_offset + offsetof(HCAttrs, attr_list), Location::any());
// Don't need to do anything: just getting it and setting it to OWNED
// will tell the auto-refcount system to decref it.
r_hattrs->getAttr(offset * sizeof(Box*) + offsetof(HCAttrs::AttrList, attrs)) r_hattrs->getAttr(offset * sizeof(Box*) + offsetof(HCAttrs::AttrList, attrs))
->setType(RefType::OWNED) ->setType(RefType::OWNED);
->decvref();
// TODO make this stealing // TODO make this stealing
rewrite_args->attrval->incvref();
rewrite_args->attrval->stealRef();
r_hattrs->setAttr(offset * sizeof(Box*) + offsetof(HCAttrs::AttrList, attrs), r_hattrs->setAttr(offset * sizeof(Box*) + offsetof(HCAttrs::AttrList, attrs),
rewrite_args->attrval); rewrite_args->attrval);
rewrite_args->attrval->decvref();
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
...@@ -1389,8 +1387,6 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1389,8 +1387,6 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
} else { } else {
*bind_obj_out = incref(im_self); *bind_obj_out = incref(im_self);
if (rewrite_args) { if (rewrite_args) {
r_im_func->incvref();
r_im_self->incvref();
rewrite_args->setReturn(r_im_func, ReturnConvention::HAS_RETURN); rewrite_args->setReturn(r_im_func, ReturnConvention::HAS_RETURN);
*r_bind_obj_out = r_im_self; *r_bind_obj_out = r_im_self;
} }
...@@ -1951,7 +1947,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1951,7 +1947,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
// Look up the class attribute (called `descr` here because it might // Look up the class attribute (called `descr` here because it might
// be a descriptor). // be a descriptor).
Box* descr = NULL; Box* descr = NULL;
AutoDecvref r_descr = NULL; RewriterVar* r_descr = NULL;
if (rewrite_args) { if (rewrite_args) {
RewriterVar* r_obj_cls = rewrite_args->obj->getAttr(offsetof(Box, cls), Location::any()); RewriterVar* r_obj_cls = rewrite_args->obj->getAttr(offsetof(Box, cls), Location::any());
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_obj_cls, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_obj_cls, rewrite_args->destination);
...@@ -2546,13 +2542,11 @@ void setattrGeneric(Box* obj, BoxedString* attr, STOLEN(Box*) val, SetattrRewrit ...@@ -2546,13 +2542,11 @@ void setattrGeneric(Box* obj, BoxedString* attr, STOLEN(Box*) val, SetattrRewrit
raiseAttributeError(obj, attr->s()); raiseAttributeError(obj, attr->s());
} }
if (rewrite_args)
rewrite_args->attrval->stealRef();
obj->setattr(attr, val, rewrite_args);
// TODO: make setattr() stealing // TODO: make setattr() stealing
Py_DECREF(val); obj->setattr(attr, val, rewrite_args);
if (rewrite_args) if (rewrite_args)
rewrite_args->attrval->decvref(); rewrite_args->attrval->refConsumed();
Py_DECREF(val);
} }
// TODO this should be in type_setattro // TODO this should be in type_setattro
...@@ -2661,12 +2655,8 @@ extern "C" void setattr(Box* obj, BoxedString* attr, STOLEN(Box*) attr_val) { ...@@ -2661,12 +2655,8 @@ extern "C" void setattr(Box* obj, BoxedString* attr, STOLEN(Box*) attr_val) {
// rewriter->trap(); // rewriter->trap();
SetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(2)); SetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(2));
setattrGeneric<REWRITABLE>(obj, attr, attr_val, &rewrite_args); setattrGeneric<REWRITABLE>(obj, attr, attr_val, &rewrite_args);
if (rewrite_args.out_success) { if (rewrite_args.out_success)
rewriter->getArg(0)->decvref();
rewriter->getArg(1)->decvref();
// arg 2 vref got consumed by setattrGeneric
rewriter->commit(); rewriter->commit();
}
} else { } else {
setattrGeneric<NOT_REWRITABLE>(obj, attr, attr_val, NULL); setattrGeneric<NOT_REWRITABLE>(obj, attr, attr_val, NULL);
} }
...@@ -3245,10 +3235,8 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallattrRe ...@@ -3245,10 +3235,8 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallattrRe
else else
arg_array->setAttr(8, rewrite_args->rewriter->loadConst(0)); arg_array->setAttr(8, rewrite_args->rewriter->loadConst(0));
auto r_rtn = rewrite_args->rewriter->call(true, (void*)Helper::call, arg_vec); auto r_rtn = rewrite_args->rewriter->call(true, (void*)Helper::call, arg_vec)->setType(RefType::OWNED);
rewrite_args->setReturn(r_rtn, S == CXX ? ReturnConvention::HAS_RETURN : ReturnConvention::CAPI_RETURN); rewrite_args->setReturn(r_rtn, S == CXX ? ReturnConvention::HAS_RETURN : ReturnConvention::CAPI_RETURN);
if (r_bind_obj)
r_bind_obj->decvref();
void* _args[2] = { args, const_cast<std::vector<BoxedString*>*>(keyword_names) }; void* _args[2] = { args, const_cast<std::vector<BoxedString*>*>(keyword_names) };
Box* rtn = Helper::call(val, argspec, arg1, arg2, arg3, _args); Box* rtn = Helper::call(val, argspec, arg1, arg2, arg3, _args);
...@@ -3267,11 +3255,6 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallattrRe ...@@ -3267,11 +3255,6 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallattrRe
} else { } else {
r = runtimeCallInternal<S, NOT_REWRITABLE>(val, NULL, argspec, arg1, arg2, arg3, args, keyword_names); r = runtimeCallInternal<S, NOT_REWRITABLE>(val, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
} }
if (rewrite_args) {
if (r_bind_obj)
r_bind_obj->decvref();
r_val->decvref();
}
return r; return r;
} }
...@@ -3584,12 +3567,6 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa ...@@ -3584,12 +3567,6 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
if (rewrite_args) { if (rewrite_args) {
// TODO should probably rethink the whole vrefcounting thing here. // TODO should probably rethink the whole vrefcounting thing here.
// which ones actually need new vrefs? // which ones actually need new vrefs?
if (num_output_args >= 1)
rewrite_args->arg1->incvref();
if (num_output_args >= 2)
rewrite_args->arg2->incvref();
if (num_output_args >= 3)
rewrite_args->arg3->incvref();
if (num_output_args >= 3) { if (num_output_args >= 3) {
RELEASE_ASSERT(0, "not sure what to do here\n"); RELEASE_ASSERT(0, "not sure what to do here\n");
//for (int i = 0; i < num_output_args - 3; i++) { //for (int i = 0; i < num_output_args - 3; i++) {
...@@ -4177,9 +4154,6 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe ...@@ -4177,9 +4154,6 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
} }
if (rewrite_args) { if (rewrite_args) {
RELEASE_ASSERT(num_output_args <= 3, "figure out vrefs for arg array"); RELEASE_ASSERT(num_output_args <= 3, "figure out vrefs for arg array");
for (int i = 0; i < num_output_args; i++) {
getArg(i, rewrite_args)->decvref();
}
} }
return res; return res;
......
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