Skip to content
This repository
Browse code

emit dwarf metadata at compilation time and use it to establish backt…

…racing later at runtime

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@3117 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
commit 0f14388c1c21f02a780e3c4c1c1e3bff096cffc4 1 parent 09efc03
authored December 15, 2009
1  bridgesupport.cpp
@@ -13,6 +13,7 @@
13 13
 #include <llvm/Instructions.h>
14 14
 #include <llvm/ModuleProvider.h>
15 15
 #include <llvm/Intrinsics.h>
  16
+#include <llvm/Analysis/DebugInfo.h>
16 17
 #include <llvm/ExecutionEngine/JIT.h>
17 18
 #include <llvm/PassManager.h>
18 19
 #include <llvm/Target/TargetData.h>
44  compiler.cpp
@@ -8,6 +8,10 @@
8 8
 
9 9
 #define ROXOR_COMPILER_DEBUG 	0
10 10
 
  11
+#if !defined(DW_LANG_Ruby)
  12
+# define DW_LANG_Ruby 0x15 // TODO: Python is 0x14, request a real number
  13
+#endif
  14
+
11 15
 #include "llvm.h"
12 16
 #include "ruby/ruby.h"
13 17
 #include "ruby/encoding.h"
@@ -17,6 +21,7 @@
17 21
 #include "vm.h"
18 22
 #include "compiler.h"
19 23
 #include "objc.h"
  24
+#include "version.h"
20 25
 
21 26
 extern "C" const char *ruby_node_name(int node);
22 27
 
@@ -26,6 +31,9 @@ RoxorCompiler *RoxorCompiler::shared = NULL;
26 31
 
27 32
 RoxorCompiler::RoxorCompiler(void)
28 33
 {
  34
+    assert(RoxorCompiler::module != NULL);
  35
+    debug_info = new DIFactory(*RoxorCompiler::module);
  36
+
29 37
     fname = "";
30 38
     inside_eval = false;
31 39
 
@@ -58,7 +66,6 @@ RoxorCompiler::RoxorCompiler(void)
58 66
     return_from_block = -1;
59 67
     return_from_block_ids = 0;
60 68
     ensure_pn = NULL;
61  
-    current_scope = NULL;
62 69
 
63 70
     dispatcherFunc = NULL;
64 71
     fastPlusFunc = NULL;
@@ -737,10 +744,11 @@ RoxorCompiler::compile_dispatch_call(std::vector<Value *> &params)
737 744
 	    (module->getOrInsertFunction("rb_vm_dispatch", ft));
738 745
     }
739 746
 
740  
-    assert(current_scope != NULL);
741  
-    current_scope->dispatch_lines.push_back(current_line);
742  
-
743  
-    return compile_protected_call(dispatcherFunc, params);
  747
+    Instruction *insn = compile_protected_call(dispatcherFunc, params);
  748
+    if (fname != NULL) {
  749
+	debug_info->InsertStopPoint(debug_compile_unit, current_line, 0, bb);
  750
+    }
  751
+    return insn;
744 752
 }
745 753
 
746 754
 Value *
@@ -3096,10 +3104,6 @@ RoxorCompiler::compile_node(NODE *node)
3096 3104
 		Function *f = Function::Create(ft, GlobalValue::ExternalLinkage,
3097 3105
 			function_name, module);
3098 3106
 
3099  
-		RoxorScope *old_current_scope = current_scope;
3100  
-		current_scope = new RoxorScope(fname);
3101  
-		scopes[f] = current_scope;
3102  
-
3103 3107
 		BasicBlock *old_rescue_invoke_bb = rescue_invoke_bb;
3104 3108
 		BasicBlock *old_rescue_rethrow_bb = rescue_rethrow_bb;
3105 3109
 		BasicBlock *old_entry_bb = entry_bb;
@@ -3110,6 +3114,13 @@ RoxorCompiler::compile_node(NODE *node)
3110 3114
 		rescue_rethrow_bb = NULL;
3111 3115
 		bb = BasicBlock::Create(context, "MainBlock", f);
3112 3116
 
  3117
+		DISubprogram old_debug_subprogram = debug_subprogram;
  3118
+		debug_subprogram = debug_info->CreateSubprogram(
  3119
+			debug_compile_unit, f->getName(), f->getName(),
  3120
+			f->getName(), debug_compile_unit, nd_line(node),
  3121
+			DIType(), f->hasInternalLinkage(), true);
  3122
+		debug_info->InsertSubprogramStart(debug_subprogram, bb);
  3123
+
3113 3124
 		std::map<ID, Value *> old_lvars = lvars;
3114 3125
 		lvars.clear();
3115 3126
 		Value *old_self = current_self;
@@ -3360,7 +3371,7 @@ RoxorCompiler::compile_node(NODE *node)
3360 3371
 		current_self = old_self;
3361 3372
 		current_var_uses = old_current_var_uses;
3362 3373
 		running_block = old_running_block;
3363  
-		current_scope = old_current_scope;
  3374
+		debug_subprogram = old_debug_subprogram;
3364 3375
 
3365 3376
 		return cast<Value>(f);
3366 3377
 	    }
@@ -5300,6 +5311,19 @@ RoxorCompiler::compile_node(NODE *node)
5300 5311
     return NULL;
5301 5312
 }
5302 5313
 
  5314
+void
  5315
+RoxorCompiler::set_fname(const char *_fname)
  5316
+{
  5317
+    if (fname != _fname) {
  5318
+	fname = _fname;
  5319
+
  5320
+	if (fname != NULL) {
  5321
+	    debug_compile_unit = debug_info->CreateCompileUnit(DW_LANG_Ruby,
  5322
+		    fname, "", RUBY_DESCRIPTION, false, false, "");
  5323
+	}
  5324
+    }
  5325
+}
  5326
+
5303 5327
 Function *
5304 5328
 RoxorCompiler::compile_main_function(NODE *node)
5305 5329
 {
37  compiler.h
@@ -27,14 +27,6 @@
27 27
 #define DEFINED_SUPER	6
28 28
 #define DEFINED_METHOD	7
29 29
 
30  
-class RoxorScope {
31  
-    public:
32  
-	std::string path;
33  
-	std::vector<unsigned int> dispatch_lines;
34  
-
35  
-	RoxorScope(const char *fname) : path(fname) {}
36  
-};
37  
-
38 30
 class RoxorCompiler {
39 31
     public:
40 32
 	static llvm::Module *module;
@@ -43,9 +35,7 @@ class RoxorCompiler {
43 35
 	RoxorCompiler(void);
44 36
 	virtual ~RoxorCompiler(void) { }
45 37
 
46  
-	void set_fname(const char *_fname) {
47  
-	    fname = _fname;
48  
-	}
  38
+	void set_fname(const char *_fname);
49 39
 
50 40
 	Value *compile_node(NODE *node);
51 41
 
@@ -71,26 +61,11 @@ class RoxorCompiler {
71 61
 	bool is_dynamic_class(void) { return dynamic_class; }
72 62
 	void set_dynamic_class(bool flag) { dynamic_class = flag; }
73 63
 
74  
-	RoxorScope *scope_for_function(Function *f) {
75  
-	    std::map<Function *, RoxorScope *>::iterator i = scopes.find(f);
76  
-	    return i == scopes.end() ? NULL : i->second;
77  
-	}
78  
-
79  
-	bool delete_scope(Function *f) {
80  
-	    std::map<Function *, RoxorScope *>::iterator i = scopes.find(f);
81  
-	    if (i != scopes.end()) {
82  
-		scopes.erase(i);
83  
-		delete i->second;
84  
-		return true;
85  
-	    } 
86  
-	    return false;
87  
-	}
88  
-
89  
-	void clear_scopes(void) {
90  
-	    scopes.clear();
91  
-	}
92  
-
93 64
     protected:
  65
+	DIFactory *debug_info;
  66
+	DICompileUnit debug_compile_unit;
  67
+	DISubprogram debug_subprogram;
  68
+
94 69
 	const char *fname;
95 70
 	bool inside_eval;
96 71
 
@@ -99,7 +74,6 @@ class RoxorCompiler {
99 74
 	std::map<ID, Value *> ivar_slots_cache;
100 75
 	std::map<std::string, GlobalVariable *> static_strings;
101 76
 	std::map<CFHashCode, GlobalVariable *> static_ustrings;
102  
-	std::map<Function *, RoxorScope *> scopes;
103 77
 
104 78
 #if ROXOR_COMPILER_DEBUG
105 79
 	int level;
@@ -142,7 +116,6 @@ class RoxorCompiler {
142 116
 	int return_from_block;
143 117
 	int return_from_block_ids;
144 118
 	PHINode *ensure_pn;
145  
-	RoxorScope *current_scope;
146 119
 	bool class_declaration;
147 120
 
148 121
 	Function *dispatcherFunc;
1  llvm.h
@@ -11,6 +11,7 @@
11 11
 #include <llvm/Instructions.h>
12 12
 #include <llvm/ModuleProvider.h>
13 13
 #include <llvm/Intrinsics.h>
  14
+#include <llvm/Analysis/DebugInfo.h>
14 15
 #include <llvm/ExecutionEngine/JIT.h>
15 16
 #include <llvm/PassManager.h>
16 17
 #include <llvm/Target/TargetData.h>
143  vm.cpp
@@ -16,10 +16,13 @@
16 16
 #include <llvm/Instructions.h>
17 17
 #include <llvm/ModuleProvider.h>
18 18
 #include <llvm/PassManager.h>
  19
+#include <llvm/Analysis/DebugInfo.h>
19 20
 #include <llvm/Analysis/Verifier.h>
20 21
 #include <llvm/Target/TargetData.h>
  22
+#include <llvm/CodeGen/MachineFunction.h>
21 23
 #include <llvm/ExecutionEngine/JIT.h>
22 24
 #include <llvm/ExecutionEngine/JITMemoryManager.h>
  25
+#include <llvm/ExecutionEngine/JITEventListener.h>
23 26
 #include <llvm/ExecutionEngine/GenericValue.h>
24 27
 #include <llvm/Target/TargetData.h>
25 28
 #include <llvm/Target/TargetMachine.h>
@@ -61,35 +64,55 @@ pthread_key_t RoxorVM::vm_thread_key;
61 64
 
62 65
 VALUE rb_cTopLevel = 0;
63 66
 
64  
-struct RoxorFunction {
65  
-    Function *f;
66  
-    RoxorScope *scope;
67  
-    unsigned char *start;
68  
-    unsigned char *end;
69  
-    void *imp;
70  
-    std::vector<unsigned char *> ehs;
71  
-
72  
-    RoxorFunction(Function *_f, RoxorScope *_scope, unsigned char *_start,
73  
-	    unsigned char *_end) {
74  
-	f = _f;
75  
-	scope = _scope;
76  
-	start = _start;
77  
-	end = _end;
78  
-	imp = NULL; 	// lazy
79  
-    }
  67
+class RoxorFunction {
  68
+    public: 
  69
+	// Information retrieved from JITManager.
  70
+	Function *f;
  71
+	unsigned char *start;
  72
+	unsigned char *end;
  73
+	std::vector<unsigned char *> ehs;
  74
+
  75
+	// Information retrieved from JITListener.
  76
+	std::string file;
  77
+	class Line {
  78
+	    public:
  79
+		uintptr_t address;
  80
+		unsigned line;
  81
+		Line(uintptr_t _address, unsigned _line) {
  82
+		    address = _address;
  83
+		    line = _line;
  84
+		}
  85
+	};
  86
+	std::vector<Line> lines;
  87
+
  88
+	// Information retrieved later (lazily).
  89
+	void *imp;
  90
+
  91
+	RoxorFunction(Function *_f, unsigned char *_start,
  92
+		unsigned char *_end) {
  93
+	    f = _f;
  94
+	    start = _start;
  95
+	    end = _end;
  96
+	    imp = NULL;
  97
+	}
80 98
 };
81 99
 
82  
-class RoxorJITManager : public JITMemoryManager {
  100
+class RoxorJITManager : public JITMemoryManager, public JITEventListener {
83 101
     private:
84 102
         JITMemoryManager *mm;
85 103
 	std::vector<struct RoxorFunction *> functions;
86 104
 
  105
+	RoxorFunction *current_function(void) {
  106
+	    assert(!functions.empty());
  107
+	    return functions.back();
  108
+	}
  109
+
87 110
     public:
88 111
 	RoxorJITManager() : JITMemoryManager() { 
89 112
 	    mm = CreateDefaultMemManager(); 
90 113
 	}
91 114
 
92  
-	struct RoxorFunction *find_function(uint8_t *addr) {
  115
+	RoxorFunction *find_function(uint8_t *addr) {
93 116
 	     if (functions.empty()) {
94 117
 		return NULL;
95 118
 	     }
@@ -125,6 +148,8 @@ class RoxorJITManager : public JITMemoryManager {
125 148
 	    return NULL;
126 149
 	}
127 150
 
  151
+	// JITMemoryManager callbacks.
  152
+
128 153
 	void setMemoryWritable(void) { 
129 154
 	    mm->setMemoryWritable(); 
130 155
 	}
@@ -172,8 +197,7 @@ class RoxorJITManager : public JITMemoryManager {
172 197
 		uint8_t *FunctionEnd) {
173 198
 	    mm->endFunctionBody(F, FunctionStart, FunctionEnd);
174 199
 	    Function *f = const_cast<Function *>(F);
175  
-	    RoxorScope *s = RoxorCompiler::shared->scope_for_function(f);
176  
-	    functions.push_back(new RoxorFunction(f, s, FunctionStart,
  200
+	    functions.push_back(new RoxorFunction(f, FunctionStart,
177 201
 			FunctionEnd));
178 202
 	}
179 203
 
@@ -198,14 +222,37 @@ class RoxorJITManager : public JITMemoryManager {
198 222
 
199 223
 	void endExceptionTable(const Function *F, uint8_t *TableStart, 
200 224
 		uint8_t *TableEnd, uint8_t* FrameRegister) {
201  
-	    assert(!functions.empty());
202  
-	    functions.back()->ehs.push_back(FrameRegister);
  225
+	    current_function()->ehs.push_back(FrameRegister);
203 226
 	    mm->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
204 227
 	}
205 228
 
206 229
 	void setPoisonMemory(bool poison) {
207 230
 	    mm->setPoisonMemory(poison);
208 231
 	}
  232
+
  233
+	// JITEventListener callbacks.
  234
+
  235
+	void NotifyFunctionEmitted(const Function &F,
  236
+		void *Code, size_t Size,
  237
+		const EmittedFunctionDetails &Details)
  238
+	{
  239
+	    RoxorFunction *function = current_function();
  240
+
  241
+	    std::string file;
  242
+	    for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator iter = Details.LineStarts.begin(); iter != Details.LineStarts.end(); ++iter) {
  243
+		DebugLocTuple dlt = Details.MF->getDebugLocTuple(iter->Loc);
  244
+		if (file.size() == 0) {
  245
+		    DICompileUnit unit(dlt.CompileUnit);
  246
+		    unit.getFilename(file);
  247
+		    assert(file.size() != 0);
  248
+		}
  249
+
  250
+		RoxorFunction::Line line(iter->Address, dlt.Line);
  251
+		function->lines.push_back(line);
  252
+	    }
  253
+
  254
+	    function->file = file;
  255
+	}
209 256
 };
210 257
 
211 258
 extern "C" void *__cxa_allocate_exception(size_t);
@@ -248,6 +295,7 @@ RoxorCore::RoxorCore(void)
248 295
 	abort();
249 296
     }
250 297
     ee->DisableLazyCompilation();
  298
+    ee->RegisterJITEventListener(jmm);
251 299
 
252 300
     fpm = new FunctionPassManager(emp);
253 301
     fpm->add(new TargetData(*ee->getTargetData()));
@@ -482,7 +530,6 @@ RoxorCore::delenda(Function *func)
482 530
     }
483 531
 
484 532
     // Remove the compiler scope.
485  
-    RoxorCompiler::shared->delete_scope(func);
486 533
     delete f;
487 534
 
488 535
     // Delete machine code.
@@ -526,49 +573,21 @@ RoxorCore::symbolize_call_address(void *addr, void **startp, char *path,
526 573
 	}
527 574
 
528 575
 	rb_vm_method_node_t *node = iter->second;
529  
-
530  
-	RoxorScope *scope = f == NULL ? NULL : f->scope;
531 576
 	if (ln != NULL) {
532  
-	    if (scope != NULL) {
533  
-#if __LP64__
534  
-		// So, we need to determine here which call to the dispatcher
535  
-		// we are exactly, so that we can retrieve the appropriate
536  
-		// line number from the annotation.
537  
-		// Unfortunately, the only way to achieve that seems to scan
538  
-		// the current function's machine code.
539  
-		// This code has only been tested on x86_64 but could be
540  
-		// easily ported to i386.
541  
-		const uint32_t sym = *(uint32_t *)((unsigned char *)addr - 8);
542  
-		const int sentinel = sym & 0xff;
543  
-
544  
-		unsigned char *p = f->start;
545  
-		unsigned int i = 0;
546  
-		while ((p = (unsigned char *)memchr(p, sentinel,
547  
-				(unsigned char *)addr - p)) != NULL) {
548  
-		    if (*(uint32_t *)p == sym) {
549  
-			i++;
  577
+	    *ln = 0;
  578
+	    if (f != NULL) {
  579
+		for (std::vector<RoxorFunction::Line>::iterator iter =
  580
+			f->lines.begin(); iter != f->lines.end(); ++iter) {
  581
+		    if ((*iter).address == (uintptr_t)addr) {
  582
+			*ln = (*iter).line;
  583
+			break;
550 584
 		    }
551  
-		    p++;
552  
-		}
553  
-
554  
-		if (i > 0 && i - 1 < scope->dispatch_lines.size()) {
555  
-		    *ln = scope->dispatch_lines[i - 1];
556  
-		}
557  
-		else {
558  
-		    *ln = 0;
559 585
 		}
560  
-#else
561  
-		// TODO 32-bit hack...
562  
-		*ln = 0;
563  
-#endif
564  
-	    }
565  
-	    else {
566  
-		*ln = 0;
567 586
 	    }
568 587
 	}
569 588
 	if (path != NULL) {
570  
-	    if (scope != NULL) {
571  
-		strncpy(path, scope->path.c_str(), path_len);
  589
+	    if (f != NULL && f->file.size() > 0) {
  590
+		strncpy(path, f->file.c_str(), path_len);
572 591
 	    }
573 592
 	    else {
574 593
 		strncpy(path, "core", path_len);
@@ -3765,6 +3784,8 @@ rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node,
3765 3784
     return rb_vm_run(fname, node, binding, inside_eval);
3766 3785
 }
3767 3786
 
  3787
+extern VALUE rb_progname;
  3788
+
3768 3789
 extern "C"
3769 3790
 void
3770 3791
 rb_vm_aot_compile(NODE *node)
@@ -3773,6 +3794,7 @@ rb_vm_aot_compile(NODE *node)
3773 3794
     assert(ruby_aot_init_func);
3774 3795
 
3775 3796
     // Compile the program as IR.
  3797
+    RoxorCompiler::shared->set_fname(RSTRING_PTR(rb_progname));
3776 3798
     Function *f = RoxorCompiler::shared->compile_main_function(node);
3777 3799
     f->setName(RSTRING_PTR(ruby_aot_init_func));
3778 3800
     GET_CORE()->optimize(f);
@@ -4622,6 +4644,7 @@ void
4622 4644
 Init_PreVM(void)
4623 4645
 {
4624 4646
     llvm::DwarfExceptionHandling = true; // required!
  4647
+    llvm::JITEmitDebugInfo = true;
4625 4648
 
4626 4649
     RoxorCompiler::module = new llvm::Module("Roxor", getGlobalContext());
4627 4650
     RoxorCompiler::module->setTargetTriple(TARGET_TRIPLE);

0 notes on commit 0f14388

Please sign in to comment.
Something went wrong with that request. Please try again.