Commit 61dc4620 authored by Marius Wachtler's avatar Marius Wachtler Committed by Kevin Modzelewski

generate a decref info table and fix the bjit

we need this map to know which object refcounter we have to decrement in case an exception gets throwen inside an IC or the bjit.
in addition fix all bjit related problems
parent 4eb5b941
......@@ -23,6 +23,7 @@
#include "asm_writing/assembler.h"
#include "asm_writing/mc_writer.h"
#include "codegen/patchpoints.h"
#include "codegen/unwinding.h"
#include "core/common.h"
#include "core/options.h"
#include "core/types.h"
......@@ -53,6 +54,7 @@ void ICInvalidator::invalidateAll() {
void ICSlotInfo::clear() {
ic->clear(this);
decref_infos.clear();
}
ICSlotRewrite::ICSlotRewrite(ICInfo* ic, const char* debug_name)
......@@ -82,7 +84,8 @@ uint8_t* ICSlotRewrite::getSlotStart() {
return (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize();
}
void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references) {
void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references,
std::vector<std::pair<uint64_t, std::vector<Location>>> decref_infos) {
bool still_valid = true;
for (int i = 0; i < dependencies.size(); i++) {
int orig_version = dependencies[i].second;
......@@ -130,6 +133,21 @@ void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references) {
megamorphic_ics.log();
}
// deregister old decref infos
ic_entry->decref_infos.clear();
// register new decref info
for (auto&& decref_info : decref_infos) {
// add decref locations which are always to decref inside this IC
auto&& merged_locations = decref_info.second;
merged_locations.insert(merged_locations.end(), ic->ic_global_decref_locations.begin(),
ic->ic_global_decref_locations.end());
if (merged_locations.empty())
continue;
ic_entry->decref_infos.emplace_back(decref_info.first, std::move(merged_locations));
}
llvm::sys::Memory::InvalidateInstructionCache(slot_start, ic->getSlotSize());
}
......@@ -207,7 +225,8 @@ void deregisterGCTrackedICInfo(ICInfo* ic) {
ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots,
int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet _live_outs,
assembler::GenericRegister return_register, TypeRecorder* type_recorder)
assembler::GenericRegister return_register, TypeRecorder* type_recorder,
std::vector<Location> ic_global_decref_locations)
: next_slot_to_try(0),
stack_info(stack_info),
num_slots(num_slots),
......@@ -219,6 +238,7 @@ ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, S
retry_in(0),
retry_backoff(1),
times_rewritten(0),
ic_global_decref_locations(std::move(ic_global_decref_locations)),
start_addr(start_addr),
slowpath_rtn_addr(slowpath_rtn_addr),
continue_addr(continue_addr) {
......@@ -226,6 +246,8 @@ ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, S
for (int i = 0; i < num_slots; i++) {
slots.emplace_back(this, i);
}
if (slowpath_rtn_addr && !this->ic_global_decref_locations.empty())
slowpath_decref_info = DecrefInfo((uint64_t)slowpath_rtn_addr, this->ic_global_decref_locations);
#if MOVING_GC
assert(ics_list.count(this) == 0);
......@@ -238,9 +260,21 @@ ICInfo::~ICInfo() {
#endif
}
DecrefInfo::DecrefInfo(uint64_t ip, std::vector<Location> locations) : ip(ip) {
addDecrefInfoEntry(ip, std::move(locations));
}
void DecrefInfo::reset() {
if (ip) {
removeDecrefInfoEntry(ip);
ip = 0;
}
}
std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* slowpath_start_addr,
uint8_t* continue_addr, uint8_t* slowpath_rtn_addr,
const ICSetupInfo* ic, StackInfo stack_info, LiveOutSet live_outs) {
const ICSetupInfo* ic, StackInfo stack_info, LiveOutSet live_outs,
std::vector<Location> decref_info) {
assert(slowpath_start_addr - start_addr >= ic->num_slots * ic->slot_size);
assert(slowpath_rtn_addr > slowpath_start_addr);
assert(slowpath_rtn_addr <= start_addr + ic->totalSize());
......@@ -276,8 +310,9 @@ std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t*
writer.jmp(JumpDestination::fromStart(slowpath_start_addr - start));
}
ICInfo* icinfo = new ICInfo(start_addr, slowpath_rtn_addr, continue_addr, stack_info, ic->num_slots, ic->slot_size,
ic->getCallingConvention(), std::move(live_outs), return_register, ic->type_recorder);
ICInfo* icinfo
= new ICInfo(start_addr, slowpath_rtn_addr, continue_addr, stack_info, ic->num_slots, ic->slot_size,
ic->getCallingConvention(), std::move(live_outs), return_register, ic->type_recorder, decref_info);
assert(!ics_by_return_addr.count(slowpath_rtn_addr));
ics_by_return_addr[slowpath_rtn_addr] = icinfo;
......@@ -355,6 +390,17 @@ ICInfo* ICInfo::getICInfoForNode(AST* node) {
void ICInfo::associateNodeWithICInfo(AST* node) {
ics_by_ast_node[node] = this;
}
void ICInfo::appendDecrefInfosTo(std::vector<DecrefInfo>& dest_decref_infos) {
if (slowpath_decref_info.ip)
dest_decref_infos.emplace_back(std::move(slowpath_decref_info));
for (auto&& slot : slots) {
for (DecrefInfo& decref_info : slot.decref_infos) {
dest_decref_infos.emplace_back(std::move(decref_info));
assert(decref_info.ip == 0 && "this can only happen if we copied instead of moved the value");
}
slot.decref_infos.clear();
}
}
void clearAllICs() {
for (auto&& p : ics_by_ast_node) {
......
......@@ -35,6 +35,24 @@ class ICInvalidator;
#define IC_INVALDITION_HEADER_SIZE 6
#define IC_MEGAMORPHIC_THRESHOLD 100
// This registers a decref info in the constructor and deregisters it in the destructor.
struct DecrefInfo {
uint64_t ip;
DecrefInfo() : ip(0) {}
DecrefInfo(uint64_t ip, std::vector<Location> locations);
// we only allow moves
DecrefInfo(DecrefInfo&& other) : ip(0) { std::swap(other.ip, ip); }
DecrefInfo& operator=(DecrefInfo&& other) {
std::swap(other.ip, ip);
return *this;
}
~DecrefInfo() { reset(); }
void reset();
};
struct ICSlotInfo {
public:
ICSlotInfo(ICInfo* ic, int idx) : ic(ic), idx(idx), num_inside(0) {}
......@@ -44,6 +62,7 @@ public:
int num_inside; // the number of stack frames that are currently inside this slot
std::vector<void*> gc_references;
std::vector<DecrefInfo> decref_infos;
void clear();
};
......@@ -85,7 +104,8 @@ public:
ICSlotInfo* prepareEntry();
void addDependenceOn(ICInvalidator&);
void commit(CommitHook* hook, std::vector<void*> gc_references);
void commit(CommitHook* hook, std::vector<void*> gc_references,
std::vector<std::pair<uint64_t, std::vector<Location>>> decref_infos);
void abort();
const ICInfo* getICInfo() { return ic; }
......@@ -117,13 +137,20 @@ private:
int retry_in, retry_backoff;
int times_rewritten;
DecrefInfo slowpath_decref_info;
// This is a vector of locations which always need to get decrefed inside this IC.
// Calls inside the ICSlots may need to decref additional locations but they will always contain at least the IC
// global ones.
std::vector<Location> ic_global_decref_locations;
// for ICSlotRewrite:
ICSlotInfo* pickEntryForRewrite(const char* debug_name);
public:
ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots,
int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet live_outs,
assembler::GenericRegister return_register, TypeRecorder* type_recorder);
assembler::GenericRegister return_register, TypeRecorder* type_recorder,
std::vector<Location> ic_global_decref_locations);
~ICInfo();
void* const start_addr, *const slowpath_rtn_addr, *const continue_addr;
......@@ -152,6 +179,8 @@ public:
static ICInfo* getICInfoForNode(AST* node);
void associateNodeWithICInfo(AST* node);
void appendDecrefInfosTo(std::vector<DecrefInfo>& dest_decref_infos);
};
void registerGCTrackedICInfo(ICInfo* ic);
......@@ -159,9 +188,10 @@ void deregisterGCTrackedICInfo(ICInfo* ic);
class ICSetupInfo;
struct CompiledFunction;
std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* slowpath_start_addr,
uint8_t* continue_addr, uint8_t* slowpath_rtn_addr,
const ICSetupInfo*, StackInfo stack_info, LiveOutSet live_outs);
std::unique_ptr<ICInfo>
registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* slowpath_start_addr, uint8_t* continue_addr,
uint8_t* slowpath_rtn_addr, const ICSetupInfo*, StackInfo stack_info, LiveOutSet live_outs,
std::vector<Location> ic_global_decref_locations = std::vector<Location>());
void deregisterCompiledPatchpoint(ICInfo* ic);
ICInfo* getICInfo(void* rtn_addr);
......
......@@ -1186,6 +1186,9 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
assert(assembler->hasFailed() || asm_address == (uint64_t)assembler->curInstPointer());
}
// TODO: we don't need to generate the decref info for calls which can't throw
registerDecrefInfoHere();
if (!failed) {
assert(vars_by_location.count(assembler::RAX) == 0);
......@@ -1198,6 +1201,33 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
result->releaseIfNoUses();
}
std::vector<Location> Rewriter::getDecrefLocations() {
std::vector<Location> decref_infos;
for (RewriterVar& var : vars) {
if (var.locations.size() && var.needsDecref()) {
// TODO: add code to handle other location types and choose best location if there are several
Location l = *var.locations.begin();
if (l.type == Location::Scratch) {
// convert to stack based location because later on we may not know the offset of the scratch area from
// the SP.
assert(indirectFor(l).offset % 8 == 0);
decref_infos.emplace_back(Location::Stack, indirectFor(l).offset / 8);
} else if (l.type == Location::Register) {
decref_infos.emplace_back(l);
} else
RELEASE_ASSERT(0, "not implemented");
}
}
return decref_infos;
}
void Rewriter::registerDecrefInfoHere() {
std::vector<Location> decref_locations = getDecrefLocations();
auto call_offset = assembler->bytesWritten();
uint64_t ip = (uint64_t)rewrite->getSlotStart() + call_offset;
decref_infos.emplace_back(std::make_pair(ip, std::move(decref_locations)));
}
void Rewriter::abort() {
STAT_TIMER(t0, "us_timer_rewriter", 10);
......@@ -1224,23 +1254,6 @@ RewriterVar* RewriterVar::setType(RefType type) {
assert(this->reftype == RefType::UNKNOWN || this->reftype == type);
if (this->reftype == RefType::UNKNOWN) {
rewriter->addAction(
[=]() {
int num_needed_refs = this->num_refs_consumed - (this->refHandedOff() ? 1 : 0);
assert(num_needed_refs >= 0);
if (num_needed_refs > 0) {
if (rewriter->isDoneGuarding()) {
this->rewriter->_incref(this, num_needed_refs);
} else {
rewriter->pending_increfs.push_back(std::make_pair(this, num_needed_refs));
}
}
this->bumpUse();
// Register this as a NORMAL (ie non-MUTATION) action since we will be careful to not do any mutations
// if we are still in the guarding phase.
},
{ this }, ActionType::NORMAL);
this->reftype = type;
}
......@@ -1272,9 +1285,17 @@ void RewriterVar::_release() {
this->locations.clear();
}
void RewriterVar::refConsumed() {
void RewriterVar::refConsumed(RewriterAction* action) {
assert(reftype != RefType::UNKNOWN || (isConstant() && constant_value == 0));
num_refs_consumed++;
last_refconsumed_numuses = uses.size();
if (!action)
action = rewriter->getLastAction();
action->consumed_refs.emplace_back(this);
}
bool RewriterVar::needsDecref() {
return reftype == RefType::OWNED && !this->refHandedOff();
}
void RewriterVar::bumpUse() {
......@@ -1374,12 +1395,6 @@ void Rewriter::commit() {
}
}
for (auto&& p : pending_increfs) {
// TODO use a single add rather than N inc's
for (int i = 0; i < p.second; i++) {
_incref(p.first);
}
}
assertConsistent();
};
......@@ -1395,6 +1410,21 @@ void Rewriter::commit() {
// Now, start emitting assembly; check if we're dong guarding after each.
for (int i = 0; i < actions.size(); i++) {
// add increfs if required
for (auto&& var : actions[i].consumed_refs) {
if (var->refHandedOff()) {
// if this action is the one which the variable gets handed off we don't need todo anything
assert(var->last_refconsumed_numuses > 0 && var->last_refconsumed_numuses <= var->uses.size());
int last_used_action_id = var->uses[var->last_refconsumed_numuses - 1];
if (last_used_action_id == i)
continue;
assert(last_used_action_id >= i);
}
assert(isDoneGuarding());
_incref(var, 1);
}
actions[i].action();
if (failed) {
......@@ -1561,7 +1591,7 @@ void Rewriter::commit() {
}
#endif
rewrite->commit(this, std::move(gc_references));
rewrite->commit(this, std::move(gc_references), std::move(decref_infos));
assert(gc_references.empty());
if (assembler->hasFailed()) {
......@@ -1827,6 +1857,8 @@ void Rewriter::_checkAndThrowCAPIException(RewriterVar* r, int64_t exc_val) {
assembler::ForwardJump jnz(*assembler, assembler::COND_NOT_ZERO);
assembler->mov(assembler::Immediate((void*)throwCAPIException), assembler::R11);
assembler->callq(assembler::R11);
registerDecrefInfoHere();
}
r->bumpUse();
......
......@@ -27,6 +27,7 @@
#include "asm_writing/assembler.h"
#include "asm_writing/icinfo.h"
#include "asm_writing/types.h"
#include "core/threading.h"
#include "core/types.h"
......@@ -164,7 +165,8 @@ public:
// This should get called *after* the ref got consumed, ie something like
// r_array->setAttr(0, r_val);
// r_val->refConsumed()
void refConsumed();
// if no action is specified it will assume the last action consumed the reference
void refConsumed(RewriterAction* action = NULL);
template <typename Src, typename Dst> inline RewriterVar* getAttrCast(int offset, Location loc = Location::any());
......@@ -202,6 +204,7 @@ private:
bool isDoneUsing() { return next_use == uses.size(); }
bool hasScratchAllocation() const { return scratch_allocation.second > 0; }
void resetHasScratchAllocation() { scratch_allocation = std::make_pair(0, 0); }
bool needsDecref();
// Indicates if this variable is an arg, and if so, what location the arg is from.
bool is_arg;
......@@ -287,6 +290,7 @@ public:
class RewriterAction {
public:
SmallFunction<56> action;
std::vector<RewriterVar*> consumed_refs;
template <typename F> RewriterAction(F&& action) : action(std::forward<F>(action)) {}
......@@ -306,7 +310,7 @@ class Rewriter : public ICSlotRewrite::CommitHook {
private:
class RegionAllocator {
public:
static const int BLOCK_SIZE = 200; // reserve a bit of space for list/malloc overhead
static const int BLOCK_SIZE = 1024; // reserve a bit of space for list/malloc overhead
std::list<char[BLOCK_SIZE]> blocks;
int cur_offset = BLOCK_SIZE + 1;
......@@ -397,7 +401,7 @@ protected:
bool needs_invalidation_support = true);
std::deque<RewriterAction, RegionAllocatorAdaptor<RewriterAction>> actions;
template <typename F> void addAction(F&& action, llvm::ArrayRef<RewriterVar*> vars, ActionType type) {
template <typename F> RewriterAction* addAction(F&& action, llvm::ArrayRef<RewriterVar*> vars, ActionType type) {
assertPhaseCollecting();
for (RewriterVar* var : vars) {
assert(var != NULL);
......@@ -408,7 +412,7 @@ protected:
} else if (type == ActionType::GUARD) {
if (added_changing_action) {
failed = true;
return;
return NULL;
}
for (RewriterVar* arg : args) {
arg->uses.push_back(actions.size());
......@@ -417,10 +421,17 @@ protected:
last_guard_action = (int)actions.size();
}
actions.emplace_back(std::forward<F>(action));
return &actions.back();
}
RewriterAction* getLastAction() {
assert(!actions.empty());
return &actions.back();
}
bool added_changing_action;
bool marked_inside_ic;
std::vector<void*> gc_references;
std::vector<std::pair<uint64_t, std::vector<Location>>> decref_infos;
bool done_guarding;
bool isDoneGuarding() {
......@@ -550,6 +561,10 @@ public:
#else
void comment(const llvm::Twine& msg) {}
#endif
// returns a vector of locations of variables which need to get decrefed if the last action throwes
std::vector<Location> getDecrefLocations();
// calls getDecrefLocations and registers the current assembler address with the retrieved decref info
void registerDecrefInfoHere();
void trap();
RewriterVar* loadConst(int64_t val, Location loc = Location::any());
......
......@@ -66,7 +66,7 @@ extern "C" Box* executeInnerAndSetupFrame(ASTInterpreter& interpreter, CFGBlock*
*/
class ASTInterpreter {
public:
ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs);
ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs, FrameInfo* deopt_frame_info = NULL);
void initArguments(BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3, Box** args);
......@@ -183,7 +183,6 @@ public:
void setPassedClosure(Box* closure);
void setCreatedClosure(Box* closure);
void setBoxedLocals(STOLEN(Box*));
void setFrameInfo(const FrameInfo* frame_info);
void setGlobals(Box* globals);
friend struct pyston::ASTInterpreterJitInterface;
......@@ -215,7 +214,8 @@ void ASTInterpreter::setPassedClosure(Box* closure) {
void ASTInterpreter::setCreatedClosure(Box* closure) {
assert(!this->created_closure); // This should only used for initialization
assert(closure->cls == closure_cls);
this->created_closure = static_cast<BoxedClosure*>(closure);
// we have to incref the closure because the interpreter destructor will decref it
this->created_closure = static_cast<BoxedClosure*>(incref(closure));
}
void ASTInterpreter::setBoxedLocals(Box* boxedLocals) {
......@@ -223,20 +223,12 @@ void ASTInterpreter::setBoxedLocals(Box* boxedLocals) {
this->frame_info.boxedLocals = boxedLocals;
}
void ASTInterpreter::setFrameInfo(const FrameInfo* frame_info) {
Box** vregs = this->frame_info.vregs;
int num_vregs = this->frame_info.num_vregs;
this->frame_info = *frame_info;
this->frame_info.vregs = vregs;
this->frame_info.num_vregs = num_vregs;
}
void ASTInterpreter::setGlobals(Box* globals) {
assert(!this->frame_info.globals);
this->frame_info.globals = incref(globals);
}
ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs)
ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs, FrameInfo* deopt_frame_info)
: current_block(0),
frame_info(ExcInfo(NULL, NULL, NULL)),
edgecount(0),
......@@ -251,6 +243,15 @@ ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs)
should_jit(false) {
scope_info = source_info->getScopeInfo();
if (deopt_frame_info) {
// copy over all fields and clear the deopt frame info
frame_info = *deopt_frame_info;
for (int i = 0; i < deopt_frame_info->num_vregs; ++i)
Py_XDECREF(deopt_frame_info->vregs[i]);
memset(deopt_frame_info, 0, sizeof(*deopt_frame_info));
}
frame_info.vregs = vregs;
frame_info.md = md;
frame_info.num_vregs = num_vregs;
......@@ -470,6 +471,8 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) {
if (jit) {
if (!closure) {
bool is_live = source_info->getLiveness()->isLiveAtEnd(name, current_block);
// HACK: this disable the 'this variable is dead at the end of this block' optimization
is_live = true;
if (is_live)
jit->emitSetLocal(name, node->vreg, closure, value);
else
......@@ -2006,9 +2009,7 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
memset(vregs, 0, sizeof(Box*) * num_vregs);
}
ASTInterpreter interpreter(md, vregs, num_vregs);
if (source_info->scoping->areGlobalsFromModule())
interpreter.setGlobals(source_info->parent_module);
ASTInterpreter interpreter(md, vregs, num_vregs, frame_state.frame_info);
for (const auto& p : *frame_state.locals) {
assert(p.first->cls == str_cls);
......@@ -2016,7 +2017,8 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
if (name == PASSED_GENERATOR_NAME) {
interpreter.setGenerator(p.second);
} else if (name == PASSED_CLOSURE_NAME) {
interpreter.setPassedClosure(p.second);
// this should have already got set because its stored in the frame info
assert(p.second == interpreter.getFrameInfo()->passed_closure);
} else if (name == CREATED_CLOSURE_NAME) {
interpreter.setCreatedClosure(p.second);
} else {
......@@ -2025,8 +2027,6 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
}
}
interpreter.setFrameInfo(frame_state.frame_info);
CFGBlock* start_block = NULL;
AST_stmt* starting_statement = NULL;
while (true) {
......@@ -2043,7 +2043,6 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
auto expr = ast_cast<AST_Expr>(enclosing_stmt);
RELEASE_ASSERT(expr->value == after_expr, "%p %p", expr->value, after_expr);
assert(expr->value == after_expr);
assert(0 && "check refcounting");
break;
} else if (enclosing_stmt->type == AST_TYPE::Invoke) {
auto invoke = ast_cast<AST_Invoke>(enclosing_stmt);
......
This diff is collapsed.
......@@ -146,6 +146,9 @@ private:
assembler::Assembler a;
bool is_currently_writing;
bool asm_failed;
// this contains all the decref infos the bjit generated inside the memory block,
// this allows us to deregister them when we release the code
std::vector<DecrefInfo> decref_infos;
public:
JitCodeBlock(llvm::StringRef name);
......@@ -153,7 +156,7 @@ public:
std::unique_ptr<JitFragmentWriter> newFragment(CFGBlock* block, int patch_jump_offset = 0);
bool shouldCreateNewBlock() const { return asm_failed || a.bytesLeft() < 128; }
void fragmentAbort(bool not_enough_space);
void fragmentFinished(int bytes_witten, int num_bytes_overlapping, void* next_fragment_start);
void fragmentFinished(int bytes_witten, int num_bytes_overlapping, void* next_fragment_start, ICInfo& ic_info);
};
class JitFragmentWriter : public Rewriter {
......@@ -199,6 +202,7 @@ private:
std::unique_ptr<ICSetupInfo> ic;
StackInfo stack_info;
AST* node;
std::vector<Location> decref_infos;
};
llvm::SmallVector<PPInfo, 8> pp_infos;
......@@ -284,8 +288,15 @@ private:
uint64_t asUInt(InternedString s);
#endif
RewriterVar* emitPPCall(void* func_addr, llvm::ArrayRef<RewriterVar*> args, int num_slots, int slot_size,
AST* ast_node = NULL, TypeRecorder* type_recorder = NULL);
// use this function when one emits a call where one argument is variable created with allocArgs(vars).
// it let's one specify the additional uses the call has which are unknown to the rewriter because it is hidden in
// the allocArgs call.
RewriterVar* emitCallWithAllocatedArgs(void* func_addr, const llvm::ArrayRef<RewriterVar*> args,
const llvm::ArrayRef<RewriterVar*> additional_uses);
std::pair<RewriterVar*, RewriterAction*> emitPPCall(void* func_addr, llvm::ArrayRef<RewriterVar*> args,
int num_slots, int slot_size, AST* ast_node = NULL,
TypeRecorder* type_recorder = NULL);
static void assertNameDefinedHelper(const char* id);
static Box* callattrHelper(Box* obj, BoxedString* attr, CallattrFlags flags, TypeRecorder* type_recorder,
......
......@@ -498,7 +498,7 @@ public:
Box* deserializeFromFrame(const FrameVals& vals) override {
assert(vals.size() == 1);
return reinterpret_cast<Box*>(vals[0]);
return incref(reinterpret_cast<Box*>(vals[0]));
}
std::vector<CompilerVariable*> unpack(IREmitter& emitter, const OpInfo& info, VAR* var, int num_into) override {
......@@ -1615,6 +1615,7 @@ public:
std::string debugName() override { return "phony(" + ConcreteCompilerType::debugName() + ")"; }
CompilerType* getUsableType() override { return usable_type; }
ConcreteCompilerType* getBoxType() override { return getUsableType()->getBoxType(); }
llvm::Type* llvmType() override { return t; }
......@@ -2190,7 +2191,7 @@ public:
Box* deserializeFromFrame(const FrameVals& vals) override {
assert(vals.size() == 1);
return reinterpret_cast<Box*>(vals[0]);
return incref(reinterpret_cast<Box*>(vals[0]));
}
};
std::unordered_map<BoxedClass*, NormalObjectType*> NormalObjectType::made;
......@@ -2221,7 +2222,7 @@ public:
Box* deserializeFromFrame(const FrameVals& vals) override {
assert(vals.size() == 1);
return reinterpret_cast<Box*>(vals[0]);
return incref(reinterpret_cast<Box*>(vals[0]));
}
} _CLOSURE;
ConcreteCompilerType* CLOSURE = &_CLOSURE;
......@@ -2236,7 +2237,7 @@ public:
Box* deserializeFromFrame(const FrameVals& vals) override {
assert(vals.size() == numFrameArgs());
return reinterpret_cast<Box*>(vals[0]);
return incref(reinterpret_cast<Box*>(vals[0]));
}
} _GENERATOR;
ConcreteCompilerType* GENERATOR = &_GENERATOR;
......
......@@ -429,6 +429,9 @@ static inline unw_word_t get_cursor_ip(unw_cursor_t* cursor) {
static inline unw_word_t get_cursor_bp(unw_cursor_t* cursor) {
return get_cursor_reg(cursor, UNW_TDEP_BP);
}
static inline unw_word_t get_cursor_sp(unw_cursor_t* cursor) {
return get_cursor_reg(cursor, UNW_REG_SP);
}
// if the given ip/bp correspond to a jitted frame or
// ASTInterpreter::execute_inner frame, return true and return the
......@@ -507,6 +510,34 @@ static FrameInfo* getTopFrameInfo() {
return (FrameInfo*)cur_thread_state.frame_info;
}
llvm::DenseMap<uint64_t /*ip*/, std::vector<Location>> decref_infos;
void executeDecrefs(unw_cursor_t* cursor) {
unw_word_t ip = get_cursor_ip(cursor);
auto it = decref_infos.find(ip);
if (it == decref_infos.end())
return;
for (Location& l : it->second) {
Box* b = NULL;
if (l.type == Location::Stack) {
unw_word_t sp = get_cursor_sp(cursor);
b = ((Box**)sp)[l.stack_offset];
} else {
RELEASE_ASSERT(0, "not implemented");
}
Py_XDECREF(b);
}
}
void addDecrefInfoEntry(uint64_t ip, std::vector<Location> location) {
assert(!decref_infos.count(ip) && "why is there already an entry??");
decref_infos[ip] = std::move(location);
}
void removeDecrefInfoEntry(uint64_t ip) {
decref_infos.erase(ip);
}
class PythonUnwindSession {
ExcInfo exc_info;
PythonStackExtractor pystack_extractor;
......@@ -539,6 +570,8 @@ public:
prev_frame_info = NULL;
}
executeDecrefs(cursor);
PythonFrameIteratorImpl frame_iter;
bool found_frame = pystack_extractor.handleCFrame(cursor, &frame_iter);
if (found_frame) {
......@@ -830,7 +863,8 @@ DeoptState getDeoptState() {
if (!v)
continue;
d->d[incref(p.first.getBox())] = v;
assert(!d->d.count(p.first.getBox()));
d->d[incref(p.first.getBox())] = incref(v);
}
for (const auto& p : cf->location_map->names) {
......@@ -851,6 +885,7 @@ DeoptState getDeoptState() {
vals.push_back(frame_iter->readLocation(loc));
}
// this returns an owned reference so we don't incref it
Box* v = e->type->deserializeFromFrame(vals);
// printf("%s: (pp id %ld) %p\n", p.first().c_str(), e._debug_pp_id, v);
d->d[boxString(p.first())] = v;
......
......@@ -97,6 +97,9 @@ ExcInfo* getFrameExcInfo();
// but just as slow if it's not.
void updateFrameExcInfoIfNeeded(ExcInfo* latest);
void addDecrefInfoEntry(uint64_t ip, std::vector<class Location> location);
void removeDecrefInfoEntry(uint64_t ip);
struct FrameStackState {
// This includes all # variables (but not the ! ones).
// Therefore, it's not the same as the BoxedLocals.
......
......@@ -30,7 +30,7 @@ bool LOG_BJIT_ASSEMBLY = 0;
bool FORCE_INTERPRETER = false;
bool FORCE_OPTIMIZE = false;
bool ENABLE_INTERPRETER = true;
bool ENABLE_BASELINEJIT = false; // XXX
bool ENABLE_BASELINEJIT = true;
bool CONTINUE_AFTER_FATAL = false;
bool SHOW_DISASM = false;
......@@ -50,8 +50,8 @@ bool ENABLE_TRACEBACKS = true;
bool FORCE_LLVM_CAPI_CALLS = false;
bool FORCE_LLVM_CAPI_THROWS = false;
int OSR_THRESHOLD_INTERPRETER = 5; // XXX
int REOPT_THRESHOLD_INTERPRETER = 1; // XXX
int OSR_THRESHOLD_INTERPRETER = 25;
int REOPT_THRESHOLD_INTERPRETER = 25;
int OSR_THRESHOLD_BASELINE = 2500;
int REOPT_THRESHOLD_BASELINE = 1500;
int OSR_THRESHOLD_T2 = 10000;
......
# expected: statfail
# skip-if: '-O' in EXTRA_JIT_ARGS or '-n' in EXTRA_JIT_ARGS
# statcheck: 4 == noninit_count('num_deopt')
# this used to hit an abort in our LLVM tier codegen
......
def f(x):
float(x)
try:
f(1)
f(1)
f(1)
f("str")
except Exception 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