diff options
author | Alon Zakai <azakai@mozilla.com> | 2011-02-27 16:54:21 -0800 |
---|---|---|
committer | Alon Zakai <azakai@mozilla.com> | 2011-02-27 16:54:21 -0800 |
commit | 40ab3e284734cd54a4e1342cdd8df483b32078d4 (patch) | |
tree | 984f4bfe85a6dda7a203328dfc70d793a747a2f5 | |
parent | 26ab22af91138dcad765cef82d312c99914b5093 (diff) |
debugging info and test runner fixes
-rw-r--r-- | src/modules.js | 11 | ||||
-rw-r--r-- | src/parseTools.js | 2 | ||||
-rw-r--r-- | tests/runner.py | 128 | ||||
-rwxr-xr-x | tools/emmaken.py | 5 | ||||
-rw-r--r-- | tools/shared.py | 5 |
5 files changed, 119 insertions, 32 deletions
diff --git a/src/modules.js b/src/modules.js index ed3f1f23..4019116f 100644 --- a/src/modules.js +++ b/src/modules.js @@ -16,6 +16,7 @@ var Debugging = { var metadataToSourceLine = {}; var metadataToParentMetadata = {}; var metadataToFilename = {}; + var form1 = new RegExp(/^ .*, !dbg !(\d+)$/); var form2 = new RegExp(/^ .*, !dbg !(\d+) +; \[#uses=\d+\]$/); var form3 = new RegExp(/^!(\d+) = metadata !{i32 (\d+), i32 \d+, metadata !(\d+), .*}$/); @@ -24,12 +25,12 @@ var Debugging = { var form3ac = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !\d+, metadata !"[^"]+", metadata !(\d+)[^\[]* ; \[ DW_TAG_structure_type \]$/); var form3b = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !"([^"]+)", metadata !"([^"]+)", metadata !\d+} ; \[ DW_TAG_file_type \]$/); var form3c = 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 form4 = new RegExp(/^!llvm.dbg.[\w\.]+ = .*$/); + var form5 = new RegExp(/^!(\d+) = metadata !{.*$/); + var form6 = new RegExp(/^ (tail )?call void \@llvm.dbg.\w+\(metadata .*$/); var ret = lines.map(function(line, i) { - if (form6.exec(line)) return null; + if (form6.exec(line)) return ';'; var calc = form1.exec(line) || form2.exec(line); if (calc) { @@ -84,11 +85,13 @@ var Debugging = { }, getComment: function(lineNum) { + if (!this.on) return null; return lineNum in this.llvmLineToSourceLine ? ' //@line ' + this.llvmLineToSourceLine[lineNum] + ' "' + this.llvmLineToSourceFile[lineNum] + '"' : ''; }, getIdentifier: function(lineNum) { + if (!this.on) return null; var sourceFile = this.llvmLineToSourceFile[lineNum]; if (!sourceFile) return null; return sourceFile.split('/').slice(-1)[0] + ':' + this.llvmLineToSourceLine[lineNum]; diff --git a/src/parseTools.js b/src/parseTools.js index a6a1038b..7d90e246 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -556,6 +556,7 @@ function indentify(text, indent) { // Correction tools function correctSpecificSign() { + assert(!(CORRECT_SIGNS === 2 && !Debugging.on), 'Need debugging for line-specific corrections'); return CORRECT_SIGNS === 2 && Debugging.getIdentifier(Framework.currItem.lineNum) in CORRECT_SIGNS_LINES; } function correctSigns() { @@ -563,6 +564,7 @@ function correctSigns() { } function correctSpecificOverflow() { + assert(!(CORRECT_SIGNS === 2 && !Debugging.on), 'Need debugging for line-specific corrections'); return CORRECT_OVERFLOWS === 2 && Debugging.getIdentifier(Framework.currItem.lineNum) in CORRECT_OVERFLOWS_LINES; } function correctOverflows() { diff --git a/tests/runner.py b/tests/runner.py index b775d77c..496f9764 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -5,7 +5,7 @@ See settings.py file for options¶ms. Edit as needed. ''' from subprocess import Popen, PIPE, STDOUT -import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile +import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re # Setup @@ -103,6 +103,9 @@ class RunnerCore(unittest.TestCase): # LLVM binary ==> LLVM assembly Popen([LLVM_DIS, filename + '.o'] + LLVM_DIS_OPTS + ['-o=' + filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0] + def do_link(self, files, target): + Popen([LLVM_LINK] + files + ['-o', target], stdout=PIPE, stderr=STDOUT).communicate()[0] + # Build JavaScript code from source code def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[]): # Copy over necessary files for compiling the source @@ -145,10 +148,8 @@ class RunnerCore(unittest.TestCase): # Link all files if len(additional_files) + len(libraries) > 0: shutil.move(filename + '.o', filename + '.o.alone') - output = Popen([LLVM_LINK, filename + '.o.alone'] + - map(lambda f: f + '.o', additional_files) + - libraries + - ['-o', filename + '.o'], stdout=PIPE, stderr=STDOUT).communicate()[0] + self.do_link([filename + '.o.alone'] + map(lambda f: f + '.o', additional_files) + libraries, + filename + '.o') if not os.path.exists(filename + '.o'): print "Failed to link LLVM binaries:\n\n", output raise Exception("Linkage error"); @@ -175,8 +176,11 @@ class RunnerCore(unittest.TestCase): if output is not None and 'Traceback' in output and 'in test_' in output: print output; assert 0 def run_generated_code(self, engine, filename, args=[], check_timeout=True): - ret = run_js(engine, filename, args, check_timeout) - assert 'strict warning:' not in ret, 'We should pass all strict mode checks' + stdout = os.path.join(self.get_dir(), 'stdout') # use files, as PIPE can get too full and hang us + stderr = os.path.join(self.get_dir(), 'stderr') + run_js(engine, filename, args, check_timeout, stdout=open(stdout, 'w'), stderr=open(stderr, 'w')) + ret = open(stdout, 'r').read() + open(stderr, 'r').read() + assert 'strict warning:' not in ret, 'We should pass all strict mode checks: ' + ret return ret def assertContained(self, value, string): @@ -224,7 +228,7 @@ if 'benchmark' not in sys.argv: #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging def prep_ll_test(self, filename, ll_file): - if ll_file.endswith('.bc'): + if ll_file.endswith(('.bc', '.o')): shutil.copy(ll_file, filename + '.o') self.do_llvm_dis(filename) shutil.copy(filename + '.o.ll', filename + '.o.ll.in') @@ -1536,10 +1540,15 @@ if 'benchmark' not in sys.argv: args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''], output_nicerizer=lambda string: string.replace('\n\n', '\n').replace('\n\n', '\n')) + def get_building_dir(self): + return os.path.join(self.get_dir(), 'building') + # Build a library into a .bc file. We build the .bc file once and cache it for all our tests. (We cache in # memory since the test directory is destroyed and recreated for each test. Note that we cache separately # for different compilers) - def get_library(self, name, generated_lib, make_args=[]): + def get_library(self, name, generated_libs, configure_args=[], make_args=['-j', '2']): + if type(generated_libs) is not list: generated_libs = [generated_libs] + cache_name = name + '|' + COMPILER if GlobalCache.get(cache_name): bc_file = os.path.join(self.get_dir(), 'lib' + name + '.bc') @@ -1548,19 +1557,18 @@ if 'benchmark' not in sys.argv: f.close() return bc_file - temp_dir = os.path.join(self.get_dir(), 'building') - ft_dir = os.path.join(temp_dir, name) - shutil.copytree(path_from_root('tests', name), ft_dir) - os.chdir(ft_dir) + temp_dir = self.get_building_dir() + project_dir = os.path.join(temp_dir, name) + shutil.copytree(path_from_root('tests', name), project_dir) + os.chdir(project_dir) env = os.environ.copy() env['RANLIB'] = env['AR'] = env['CXX'] = env['CC'] = EMMAKEN - env['CFLAGS'] = '%s' % ' '.join(COMPILER_OPTS + COMPILER_TEST_OPTS) env['EMMAKEN_COMPILER'] = COMPILER - Popen(['./configure'], stdout=PIPE, stderr=STDOUT, env=env).communicate()[0] - Popen(['make', '-j', '2'] + make_args, stdout=PIPE, stderr=STDOUT, env=env).communicate()[0] - bc_file = os.path.join(ft_dir, generated_lib) - shutil.copyfile(bc_file, bc_file + '.bc') - bc_file += '.bc' + env['CFLAGS'] = env['EMMAKEN_CFLAGS'] = ' '.join(COMPILER_OPTS + COMPILER_TEST_OPTS) # Normal CFLAGS is ignored by some configure's. + Popen(['./configure'] + configure_args, stdout=PIPE, stderr=STDOUT, env=env).communicate()[0] + Popen(['make'] + make_args, stdout=PIPE, stderr=STDOUT, env=env).communicate()[0] + bc_file = os.path.join(project_dir, 'bc.bc') + self.do_link(map(lambda lib: os.path.join(project_dir, lib), generated_libs), bc_file) GlobalCache[cache_name] = open(bc_file, 'rb').read() return bc_file @@ -1602,10 +1610,82 @@ if 'benchmark' not in sys.argv: self.do_test(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(), open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(), - libraries=[self.get_library('zlib', os.path.join('libz.a'), ['libz.a'])], + libraries=[self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a'])], includes=[path_from_root('tests', 'zlib')], force_c=True) + def zzztest_openjpeg(self): + if COMPILER == LLVM_GCC: return # Not sure why, but fails in gcc - generally correct, but noisy output + + original_j2k = path_from_root('tests', 'openjpeg', 'syntensity_lobby.j2k') + + def post(filename): + src = open(filename, 'r').read().replace( + '// {{PRE_RUN_ADDITIONS}}', + '''this._STDIO.prepare('image.j2k', %s);''' % str( + map(ord, open(original_j2k, 'rb').read()) + ) + ).replace( + '// {{POST_RUN_ADDITIONS}}', + '''print("Data: " + JSON.stringify(this._STDIO.streams[this._STDIO.filenames['image.raw']].data));''' + ) + open(filename, 'w').write(src) + + lib = self.get_library('openjpeg', + [os.path.join('bin', 'libopenjpeg.a'), + os.path.join('codec', 'index.o'), + os.path.join('codec', 'convert.o'), + os.path.join('codec', 'color.o'), + os.path.join('codec', 'getopt.o')], + configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'], + make_args=[]) # no -j 2, since parallel builds can fail + + # We use doubles in JS, so we get slightly different values than native code. So we + # check our output by comparing the average pixel difference + def image_compare(output): + # Get the image generated by JS, from the JSON.stringify'd array + m = re.search('\[[\d, ]*\]', output) + js_data = eval(m.group(0)) + + # Generate the native code output using lli + lli_file = os.path.join(self.get_dir(), 'lli.raw') + stdout = Popen([LLVM_INTERPRETER, os.path.join(self.get_dir(), 'src.c.o'), '-i', original_j2k, '-o', lli_file], + stdout=PIPE, stderr=STDOUT).communicate()[0] + assert 'Successfully generated' in stdout, 'Error in lli run: ' + stdout + lli_data = open(lli_file, 'rb').read() + + # Compare them + assert(len(js_data) == len(lli_data)) + num = len(js_data) + diff_total = js_total = lli_total = 0 + for i in range(num): + js_total += js_data[i] + lli_total += ord(lli_data[i]) + diff_total += abs(js_data[i] - ord(lli_data[i])) + js_mean = js_total/float(num) + lli_mean = lli_total/float(num) + diff_mean = diff_total/float(num) + + image_mean = 83 + assert abs(js_mean - image_mean) < 1 + assert abs(lli_mean - image_mean) < 1 + #print js_mean, image_mean, lli_mean, diff_mean, num + assert diff_mean < 1.1 # 1+epsilon out of 255 values, means basically 1 - a rounding error + + return output + + self.do_test(open(path_from_root('tests', 'openjpeg', 'codec', 'j2k_to_image.c'), 'r').read(), + 'Successfully generated', # The real test for valid output is in image_compare + ['-i', 'image.j2k', '-o', 'image.raw'], + libraries=[lib], + includes=[path_from_root('tests', 'openjpeg', 'libopenjpeg'), + path_from_root('tests', 'openjpeg', 'codec'), + path_from_root('tests', 'openjpeg', 'common'), + os.path.join(self.get_building_dir(), 'openjpeg')], + force_c=True, + post_build=post, + output_nicerizer=image_compare) + def zzztest_poppler(self): # Has 'Object', which has a big union with a value that can be of any type (like a dynamic value) global SAFE_HEAP; SAFE_HEAP = 0 @@ -1728,8 +1808,7 @@ if 'benchmark' not in sys.argv: assert 'CHECK_OVERFLOW' in str(e), str(e) def test_debug(self): - global COMPILER_TEST_OPTS - COMPILER_TEST_OPTS = ['-g'] + global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = ['-g'] src = ''' #include <stdio.h> #include <assert.h> @@ -1755,9 +1834,8 @@ if 'benchmark' not in sys.argv: # This test *should* fail assert 'Assertion failed' in str(e), str(e) - def test_linebyline_corrections(self): - global COMPILER_TEST_OPTS - COMPILER_TEST_OPTS = ['-g'] + def test_linespecific(self): + global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = ['-g'] global CHECK_SIGNS; CHECK_SIGNS = 0 global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0 diff --git a/tools/emmaken.py b/tools/emmaken.py index 3590f86b..b860bacb 100755 --- a/tools/emmaken.py +++ b/tools/emmaken.py @@ -55,11 +55,14 @@ try: CC = to_cc(CXX) CC_ARG_SKIP = ['-O1', '-O2', '-O3'] - CC_ADDITIONAL_ARGS = ['-m32', '-U__i386__', '-U__x86_64__', '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87'] + CC_ADDITIONAL_ARGS = ['-m32', '-U__i386__', '-U__x86_64__', '-U__SSE__', '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87'] ALLOWED_LINK_ARGS = ['-f', '-help', '-o', '-print-after', '-print-after-all', '-print-before', '-print-before-all', '-time-passes', '-v', '-verify-dom-info', '-version' ] DISALLOWED_LINK_ARGS = []#['rc'] + EMMAKEN_CFLAGS = os.environ.get('EMMAKEN_CFLAGS') + if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += EMMAKEN_CFLAGS.split(' ') + # ---------------- End configs ------------- if len(sys.argv) == 2 and 'conftest' not in ' '.join(sys.argv): # Avoid messing with configure, see below too diff --git a/tools/shared.py b/tools/shared.py index 55a8412a..ad3b1912 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -14,6 +14,7 @@ LLVM_OPT=os.path.expanduser(os.path.join(LLVM_ROOT, 'opt')) LLVM_AS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-as')) LLVM_DIS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-dis')) LLVM_DIS_OPTS = ['-show-annotations'] # For LLVM 2.8+. For 2.7, you may need to do just [] +LLVM_INTERPRETER=os.path.expanduser(os.path.join(LLVM_ROOT, 'lli')) # Engine tweaks @@ -32,9 +33,9 @@ def timeout_run(proc, timeout, note): raise Exception("Timed out: " + note) return proc.communicate()[0] -def run_js(engine, filename, args, check_timeout=False): +def run_js(engine, filename, args, check_timeout=False, stdout=PIPE, stderr=STDOUT): return timeout_run(Popen(engine + [filename] + (['--'] if 'v8' in engine[0] else []) + args, - stdout=PIPE, stderr=STDOUT), 120 if check_timeout else None, 'Execution') + stdout=stdout, stderr=stderr), 120 if check_timeout else None, 'Execution') def to_cc(cxx): # By default, LLVM_GCC and CLANG are really the C++ versions. This gets an explicit C version |