2011-09-27 14 views
5

नहीं कहा गया है, मैं जेआईटी 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 पढ़ा है, लेकिन यह स्पष्ट नहीं है कि कैसे उन परिवर्तनों को वास्तविक रूप से अनुवाद करें, तुम्हें पता है, कोड

उत्तर

2

अभी ईएच कोड में बड़ी संख्या में संशोधन किया जा रहा है। डेमो, अगर मैं सही ढंग से याद करता हूं, संस्करण 2.9 नहीं है, लेकिन वर्तमान विकास स्रोत - जिसका अर्थ 2.9 के साथ कुछ करने का प्रयास करना है, यदि आप इस तरह से प्रयास करते हैं तो चोट लगने वाली दुनिया होगी।

उस ने कहा, ईएच प्रतिनिधित्व अब बेहतर है और इस सप्ताह दस्तावेज़ों में सुधार के लिए कई पैच चले गए हैं। यदि आप एक ऐसी भाषा लिखने की कोशिश कर रहे हैं जो llvm के माध्यम से अपवादों का उपयोग करता है तो मैं अत्यधिक सुझाव देता हूं कि आप अपने कोड को वर्तमान विकास स्रोतों में माइग्रेट करें।

उन सभी ने कहा, मुझे यकीन नहीं है कि अभी जेआईटी में अपवाद हैंडलिंग कितनी अच्छी तरह से काम करती है। यह नाममात्र रूप से समर्थित है, लेकिन आपको यह सुनिश्चित करने के लिए स्मृति में रखे गए अनदेखी तालिकाओं को डीबग करने की आवश्यकता हो सकती है कि वे सही हैं।

+0

उत्कृष्ट, क्या आप नए दृष्टिकोण का उपयोग करके कुछ उदाहरण इंगित कर सकते हैं, मैं इस पोस्ट को पढ़ रहा हूं: http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-July/041768.html लेकिन मैं ' मुझे यकीन नहीं है कि मुझे – lurscher

+0

क्या करना चाहिए eh दस्तावेज़ों को फिर से लिखा गया है, इसलिए सटीक होना चाहिए। एक अन्य विकल्प यह है कि यह कैसे दिखना चाहिए इसका विचार पाने के लिए क्लैंग आउटपुट को देखना है। – echristo

संबंधित मुद्दे