Commit fb2eef6e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #814 from kmod/throw_capis3

Be able to jit functions that throw CAPI exceptions
parents 24041726 8b122bfe
import os import os
import sys import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "../test/integration/django")) sys.path.append(os.path.join(os.path.dirname(__file__), "../test/testsuite/lib/django"))
from django.template.base import Origin, Template, Context, TemplateDoesNotExist from django.template.base import Origin, Template, Context, TemplateDoesNotExist
from django.conf import settings from django.conf import settings
......
import os import os
import sys import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "../test/integration/pyxl/")) sys.path.append(os.path.join(os.path.dirname(__file__), "../test/testsuite/lib/pyxl/"))
from pyxl.codec.register import pyxl_transform_string from pyxl.codec.register import pyxl_transform_string
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import os import os
import sys import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "../test/integration/sqlalchemy/lib")) sys.path.append(os.path.join(os.path.dirname(__file__), "../test/testsuite/lib/sqlalchemy/lib"))
from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
......
import os import os
import sys import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "../test/integration/sqlalchemy/lib")) sys.path.append(os.path.join(os.path.dirname(__file__), "../test/testsuite/lib/sqlalchemy/lib"))
from sqlalchemy import Column, ForeignKey, Integer, String, Table, MetaData from sqlalchemy import Column, ForeignKey, Integer, String, Table, MetaData
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
......
...@@ -743,12 +743,19 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) { ...@@ -743,12 +743,19 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_jitted_code"); UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_jitted_code");
CompiledFunction* partial_func = compilePartialFuncInternal(&exit); CompiledFunction* partial_func = compilePartialFuncInternal(&exit);
auto arg_tuple = getTupleFromArgsArray(&arg_array[0], arg_array.size()); auto arg_tuple = getTupleFromArgsArray(&arg_array[0], arg_array.size());
Box* r = partial_func->call(std::get<0>(arg_tuple), std::get<1>(arg_tuple), std::get<2>(arg_tuple), Box* r = partial_func->call(std::get<0>(arg_tuple), std::get<1>(arg_tuple), std::get<2>(arg_tuple),
std::get<3>(arg_tuple)); std::get<3>(arg_tuple));
assert(r); if (partial_func->exception_style == CXX) {
return r; assert(r);
return r;
} else {
if (!r)
throwCAPIException();
return r;
}
} }
Value ASTInterpreter::visit_invoke(AST_Invoke* node) { Value ASTInterpreter::visit_invoke(AST_Invoke* node) {
...@@ -1725,14 +1732,24 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene ...@@ -1725,14 +1732,24 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene
clfunc->dependent_interp_callsites.invalidateAll(); clfunc->dependent_interp_callsites.invalidateAll();
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_jitted_code"); UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_jitted_code");
Box* r;
if (closure && generator) if (closure && generator)
return optimized->closure_generator_call((BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, r = optimized->closure_generator_call((BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, arg3,
arg3, args); args);
else if (closure) else if (closure)
return optimized->closure_call((BoxedClosure*)closure, arg1, arg2, arg3, args); r = optimized->closure_call((BoxedClosure*)closure, arg1, arg2, arg3, args);
else if (generator) else if (generator)
return optimized->generator_call((BoxedGenerator*)generator, arg1, arg2, arg3, args); r = optimized->generator_call((BoxedGenerator*)generator, arg1, arg2, arg3, args);
return optimized->call(arg1, arg2, arg3, args); else
r = optimized->call(arg1, arg2, arg3, args);
if (optimized->exception_style == CXX)
return r;
else {
if (!r)
throwCAPIException();
return r;
}
} }
Box** vregs = NULL; Box** vregs = NULL;
......
...@@ -337,9 +337,7 @@ public: ...@@ -337,9 +337,7 @@ public:
CompilerVariable* slice) override { CompilerVariable* slice) override {
ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType()); ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType());
ExceptionStyle target_exception_style = CXX; ExceptionStyle target_exception_style = info.preferredExceptionStyle();
if (FORCE_LLVM_CAPI || info.unw_info.capi_exc_dest)
target_exception_style = CAPI;
bool do_patchpoint = ENABLE_ICGETITEMS; bool do_patchpoint = ENABLE_ICGETITEMS;
llvm::Value* rtn; llvm::Value* rtn;
...@@ -500,9 +498,7 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C ...@@ -500,9 +498,7 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C
llvm::Value* rtn_val = NULL; llvm::Value* rtn_val = NULL;
ExceptionStyle target_exception_style = CXX; ExceptionStyle target_exception_style = cls_only ? CXX : info.preferredExceptionStyle();
if (info.unw_info.capi_exc_dest || (!cls_only && FORCE_LLVM_CAPI))
target_exception_style = CAPI;
llvm::Value* llvm_func; llvm::Value* llvm_func;
void* raw_func; void* raw_func;
...@@ -656,9 +652,7 @@ CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, Conc ...@@ -656,9 +652,7 @@ CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, Conc
bool pass_keywords = (argspec.num_keywords != 0); bool pass_keywords = (argspec.num_keywords != 0);
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
ExceptionStyle exception_style = ((FORCE_LLVM_CAPI && !info.unw_info.cxx_exc_dest) || info.unw_info.capi_exc_dest) ExceptionStyle exception_style = info.preferredExceptionStyle();
? ExceptionStyle::CAPI
: ExceptionStyle::CXX;
llvm::Value* func; llvm::Value* func;
if (pass_keywords) if (pass_keywords)
...@@ -691,10 +685,7 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ...@@ -691,10 +685,7 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info,
bool pass_keywords = (flags.argspec.num_keywords != 0); bool pass_keywords = (flags.argspec.num_keywords != 0);
int npassed_args = flags.argspec.totalPassed(); int npassed_args = flags.argspec.totalPassed();
ExceptionStyle exception_style = ((FORCE_LLVM_CAPI && !info.unw_info.cxx_exc_dest && !flags.null_on_nonexistent) ExceptionStyle exception_style = flags.null_on_nonexistent ? CXX : info.preferredExceptionStyle();
|| info.unw_info.capi_exc_dest)
? ExceptionStyle::CAPI
: ExceptionStyle::CXX;
if (exception_style == CAPI) if (exception_style == CAPI)
assert(!flags.null_on_nonexistent); // Will conflict with CAPI's null-on-exception assert(!flags.null_on_nonexistent); // Will conflict with CAPI's null-on-exception
...@@ -1522,7 +1513,7 @@ public: ...@@ -1522,7 +1513,7 @@ public:
if (canStaticallyResolveGetattrs()) { if (canStaticallyResolveGetattrs()) {
Box* rtattr = typeLookup(cls, attr, nullptr); Box* rtattr = typeLookup(cls, attr, nullptr);
if (rtattr == NULL) { if (rtattr == NULL) {
ExceptionStyle exception_style = (FORCE_LLVM_CAPI || info.unw_info.capi_exc_dest) ? CAPI : CXX; ExceptionStyle exception_style = info.preferredExceptionStyle();
llvm::Value* raise_func = exception_style == CXX ? g.funcs.raiseAttributeErrorStr llvm::Value* raise_func = exception_style == CXX ? g.funcs.raiseAttributeErrorStr
: g.funcs.raiseAttributeErrorStrCapi; : g.funcs.raiseAttributeErrorStrCapi;
llvm::CallSite call = emitter.createCall3( llvm::CallSite call = emitter.createCall3(
...@@ -1619,15 +1610,13 @@ public: ...@@ -1619,15 +1610,13 @@ public:
"%d", info.unw_info.current_stmt->lineno); "%d", info.unw_info.current_stmt->lineno);
CompiledFunction* cf = NULL; CompiledFunction* cf = NULL;
CompiledFunction* best_exception_mismatch = NULL;
bool found = false; bool found = false;
// TODO have to find the right version.. similar to resolveclfunc? // TODO have to find the right version.. similar to resolveclfunc?
for (int i = 0; i < cl->versions.size(); i++) { for (int i = 0; i < cl->versions.size(); i++) {
cf = cl->versions[i]; cf = cl->versions[i];
assert(cf->spec->arg_types.size() == cl->numReceivedArgs()); assert(cf->spec->arg_types.size() == cl->numReceivedArgs());
if (cf->exception_style != exception_style)
continue;
bool fits = true; bool fits = true;
for (int j = 0; j < args.size(); j++) { for (int j = 0; j < args.size(); j++) {
if (!args[j]->canConvertTo(cf->spec->arg_types[j + 1])) { if (!args[j]->canConvertTo(cf->spec->arg_types[j + 1])) {
...@@ -1638,14 +1627,22 @@ public: ...@@ -1638,14 +1627,22 @@ public:
if (!fits) if (!fits)
continue; continue;
if (cf->exception_style != exception_style) {
if (!best_exception_mismatch)
best_exception_mismatch = cf;
continue;
}
found = true; found = true;
break; break;
} }
if (!found && exception_style == CAPI) { if (!found) {
std::string name = g.func_addr_registry.getFuncNameAtAddress(cl->versions[0]->code, true); assert(best_exception_mismatch);
RELEASE_ASSERT(0, "Please define a capi variant for %s", name.c_str()); cf = best_exception_mismatch;
found = true;
} }
RELEASE_ASSERT(found, ""); RELEASE_ASSERT(found, "");
RELEASE_ASSERT(cf->code, ""); RELEASE_ASSERT(cf->code, "");
...@@ -1717,10 +1714,7 @@ public: ...@@ -1717,10 +1714,7 @@ public:
CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, BoxedString* attr, CompilerVariable* callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, BoxedString* attr,
CallattrFlags flags, const std::vector<CompilerVariable*>& args, CallattrFlags flags, const std::vector<CompilerVariable*>& args,
const std::vector<BoxedString*>* keyword_names) override { const std::vector<BoxedString*>* keyword_names) override {
ExceptionStyle exception_style = CXX; ExceptionStyle exception_style = info.preferredExceptionStyle();
// Not safe to force-capi here since most of the functions won't have capi variants:
if (/*FORCE_LLVM_CAPI ||*/ info.unw_info.capi_exc_dest)
exception_style = CAPI;
ConcreteCompilerVariable* called_constant = tryCallattrConstant( ConcreteCompilerVariable* called_constant = tryCallattrConstant(
emitter, info, var, attr, flags.cls_only, flags.argspec, args, keyword_names, NULL, exception_style); emitter, info, var, attr, flags.cls_only, flags.argspec, args, keyword_names, NULL, exception_style);
...@@ -1783,9 +1777,7 @@ public: ...@@ -1783,9 +1777,7 @@ public:
static BoxedString* attr = internStringImmortal("__getitem__"); static BoxedString* attr = internStringImmortal("__getitem__");
bool no_attribute = false; bool no_attribute = false;
ExceptionStyle exception_style = CXX; ExceptionStyle exception_style = info.preferredExceptionStyle();
if (FORCE_LLVM_CAPI || info.unw_info.capi_exc_dest)
exception_style = CAPI;
ConcreteCompilerVariable* called_constant = tryCallattrConstant( ConcreteCompilerVariable* called_constant = tryCallattrConstant(
emitter, info, var, attr, true, ArgPassSpec(1, 0, 0, 0), { slice }, NULL, &no_attribute, exception_style); emitter, info, var, attr, true, ArgPassSpec(1, 0, 0, 0), { slice }, NULL, &no_attribute, exception_style);
...@@ -2293,9 +2285,7 @@ public: ...@@ -2293,9 +2285,7 @@ public:
rtn->incvref(); rtn->incvref();
return rtn; return rtn;
} else { } else {
ExceptionStyle target_exception_style = CXX; ExceptionStyle target_exception_style = info.preferredExceptionStyle();
if (FORCE_LLVM_CAPI || info.unw_info.capi_exc_dest)
target_exception_style = CAPI;
if (target_exception_style == CAPI) { if (target_exception_style == CAPI) {
llvm::CallSite call = emitter.createCall(info.unw_info, g.funcs.raiseIndexErrorStrCapi, llvm::CallSite call = emitter.createCall(info.unw_info, g.funcs.raiseIndexErrorStrCapi,
......
...@@ -495,6 +495,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc ...@@ -495,6 +495,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
std::unordered_map<CFGBlock*, ConcreteSymbolTable*> phi_ending_symbol_tables; std::unordered_map<CFGBlock*, ConcreteSymbolTable*> phi_ending_symbol_tables;
typedef std::unordered_map<InternedString, std::pair<ConcreteCompilerType*, llvm::PHINode*>> PHITable; typedef std::unordered_map<InternedString, std::pair<ConcreteCompilerType*, llvm::PHINode*>> PHITable;
std::unordered_map<CFGBlock*, PHITable*> created_phis; std::unordered_map<CFGBlock*, PHITable*> created_phis;
std::unordered_map<CFGBlock*, llvm::SmallVector<IRGenerator::ExceptionState, 2>> incoming_exception_state;
CFGBlock* initial_block = NULL; CFGBlock* initial_block = NULL;
if (entry_descriptor) { if (entry_descriptor) {
...@@ -759,6 +760,11 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc ...@@ -759,6 +760,11 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
} }
} }
auto exc_it = incoming_exception_state.find(block);
if (exc_it != incoming_exception_state.end()) {
generator->setIncomingExceptionState(exc_it->second);
}
// Generate loop safepoints on backedges. // Generate loop safepoints on backedges.
for (CFGBlock* predecessor : block->predecessors) { for (CFGBlock* predecessor : block->predecessors) {
if (predecessor->idx > block->idx) { if (predecessor->idx > block->idx) {
...@@ -777,6 +783,15 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc ...@@ -777,6 +783,15 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
phi_ending_symbol_tables[block] = ending_st.phi_symbol_table; phi_ending_symbol_tables[block] = ending_st.phi_symbol_table;
llvm_exit_blocks[block] = ending_st.ending_block; llvm_exit_blocks[block] = ending_st.ending_block;
if (ending_st.exception_state.size()) {
AST_stmt* last_stmt = block->body.back();
assert(last_stmt->type == AST_TYPE::Invoke);
CFGBlock* exc_block = ast_cast<AST_Invoke>(last_stmt)->exc_dest;
assert(!incoming_exception_state.count(exc_block));
incoming_exception_state.insert(std::make_pair(exc_block, ending_st.exception_state));
}
if (into_hax.count(block)) if (into_hax.count(block))
ASSERT(ending_st.symbol_table->size() == 0, "%d", block->idx); ASSERT(ending_st.symbol_table->size() == 0, "%d", block->idx);
} }
...@@ -952,7 +967,7 @@ static std::string getUniqueFunctionName(std::string nameprefix, EffortLevel eff ...@@ -952,7 +967,7 @@ static std::string getUniqueFunctionName(std::string nameprefix, EffortLevel eff
CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames* param_names, CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames* param_names,
const OSREntryDescriptor* entry_descriptor, EffortLevel effort, const OSREntryDescriptor* entry_descriptor, EffortLevel effort,
FunctionSpecialization* spec, std::string nameprefix) { ExceptionStyle exception_style, FunctionSpecialization* spec, std::string nameprefix) {
Timer _t("in doCompile"); Timer _t("in doCompile");
Timer _t2; Timer _t2;
long irgen_us = 0; long irgen_us = 0;
...@@ -1015,8 +1030,7 @@ CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames* ...@@ -1015,8 +1030,7 @@ CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames*
} }
} }
CompiledFunction* cf = new CompiledFunction(NULL, spec, NULL, effort, exception_style, entry_descriptor);
CompiledFunction* cf = new CompiledFunction(NULL, spec, NULL, effort, ExceptionStyle::CXX, entry_descriptor);
// Make sure that the instruction memory keeps the module object alive. // Make sure that the instruction memory keeps the module object alive.
// TODO: implement this for real // TODO: implement this for real
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
#include "core/options.h"
#include "core/types.h" #include "core/types.h"
namespace pyston { namespace pyston {
...@@ -33,18 +34,18 @@ struct UnwindInfo { ...@@ -33,18 +34,18 @@ struct UnwindInfo {
public: public:
AST_stmt* current_stmt; AST_stmt* current_stmt;
llvm::BasicBlock* capi_exc_dest; llvm::BasicBlock* exc_dest;
llvm::BasicBlock* cxx_exc_dest;
bool hasHandler() const { return cxx_exc_dest != NULL || capi_exc_dest != NULL; } bool hasHandler() const { return exc_dest != NULL; }
UnwindInfo(AST_stmt* current_stmt, llvm::BasicBlock* capi_exc_dest, llvm::BasicBlock* cxx_exc_dest) UnwindInfo(AST_stmt* current_stmt, llvm::BasicBlock* exc_dest) : current_stmt(current_stmt), exc_dest(exc_dest) {}
: current_stmt(current_stmt), capi_exc_dest(capi_exc_dest), cxx_exc_dest(cxx_exc_dest) {}
ExceptionStyle preferredExceptionStyle() const;
// Risky! This means that we can't unwind from this location, and should be used in the // Risky! This means that we can't unwind from this location, and should be used in the
// rare case that there are language-specific reasons that the statement should not unwind // rare case that there are language-specific reasons that the statement should not unwind
// (ex: loading function arguments into the appropriate scopes). // (ex: loading function arguments into the appropriate scopes).
static UnwindInfo cantUnwind() { return UnwindInfo(NULL, NULL, NULL); } static UnwindInfo cantUnwind() { return UnwindInfo(NULL, NULL); }
}; };
// TODO get rid of this // TODO get rid of this
...@@ -112,7 +113,7 @@ bool isIsDefinedName(llvm::StringRef name); ...@@ -112,7 +113,7 @@ bool isIsDefinedName(llvm::StringRef name);
CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames* param_names, CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames* param_names,
const OSREntryDescriptor* entry_descriptor, EffortLevel effort, const OSREntryDescriptor* entry_descriptor, EffortLevel effort,
FunctionSpecialization* spec, std::string nameprefix); ExceptionStyle exception_style, FunctionSpecialization* spec, std::string nameprefix);
// A common pattern is to branch based off whether a variable is defined but only if it is // A common pattern is to branch based off whether a variable is defined but only if it is
// potentially-undefined. If it is potentially-undefined, we have to generate control-flow // potentially-undefined. If it is potentially-undefined, we have to generate control-flow
...@@ -146,6 +147,8 @@ public: ...@@ -146,6 +147,8 @@ public:
: effort(effort), type_recorder(type_recorder), unw_info(unw_info) {} : effort(effort), type_recorder(type_recorder), unw_info(unw_info) {}
TypeRecorder* getTypeRecorder() const { return type_recorder; } TypeRecorder* getTypeRecorder() const { return type_recorder; }
ExceptionStyle preferredExceptionStyle() const { return unw_info.preferredExceptionStyle(); }
}; };
} }
......
...@@ -197,6 +197,12 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E ...@@ -197,6 +197,12 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
ASSERT(f->versions.size() < 20, "%s %ld", name.c_str(), f->versions.size()); ASSERT(f->versions.size() < 20, "%s %ld", name.c_str(), f->versions.size());
ExceptionStyle exception_style = CXX;
if (FORCE_LLVM_CAPI_THROWS)
exception_style = CAPI;
if (name == "next")
exception_style = CAPI;
if (VERBOSITY("irgen") >= 1) { if (VERBOSITY("irgen") >= 1) {
std::string s; std::string s;
llvm::raw_string_ostream ss(s); llvm::raw_string_ostream ss(s);
...@@ -223,7 +229,8 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E ...@@ -223,7 +229,8 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
ss << "\033[" << colors[(int)effort] << ";1mDoing OSR-entry partial compile of " << source->fn << ":" ss << "\033[" << colors[(int)effort] << ";1mDoing OSR-entry partial compile of " << source->fn << ":"
<< name << ", starting with backedge to block " << entry_descriptor->backedge->target->idx; << name << ", starting with backedge to block " << entry_descriptor->backedge->target->idx;
} }
ss << " at effort level " << (int)effort << '\n'; ss << " at effort level " << (int)effort << " with exception style "
<< (exception_style == CXX ? "C++" : "CAPI") << '\n';
if (entry_descriptor && VERBOSITY("irgen") >= 2) { if (entry_descriptor && VERBOSITY("irgen") >= 2) {
for (const auto& p : entry_descriptor->args) { for (const auto& p : entry_descriptor->args) {
...@@ -241,8 +248,7 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E ...@@ -241,8 +248,7 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
} }
CompiledFunction* cf = doCompile(f, source, &f->param_names, entry_descriptor, effort, exception_style, spec, name);
CompiledFunction* cf = doCompile(f, source, &f->param_names, entry_descriptor, effort, spec, name);
compileIR(cf, effort); compileIR(cf, effort);
f->addVersion(cf); f->addVersion(cf);
...@@ -822,7 +828,9 @@ extern "C" CompiledFunction* reoptCompiledFuncInternal(CompiledFunction* cf) { ...@@ -822,7 +828,9 @@ extern "C" CompiledFunction* reoptCompiledFuncInternal(CompiledFunction* cf) {
extern "C" char* reoptCompiledFunc(CompiledFunction* cf) { extern "C" char* reoptCompiledFunc(CompiledFunction* cf) {
return (char*)reoptCompiledFuncInternal(cf)->code; CompiledFunction* new_cf = reoptCompiledFuncInternal(cf);
assert(new_cf->exception_style == cf->exception_style);
return (char*)new_cf->code;
} }
CLFunction* createRTFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs, CLFunction* createRTFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs,
......
This diff is collapsed.
...@@ -72,8 +72,6 @@ private: ...@@ -72,8 +72,6 @@ private:
llvm::Value* frame_info_arg; llvm::Value* frame_info_arg;
int scratch_size; int scratch_size;
llvm::DenseMap<CFGBlock*, ExceptionStyle> landingpad_styles;
public: public:
IRGenState(CLFunction* clfunc, CompiledFunction* cf, SourceInfo* source_info, std::unique_ptr<PhiAnalysis> phis, IRGenState(CLFunction* clfunc, CompiledFunction* cf, SourceInfo* source_info, std::unique_ptr<PhiAnalysis> phis,
ParamNames* param_names, GCBuilder* gc, llvm::MDNode* func_dbg_info); ParamNames* param_names, GCBuilder* gc, llvm::MDNode* func_dbg_info);
...@@ -82,6 +80,8 @@ public: ...@@ -82,6 +80,8 @@ public:
CompiledFunction* getCurFunction() { return cf; } CompiledFunction* getCurFunction() { return cf; }
CLFunction* getCL() { return clfunc; } CLFunction* getCL() { return clfunc; }
ExceptionStyle getExceptionStyle() { return cf->exception_style; }
llvm::Function* getLLVMFunction() { return cf->func; } llvm::Function* getLLVMFunction() { return cf->func; }
EffortLevel getEffortLevel() { return cf->effort; } EffortLevel getEffortLevel() { return cf->effort; }
...@@ -107,15 +107,19 @@ public: ...@@ -107,15 +107,19 @@ public:
ParamNames* getParamNames() { return param_names; } ParamNames* getParamNames() { return param_names; }
void setFrameInfoArgument(llvm::Value* v) { frame_info_arg = v; } void setFrameInfoArgument(llvm::Value* v) { frame_info_arg = v; }
ExceptionStyle getLandingpadStyle(AST_Invoke* invoke);
ExceptionStyle getLandingpadStyle(CFGBlock* block);
}; };
// turns CFGBlocks into LLVM IR // turns CFGBlocks into LLVM IR
class IRGenerator { class IRGenerator {
private: private:
public: public:
struct ExceptionState {
llvm::BasicBlock* from_block;
ConcreteCompilerVariable* exc_type, *exc_value, *exc_tb;
ExceptionState(llvm::BasicBlock* from_block, ConcreteCompilerVariable* exc_type,
ConcreteCompilerVariable* exc_value, ConcreteCompilerVariable* exc_tb)
: from_block(from_block), exc_type(exc_type), exc_value(exc_value), exc_tb(exc_tb) {}
};
struct EndingState { struct EndingState {
// symbol_table records which Python variables are bound to what CompilerVariables at the end of this block. // symbol_table records which Python variables are bound to what CompilerVariables at the end of this block.
// phi_symbol_table records the ones that will need to be `phi'd. // phi_symbol_table records the ones that will need to be `phi'd.
...@@ -123,8 +127,14 @@ public: ...@@ -123,8 +127,14 @@ public:
SymbolTable* symbol_table; SymbolTable* symbol_table;
ConcreteSymbolTable* phi_symbol_table; ConcreteSymbolTable* phi_symbol_table;
llvm::BasicBlock* ending_block; llvm::BasicBlock* ending_block;
EndingState(SymbolTable* symbol_table, ConcreteSymbolTable* phi_symbol_table, llvm::BasicBlock* ending_block) llvm::SmallVector<ExceptionState, 2> exception_state;
: symbol_table(symbol_table), phi_symbol_table(phi_symbol_table), ending_block(ending_block) {}
EndingState(SymbolTable* symbol_table, ConcreteSymbolTable* phi_symbol_table, llvm::BasicBlock* ending_block,
llvm::ArrayRef<ExceptionState> exception_state)
: symbol_table(symbol_table),
phi_symbol_table(phi_symbol_table),
ending_block(ending_block),
exception_state(exception_state.begin(), exception_state.end()) {}
}; };
virtual ~IRGenerator() {} virtual ~IRGenerator() {}
...@@ -139,6 +149,10 @@ public: ...@@ -139,6 +149,10 @@ public:
virtual void doSafePoint(AST_stmt* next_statement) = 0; virtual void doSafePoint(AST_stmt* next_statement) = 0;
virtual void addFrameStackmapArgs(PatchpointInfo* pp, AST_stmt* current_stmt, virtual void addFrameStackmapArgs(PatchpointInfo* pp, AST_stmt* current_stmt,
std::vector<llvm::Value*>& stackmap_args) = 0; std::vector<llvm::Value*>& stackmap_args) = 0;
virtual void addOutgoingExceptionState(ExceptionState exception_state) = 0;
virtual void setIncomingExceptionState(llvm::SmallVector<ExceptionState, 2> exc_state) = 0;
virtual llvm::BasicBlock* getCXXExcDest(llvm::BasicBlock* final_dest) = 0;
virtual llvm::BasicBlock* getCAPIExcDest(llvm::BasicBlock* final_dest, AST_stmt* current_stmt) = 0;
}; };
class IREmitter; class IREmitter;
......
...@@ -311,6 +311,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -311,6 +311,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(raise3_capi); GET(raise3_capi);
GET(PyErr_Fetch); GET(PyErr_Fetch);
GET(PyErr_NormalizeException); GET(PyErr_NormalizeException);
GET(PyErr_Restore);
GET(capiExcCaughtInJit); GET(capiExcCaughtInJit);
GET(reraiseJitCapiExc); GET(reraiseJitCapiExc);
GET(deopt); GET(deopt);
......
...@@ -51,7 +51,7 @@ struct GlobalFuncs { ...@@ -51,7 +51,7 @@ struct GlobalFuncs {
llvm::Value* __cxa_end_catch; llvm::Value* __cxa_end_catch;
llvm::Value* raise0, *raise3, *raise3_capi; llvm::Value* raise0, *raise3, *raise3_capi;
llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *capiExcCaughtInJit, *reraiseJitCapiExc; llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *PyErr_Restore, *capiExcCaughtInJit, *reraiseJitCapiExc;
llvm::Value* deopt; llvm::Value* deopt;
llvm::Value* div_float_float, *floordiv_float_float, *mod_float_float, *pow_float_float; llvm::Value* div_float_float, *floordiv_float_float, *mod_float_float, *pow_float_float;
......
...@@ -45,8 +45,10 @@ bool USE_REGALLOC_BASIC = true; ...@@ -45,8 +45,10 @@ bool USE_REGALLOC_BASIC = true;
bool PAUSE_AT_ABORT = false; bool PAUSE_AT_ABORT = false;
bool ENABLE_TRACEBACKS = true; bool ENABLE_TRACEBACKS = true;
// Forces the llvm jit to use capi exceptions whenever it can, as opposed to whenever it thinks // Forces the llvm jit to use capi exceptions whenever it can, as opposed to whenever it thinks
// it is faster: // it is faster. The CALLS version is for calls that the llvm jit will make, and the THROWS version
bool FORCE_LLVM_CAPI = false; // is for the exceptions it will throw.
bool FORCE_LLVM_CAPI_CALLS = false;
bool FORCE_LLVM_CAPI_THROWS = false;
int OSR_THRESHOLD_INTERPRETER = 25; int OSR_THRESHOLD_INTERPRETER = 25;
int REOPT_THRESHOLD_INTERPRETER = 25; int REOPT_THRESHOLD_INTERPRETER = 25;
......
...@@ -39,7 +39,7 @@ extern int MAX_OBJECT_CACHE_ENTRIES; ...@@ -39,7 +39,7 @@ extern int MAX_OBJECT_CACHE_ENTRIES;
extern bool SHOW_DISASM, FORCE_INTERPRETER, FORCE_OPTIMIZE, PROFILE, DUMPJIT, TRAP, USE_STRIPPED_STDLIB, extern bool SHOW_DISASM, FORCE_INTERPRETER, FORCE_OPTIMIZE, PROFILE, DUMPJIT, TRAP, USE_STRIPPED_STDLIB,
CONTINUE_AFTER_FATAL, ENABLE_INTERPRETER, ENABLE_BASELINEJIT, ENABLE_PYPA_PARSER, USE_REGALLOC_BASIC, CONTINUE_AFTER_FATAL, ENABLE_INTERPRETER, ENABLE_BASELINEJIT, ENABLE_PYPA_PARSER, USE_REGALLOC_BASIC,
PAUSE_AT_ABORT, ENABLE_TRACEBACKS, ASSEMBLY_LOGGING, FORCE_LLVM_CAPI; PAUSE_AT_ABORT, ENABLE_TRACEBACKS, ASSEMBLY_LOGGING, FORCE_LLVM_CAPI_CALLS, FORCE_LLVM_CAPI_THROWS;
extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ENABLE_ICDELITEMS, ENABLE_ICBINEXPS, extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ENABLE_ICDELITEMS, ENABLE_ICBINEXPS,
ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENALBE_ICDELATTRS, ENABLE_ICGETGLOBALS, ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENALBE_ICDELATTRS, ENABLE_ICGETGLOBALS,
......
...@@ -117,19 +117,33 @@ Box* generatorIter(Box* s) { ...@@ -117,19 +117,33 @@ Box* generatorIter(Box* s) {
} }
// called from both generatorHasNext and generatorSend/generatorNext (but only if generatorHasNext hasn't been called) // called from both generatorHasNext and generatorSend/generatorNext (but only if generatorHasNext hasn't been called)
static void generatorSendInternal(BoxedGenerator* self, Box* v) { template <ExceptionStyle S> static bool generatorSendInternal(BoxedGenerator* self, Box* v) noexcept(S == CAPI) {
STAT_TIMER(t0, "us_timer_generator_switching", 0); STAT_TIMER(t0, "us_timer_generator_switching", 0);
if (!self->returnContext && v != None) if (!self->returnContext && v != None) {
raiseExcHelper(TypeError, "can't send non-None value to a just-started generator"); if (S == CAPI) {
PyErr_SetString(TypeError, "can't send non-None value to a just-started generator");
return true;
} else
raiseExcHelper(TypeError, "can't send non-None value to a just-started generator");
}
if (self->running) if (self->running) {
raiseExcHelper(ValueError, "generator already executing"); if (S == CAPI) {
PyErr_SetString(ValueError, "generator already executing");
return true;
} else
raiseExcHelper(ValueError, "generator already executing");
}
// check if the generator already exited // check if the generator already exited
if (self->entryExited) { if (self->entryExited) {
freeGeneratorStack(self); freeGeneratorStack(self);
raiseExcHelper(StopIteration, (const char*)nullptr); if (S == CAPI) {
PyErr_SetObject(StopIteration, None);
return true;
} else
raiseExcHelper(StopIteration, (const char*)nullptr);
} }
self->returnValue = v; self->returnValue = v;
...@@ -158,9 +172,14 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) { ...@@ -158,9 +172,14 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) {
if (self->exception.type) { if (self->exception.type) {
freeGeneratorStack(self); freeGeneratorStack(self);
// don't raise StopIteration exceptions because those are handled specially. // don't raise StopIteration exceptions because those are handled specially.
if (!self->exception.matches(StopIteration)) if (!self->exception.matches(StopIteration)) {
throw self->exception; if (S == CAPI) {
return; setCAPIException(self->exception);
return true;
} else
throw self->exception;
}
return false;
} }
if (self->entryExited) { if (self->entryExited) {
...@@ -169,18 +188,21 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) { ...@@ -169,18 +188,21 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) {
// We could directly create the StopIteration exception but we delay creating it because often the caller is not // We could directly create the StopIteration exception but we delay creating it because often the caller is not
// interested in the exception (=generatorHasnext). If we really need it we will create it inside generatorSend. // interested in the exception (=generatorHasnext). If we really need it we will create it inside generatorSend.
self->exception = ExcInfo(NULL, NULL, NULL); self->exception = ExcInfo(NULL, NULL, NULL);
return; return false;
} }
return false;
} }
Box* generatorSend(Box* s, Box* v) { template <ExceptionStyle S> static Box* generatorSend(Box* s, Box* v) noexcept(S == CAPI) {
assert(s->cls == generator_cls); assert(s->cls == generator_cls);
BoxedGenerator* self = static_cast<BoxedGenerator*>(s); BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
if (self->iterated_from__hasnext__) if (self->iterated_from__hasnext__)
Py_FatalError(".throw called on generator last advanced with __hasnext__"); Py_FatalError(".throw called on generator last advanced with __hasnext__");
generatorSendInternal(self, v); bool exc = generatorSendInternal<S>(self, v);
if (S == CAPI && exc)
return NULL;
// throw StopIteration if the generator exited // throw StopIteration if the generator exited
if (self->entryExited) { if (self->entryExited) {
...@@ -195,9 +217,19 @@ Box* generatorSend(Box* s, Box* v) { ...@@ -195,9 +217,19 @@ Box* generatorSend(Box* s, Box* v) {
ExcInfo old_exc = self->exception; ExcInfo old_exc = self->exception;
// Clear the exception for GC purposes: // Clear the exception for GC purposes:
self->exception = ExcInfo(nullptr, nullptr, nullptr); self->exception = ExcInfo(nullptr, nullptr, nullptr);
if (old_exc.type == NULL) if (old_exc.type == NULL) {
raiseExcHelper(StopIteration, (const char*)nullptr); if (S == CAPI) {
throw old_exc; PyErr_SetObject(StopIteration, None);
return NULL;
} else
raiseExcHelper(StopIteration, (const char*)nullptr);
} else {
if (S == CAPI) {
setCAPIException(old_exc);
return NULL;
} else
throw old_exc;
}
} }
return self->returnValue; return self->returnValue;
...@@ -223,7 +255,7 @@ Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** a ...@@ -223,7 +255,7 @@ Box* generatorThrow(Box* s, BoxedClass* exc_cls, Box* exc_val = nullptr, Box** a
throw exc_info; throw exc_info;
self->exception = exc_info; self->exception = exc_info;
return generatorSend(self, None); return generatorSend<CXX>(self, None);
} }
Box* generatorClose(Box* s) { Box* generatorClose(Box* s) {
...@@ -245,7 +277,7 @@ Box* generatorClose(Box* s) { ...@@ -245,7 +277,7 @@ Box* generatorClose(Box* s) {
assert(0); // unreachable assert(0); // unreachable
} }
Box* generatorNext(Box* s) { template <ExceptionStyle S> static Box* generatorNext(Box* s) noexcept(S == CAPI) {
assert(s->cls == generator_cls); assert(s->cls == generator_cls);
BoxedGenerator* self = static_cast<BoxedGenerator*>(s); BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
...@@ -254,7 +286,7 @@ Box* generatorNext(Box* s) { ...@@ -254,7 +286,7 @@ Box* generatorNext(Box* s) {
return self->returnValue; return self->returnValue;
} }
return generatorSend(s, None); return generatorSend<S>(s, None);
} }
i1 generatorHasnextUnboxed(Box* s) { i1 generatorHasnextUnboxed(Box* s) {
...@@ -262,7 +294,7 @@ i1 generatorHasnextUnboxed(Box* s) { ...@@ -262,7 +294,7 @@ i1 generatorHasnextUnboxed(Box* s) {
BoxedGenerator* self = static_cast<BoxedGenerator*>(s); BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
if (!self->iterated_from__hasnext__) { if (!self->iterated_from__hasnext__) {
generatorSendInternal(self, None); generatorSendInternal<CXX>(self, None);
self->iterated_from__hasnext__ = true; self->iterated_from__hasnext__ = true;
} }
...@@ -455,13 +487,16 @@ void setupGenerator() { ...@@ -455,13 +487,16 @@ void setupGenerator() {
new BoxedFunction(boxRTFunction((void*)generatorIter, typeFromClass(generator_cls), 1))); new BoxedFunction(boxRTFunction((void*)generatorIter, typeFromClass(generator_cls), 1)));
generator_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)generatorClose, UNKNOWN, 1))); generator_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)generatorClose, UNKNOWN, 1)));
generator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)generatorNext, UNKNOWN, 1)));
auto generator_next = boxRTFunction((void*)generatorNext<CXX>, UNKNOWN, 1, ParamNames::empty(), CXX);
addRTFunction(generator_next, (void*)generatorNext<CAPI>, UNKNOWN, CAPI);
generator_cls->giveAttr("next", new BoxedFunction(generator_next));
CLFunction* hasnext = boxRTFunction((void*)generatorHasnextUnboxed, BOOL, 1); CLFunction* hasnext = boxRTFunction((void*)generatorHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)generatorHasnext, BOXED_BOOL); addRTFunction(hasnext, (void*)generatorHasnext, BOXED_BOOL);
generator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext)); generator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext));
generator_cls->giveAttr("send", new BoxedFunction(boxRTFunction((void*)generatorSend, UNKNOWN, 2))); generator_cls->giveAttr("send", new BoxedFunction(boxRTFunction((void*)generatorSend<CXX>, UNKNOWN, 2)));
auto gthrow = new BoxedFunction(boxRTFunction((void*)generatorThrow, UNKNOWN, 4, 2, false, false), { NULL, NULL }); auto gthrow = new BoxedFunction(boxRTFunction((void*)generatorThrow, UNKNOWN, 4, 2, false, false), { NULL, NULL });
generator_cls->giveAttr("throw", gthrow); generator_cls->giveAttr("throw", gthrow);
......
...@@ -129,6 +129,7 @@ void force() { ...@@ -129,6 +129,7 @@ void force() {
FORCE(raise3_capi); FORCE(raise3_capi);
FORCE(PyErr_Fetch); FORCE(PyErr_Fetch);
FORCE(PyErr_NormalizeException); FORCE(PyErr_NormalizeException);
FORCE(PyErr_Restore);
FORCE(capiExcCaughtInJit); FORCE(capiExcCaughtInJit);
FORCE(reraiseJitCapiExc); FORCE(reraiseJitCapiExc);
FORCE(deopt); FORCE(deopt);
......
...@@ -262,6 +262,10 @@ extern "C" void dumpEx(void* p, int levels) { ...@@ -262,6 +262,10 @@ extern "C" void dumpEx(void* p, int levels) {
printf("Has %ld function versions\n", cl->versions.size()); printf("Has %ld function versions\n", cl->versions.size());
for (CompiledFunction* cf : cl->versions) { for (CompiledFunction* cf : cl->versions) {
bool got_name; bool got_name;
if (cf->exception_style == CXX)
printf("CXX style: ");
else
printf("CAPI style: ");
std::string name = g.func_addr_registry.getFuncNameAtAddress(cf->code, true, &got_name); std::string name = g.func_addr_registry.getFuncNameAtAddress(cf->code, true, &got_name);
if (got_name) if (got_name)
printf("%s\n", name.c_str()); printf("%s\n", name.c_str());
......
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