aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@mozilla.com>2011-02-12 19:36:02 -0800
committerAlon Zakai <azakai@mozilla.com>2011-02-12 19:36:02 -0800
commitbace573eb4e44e43227d4134e34158969d914efa (patch)
treecb50163af1c4a424132b20e1ded77e5cf8e6f4b2
parentffb61d77cae700fe2f45c60e06715033ae9f653a (diff)
line number debugging info
-rw-r--r--src/intertyper.js46
-rw-r--r--src/jsifier.js2
-rw-r--r--tests/runner.py33
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