नहीं कहा गया है, मैं जेआईटी llvm कोड के अंदर एक अपवाद हैंडलर बनाने की कोशिश कर रहा हूं। exception handling in LLVM के बारे में वर्तमान दस्तावेज इस समय बहुत ही आसान है, इसलिए मैं काम करने के उदाहरण के लिए http://llvm.org/demo से प्राप्त अधिकांश स्निपेट का पुन: उपयोग करने का प्रयास कर रहा हूं, लेकिन मुझे यकीन नहीं है कि वे llvm के साथ अद्यतित हैं या नहीं 2.9 (संस्करण जिसका मैं उपयोग कर रहा हूं)। मॉड्यूल :: डंप() के बाद यह मॉड्यूल देखता है;llvm अपवाद; पकड़ने वाले हैंडलर को संभालना नहीं, क्लीनअप को
; ModuleID = 'testModule'
declare i32 @myfunc()
define i32 @test_function_that_invokes_another() {
entryBlock:
%0 = alloca i8*
%1 = alloca i32
%someName = invoke i32 @myfunc()
to label %exitBlock unwind label %unwindBlock
exitBlock: ; preds = %entryBlock
ret i32 1
unwindBlock: ; preds = %entryBlock
%2 = call i8* @llvm.eh.exception()
store i8* %2, i8** %0
%3 = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %2, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)
store i32 1, i32* %1
%4 = load i8** %0
%5 = call i32 (...)* @__cxa_begin_catch(i8* %4) nounwind
%cleanup_call = call i32 @myCleanup()
%6 = call i32 (...)* @__cxa_end_catch()
ret i32 1
}
declare i32 @__gxx_personality_v0(...)
declare i32 @__cxa_begin_catch(...)
declare i32 @__cxa_end_catch(...)
declare i8* @llvm.eh.exception() nounwind readonly
declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind
declare i32 @myCleanup()
और इस क्या होता है जब मैं समारोह निष्पादित करने के लिए कोशिश है:
inside JIT calling C/C++ call
terminate called after throwing an instance of 'int'
Aborted
यह दिखाता है कि समारोह फेंकता कहा जाता हो जाता है कि, यह फेंकता है, लेकिन मैं सफाई कॉल में देश कभी नहीं।
const inline llvm::FunctionType* getTestFunctionSignature(llvm::LLVMContext& context) {
return llvm::TypeBuilder< unsigned int(), false > ::get(context);
}
llvm::Function* createFunctionThatInvokesAnother(llvm::LLVMContext& ctx, llvm::Module* mod , llvm::Function* another) {
llvm::Function* result = llvm::Function::Create(getTestFunctionSignature(ctx),
llvm::GlobalValue::ExternalLinkage,
"test_function_that_invokes_another",
mod);
llvm::BasicBlock* entry_block = llvm::BasicBlock::Create(ctx, "entryBlock", result);
llvm::BasicBlock* exit_block = llvm::BasicBlock::Create(ctx, "exitBlock", result);
llvm::BasicBlock* unwind_block = llvm::BasicBlock::Create(ctx, "unwindBlock", result);
llvm::IRBuilder<> builder(entry_block);
llvm::ConstantInt* ci = llvm::ConstantInt::get(mod->getContext() , llvm::APInt(32 , llvm::StringRef("1"), 10));
llvm::PointerType* pty3 = llvm::PointerType::get(llvm::IntegerType::get(mod->getContext(), 8), 0);
llvm::AllocaInst* ptr_24 = new llvm::AllocaInst(pty3, "", entry_block);
llvm::AllocaInst* ptr_25 = new llvm::AllocaInst(llvm::IntegerType::get(mod->getContext(), 32), "", entry_block);
llvm::Twine name("someName");
builder.CreateInvoke(another , exit_block , unwind_block , "someName");
builder.SetInsertPoint(exit_block);
builder.CreateRet(ci);
builder.SetInsertPoint(unwind_block);
llvm::Function* func___gxx_personality_v0 = func__gxx_personality_v0(mod);
llvm::Function* func___cxa_begin_catch = func__cxa_begin_catch(mod);
llvm::Function* func___cxa_end_catch = func__cxa_end_catch(mod);
llvm::Function* func_eh_ex = func_llvm_eh_exception(mod);
llvm::Function* func_eh_sel = func__llvm_eh_selector(mod);
llvm::Constant* const_ptr_17 = llvm::ConstantExpr::getCast(llvm::Instruction::BitCast, func___gxx_personality_v0, pty3);
llvm::ConstantPointerNull* const_ptr_18 = llvm::ConstantPointerNull::get(pty3);
llvm::CallInst* get_ex = llvm::CallInst::Create(func_eh_ex, "", unwind_block);
get_ex->setCallingConv(llvm::CallingConv::C);
get_ex->setTailCall(false);
new llvm::StoreInst(get_ex, ptr_24, false, unwind_block);
std::vector<llvm::Value*> int32_37_params;
int32_37_params.push_back(get_ex);
int32_37_params.push_back(const_ptr_17);
int32_37_params.push_back(const_ptr_18);
llvm::CallInst* eh_sel = llvm::CallInst::Create(func_eh_sel, int32_37_params.begin(), int32_37_params.end(), "", unwind_block);
eh_sel->setCallingConv(llvm::CallingConv::C);
eh_sel->setTailCall(false);
new llvm::StoreInst(ci, ptr_25, false, unwind_block);
llvm::LoadInst* ptr_29 = new llvm::LoadInst(ptr_24, "", false, unwind_block);
llvm::CallInst* ptr_30 = llvm::CallInst::Create(func___cxa_begin_catch, ptr_29, "", unwind_block);
ptr_30->setCallingConv(llvm::CallingConv::C);
ptr_30->setTailCall(false);
llvm::AttrListPtr ptr_30_PAL;
{
llvm::SmallVector<llvm::AttributeWithIndex, 4 > Attrs;
llvm::AttributeWithIndex PAWI;
PAWI.Index = 4294967295U;
PAWI.Attrs = 0 | llvm::Attribute::NoUnwind;
Attrs.push_back(PAWI);
ptr_30_PAL = llvm::AttrListPtr::get(Attrs.begin(), Attrs.end());
}
ptr_30->setAttributes(ptr_30_PAL);
llvm::Function* cleanup = call_myCleanup(mod);
builder.CreateCall(cleanup , "cleanup_call");
llvm::CallInst* end_catch = llvm::CallInst::Create(func___cxa_end_catch, "", unwind_block);
builder.CreateRet(ci);
//createCatchHandler(mod , unwind_block);
return result;
}
यह सामान्य व्यापार की तरह कहा जाता हो जाता है:
समारोह है कि invokes और (प्रयास) को पकड़ने के लिए एक फेंका अपवाद नहीं है (मेरी सफाई कॉल 'JIT बुला C/C++ सफाई के अंदर' कहा जाना चाहिए था) :
testMain() {
llvm::LLVMContext ctx;
llvm::InitializeNativeTarget();
llvm::StringRef idRef("testModule");
llvm::Module* module = new llvm::Module(idRef, ctx);
std::string jitErrorString;
llvm::ExecutionEngine* execEngine = executionEngine(module , jitErrorString);
llvm::FunctionPassManager* OurFPM = new llvm::FunctionPassManager(module);
llvm::Function *thr = call_my_func_that_throws(module);
llvm::Function* result = createFunctionThatInvokesAnother(ctx, module ,thr);
std::string errorInfo;
llvm::verifyModule(* module, llvm::PrintMessageAction, & errorInfo);
module->dump();
void *fptr = execEngine->getPointerToFunction(result);
unsigned int (*fp)() = (unsigned int (*)())fptr;
try {
unsigned int value = fp();
} catch (...) {
std::cout << " handled a throw from JIT function" << std::endl;
}
}
जहाँ मेरे समारोह है कि फेंकता है:
int myfunc() {
std::cout << " inside JIT calling C/C++ call" << std::endl;
throw 0;
};
llvm::Function* call_my_func_that_throws (llvm::Module* mod) {
std::vector< const llvm::Type* > FuncTy_ex_args;
llvm::FunctionType* FuncTy_ex = llvm::FunctionType::get(llvm::IntegerType::get(mod->getContext() , 32) , FuncTy_ex_args , false);
llvm::Function* result = llvm::Function::Create(FuncTy_ex, llvm::GlobalValue::ExternalLinkage, "myfunc", mod);
result->setCallingConv(llvm::CallingConv::C);
llvm::AttrListPtr PAL;
result->setAttributes(PAL);
llvm::sys::DynamicLibrary::AddSymbol("myfunc" , (void*) &myfunc);
return result;
}
और मेरी सफाई समारोह एक समान तरीके से परिभाषित किया गया है:
int myCleanup() {
std::cout << " inside JIT calling C/C++ Cleanup" << std::endl;
return 18;
};
llvm::Function* call_myCleanup (llvm::Module* mod) {
std::vector< const llvm::Type* > FuncTy_ex_args;
llvm::FunctionType* FuncTy_ex = llvm::FunctionType::get(llvm::IntegerType::get(mod->getContext() , 32) , FuncTy_ex_args , false);
llvm::Function* result = llvm::Function::Create(FuncTy_ex, llvm::GlobalValue::ExternalLinkage, "myCleanup", mod);
result->setCallingConv(llvm::CallingConv::C);
llvm::AttrListPtr PAL;
result->setAttributes(PAL);
llvm::sys::DynamicLibrary::AddSymbol("myCleanup" , (void*) &myCleanup);
return result;
}
मैं भी LLVM में हाल ही में अपवाद हैंडलिंग परिवर्तन के बारे में this document पढ़ा है, लेकिन यह स्पष्ट नहीं है कि कैसे उन परिवर्तनों को वास्तविक रूप से अनुवाद करें, तुम्हें पता है, कोड
उत्कृष्ट, क्या आप नए दृष्टिकोण का उपयोग करके कुछ उदाहरण इंगित कर सकते हैं, मैं इस पोस्ट को पढ़ रहा हूं: http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-July/041768.html लेकिन मैं ' मुझे यकीन नहीं है कि मुझे – lurscher
क्या करना चाहिए eh दस्तावेज़ों को फिर से लिखा गया है, इसलिए सटीक होना चाहिए। एक अन्य विकल्प यह है कि यह कैसे दिखना चाहिए इसका विचार पाने के लिए क्लैंग आउटपुट को देखना है। – echristo