diff options
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/runner.py | 100 | ||||
-rw-r--r-- | tests/worker_api_2_main.cpp | 108 | ||||
-rw-r--r-- | tests/worker_api_2_worker.cpp | 44 | ||||
-rw-r--r-- | tests/worker_api_main.cpp | 24 | ||||
-rw-r--r-- | tests/worker_api_worker.cpp | 16 |
5 files changed, 271 insertions, 21 deletions
diff --git a/tests/runner.py b/tests/runner.py index f920defb..71acb4da 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -2742,6 +2742,8 @@ def process(filename): self.do_run(src, 'Inline JS is very cool') def test_memorygrowth(self): + if Settings.USE_TYPED_ARRAYS == 0: return self.skip('memory growth is only supported with typed arrays') + # With typed arrays in particular, it is dangerous to use more memory than TOTAL_MEMORY, # since we then need to enlarge the heap(s). src = r''' @@ -2779,7 +2781,22 @@ def process(filename): return 0; } ''' + + # Fail without memory growth + self.do_run(src, 'Cannot enlarge memory arrays. Adjust TOTAL_MEMORY or compile with ALLOW_MEMORY_GROWTH') + fail = open('src.cpp.o.js').read() + + # Win with it + Settings.ALLOW_MEMORY_GROWTH = 1 self.do_run(src, '*pre: hello,4.955*\n*hello,4.955*\n*hello,4.955*') + win = open('src.cpp.o.js').read() + + if self.emcc_args and '-O2' in self.emcc_args: + # Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized) + code_start = 'var TOTAL_MEMORY = ' + fail = fail[fail.find(code_start):] + win = win[win.find(code_start):] + assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller' def test_ssr(self): # struct self-ref src = ''' @@ -4341,6 +4358,26 @@ Pass: 123456.789000 123456.789000 Pass: 0.000012 0.000012 Pass: 0.000012 0.000012''') + def test_sscanf_n(self): + src = r''' + #include<stdio.h> + int main() { + char *line = "version 1.0"; + int i, l, lineno; + char word[80]; + if (sscanf(line, "%s%n", word, &l) != 1) { + printf("Header format error, line %d\n", lineno); + } + printf("[DEBUG] word 1: %s, l: %d\n", word, l); + + int x = sscanf("one %n two", "%s %n", word, &l); + printf("%d,%s,%d\n", x, word, l); + + return 0; + } + ''' + self.do_run(src, '''[DEBUG] word 1: version, l: 7\n1,one,4''') + def test_langinfo(self): src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read() expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read() @@ -5872,17 +5909,31 @@ def process(filename): return output - self.do_run(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'.split(' '), - 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_build_dir(), 'openjpeg')], - force_c=True, - post_build=post, - output_nicerizer=image_compare)#, build_ll_hook=self.do_autodebug) + def do_test(): + self.do_run(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'.split(' '), + 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_build_dir(), 'openjpeg')], + force_c=True, + post_build=post, + output_nicerizer=image_compare)#, build_ll_hook=self.do_autodebug) + + do_test() + + # some test coverage for EMCC_DEBUG + if self.emcc_args and '-O2' in self.emcc_args and 'EMCC_DEBUG' not in os.environ: + shutil.copyfile('src.c.o.js', 'release.js') + try: + os.environ['EMCC_DEBUG'] = '1' + do_test() + finally: + del os.environ['EMCC_DEBUG'] + shutil.copyfile('src.c.o.js', 'debug.js') + self.assertIdentical(open('release.js').read().replace('\n\n', '\n').replace('\n\n', '\n'), open('debug.js').read().replace('\n\n', '\n').replace('\n\n', '\n')) # EMCC_DEBUG=1 mode must not generate different code! def test_python(self): if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work') @@ -7189,8 +7240,8 @@ Options that are modified or new in %s include: assert ('(__label__)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2' assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0' assert 'var $i;' in generated or 'var $i_01;' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on' - if opt_level >= 1: - assert 'HEAP8[HEAP32[' in generated or 'HEAP8[$vla1 + (($storemerge4 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$vla1 + (($storemerge4 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$vla1 + (($i_04 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$vla1 + ($i_04 / 2 & -1)]' in generated or 'HEAP8[$1 + (($i_01 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$1 + (($i_01 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$1 + ($i_01 / 2 & -1)]' in generated, 'eliminator should create compound expressions, and fewer one-time vars' + if opt_level >= 2: + assert 'HEAP8[HEAP32[' in generated or 'HEAP8[$vla1 + (($storemerge4 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$vla1 + (($storemerge4 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$vla1 + (($i_04 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$vla1 + ($i_04 / 2 & -1)]' in generated or 'HEAP8[$1 + (($i_01 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$1 + (($i_01 | 0) / 2 & -1) | 0]' in generated or 'HEAP8[$1 + ($i_01 / 2 & -1)]' in generated, 'eliminator should create compound expressions, and fewer one-time vars' # also in -O1, but easier to test in -O2 assert ('_puts(' in generated) == (opt_level >= 1), 'with opt >= 1, llvm opts are run and they should optimize printf to puts' assert ('function _malloc(bytes) {' in generated) == (not has_malloc), 'If malloc is needed, it should be there, if not not' assert 'function _main() {' in generated, 'Should be unminified, including whitespace' @@ -7856,11 +7907,6 @@ f.close() Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '--pre-js', 'pre2.js']).communicate() self.assertContained('prepre\npre-run\nhello from main\n', run_js(os.path.join(self.get_dir(), 'a.out.js'))) - def test_eliminator(self): - expected = open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read() - output = Popen([NODE_JS, COFFEESCRIPT, VARIABLE_ELIMINATOR, path_from_root('tools', 'eliminator', 'eliminator-test.js')], stdout=PIPE).communicate()[0] - self.assertIdentical(expected, output) - def test_fix_closure(self): input = path_from_root('tests', 'test-fix-closure.js') expected = path_from_root('tests', 'test-fix-closure.out.js') @@ -7873,7 +7919,7 @@ f.close() def test_js_optimizer(self): for input, expected, passes in [ (path_from_root('tools', 'test-js-optimizer.js'), open(path_from_root('tools', 'test-js-optimizer-output.js')).read(), - ['hoistMultiples', 'loopOptimizer', 'unGlobalize', 'removeAssignsToUndefined', 'simplifyExpressionsPre', 'simplifyExpressionsPost']), + ['hoistMultiples', 'loopOptimizer', 'removeAssignsToUndefined', 'simplifyExpressionsPre', 'simplifyExpressionsPost']), (path_from_root('tools', 'test-js-optimizer-t2c.js'), open(path_from_root('tools', 'test-js-optimizer-t2c-output.js')).read(), ['simplifyExpressionsPre', 'optimizeShiftsConservative']), (path_from_root('tools', 'test-js-optimizer-t2.js'), open(path_from_root('tools', 'test-js-optimizer-t2-output.js')).read(), @@ -7883,6 +7929,10 @@ f.close() ['optimizeShiftsAggressive']), (path_from_root('tools', 'test-js-optimizer-regs.js'), open(path_from_root('tools', 'test-js-optimizer-regs-output.js')).read(), ['registerize']), + (path_from_root('tools', 'eliminator', 'eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read(), + ['eliminate']), + (path_from_root('tools', 'eliminator', 'safe-eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'safe-eliminator-test-output.js')).read(), + ['eliminateMemSafe']), ]: output = Popen([NODE_JS, JS_OPTIMIZER, input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] self.assertIdentical(expected, output.replace('\n\n', '\n')) @@ -9136,6 +9186,14 @@ elif 'browser' in str(sys.argv): ''') self.btest('pre_run_deps.cpp', expected='10', args=['--pre-js', 'pre.js']) + def test_worker_api(self): + Popen(['python', EMCC, path_from_root('tests', 'worker_api_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-s', 'EXPORTED_FUNCTIONS=["_one"]']).communicate() + self.btest('worker_api_main.cpp', expected='566') + + def test_worker_api_2(self): + Popen(['python', EMCC, path_from_root('tests', 'worker_api_2_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-O2', '--minify', '0', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two", "_three", "_four"]']).communicate() + self.btest('worker_api_2_main.cpp', args=['-O2', '--minify', '0'], expected='11') + pids_to_clean = [] def clean_pids(self): return @@ -9360,8 +9418,8 @@ elif 'benchmark' in str(sys.argv): final_filename = os.path.join(dirname, name + '.js') try_delete(final_filename) - output = Popen(['python', EMCC, filename, '-O3', - #'-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0', + output = Popen(['python', EMCC, filename, #'-O3', + '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0', '-s', 'TOTAL_MEMORY=100*1024*1024', '-s', 'FAST_MEMORY=10*1024*1024', '-o', final_filename] + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate() assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0] diff --git a/tests/worker_api_2_main.cpp b/tests/worker_api_2_main.cpp new file mode 100644 index 00000000..ec8a6d4b --- /dev/null +++ b/tests/worker_api_2_main.cpp @@ -0,0 +1,108 @@ +#include <stdio.h> +#include <assert.h> +#include <emscripten.h> + +struct Info { + int i; + float f; + char c; + double d; +}; + +int w1; + +Info x[3] = { { 22, 3.159, 97, 2.1828 }, + { 55123, 987612.563, 190, 0.0009 }, + { -102, -12.532, -21, -51252 } }; + +int stage = -1; + +int c3_7 = 0, c3_8 = 0; + +void c3(char *data, int size, void *arg) { // tests calls different in different workers. + int calls = *((int*)data); + printf("%d: %d\n", (int)arg, calls); + if ((int)arg == 7) { + assert(c3_7 == 0); + c3_7++; + assert(calls == 5); + } else { + assert((int)arg == 8); + assert(c3_8 == 0); + c3_8++; + assert(calls == 1); + } + if (c3_7 && c3_7) { // note: racey, responses from 2 workers here + emscripten_destroy_worker(w1); + int result = 11; + REPORT_RESULT(); + } +} + +void c2(char *data, int size, void *arg) { // tests queuing up several messages, each with different data + assert((int)arg == stage); + Info *x2 = (Info*)data; + + int i = stage - 3; + printf("c2-%d\n", i); + printf("%d, %.2f, %d, %.2f\n", x2[0].i, x2[0].f, x2[0].c, x2[0].d); + printf("%d, %.2f, %d, %.2f\n", x[i].i, x[i].f, x[i].c, x[i].d); + assert(x2[0].i == x[i].i+1); + assert(x2[0].f == x[i].f-1); + assert(x2[0].c == x[i].c+1); + assert(x2[0].d == x[i].d-1); + + if (stage == 5) { + int w2 = emscripten_create_worker("worker.js"); + emscripten_call_worker(w2, "three", NULL, 0, NULL, (void*)6); // bump calls in new worker, once + + emscripten_call_worker(w1, "four", NULL, 0, c3, (void*)7); + emscripten_call_worker(w2, "four", NULL, 0, c3, (void*)8); + } + stage++; +} + +void c1(char *data, int size, void *arg) { // tests copying + buffer enlargement + assert((int)arg == stage); + if (stage == 1) { + printf("wait 0? %d\n", emscripten_get_worker_queue_size(w1)); + assert(emscripten_get_worker_queue_size(w1) == 0); + } + Info *x2 = (Info*)data; + assert(x2 != x && x2 != x+1 && x2 != x+2); + for (int i = 0; i < size/sizeof(Info); i++) { + printf("c1-%d\n", i); + printf(" %d, %.2f, %d, %.2f\n", x2[i].i, x2[i].f, x2[i].c, x2[i].d); + printf(" %d, %.2f, %d, %.2f\n", x[i].i, x[i].f, x[i].c, x[i].d); + assert(x2[i].i == x[i].i); + assert(x2[i].f == x[i].f); + assert(x2[i].c == x[i].c); + assert(x2[i].d == x[i].d); + } + if (stage < 2) { + emscripten_call_worker(w1, "one", (char*)x, sizeof(Info)*3, c1, (void*)2); + } else { + printf("wait 1? %d\n", emscripten_get_worker_queue_size(w1)); + assert(emscripten_get_worker_queue_size(w1) == 0); + emscripten_call_worker(w1, "two", (char*)&x[0], sizeof(Info), c2, (void*)3); + emscripten_call_worker(w1, "two", (char*)&x[1], sizeof(Info), c2, (void*)4); + emscripten_call_worker(w1, "two", (char*)&x[2], sizeof(Info), c2, (void*)5); + printf("wait 2? %d\n", emscripten_get_worker_queue_size(w1)); + assert(emscripten_get_worker_queue_size(w1) == 3); + } + stage++; +} + +int main() { + w1 = emscripten_create_worker("worker.js"); + + printf("wait -1? %d\n", emscripten_get_worker_queue_size(w1)); + assert(emscripten_get_worker_queue_size(w1) == 0); + emscripten_call_worker(w1, "one", (char*)x, sizeof(Info)*2, c1, (void*)1); + printf("wait -1? %d\n", emscripten_get_worker_queue_size(w1)); + assert(emscripten_get_worker_queue_size(w1) == 1); + stage = 1; // make sure we get here + + return 0; +} + diff --git a/tests/worker_api_2_worker.cpp b/tests/worker_api_2_worker.cpp new file mode 100644 index 00000000..d7033bc4 --- /dev/null +++ b/tests/worker_api_2_worker.cpp @@ -0,0 +1,44 @@ +#include <assert.h> +#include <emscripten.h> + +struct Info { + int i; + float f; + char c; + double d; +}; + +int calls = 0; // global state that is not in all workers + +extern "C" { + +void one(char *data, int size) { + calls++; + emscripten_worker_respond(data, size); +} + +void two(char *data, int size) { + calls++; + Info *x = (Info*)data; + x[0].i++; + x[0].f--; + x[0].c++; + x[0].d--; + emscripten_worker_respond(data, size); +} + +void three(char *data, int size) { + assert(data == 0); + assert(size == 0); + calls++; + // no response +} + +void four(char *data, int size) { + assert(data == 0); + assert(size == 0); + emscripten_worker_respond((char*)&calls, sizeof(calls)); +} + +} + diff --git a/tests/worker_api_main.cpp b/tests/worker_api_main.cpp new file mode 100644 index 00000000..f91102b2 --- /dev/null +++ b/tests/worker_api_main.cpp @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <assert.h> +#include <emscripten.h> + +int w1; + +void c1(char *data, int size, void *arg) { + assert((int)arg == 93); + int *x = (int*)data; + printf("c1: %d,%d\n", x[0], x[1]); + + int result = x[1] % x[0]; + REPORT_RESULT(); +} + +int main() { + w1 = emscripten_create_worker("worker.js"); + + int x[2] = { 100, 6002 }; + emscripten_call_worker(w1, "one", (char*)x, sizeof(x), c1, (void*)93); + + return 0; +} + diff --git a/tests/worker_api_worker.cpp b/tests/worker_api_worker.cpp new file mode 100644 index 00000000..9a671a91 --- /dev/null +++ b/tests/worker_api_worker.cpp @@ -0,0 +1,16 @@ +#include <assert.h> +#include <emscripten.h> + +extern "C" { + +void one(char *data, int size) { + int *x = (int*)data; + int num = size/sizeof(int); + for (int i = 0; i < num; i++) { + x[i] += 1234; + } + emscripten_worker_respond(data, size); +} + +} + |