aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/embind/shell.html6
-rwxr-xr-xtests/fuzz/creduce_tester.py54
-rwxr-xr-xtests/fuzz/csmith_driver.py30
-rw-r--r--tests/hello_world_gles_shell.html3
-rwxr-xr-xtests/runner.py544
5 files changed, 367 insertions, 270 deletions
diff --git a/tests/embind/shell.html b/tests/embind/shell.html
index 6664ec78..c3655e03 100644
--- a/tests/embind/shell.html
+++ b/tests/embind/shell.html
@@ -85,10 +85,6 @@
};
Module.setStatus('Downloading...');
</script>
- <script type='text/javascript'>
-
- {{{ SCRIPT_CODE }}}
-
- </script>
+ <script type='text/javascript'>{{{ SCRIPT_CODE }}}</script>
</body>
</html>
diff --git a/tests/fuzz/creduce_tester.py b/tests/fuzz/creduce_tester.py
index c3460e9d..d5618c2e 100755
--- a/tests/fuzz/creduce_tester.py
+++ b/tests/fuzz/creduce_tester.py
@@ -1,53 +1,53 @@
#!/usr/bin/python
'''
-Runs csmith, a C fuzzer, and looks for bugs
+Usage: creduce ./creduce_tester.py newfail1.c
'''
-import os, sys, difflib
+import os, sys
from subprocess import Popen, PIPE, STDOUT
sys.path += [os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'tools')]
-import shared
+import shared, jsrun
+
+# creduce will only pass the filename of the C file as the first arg, so other
+# configuration options will have to be hardcoded.
+CSMITH_CFLAGS = ['-I', os.path.join(os.environ['CSMITH_PATH'], 'runtime')]
+ENGINE = shared.JS_ENGINES[0]
+EMCC_ARGS = ['-O2', '-s', 'ASM_JS=1', '-s', 'PRECISE_I64_MATH=1', '-s',
+ 'PRECISE_I32_MUL=1']
filename = sys.argv[1]
+obj_filename = os.path.splitext(filename)[0]
+js_filename = obj_filename + '.js'
print 'testing file', filename
-print '2) Compile natively'
-shared.try_delete(filename)
-shared.execute([shared.CLANG_CC, '-O2', filename + '.c', '-o', filename] + CSMITH_CFLAGS, stderr=PIPE)
-assert os.path.exists(filename)
-print '3) Run natively'
try:
- correct = shared.timeout_run(Popen([filename], stdout=PIPE, stderr=PIPE), 3)
+ print '2) Compile natively'
+ shared.check_execute([shared.CLANG_CC, '-O2', filename, '-o', obj_filename] + CSMITH_CFLAGS)
+ print '3) Run natively'
+ correct = jsrun.timeout_run(Popen([obj_filename], stdout=PIPE, stderr=PIPE), 3)
except Exception, e:
print 'Failed or infinite looping in native, skipping', e
- notes['invalid'] += 1
- os.exit(0) # boring
+ sys.exit(1) # boring
print '4) Compile JS-ly and compare'
def try_js(args):
- shared.try_delete(filename + '.js')
- shared.execute([shared.EMCC, '-O2', '-s', 'ASM_JS=1', '-s', 'PRECISE_I64_MATH=1', '-s', 'PRECISE_I32_MUL=1', filename + '.c', '-o', filename + '.js'] + CSMITH_CFLAGS + args, stderr=PIPE)
- assert os.path.exists(filename + '.js')
- js = shared.run_js(filename + '.js', stderr=PIPE, engine=engine1)
- assert correct == js, ''.join([a.rstrip()+'\n' for a in difflib.unified_diff(correct.split('\n'), js.split('\n'), fromfile='expected', tofile='actual')])
+ shared.check_execute([shared.EMCC] + EMCC_ARGS + CSMITH_CFLAGS + args +
+ [filename, '-o', js_filename])
+ js = shared.run_js(js_filename, stderr=PIPE, engine=ENGINE)
+ assert correct == js
# Try normally, then try unaligned because csmith does generate nonportable code that requires x86 alignment
-ok = False
-normal = True
-for args, note in [([], None), (['-s', 'UNALIGNED_MEMORY=1'], 'unaligned')]:
+# If you are sure that alignment is not the cause, disable it for a faster reduction
+for args in [[]]:
try:
try_js(args)
- ok = True
- if note:
- notes[note] += 1
break
except Exception, e:
- print e
- normal = False
-if not ok: sys.exit(1)
-
-sys.exit(0) # boring
+ pass
+else:
+ sys.exit(0)
+sys.exit(1) # boring
diff --git a/tests/fuzz/csmith_driver.py b/tests/fuzz/csmith_driver.py
index b60e67f7..c987a3be 100755
--- a/tests/fuzz/csmith_driver.py
+++ b/tests/fuzz/csmith_driver.py
@@ -1,11 +1,14 @@
#!/usr/bin/python
'''
-Runs csmith, a C fuzzer, and looks for bugs
+Runs csmith, a C fuzzer, and looks for bugs.
+
+CSMITH_PATH should be set to something like /usr/local/include/csmith
'''
import os, sys, difflib, shutil
-from subprocess import Popen, PIPE, STDOUT
+from distutils.spawn import find_executable
+from subprocess import check_call, Popen, PIPE, STDOUT, CalledProcessError
sys.path += [os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'tools')]
import shared
@@ -15,8 +18,11 @@ engine2 = eval('shared.' + sys.argv[2]) if len(sys.argv) > 2 else None
print 'testing js engines', engine1, engine2
-CSMITH = os.path.expanduser('~/Dev/csmith/src/csmith')
-CSMITH_CFLAGS = ['-I' + os.path.expanduser('~/Dev/csmith/runtime/')]
+CSMITH = os.environ.get('CSMITH') or find_executable('csmith')
+assert CSMITH, 'Could not find CSmith on your PATH. Please set the environment variable CSMITH.'
+CSMITH_PATH = os.environ.get('CSMITH_PATH')
+assert CSMITH_PATH, 'Please set the environment variable CSMITH_PATH.'
+CSMITH_CFLAGS = ['-I', os.path.join(CSMITH_PATH, 'runtime')]
filename = os.path.join(shared.CANONICAL_TEMP_DIR, 'fuzzcode')
@@ -31,7 +37,7 @@ fails = 0
while 1:
print 'Tried %d, notes: %s' % (tried, notes)
print '1) Generate C'
- shared.execute([CSMITH, '--no-volatiles', '--no-math64', '--no-packed-struct'],# +
+ check_call([CSMITH, '--no-volatiles', '--no-math64', '--no-packed-struct'],# +
#['--max-block-depth', '2', '--max-block-size', '2', '--max-expr-complexity', '2', '--max-funcs', '2'],
stdout=open(filename + '.c', 'w'))
#shutil.copyfile(filename + '.c', 'testcase%d.c' % tried)
@@ -41,11 +47,11 @@ while 1:
print '2) Compile natively'
shared.try_delete(filename)
- shared.execute([shared.CLANG_CC, '-O2', filename + '.c', '-o', filename + '1'] + CSMITH_CFLAGS, stderr=PIPE) # + shared.EMSDK_OPTS
- shared.execute([shared.CLANG_CC, '-O2', '-emit-llvm', '-c', '-Xclang', '-triple=i386-pc-linux-gnu', filename + '.c', '-o', filename + '.bc'] + CSMITH_CFLAGS + shared.EMSDK_OPTS, stderr=PIPE)
- shared.execute([shared.path_from_root('tools', 'nativize_llvm.py'), filename + '.bc'], stdout=PIPE, stderr=PIPE)
+ shared.check_execute([shared.CLANG_CC, '-O2', filename + '.c', '-o', filename + '1'] + CSMITH_CFLAGS) # + shared.EMSDK_OPTS
+ shared.check_execute([shared.CLANG_CC, '-O2', '-emit-llvm', '-c', '-Xclang', '-triple=i386-pc-linux-gnu', filename + '.c', '-o', filename + '.bc'] + CSMITH_CFLAGS + shared.EMSDK_OPTS)
+ shared.check_execute([shared.path_from_root('tools', 'nativize_llvm.py'), filename + '.bc'])
shutil.move(filename + '.bc.run', filename + '2')
- shared.execute([shared.CLANG_CC, filename + '.c', '-o', filename + '3'] + CSMITH_CFLAGS, stderr=PIPE)
+ shared.check_execute([shared.CLANG_CC, filename + '.c', '-o', filename + '3'] + CSMITH_CFLAGS)
print '3) Run natively'
try:
correct1 = shared.jsrun.timeout_run(Popen([filename + '1'], stdout=PIPE, stderr=PIPE), 3)
@@ -65,7 +71,7 @@ while 1:
def try_js(args):
shared.try_delete(filename + '.js')
print '(compile)'
- shared.execute([shared.EMCC, '-O2', '-s', 'ASM_JS=1', filename + '.c', '-o', filename + '.js'] + CSMITH_CFLAGS + args, stderr=PIPE)
+ shared.check_execute([shared.EMCC, '-O2', '-s', 'ASM_JS=1', filename + '.c', '-o', filename + '.js'] + CSMITH_CFLAGS + args)
assert os.path.exists(filename + '.js')
print '(run)'
js = shared.run_js(filename + '.js', stderr=PIPE, engine=engine1, check_timeout=True)
@@ -91,7 +97,7 @@ while 1:
print "EMSCRIPTEN BUG"
notes['embug'] += 1
fails += 1
- shutil.copyfile('fuzzcode.c', 'newfail%d.c' % fails)
+ shutil.copyfile(filename + '.c', 'newfail%d.c' % fails)
continue
#if not ok:
# try: # finally, try with safe heap. if that is triggered, this is nonportable code almost certainly
@@ -118,7 +124,7 @@ while 1:
print "ODIN VALIDATION BUG"
notes['embug'] += 1
fails += 1
- shutil.copyfile('fuzzcode.c', 'newfail%d.c' % fails)
+ shutil.copyfile(filename + '.c', 'newfail%d.c' % fails)
continue
js2 = js2.replace('\nwarning: Successfully compiled asm.js code\n', '')
diff --git a/tests/hello_world_gles_shell.html b/tests/hello_world_gles_shell.html
index 4abee90c..2459d755 100644
--- a/tests/hello_world_gles_shell.html
+++ b/tests/hello_world_gles_shell.html
@@ -48,9 +48,8 @@
}
Module.postRun = doTest;
- // The compiled code
- {{{ SCRIPT_CODE }}}
</script>
+ <script>{{{ SCRIPT_CODE }}}</script>
</body>
</html>
diff --git a/tests/runner.py b/tests/runner.py
index 2c459f6f..2ce72240 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -170,16 +170,13 @@ class RunnerCore(unittest.TestCase):
post1 = post_build
post2 = None
- def run_post(post):
- if not post: return
- exec post in locals()
- shutil.copyfile(filename + '.o.js', filename + '.o.js.prepost.js')
- process(filename + '.o.js')
-
if self.emcc_args is None:
Building.emscripten(filename, append_ext=True, extra_args=extra_emscripten_args)
- run_post(post1)
- run_post(post2)
+ if post1:
+ exec post1 in locals()
+ shutil.copyfile(filename + '.o.js', filename + '.o.js.prepost.js')
+ process(filename + '.o.js')
+ if post2: post2(filename + '.o.js')
else:
transform_args = []
if post1:
@@ -196,7 +193,7 @@ process(sys.argv[1])
transform.close()
transform_args = ['--js-transform', "%s %s" % (PYTHON, transform_filename)]
Building.emcc(filename + '.o.ll', Settings.serialize() + self.emcc_args + transform_args + Building.COMPILER_TEST_OPTS, filename + '.o.js')
- run_post(post2)
+ if post2: post2(filename + '.o.js')
# Build JavaScript code from source code
def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None, extra_emscripten_args=[], post_build=None):
@@ -233,11 +230,11 @@ process(sys.argv[1])
os.remove(f + '.o')
except:
pass
- args = [PYTHON, EMCC] + Building.COMPILER_TEST_OPTS + \
+ args = [PYTHON, EMCC] + Building.COMPILER_TEST_OPTS + Settings.serialize() + \
['-I', dirname, '-I', os.path.join(dirname, 'include')] + \
map(lambda include: '-I' + include, includes) + \
['-c', f, '-o', f + '.o']
- output = Popen(args, stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
+ output = Popen(args, stdout=PIPE, stderr=self.stderr_redirect if not DEBUG else None).communicate()[0]
assert os.path.exists(f + '.o'), 'Source compilation error: ' + output
# Link all files
@@ -438,7 +435,7 @@ process(sys.argv[1])
sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv)
-test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2g', 'asm2x86', 's_0_0', 's_0_1', 's_1_0', 's_1_1']
+test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2g', 'asm2x86', 's_0_0', 's_0_1']
test_index = 0
@@ -2107,12 +2104,12 @@ Succeeded!
}
return int(&x); // both for the number, and forces x to not be nativized
}
- int main()
+ int main(int argc, char **argv)
{
// We should get the same value for the first and last - stack has unwound
- int x1 = test(0);
+ int x1 = test(argc - 2);
int x2 = test(100);
- int x3 = test(0);
+ int x3 = test((argc - 2) / 4);
printf("*%d,%d*\\n", x3-x1, x2 != x1);
return 0;
}
@@ -4082,7 +4079,7 @@ def process(filename):
#include <assert.h>
#include "emscripten.h"
- int main()
+ int main(int argc, char **argv)
{
char *buf1 = (char*)malloc(100);
char *data1 = "hello";
@@ -4096,6 +4093,8 @@ def process(filename):
int totalMemory = emscripten_run_script_int("TOTAL_MEMORY");
char *buf3 = (char*)malloc(totalMemory+1);
+ buf3[argc] = (int)buf2;
+ if (argc % 7 == 6) printf("%d\n", memcpy(buf3, buf1, argc));
char *buf4 = (char*)malloc(100);
float *buf5 = (float*)malloc(100);
//printf("totalMemory: %d bufs: %d,%d,%d,%d,%d\n", totalMemory, buf1, buf2, buf3, buf4, buf5);
@@ -4233,6 +4232,8 @@ def process(filename):
''', args=['34962', '26214', '35040'])
def test_indirectbr(self):
+ Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS)
+
src = '''
#include <stdio.h>
int main(void) {
@@ -7553,11 +7554,11 @@ def process(filename):
return 0;
}
'''
- self.do_run(src, '''www.cheezburger.com : 1 : 4
+ self.do_run(src, '''www.cheezburger.com : 2 : 4
* -84.29.1.0.
-fail.on.this.never.work : 1 : 4
+fail.on.this.never.work : 2 : 4
* -84.29.2.0.
-localhost : 1 : 4
+localhost : 2 : 4
* -84.29.3.0.
''')
@@ -8220,7 +8221,7 @@ void*:16
if self.run_name == 'o2':
self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
- Building.COMPILER_TEST_OPTS = [] # remove -g, so we have one test without it by default
+ Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS) # remove -g, so we have one test without it by default
if self.emcc_args is None: Settings.SAFE_HEAP = 0 # Has some actual loads of unwritten-to places, in the C++ code...
# Overflows happen in hash loop
@@ -8252,7 +8253,7 @@ void*:16
def test_gcc_unmangler(self):
Settings.NAMED_GLOBALS = 1 # test coverage for this
- Building.COMPILER_TEST_OPTS = ['-I' + path_from_root('third_party')]
+ Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('third_party')]
self.do_run(open(path_from_root('third_party', 'gcc_demangler.c')).read(), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'])
@@ -8367,6 +8368,8 @@ def process(filename):
force_c=True)
def test_zlib(self):
+ if not Settings.USE_TYPED_ARRAYS == 2: return self.skip('works in general, but cached build will be optimized and fail, so disable this')
+
if Settings.ASM_JS:
self.banned_js_engines = [NODE_JS] # TODO investigate
@@ -8475,6 +8478,8 @@ def process(filename):
def test_openjpeg(self):
if self.emcc_args is None: return self.skip('needs libc for getopt')
+ Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS) # remove -g, so we have one test without it by default
+
if Settings.USE_TYPED_ARRAYS == 2:
Settings.CORRECT_SIGNS = 1
else:
@@ -8596,6 +8601,7 @@ def process(filename):
def test_python(self):
if self.emcc_args is None: return self.skip('requires emcc')
if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work')
+ if not self.is_le32(): return self.skip('fails on non-le32') # FIXME
#Settings.EXPORTED_FUNCTIONS += ['_PyRun_SimpleStringFlags'] # for the demo
@@ -8695,6 +8701,7 @@ def process(filename):
def test_autodebug(self):
if Building.LLVM_OPTS: return self.skip('LLVM opts mess us up')
+ Building.COMPILER_TEST_OPTS += ['--llvm-opts', '0']
# Run a test that should work, generating some code
self.test_structs()
@@ -8973,13 +8980,11 @@ def process(filename):
self.do_run(src, output)
shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('normal.js'))
- self.emcc_args.append('-s')
- self.emcc_args.append('ASM_JS=0')
+ Settings.ASM_JS = 0
Settings.PGO = 1
self.do_run(src, output)
+ Settings.ASM_JS = 1
Settings.PGO = 0
- self.emcc_args.append('-s')
- self.emcc_args.append('ASM_JS=1')
shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgo.js'))
pgo_output = run_js(self.in_dir('pgo.js')).split('\n')[1]
@@ -9215,97 +9220,92 @@ def process(filename):
src.close()
'''
- post3 = '''
-def process(filename):
- script_src_2 = \'\'\'
- var sme = new Module.Parent(42);
- sme.mulVal(2);
- Module.print('*')
- Module.print(sme.getVal());
-
- Module.print('c1');
-
- var c1 = new Module.Child1();
- Module.print(c1.getVal());
- c1.mulVal(2);
- Module.print(c1.getVal());
- Module.print(c1.getValSqr());
- Module.print(c1.getValSqr(3));
- Module.print(c1.getValTimes()); // default argument should be 1
- Module.print(c1.getValTimes(2));
-
- Module.print('c1 v2');
-
- c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2
- Module.print(c1.getVal());
- c1.mulVal(2);
- Module.print(c1.getVal());
- Module.print(c1.getValSqr());
- Module.print(c1.getValSqr(3));
-
- Module.print('c2')
-
- var c2 = new Module.Child2();
- Module.print(c2.getVal());
- c2.mulVal(2);
- Module.print(c2.getVal());
- Module.print(c2.getValCube());
- var succeeded;
- try {
- succeeded = 0;
- Module.print(c2.doSomethingSecret()); // should fail since private
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
- try {
- succeeded = 0;
- Module.print(c2.getValSqr()); // function from the other class
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
- try {
- succeeded = 0;
- c2.getValCube(); // sanity
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
-
- Module.Child2.prototype.printStatic(); // static calls go through the prototype
-
- // virtual function
- c2.virtualFunc();
- Module.Child2.prototype.runVirtualFunc(c2);
- c2.virtualFunc2();
-
-''' + ('''
- // extend the class from JS
- var c3 = new Module.Child2;
- Module.customizeVTable(c3, [{
- original: Module.Child2.prototype.virtualFunc,
- replacement: function() {
- Module.print('*js virtualf replacement*');
- }
- }, {
- original: Module.Child2.prototype.virtualFunc2,
- replacement: function() {
- Module.print('*js virtualf2 replacement*');
- }
- }]);
- c3.virtualFunc();
- Module.Child2.prototype.runVirtualFunc(c3);
- c3.virtualFunc2();
-
- c2.virtualFunc(); // original should remain the same
- Module.Child2.prototype.runVirtualFunc(c2);
- c2.virtualFunc2();
-''') + '''
-
- Module.print('*ok*');
- \'\'\'
- src = open(filename, 'a')
- src.write(script_src_2 + '\\n')
- src.close()
-'''
+ def post3(filename):
+ script_src_2 = '''
+ var sme = new Module.Parent(42);
+ sme.mulVal(2);
+ Module.print('*')
+ Module.print(sme.getVal());
+
+ Module.print('c1');
+
+ var c1 = new Module.Child1();
+ Module.print(c1.getVal());
+ c1.mulVal(2);
+ Module.print(c1.getVal());
+ Module.print(c1.getValSqr());
+ Module.print(c1.getValSqr(3));
+ Module.print(c1.getValTimes()); // default argument should be 1
+ Module.print(c1.getValTimes(2));
+
+ Module.print('c1 v2');
+
+ c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2
+ Module.print(c1.getVal());
+ c1.mulVal(2);
+ Module.print(c1.getVal());
+ Module.print(c1.getValSqr());
+ Module.print(c1.getValSqr(3));
+
+ Module.print('c2')
+
+ var c2 = new Module.Child2();
+ Module.print(c2.getVal());
+ c2.mulVal(2);
+ Module.print(c2.getVal());
+ Module.print(c2.getValCube());
+ var succeeded;
+ try {
+ succeeded = 0;
+ Module.print(c2.doSomethingSecret()); // should fail since private
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+ try {
+ succeeded = 0;
+ Module.print(c2.getValSqr()); // function from the other class
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+ try {
+ succeeded = 0;
+ c2.getValCube(); // sanity
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+
+ Module.Child2.prototype.printStatic(); // static calls go through the prototype
+
+ // virtual function
+ c2.virtualFunc();
+ Module.Child2.prototype.runVirtualFunc(c2);
+ c2.virtualFunc2();
+
+ // extend the class from JS
+ var c3 = new Module.Child2;
+ Module.customizeVTable(c3, [{
+ original: Module.Child2.prototype.virtualFunc,
+ replacement: function() {
+ Module.print('*js virtualf replacement*');
+ }
+ }, {
+ original: Module.Child2.prototype.virtualFunc2,
+ replacement: function() {
+ Module.print('*js virtualf2 replacement*');
+ }
+ }]);
+ c3.virtualFunc();
+ Module.Child2.prototype.runVirtualFunc(c3);
+ c3.virtualFunc2();
+
+ c2.virtualFunc(); // original should remain the same
+ Module.Child2.prototype.runVirtualFunc(c2);
+ c2.virtualFunc2();
+ Module.print('*ok*');
+ '''
+ src = open(filename, 'a')
+ src.write(script_src_2 + '\n')
+ src.close()
Settings.RESERVED_FUNCTION_POINTERS = 20
@@ -9349,7 +9349,7 @@ Child2:9
*virtualf*
*virtualf2*''') + '''
*ok*
-''', post_build=[post2, post3])
+''', post_build=(post2, post3))
def test_scriptaclass_2(self):
if self.emcc_args is None: return self.skip('requires emcc')
@@ -9578,25 +9578,138 @@ def process(filename):
}
'''
try:
- post = r'''
-def process(filename):
- lines = open(filename, 'r').readlines()
- lines = filter(lambda line: '___assert_fail(' in line or '___assert_func(' in line, lines)
- found_line_num = any(('//@line 7 "' in line) for line in lines)
- found_filename = any(('src.cpp"\n' in line) for line in lines)
- assert found_line_num, 'Must have debug info with the line number'
- assert found_filename, 'Must have debug info with the filename'
-'''
- self.do_run(src, '*nothingatall*', post_build=post)
+ self.do_run(src, '*nothingatall*')
except Exception, e:
# This test *should* fail
- assert 'Assertion failed' in str(e), str(e)
+ assert 'Assertion failed: x < 15' in str(e), str(e)
+
+ lines = open('src.cpp.o.js', 'r').readlines()
+ lines = filter(lambda line: '___assert_fail(' in line or '___assert_func(' in line, lines)
+ found_line_num = any(('//@line 7 "' in line) for line in lines)
+ found_filename = any(('src.cpp"\n' in line) for line in lines)
+ assert found_line_num, 'Must have debug info with the line number'
+ assert found_filename, 'Must have debug info with the filename'
+
+ def test_source_map(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays")
+ if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run')
+ if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
+
+ src = '''
+ #include <stdio.h>
+ #include <assert.h>
+
+ __attribute__((noinline)) int foo() {
+ printf("hi"); // line 6
+ return 1; // line 7
+ }
+
+ int main() {
+ printf("%d", foo()); // line 11
+ return 0; // line 12
+ }
+ '''
+
+ dirname = self.get_dir()
+ src_filename = os.path.join(dirname, 'src.cpp')
+ out_filename = os.path.join(dirname, 'a.out.js')
+ no_maps_filename = os.path.join(dirname, 'no-maps.out.js')
+
+ with open(src_filename, 'w') as f: f.write(src)
+ assert '-g4' not in Building.COMPILER_TEST_OPTS
+ Building.emcc(src_filename, Settings.serialize() + self.emcc_args +
+ Building.COMPILER_TEST_OPTS, out_filename)
+ # the file name may find its way into the generated code, so make sure we
+ # can do an apples-to-apples comparison by compiling with the same file name
+ shutil.move(out_filename, no_maps_filename)
+ with open(no_maps_filename) as f: no_maps_file = f.read()
+ no_maps_file = re.sub(' *//@.*$', '', no_maps_file, flags=re.MULTILINE)
+ Building.COMPILER_TEST_OPTS.append('-g4')
+
+ def build_and_check():
+ import json
+ Building.emcc(src_filename, Settings.serialize() + self.emcc_args +
+ Building.COMPILER_TEST_OPTS, out_filename, stderr=PIPE)
+ with open(out_filename) as f: out_file = f.read()
+ # after removing the @line and @sourceMappingURL comments, the build
+ # result should be identical to the non-source-mapped debug version.
+ # this is worth checking because the parser AST swaps strings for token
+ # objects when generating source maps, so we want to make sure the
+ # optimizer can deal with both types.
+ out_file = re.sub(' *//@.*$', '', out_file, flags=re.MULTILINE)
+ self.assertIdentical(no_maps_file, out_file)
+ map_filename = out_filename + '.map'
+ data = json.load(open(map_filename, 'r'))
+ self.assertIdentical(out_filename, data['file'])
+ self.assertIdentical(src_filename, data['sources'][0])
+ self.assertIdentical(src, data['sourcesContent'][0])
+ mappings = json.loads(jsrun.run_js(
+ path_from_root('tools', 'source-maps', 'sourcemap2json.js'),
+ tools.shared.NODE_JS, [map_filename]))
+ seen_lines = set()
+ for m in mappings:
+ self.assertIdentical(src_filename, m['source'])
+ seen_lines.add(m['originalLine'])
+ # ensure that all the 'meaningful' lines in the original code get mapped
+ assert seen_lines.issuperset([6, 7, 11, 12])
+
+ # EMCC_DEBUG=2 causes lots of intermediate files to be written, and so
+ # serves as a stress test for source maps because it needs to correlate
+ # line numbers across all those files.
+ old_emcc_debug = os.environ.get('EMCC_DEBUG', None)
+ os.environ.pop('EMCC_DEBUG', None)
+ try:
+ build_and_check()
+ os.environ['EMCC_DEBUG'] = '2'
+ build_and_check()
+ finally:
+ if old_emcc_debug is not None:
+ os.environ['EMCC_DEBUG'] = old_emcc_debug
+ else:
+ os.environ.pop('EMCC_DEBUG', None)
+
+ def test_exception_source_map(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays")
+ if '-g4' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g4')
+ if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run')
+
+ src = '''
+ #include <stdio.h>
+
+ __attribute__((noinline)) void foo(int i) {
+ if (i < 10) throw i; // line 5
+ }
+
+ int main() {
+ int i;
+ scanf("%d", &i);
+ foo(i);
+ return 0;
+ }
+ '''
+
+ def post(filename):
+ import json
+ map_filename = filename + '.map'
+ mappings = json.loads(jsrun.run_js(
+ path_from_root('tools', 'source-maps', 'sourcemap2json.js'),
+ tools.shared.NODE_JS, [map_filename]))
+ with open(filename) as f: lines = f.readlines()
+ for m in mappings:
+ if m['originalLine'] == 5 and '__cxa_throw' in lines[m['generatedLine']]:
+ return
+ assert False, 'Must label throw statements with line numbers'
+
+ dirname = self.get_dir()
+ self.build(src, dirname, os.path.join(dirname, 'src.cpp'), post_build=(None, post))
def test_linespecific(self):
if Settings.ASM_JS: return self.skip('asm always has corrections on')
if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
- if self.emcc_args: self.emcc_args += ['--llvm-opts', '0'] # llvm full opts make the expected failures here not happen
+ if self.emcc_args:
+ self.emcc_args += ['--llvm-opts', '0'] # llvm full opts make the expected failures here not happen
+ Building.COMPILER_TEST_OPTS += ['--llvm-opts', '0']
Settings.CHECK_SIGNS = 0
Settings.CHECK_OVERFLOWS = 0
@@ -9902,7 +10015,7 @@ finalizing 3 (global == 0)
''')
# Generate tests for everything
- def make_run(fullname, name=-1, compiler=-1, llvm_opts=0, embetter=0, quantum_size=0, typed_arrays=0, emcc_args=None, env='{}'):
+ def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0, typed_arrays=0, emcc_args=None, env='{}'):
exec('''
class %s(T):
run_name = '%s'
@@ -9937,9 +10050,18 @@ class %s(T):
Building.LLVM_OPTS = 0
if '-O2' in self.emcc_args:
Building.COMPILER_TEST_OPTS = [] # remove -g in -O2 tests, for more coverage
+ #Building.COMPILER_TEST_OPTS += self.emcc_args
+ for arg in self.emcc_args:
+ if arg.startswith('-O'):
+ Building.COMPILER_TEST_OPTS.append(arg) # so bitcode is optimized too, this is for cpp to ll
+ else:
+ try:
+ key, value = arg.split('=')
+ Settings[key] = value # forward -s K=V
+ except:
+ pass
return
- llvm_opts = %d # 1 is yes, 2 is yes and unsafe
embetter = %d
quantum_size = %d
# TODO: Move much of these to a init() function in shared.py, and reuse that
@@ -9949,14 +10071,13 @@ class %s(T):
Settings.MICRO_OPTS = embetter
Settings.QUANTUM_SIZE = quantum_size
Settings.ASSERTIONS = 1-embetter
- Settings.SAFE_HEAP = 1-(embetter and llvm_opts)
- Building.LLVM_OPTS = llvm_opts
- Settings.CHECK_OVERFLOWS = 1-(embetter or llvm_opts)
- Settings.CORRECT_OVERFLOWS = 1-(embetter and llvm_opts)
+ Settings.SAFE_HEAP = 1-embetter
+ Settings.CHECK_OVERFLOWS = 1-embetter
+ Settings.CORRECT_OVERFLOWS = 1-embetter
Settings.CORRECT_SIGNS = 0
Settings.CORRECT_ROUNDINGS = 0
Settings.CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = []
- Settings.CHECK_SIGNS = 0 #1-(embetter or llvm_opts)
+ Settings.CHECK_SIGNS = 0 #1-embetter
Settings.RUNTIME_TYPE_INFO = 0
Settings.DISABLE_EXCEPTION_CATCHING = 0
Settings.INCLUDE_FULL_LIBRARY = 0
@@ -9965,12 +10086,10 @@ class %s(T):
Settings.EMULATE_UNALIGNED_ACCESSES = int(Settings.USE_TYPED_ARRAYS == 2 and Building.LLVM_OPTS == 2)
Settings.DOUBLE_MODE = 1 if Settings.USE_TYPED_ARRAYS and Building.LLVM_OPTS == 0 else 0
Settings.PRECISE_I64_MATH = 0
- Settings.NAMED_GLOBALS = 0 if not (embetter and llvm_opts) else 1
-
- Building.pick_llvm_opts(3)
+ Settings.NAMED_GLOBALS = 0 if not embetter else 1
TT = %s
-''' % (fullname, fullname, env, fullname, fullname, compiler, str(emcc_args), llvm_opts, embetter, quantum_size, typed_arrays, fullname))
+''' % (fullname, fullname, env, fullname, fullname, compiler, str(emcc_args), embetter, quantum_size, typed_arrays, fullname))
return TT
# Make one run with the defaults
@@ -9989,16 +10108,14 @@ TT = %s
exec('''asm2x86 = make_run("asm2x86", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "CHECK_HEAP_ALIGN=1"], env='{"EMCC_LLVM_TARGET": "i386-pc-linux-gnu"}')''')
# Make custom runs with various options
- for compiler, quantum, embetter, typed_arrays, llvm_opts in [
- (CLANG, 4, 0, 0, 0),
- (CLANG, 4, 0, 0, 1),
- (CLANG, 4, 1, 1, 0),
- (CLANG, 4, 1, 1, 1),
+ for compiler, quantum, embetter, typed_arrays in [
+ (CLANG, 4, 0, 0),
+ (CLANG, 4, 1, 1),
]:
- fullname = 's_%d_%d%s%s' % (
- llvm_opts, embetter, '' if quantum == 4 else '_q' + str(quantum), '' if typed_arrays in [0, 1] else '_t' + str(typed_arrays)
+ fullname = 's_0_%d%s%s' % (
+ embetter, '' if quantum == 4 else '_q' + str(quantum), '' if typed_arrays in [0, 1] else '_t' + str(typed_arrays)
)
- exec('%s = make_run(fullname, %r,%r,%d,%d,%d,%d)' % (fullname, fullname, compiler, llvm_opts, embetter, quantum, typed_arrays))
+ exec('%s = make_run(fullname, %r,%r,%d,%d,%d)' % (fullname, fullname, compiler, embetter, quantum, typed_arrays))
del T # T is just a shape for the specific subclasses, we don't test it itself
@@ -10132,23 +10249,25 @@ Options that are modified or new in %s include:
(['-o', 'something.js', '-O3', '-s', 'ASM_JS=0'], 3, None, 1, 1),
# and, test compiling to bitcode first
(['-o', 'something.bc'], 0, [], 0, 0),
- (['-o', 'something.bc'], 0, ['-O0'], 0, 0),
- (['-o', 'something.bc'], 1, ['-O1'], 0, 0),
- (['-o', 'something.bc'], 2, ['-O2'], 0, 0),
- (['-o', 'something.bc'], 3, ['-O3', '-s', 'ASM_JS=0'], 1, 0),
- (['-O1', '-o', 'something.bc'], 0, [], 0, 0), # -Ox is ignored and warned about
+ (['-o', 'something.bc', '-O0'], 0, [], 0, 0),
+ (['-o', 'something.bc', '-O1'], 1, ['-O1'], 0, 0),
+ (['-o', 'something.bc', '-O2'], 2, ['-O2'], 0, 0),
+ (['-o', 'something.bc', '-O3'], 3, ['-O3', '-s', 'ASM_JS=0'], 1, 0),
+ (['-O1', '-o', 'something.bc'], 1, [], 0, 0),
]:
print params, opt_level, bc_params, closure, has_malloc
self.clear()
keep_debug = '-g' in params
- output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_loop' + ('_malloc' if has_malloc else '') + '.cpp')] + params,
+ args = [PYTHON, compiler, path_from_root('tests', 'hello_world_loop' + ('_malloc' if has_malloc else '') + '.cpp')] + params
+ print '..', args
+ output = Popen(args,
stdout=PIPE, stderr=PIPE).communicate()
assert len(output[0]) == 0, output[0]
if bc_params is not None:
- if '-O1' in params and 'something.bc' in params:
- assert '-Ox flags ignored, since not generating JavaScript' in output[1]
assert os.path.exists('something.bc'), output[1]
- output = Popen([PYTHON, compiler, 'something.bc', '-o', 'something.js'] + bc_params, stdout=PIPE, stderr=PIPE).communicate()
+ bc_args = [PYTHON, compiler, 'something.bc', '-o', 'something.js'] + bc_params
+ print '....', bc_args
+ output = Popen(bc_args, stdout=PIPE, stderr=PIPE).communicate()
assert os.path.exists('something.js'), output[1]
assert ('Applying some potentially unsafe optimizations!' in output[1]) == (opt_level >= 3), 'unsafe warning should appear in opt >= 3'
self.assertContained('hello, world!', run_js('something.js'))
@@ -11397,64 +11516,6 @@ seeked= file.
code = open('a.out.js').read()
assert 'SAFE_HEAP' in code, 'valid -s option had an effect'
- def test_optimize_normally(self):
- assert not os.environ.get('EMCC_OPTIMIZE_NORMALLY')
- assert not os.environ.get('EMCC_DEBUG')
-
- for optimize_normally in [0, 1]:
- print optimize_normally
- try:
- if optimize_normally: os.environ['EMCC_OPTIMIZE_NORMALLY'] = '1'
- os.environ['EMCC_DEBUG'] = '1'
-
- open(self.in_dir('main.cpp'), 'w').write(r'''
- extern "C" {
- void something();
- }
-
- int main() {
- something();
- return 0;
- }
- ''')
- open(self.in_dir('supp.cpp'), 'w').write(r'''
- #include <stdio.h>
-
- extern "C" {
- void something() {
- printf("yello\n");
- }
- }
- ''')
- out, err = Popen([PYTHON, EMCC, self.in_dir('main.cpp'), '-O2', '-o', 'main.o'], stdout=PIPE, stderr=PIPE).communicate()
- assert ("emcc: LLVM opts: ['-O3']" in err) == optimize_normally
- assert (' with -O3 since EMCC_OPTIMIZE_NORMALLY defined' in err) == optimize_normally
-
- out, err = Popen([PYTHON, EMCC, self.in_dir('supp.cpp'), '-O2', '-o', 'supp.o'], stdout=PIPE, stderr=PIPE).communicate()
- assert ("emcc: LLVM opts: ['-O3']" in err) == optimize_normally
- assert (' with -O3 since EMCC_OPTIMIZE_NORMALLY defined' in err) == optimize_normally
-
- out, err = Popen([PYTHON, EMCC, self.in_dir('main.o'), self.in_dir('supp.o'), '-O2', '-o', 'both.o'], stdout=PIPE, stderr=PIPE).communicate()
- assert "emcc: LLVM opts: ['-O3']" not in err
- assert ' with -O3 since EMCC_OPTIMIZE_NORMALLY defined' not in err
- assert ('despite EMCC_OPTIMIZE_NORMALLY since not sou