diff options
author | Alon Zakai <azakai@mozilla.com> | 2011-02-12 19:36:02 -0800 |
---|---|---|
committer | Alon Zakai <azakai@mozilla.com> | 2011-02-12 19:36:02 -0800 |
commit | bace573eb4e44e43227d4134e34158969d914efa (patch) | |
tree | cb50163af1c4a424132b20e1ded77e5cf8e6f4b2 | |
parent | ffb61d77cae700fe2f45c60e06715033ae9f653a (diff) |
line number debugging info
-rw-r--r-- | src/intertyper.js | 46 | ||||
-rw-r--r-- | src/jsifier.js | 2 | ||||
-rw-r--r-- | tests/runner.py | 33 |
3 files changed, 78 insertions, 3 deletions
diff --git a/src/intertyper.js b/src/intertyper.js index efe34216..3db09516 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -10,6 +10,45 @@ var LLVM = { CALLING_CONVENTIONS: set('ccc', 'fastcc', 'coldcc', 'cc10') }; +var Debugging = { + processMetadata: function(lines) { + var llvmLineToMetadata = {}; + var metadataToSourceLine = {}; + var form1 = new RegExp(/^ .*, !dbg !(\d+)$/); + var form2 = new RegExp(/^ .*, !dbg !(\d+) +; \[#uses=\d+\]$/); + var form3 = new RegExp(/^!(\d+) = metadata !{\w+\d* !?(\d+)[^\d].*$/); + var form4 = new RegExp(/^!llvm.dbg.\w+ = .*$/); + var form5 = new RegExp(/^!(\d+) = metadata !{null.*$/); + var form6 = new RegExp(/^ call void \@llvm.dbg.declare\(metadata .*$/); + + var ret = lines.map(function(line, i) { + if (form6.exec(line)) return null; + + var calc = form1.exec(line) || form2.exec(line); + if (calc) { + llvmLineToMetadata[i+1] = calc[1]; + return line.replace(', !dbg !' + calc[1], ''); + } + calc = form3.exec(line); + if (calc) { + metadataToSourceLine[calc[1]] = calc[2]; + return ';'; // return an empty line, to keep line numbers of subsequent lines the same + } + calc = form4.exec(line) || form5.exec(line); + if (calc) return ';'; + return line; + }, this); + + this.llvmLineToSourceLine = {}; + for (var l in llvmLineToMetadata) { + this.llvmLineToSourceLine[l] = metadataToSourceLine[llvmLineToMetadata[l]]; + } + this.on = true; + + return ret; + }, +}; + //! @param parseFunctions We parse functions only on later passes, since we do not //! want to parse all of them at once, and have all their //! lines and data in memory at the same time. @@ -25,6 +64,13 @@ function intertyper(data, parseFunctions, baseLineNum) { dprint('LLVM_STYLE: ' + LLVM_STYLE); } + // If the source contains debug info as LLVM metadata, process that out (and save the debugging info for later) + if (/!\d+ = metadata .*/.exec(data[data.length-1])) { // Fast test to see if we have metadata. If this fails when it shouldn't, we should generalize + data = Debugging.processMetadata(data); + //print(data.join('\n')); + //dprint(JSON.stringify(Debugging)); + } + substrate = new Substrate('Intertyper'); // Line splitter. diff --git a/src/jsifier.js b/src/jsifier.js index 765c41f8..32cf263d 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -436,7 +436,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria ret += indent + 'if (Date.now() - START_TIME >= ' + (EXECUTION_TIMEOUT*1000) + ') throw "Timed out!" + (new Error().stack);\n'; } // for special labels we care about (for phi), mark that we visited them - return ret + label.lines.map(function(line) { return line.JS + (line.comment ? ' // ' + line.comment : '') }) + return ret + label.lines.map(function(line) { return line.JS + (Debugging.on ? ' //@line ' + Debugging.llvmLineToSourceLine[line.lineNum] : '') }) .join('\n') .split('\n') // some lines include line breaks .map(function(line) { return indent + line }) diff --git a/tests/runner.py b/tests/runner.py index d936f10d..1e6ef8d6 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -132,7 +132,7 @@ class RunnerCore(unittest.TestCase): os.remove(f + '.o.ll') except: pass - output = Popen([COMPILER, '-DEMSCRIPTEN', '-emit-llvm'] + COMPILER_OPTS + + output = Popen([COMPILER, '-DEMSCRIPTEN', '-emit-llvm'] + COMPILER_OPTS + COMPILER_TEST_OPTS + ['-I', dirname, '-I', os.path.join(dirname, 'include')] + map(lambda include: '-I' + include, includes) + ['-c', f, '-o', f + '.o'], @@ -1713,13 +1713,41 @@ if 'benchmark' not in sys.argv: # This test *should* fail, by throwing this exception assert 'Overflow!' in str(e), str(e) + def test_debug(self): + global COMPILER_TEST_OPTS + COMPILER_TEST_OPTS = ['-g'] + src = ''' + #include <stdio.h> + #include <assert.h> + + void checker(int x) { + x += 20; + assert(x < 15); // this is line 7! + } + + int main() { + checker(10); + return 0; + } + ''' + try: + def post(filename): + lines = open(filename, 'r').readlines() + line = filter(lambda line: '___assert_fail(' in line, lines)[0] + assert '//@line 7\n' in line, 'Must have debug info with the line number' + self.do_test(src, '*nothingatall*', post_build=post) + except Exception, e: + # This test *should* fail + assert 'Assertion failed' in str(e), str(e) + # Generate tests for all our compilers def make_test(name, compiler, llvm_opts, embetter): exec(''' class %s(T): def setUp(self): - global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS, LLVM_OPTS, SAFE_HEAP, CHECK_OVERFLOWS, CORRECT_OVERFLOWS, GUARD_SIGNS + global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS, LLVM_OPTS, SAFE_HEAP, CHECK_OVERFLOWS, CORRECT_OVERFLOWS, GUARD_SIGNS, COMPILER_TEST_OPTS + COMPILER = '%s' QUANTUM_SIZE = %d llvm_opts = %d @@ -1733,6 +1761,7 @@ class %s(T): GUARD_SIGNS = 0 if LLVM_OPTS: self.pick_llvm_opts(3, True) + COMPILER_TEST_OPTS = [] shutil.rmtree(self.get_dir()) self.get_dir() # make sure it exists TT = %s |