Revision: 3117 http://trac.macosforge.org/projects/ruby/changeset/3117 Author: lsansonetti@apple.com Date: 2009-12-14 17:42:46 -0800 (Mon, 14 Dec 2009) Log Message: ----------- emit dwarf metadata at compilation time and use it to establish backtracing later at runtime Modified Paths: -------------- MacRuby/trunk/bridgesupport.cpp MacRuby/trunk/compiler.cpp MacRuby/trunk/compiler.h MacRuby/trunk/llvm.h MacRuby/trunk/vm.cpp Modified: MacRuby/trunk/bridgesupport.cpp =================================================================== --- MacRuby/trunk/bridgesupport.cpp 2009-12-15 01:33:42 UTC (rev 3116) +++ MacRuby/trunk/bridgesupport.cpp 2009-12-15 01:42:46 UTC (rev 3117) @@ -13,6 +13,7 @@ #include <llvm/Instructions.h> #include <llvm/ModuleProvider.h> #include <llvm/Intrinsics.h> +#include <llvm/Analysis/DebugInfo.h> #include <llvm/ExecutionEngine/JIT.h> #include <llvm/PassManager.h> #include <llvm/Target/TargetData.h> Modified: MacRuby/trunk/compiler.cpp =================================================================== --- MacRuby/trunk/compiler.cpp 2009-12-15 01:33:42 UTC (rev 3116) +++ MacRuby/trunk/compiler.cpp 2009-12-15 01:42:46 UTC (rev 3117) @@ -8,6 +8,10 @@ #define ROXOR_COMPILER_DEBUG 0 +#if !defined(DW_LANG_Ruby) +# define DW_LANG_Ruby 0x15 // TODO: Python is 0x14, request a real number +#endif + #include "llvm.h" #include "ruby/ruby.h" #include "ruby/encoding.h" @@ -17,6 +21,7 @@ #include "vm.h" #include "compiler.h" #include "objc.h" +#include "version.h" extern "C" const char *ruby_node_name(int node); @@ -26,6 +31,9 @@ RoxorCompiler::RoxorCompiler(void) { + assert(RoxorCompiler::module != NULL); + debug_info = new DIFactory(*RoxorCompiler::module); + fname = ""; inside_eval = false; @@ -58,7 +66,6 @@ return_from_block = -1; return_from_block_ids = 0; ensure_pn = NULL; - current_scope = NULL; dispatcherFunc = NULL; fastPlusFunc = NULL; @@ -737,10 +744,11 @@ (module->getOrInsertFunction("rb_vm_dispatch", ft)); } - assert(current_scope != NULL); - current_scope->dispatch_lines.push_back(current_line); - - return compile_protected_call(dispatcherFunc, params); + Instruction *insn = compile_protected_call(dispatcherFunc, params); + if (fname != NULL) { + debug_info->InsertStopPoint(debug_compile_unit, current_line, 0, bb); + } + return insn; } Value * @@ -3096,10 +3104,6 @@ Function *f = Function::Create(ft, GlobalValue::ExternalLinkage, function_name, module); - RoxorScope *old_current_scope = current_scope; - current_scope = new RoxorScope(fname); - scopes[f] = current_scope; - BasicBlock *old_rescue_invoke_bb = rescue_invoke_bb; BasicBlock *old_rescue_rethrow_bb = rescue_rethrow_bb; BasicBlock *old_entry_bb = entry_bb; @@ -3110,6 +3114,13 @@ rescue_rethrow_bb = NULL; bb = BasicBlock::Create(context, "MainBlock", f); + DISubprogram old_debug_subprogram = debug_subprogram; + debug_subprogram = debug_info->CreateSubprogram( + debug_compile_unit, f->getName(), f->getName(), + f->getName(), debug_compile_unit, nd_line(node), + DIType(), f->hasInternalLinkage(), true); + debug_info->InsertSubprogramStart(debug_subprogram, bb); + std::map<ID, Value *> old_lvars = lvars; lvars.clear(); Value *old_self = current_self; @@ -3360,7 +3371,7 @@ current_self = old_self; current_var_uses = old_current_var_uses; running_block = old_running_block; - current_scope = old_current_scope; + debug_subprogram = old_debug_subprogram; return cast<Value>(f); } @@ -5300,6 +5311,19 @@ return NULL; } +void +RoxorCompiler::set_fname(const char *_fname) +{ + if (fname != _fname) { + fname = _fname; + + if (fname != NULL) { + debug_compile_unit = debug_info->CreateCompileUnit(DW_LANG_Ruby, + fname, "", RUBY_DESCRIPTION, false, false, ""); + } + } +} + Function * RoxorCompiler::compile_main_function(NODE *node) { Modified: MacRuby/trunk/compiler.h =================================================================== --- MacRuby/trunk/compiler.h 2009-12-15 01:33:42 UTC (rev 3116) +++ MacRuby/trunk/compiler.h 2009-12-15 01:42:46 UTC (rev 3117) @@ -27,14 +27,6 @@ #define DEFINED_SUPER 6 #define DEFINED_METHOD 7 -class RoxorScope { - public: - std::string path; - std::vector<unsigned int> dispatch_lines; - - RoxorScope(const char *fname) : path(fname) {} -}; - class RoxorCompiler { public: static llvm::Module *module; @@ -43,9 +35,7 @@ RoxorCompiler(void); virtual ~RoxorCompiler(void) { } - void set_fname(const char *_fname) { - fname = _fname; - } + void set_fname(const char *_fname); Value *compile_node(NODE *node); @@ -71,26 +61,11 @@ bool is_dynamic_class(void) { return dynamic_class; } void set_dynamic_class(bool flag) { dynamic_class = flag; } - RoxorScope *scope_for_function(Function *f) { - std::map<Function *, RoxorScope *>::iterator i = scopes.find(f); - return i == scopes.end() ? NULL : i->second; - } - - bool delete_scope(Function *f) { - std::map<Function *, RoxorScope *>::iterator i = scopes.find(f); - if (i != scopes.end()) { - scopes.erase(i); - delete i->second; - return true; - } - return false; - } - - void clear_scopes(void) { - scopes.clear(); - } - protected: + DIFactory *debug_info; + DICompileUnit debug_compile_unit; + DISubprogram debug_subprogram; + const char *fname; bool inside_eval; @@ -99,7 +74,6 @@ std::map<ID, Value *> ivar_slots_cache; std::map<std::string, GlobalVariable *> static_strings; std::map<CFHashCode, GlobalVariable *> static_ustrings; - std::map<Function *, RoxorScope *> scopes; #if ROXOR_COMPILER_DEBUG int level; @@ -142,7 +116,6 @@ int return_from_block; int return_from_block_ids; PHINode *ensure_pn; - RoxorScope *current_scope; bool class_declaration; Function *dispatcherFunc; Modified: MacRuby/trunk/llvm.h =================================================================== --- MacRuby/trunk/llvm.h 2009-12-15 01:33:42 UTC (rev 3116) +++ MacRuby/trunk/llvm.h 2009-12-15 01:42:46 UTC (rev 3117) @@ -11,6 +11,7 @@ #include <llvm/Instructions.h> #include <llvm/ModuleProvider.h> #include <llvm/Intrinsics.h> +#include <llvm/Analysis/DebugInfo.h> #include <llvm/ExecutionEngine/JIT.h> #include <llvm/PassManager.h> #include <llvm/Target/TargetData.h> Modified: MacRuby/trunk/vm.cpp =================================================================== --- MacRuby/trunk/vm.cpp 2009-12-15 01:33:42 UTC (rev 3116) +++ MacRuby/trunk/vm.cpp 2009-12-15 01:42:46 UTC (rev 3117) @@ -16,10 +16,13 @@ #include <llvm/Instructions.h> #include <llvm/ModuleProvider.h> #include <llvm/PassManager.h> +#include <llvm/Analysis/DebugInfo.h> #include <llvm/Analysis/Verifier.h> #include <llvm/Target/TargetData.h> +#include <llvm/CodeGen/MachineFunction.h> #include <llvm/ExecutionEngine/JIT.h> #include <llvm/ExecutionEngine/JITMemoryManager.h> +#include <llvm/ExecutionEngine/JITEventListener.h> #include <llvm/ExecutionEngine/GenericValue.h> #include <llvm/Target/TargetData.h> #include <llvm/Target/TargetMachine.h> @@ -61,35 +64,55 @@ VALUE rb_cTopLevel = 0; -struct RoxorFunction { - Function *f; - RoxorScope *scope; - unsigned char *start; - unsigned char *end; - void *imp; - std::vector<unsigned char *> ehs; +class RoxorFunction { + public: + // Information retrieved from JITManager. + Function *f; + unsigned char *start; + unsigned char *end; + std::vector<unsigned char *> ehs; - RoxorFunction(Function *_f, RoxorScope *_scope, unsigned char *_start, - unsigned char *_end) { - f = _f; - scope = _scope; - start = _start; - end = _end; - imp = NULL; // lazy - } + // Information retrieved from JITListener. + std::string file; + class Line { + public: + uintptr_t address; + unsigned line; + Line(uintptr_t _address, unsigned _line) { + address = _address; + line = _line; + } + }; + std::vector<Line> lines; + + // Information retrieved later (lazily). + void *imp; + + RoxorFunction(Function *_f, unsigned char *_start, + unsigned char *_end) { + f = _f; + start = _start; + end = _end; + imp = NULL; + } }; -class RoxorJITManager : public JITMemoryManager { +class RoxorJITManager : public JITMemoryManager, public JITEventListener { private: JITMemoryManager *mm; std::vector<struct RoxorFunction *> functions; + RoxorFunction *current_function(void) { + assert(!functions.empty()); + return functions.back(); + } + public: RoxorJITManager() : JITMemoryManager() { mm = CreateDefaultMemManager(); } - struct RoxorFunction *find_function(uint8_t *addr) { + RoxorFunction *find_function(uint8_t *addr) { if (functions.empty()) { return NULL; } @@ -125,6 +148,8 @@ return NULL; } + // JITMemoryManager callbacks. + void setMemoryWritable(void) { mm->setMemoryWritable(); } @@ -172,8 +197,7 @@ uint8_t *FunctionEnd) { mm->endFunctionBody(F, FunctionStart, FunctionEnd); Function *f = const_cast<Function *>(F); - RoxorScope *s = RoxorCompiler::shared->scope_for_function(f); - functions.push_back(new RoxorFunction(f, s, FunctionStart, + functions.push_back(new RoxorFunction(f, FunctionStart, FunctionEnd)); } @@ -198,14 +222,37 @@ void endExceptionTable(const Function *F, uint8_t *TableStart, uint8_t *TableEnd, uint8_t* FrameRegister) { - assert(!functions.empty()); - functions.back()->ehs.push_back(FrameRegister); + current_function()->ehs.push_back(FrameRegister); mm->endExceptionTable(F, TableStart, TableEnd, FrameRegister); } void setPoisonMemory(bool poison) { mm->setPoisonMemory(poison); } + + // JITEventListener callbacks. + + void NotifyFunctionEmitted(const Function &F, + void *Code, size_t Size, + const EmittedFunctionDetails &Details) + { + RoxorFunction *function = current_function(); + + std::string file; + for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator iter = Details.LineStarts.begin(); iter != Details.LineStarts.end(); ++iter) { + DebugLocTuple dlt = Details.MF->getDebugLocTuple(iter->Loc); + if (file.size() == 0) { + DICompileUnit unit(dlt.CompileUnit); + unit.getFilename(file); + assert(file.size() != 0); + } + + RoxorFunction::Line line(iter->Address, dlt.Line); + function->lines.push_back(line); + } + + function->file = file; + } }; extern "C" void *__cxa_allocate_exception(size_t); @@ -248,6 +295,7 @@ abort(); } ee->DisableLazyCompilation(); + ee->RegisterJITEventListener(jmm); fpm = new FunctionPassManager(emp); fpm->add(new TargetData(*ee->getTargetData())); @@ -482,7 +530,6 @@ } // Remove the compiler scope. - RoxorCompiler::shared->delete_scope(func); delete f; // Delete machine code. @@ -526,49 +573,21 @@ } rb_vm_method_node_t *node = iter->second; - - RoxorScope *scope = f == NULL ? NULL : f->scope; if (ln != NULL) { - if (scope != NULL) { -#if __LP64__ - // So, we need to determine here which call to the dispatcher - // we are exactly, so that we can retrieve the appropriate - // line number from the annotation. - // Unfortunately, the only way to achieve that seems to scan - // the current function's machine code. - // This code has only been tested on x86_64 but could be - // easily ported to i386. - const uint32_t sym = *(uint32_t *)((unsigned char *)addr - 8); - const int sentinel = sym & 0xff; - - unsigned char *p = f->start; - unsigned int i = 0; - while ((p = (unsigned char *)memchr(p, sentinel, - (unsigned char *)addr - p)) != NULL) { - if (*(uint32_t *)p == sym) { - i++; + *ln = 0; + if (f != NULL) { + for (std::vector<RoxorFunction::Line>::iterator iter = + f->lines.begin(); iter != f->lines.end(); ++iter) { + if ((*iter).address == (uintptr_t)addr) { + *ln = (*iter).line; + break; } - p++; } - - if (i > 0 && i - 1 < scope->dispatch_lines.size()) { - *ln = scope->dispatch_lines[i - 1]; - } - else { - *ln = 0; - } -#else - // TODO 32-bit hack... - *ln = 0; -#endif } - else { - *ln = 0; - } } if (path != NULL) { - if (scope != NULL) { - strncpy(path, scope->path.c_str(), path_len); + if (f != NULL && f->file.size() > 0) { + strncpy(path, f->file.c_str(), path_len); } else { strncpy(path, "core", path_len); @@ -3765,6 +3784,8 @@ return rb_vm_run(fname, node, binding, inside_eval); } +extern VALUE rb_progname; + extern "C" void rb_vm_aot_compile(NODE *node) @@ -3773,6 +3794,7 @@ assert(ruby_aot_init_func); // Compile the program as IR. + RoxorCompiler::shared->set_fname(RSTRING_PTR(rb_progname)); Function *f = RoxorCompiler::shared->compile_main_function(node); f->setName(RSTRING_PTR(ruby_aot_init_func)); GET_CORE()->optimize(f); @@ -4622,6 +4644,7 @@ Init_PreVM(void) { llvm::DwarfExceptionHandling = true; // required! + llvm::JITEmitDebugInfo = true; RoxorCompiler::module = new llvm::Module("Roxor", getGlobalContext()); RoxorCompiler::module->setTargetTriple(TARGET_TRIPLE);