aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-02-24 14:33:34 -0800
committerAlon Zakai <alonzakai@gmail.com>2014-02-24 14:33:34 -0800
commita75d43ec8dfc66a461dbe736692e70352d7dc556 (patch)
tree78004f2935a323dc46bb2db83d72c4458e63ed7f
parentd47a30c26ab0f76c74cb53d9eb54cb049ea05d21 (diff)
parentcd3e0b2ceef728c27745d1e7f5d6b95671bcaf04 (diff)
Merge branch 'fastcomp-by-default' into incoming
-rwxr-xr-xemcc95
-rwxr-xr-xemscripten.py2
-rw-r--r--src/library_gc.js2
-rw-r--r--src/preamble.js6
-rw-r--r--src/settings.js2
-rw-r--r--system/include/emscripten/emscripten.h14
-rw-r--r--system/include/gc.h2
-rw-r--r--tests/core/test_inlinejs3.in1
-rw-r--r--tests/core/test_inlinejs3.out1
-rwxr-xr-xtests/runner.py18
-rw-r--r--tests/test_benchmark.py1
-rw-r--r--tests/test_browser.py377
-rw-r--r--tests/test_core.py148
-rw-r--r--tests/test_other.py677
-rw-r--r--tests/test_sanity.py134
-rw-r--r--tools/js-optimizer.js43
-rwxr-xr-xtools/nativize_llvm.py8
-rw-r--r--tools/shared.py13
-rw-r--r--tools/test-js-optimizer-asm-outline1-output.js48
-rw-r--r--tools/test-js-optimizer-asm-outline1.js37
-rw-r--r--tools/test-js-optimizer-asm-outline2-output.js1
21 files changed, 823 insertions, 807 deletions
diff --git a/emcc b/emcc
index 6d8ff6f6..102b7f5d 100755
--- a/emcc
+++ b/emcc
@@ -425,59 +425,6 @@ Options that are modified or new in %s include:
-v to Clang, and also enable EMCC_DEBUG
to details emcc's operations
- --jcache Use a JavaScript cache. This is disabled by
- default. When enabled, emcc will store the
- results of compilation in a cache and check
- the cache when compiling later, something
- like what ccache does. This allows incremental
- builds - where you are compiling a large
- program but only modified a small part of it -
- to be much faster (at the cost of more disk
- IO for cache accesses). Note that you need
- to enable --jcache for both loading and saving
- of data, so you must enable it on a full build
- for a later incremental build (where you also
- enable it) to be sped up.
-
- Caching works separately on 4 parts of compilation:
- 'pre' which is types and global variables; that
- information is then fed into 'funcs' which are
- the functions (which we parallelize), and then
- 'post' which adds final information based on
- the functions (e.g., do we need long64 support
- code). Finally, 'jsfuncs' are JavaScript-level
- optimizations. Each of the 4 parts can be cached
- separately, but note that they can affect each
- other: If you recompile a single C++ file that
- changes a global variable - e.g., adds, removes
- or modifies a global variable, say by adding
- a printf or by adding a compile-time timestamp,
- then 'pre' cannot be loaded from the cache. And
- since 'pre's output is sent to 'funcs' and 'post',
- they will get invalidated as well, and only
- 'jsfuncs' will be cached. So avoid modifying
- globals to let caching work fully.
-
- To work around the problem mentioned in the
- previous paragraph, you can use
-
- emscripten_jcache_printf
-
- when adding debug printfs to your code. That
- function is specially preprocessed so that it
- does not create a constant string global for
- its first argument. See emscripten.h for more
- details. Note in particular that you need to
- already have a call to that function in your
- code *before* you add one and do an incremental
- build, so that adding an external reference
- (also a global property) does not invalidate
- everything.
-
- Note that you should use -g during the linking
- stage (bitcode to JS), for jcache to work
- (otherwise, JS minification can confuse it).
-
--clear-cache Manually clears the cache of compiled
emscripten system libraries (libc++,
libc++abi, libc). This is normally
@@ -986,6 +933,7 @@ try:
logging.warning ('--remove-duplicates is deprecated as it is no longer needed. If you cannot link without it, file a bug with a testcase')
newargs[i] = ''
elif newargs[i] == '--jcache':
+ logging.warning('jcache is deprecated')
jcache = True
newargs[i] = ''
elif newargs[i] == '--clear-cache':
@@ -1200,26 +1148,33 @@ try:
logging.warning('disabling asm.js since embind is not ready for it yet')
shared.Settings.ASM_JS = 0
- fastcomp = os.environ.get('EMCC_FAST_COMPILER') == '1'
+ fastcomp = os.environ.get('EMCC_FAST_COMPILER') != '0'
if fastcomp:
shared.Settings.ASM_JS = 1 if opt_level > 0 else 2
- assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp'
- assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp yet'
- assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp'
- assert shared.Settings.ASM_HEAP_LOG == 0, 'asm heap log not supported in fastcomp'
- assert shared.Settings.LABEL_DEBUG == 0, 'label debug not supported in fastcomp'
- assert shared.Settings.EXECUTION_TIMEOUT == -1, 'execution timeout not supported in fastcomp'
- assert shared.Settings.NAMED_GLOBALS == 0, 'named globals not supported in fastcomp'
- assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp'
- assert shared.Settings.TARGET_LE32 == 1, 'fastcomp requires le32'
- assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2'
- assert not split_js_file, '--split-js is deprecated and not supported in fastcomp'
- assert not bind, 'embind not supported in fastcomp yet'
- assert shared.Settings.MAX_SETJMPS == 20, 'changing MAX_SETJMPS is not supported in fastcomp yet'
- assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)'
+ try:
+ assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp'
+ assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp yet'
+ assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp'
+ assert shared.Settings.ASM_HEAP_LOG == 0, 'asm heap log not supported in fastcomp'
+ assert shared.Settings.LABEL_DEBUG == 0, 'label debug not supported in fastcomp'
+ assert shared.Settings.EXECUTION_TIMEOUT == -1, 'execution timeout not supported in fastcomp'
+ assert shared.Settings.NAMED_GLOBALS == 0, 'named globals not supported in fastcomp'
+ assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp'
+ assert shared.Settings.TARGET_LE32 == 1, 'fastcomp requires le32'
+ assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2'
+ assert not split_js_file, '--split-js is deprecated and not supported in fastcomp'
+ assert not bind, 'embind not supported in fastcomp yet'
+ assert shared.Settings.MAX_SETJMPS == 20, 'changing MAX_SETJMPS is not supported in fastcomp yet'
+ assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)'
+ assert not shared.Settings.RUNTIME_TYPE_INFO, 'RUNTIME_TYPE_INFO is not supported in fastcomp'
+ assert not shared.Settings.CORRUPTION_CHECK, 'CORRUPTION_CHECK is not supported in asm.js mode, which is what fastcomp can emit (you can use non-asm.js mode in non-fastcomp)'
+ except Exception, e:
+ logging.error('Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend')
+ raise e
+
if jcache:
- logging.warning('jcache is not supported in fastcomp (you should not need it anyhow), disabling')
+ logging.warning('jcache is deprecated and not supported in fastcomp (you should not need it anyhow), disabling')
jcache = False
fastcomp_opts = ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt']
@@ -1284,7 +1239,7 @@ try:
shared.Settings.LINKABLE = 1 # TODO: add FORCE_DCE option for the brave people that do want to dce here and in side modules
debug_level = max(debug_level, 2)
- if shared.Settings.ASSERTIONS and shared.Settings.ALIASING_FUNCTION_POINTERS:
+ if not fastcomp and shared.Settings.ASSERTIONS and shared.Settings.ALIASING_FUNCTION_POINTERS:
logging.warning('ALIASING_FUNCTION_POINTERS is on, function pointer comparisons may be invalid across types')
if shared.Settings.STB_IMAGE and final_suffix in JS_CONTAINING_SUFFIXES:
diff --git a/emscripten.py b/emscripten.py
index 59a0666c..6b49a3cc 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -1257,7 +1257,7 @@ Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
if DEBUG: logging.debug(' emscript: final python processing took %s seconds' % (time.time() - t))
-if os.environ.get('EMCC_FAST_COMPILER') == '1':
+if os.environ.get('EMCC_FAST_COMPILER') != '0':
emscript = emscript_fast
def main(args, compiler_engine, cache, jcache, relooper, temp_files, DEBUG, DEBUG_CACHE):
diff --git a/src/library_gc.js b/src/library_gc.js
index b3dae0e9..d86f2d15 100644
--- a/src/library_gc.js
+++ b/src/library_gc.js
@@ -1,4 +1,6 @@
+// WARNING: this is deprecated. You should just build Boehm from source, it is much faster than the toy version written in emscripten
+
if (GC_SUPPORT) {
EXPORTED_FUNCTIONS['_calloc'] = 1;
EXPORTED_FUNCTIONS['_realloc'] = 1;
diff --git a/src/preamble.js b/src/preamble.js
index 27a98422..28a1dcbc 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -194,9 +194,6 @@ function SAFE_HEAP_STORE(dest, value, bytes, isFloat) {
}
function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) {
-#if SAFE_HEAP_LOG
- Module.print('SAFE_HEAP load: ' + [dest, bytes, isFloat, unsigned]);
-#endif
assert(dest > 0, 'segmentation fault');
assert(dest % bytes === 0);
assert(dest < Math.max(DYNAMICTOP, STATICTOP));
@@ -204,6 +201,9 @@ function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) {
var type = getSafeHeapType(bytes, isFloat);
var ret = getValue(dest, type, 1);
if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1);
+#if SAFE_HEAP_LOG
+ Module.print('SAFE_HEAP load: ' + [dest, ret, bytes, isFloat, unsigned]);
+#endif
return ret;
}
diff --git a/src/settings.js b/src/settings.js
index c8114059..1c6b998e 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -446,7 +446,7 @@ var HEADLESS = 0; // If 1, will include shim code that tries to 'fake' a browser
var BENCHMARK = 0; // If 1, will just time how long main() takes to execute, and not
// print out anything at all whatsoever. This is useful for benchmarking.
-var ASM_JS = 0; // If 1, generate code in asm.js format. If 2, emits the same code except
+var ASM_JS = 1; // If 1, generate code in asm.js format. If 2, emits the same code except
// for omitting 'use asm'
var PGO = 0; // Enables profile-guided optimization in the form of runtime checks for
diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h
index b92d920c..852a8e0d 100644
--- a/system/include/emscripten/emscripten.h
+++ b/system/include/emscripten/emscripten.h
@@ -40,10 +40,15 @@ extern "C" {
#define EM_ASM(...) emscripten_asm_const(#__VA_ARGS__)
/*
- * Input-output versions of EM_ASM. EM_ASM_INT receives arguments of
- * either int or double type and returns an int; EM_ASM_DOUBLE
- * receives similar arguments (int or double) but returns a double.
- * Arguments arrive as $0, $1 etc; output value should be returned:
+ * Input-output versions of EM_ASM.
+ *
+ * EM_ASM_ (an extra _ is added) allows sending values (ints
+ * or doubles) into the code. If you also want a return value,
+ * EM_ASM_INT receives arguments (of int or double type)
+ * and returns an int; EM_ASM_DOUBLE does the same and returns
+ * a double.
+ *
+ * Arguments arrive as $0, $1 etc. The output value should be returned:
*
* int x = EM_ASM_INT({
* console.log('I received: ' + [$0, $1]);
@@ -54,6 +59,7 @@ extern "C" {
* (int or double) but *not* to pass any values, you can use
* EM_ASM_INT_V and EM_ASM_DOUBLE_V respectively.
*/
+#define EM_ASM_(code, ...) emscripten_asm_const_int(#code, __VA_ARGS__)
#define EM_ASM_INT(code, ...) emscripten_asm_const_int(#code, __VA_ARGS__)
#define EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double(#code, __VA_ARGS__)
#define EM_ASM_INT_V(code) emscripten_asm_const_int(#code)
diff --git a/system/include/gc.h b/system/include/gc.h
index a21fd410..affa615f 100644
--- a/system/include/gc.h
+++ b/system/include/gc.h
@@ -1,5 +1,7 @@
/*
* Boehm-compatible GC API
+ *
+ * WARNING: this is deprecated. You should just build Boehm from source, it is much faster than the toy version written in emscripten
*/
#ifndef _GC_H_INCLUDED
#define _GC_H_INCLUDED
diff --git a/tests/core/test_inlinejs3.in b/tests/core/test_inlinejs3.in
index 9ddd5907..12e31007 100644
--- a/tests/core/test_inlinejs3.in
+++ b/tests/core/test_inlinejs3.in
@@ -7,6 +7,7 @@ int main(int argc, char **argv) {
for (int i = 0; i < 3; i++) {
EM_ASM(Module.print('hello dere3'); Module.print('hello dere' + 4););
}
+ EM_ASM_({ Module.print('hello input ' + $0) }, 123);
int sum = 0;
for (int i = 0; i < argc * 3; i++) {
sum += EM_ASM_INT({
diff --git a/tests/core/test_inlinejs3.out b/tests/core/test_inlinejs3.out
index c293e80b..1f64a89a 100644
--- a/tests/core/test_inlinejs3.out
+++ b/tests/core/test_inlinejs3.out
@@ -6,6 +6,7 @@ hello dere3
hello dere4
hello dere3
hello dere4
+hello input 123
i: 0,0.00
i: 1,0.08
i: 2,0.17
diff --git a/tests/runner.py b/tests/runner.py
index 501299c7..32575a1a 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -27,6 +27,19 @@ sys.path += [path_from_root(''), path_from_root('third_party/websockify')]
import tools.shared
from tools.shared import *
+# Utils
+
+def nonfastcomp(test):
+ try:
+ old_fastcomp = os.environ.get('EMCC_FAST_COMPILER')
+ os.environ['EMCC_FAST_COMPILER'] = '0'
+ test()
+ finally:
+ if old_fastcomp is None:
+ del os.environ['EMCC_FAST_COMPILER']
+ else:
+ os.environ['EMCC_FAST_COMPILER'] = old_fastcomp
+
# Sanity check for config
try:
@@ -36,10 +49,7 @@ except:
# Core test runner class, shared between normal tests and benchmarks
checked_sanity = False
-if os.environ.get('EMCC_FAST_COMPILER') == '1':
- test_modes = ['default', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g']
-else:
- test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g', 'asm2x86', 's_0_0', 's_0_1']
+test_modes = ['default', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g', 'slow2', 'slow2asm', 's_0_0', 's_0_1']
test_index = 0
class RunnerCore(unittest.TestCase):
diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py
index 023ac1e2..2bc34c60 100644
--- a/tests/test_benchmark.py
+++ b/tests/test_benchmark.py
@@ -134,7 +134,6 @@ try:
#JSBenchmarker('sm-f32-3.2', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2'], env={ 'LLVM': LLVM_3_2 }),
#JSBenchmarker('sm-f32-3.3', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2'], env={ 'LLVM': LLVM_3_3 }),
#JSBenchmarker('sm-f32-3.4', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2'], env={ 'LLVM': LLVM_3_4 }),
- #JSBenchmarker('sm-fc', SPIDERMONKEY_ENGINE, env={ 'EMCC_FAST_COMPILER': '1' }),
#JSBenchmarker('sm-noasm', SPIDERMONKEY_ENGINE + ['--no-asmjs']),
#JSBenchmarker('sm-noasm-f32', SPIDERMONKEY_ENGINE + ['--no-asmjs'], ['-s', 'PRECISE_F32=2']),
#JSBenchmarker('v8', V8_ENGINE)
diff --git a/tests/test_browser.py b/tests/test_browser.py
index c1d1caab..f2e17ea0 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -1,5 +1,5 @@
import BaseHTTPServer, multiprocessing, os, shutil, subprocess, unittest, zlib, webbrowser, time, shlex
-from runner import BrowserCore, path_from_root
+from runner import BrowserCore, path_from_root, nonfastcomp
from tools.shared import *
# User can specify an environment variable EMSCRIPTEN_BROWSER to force the browser test suite to
@@ -120,8 +120,6 @@ If manually bisecting:
'''
def test_emscripten_log(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('fastcomp uses asm, where call stacks are sometimes less clear')
-
src = os.path.join(self.get_dir(), 'src.cpp')
open(src, 'w').write(self.with_report_result(open(path_from_root('tests', 'emscripten_log', 'emscripten_log.cpp')).read()))
@@ -143,191 +141,193 @@ If manually bisecting:
os.chdir(cwd)
def test_split(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('no --split in fastcomp, deprecated')
+ def nfc():
+ # test HTML generation.
+ self.reftest(path_from_root('tests', 'htmltest.png'))
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '--split', '100', '--pre-js', 'reftest.js']).communicate()
+ assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'something_functions.js')), 'must be functions js file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
- # test HTML generation.
- self.reftest(path_from_root('tests', 'htmltest.png'))
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '--split', '100', '--pre-js', 'reftest.js']).communicate()
- assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
- assert os.path.exists(os.path.join(self.get_dir(), 'something_functions.js')), 'must be functions js file'
- assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
-
- open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
-
- <!doctype html>
- <html lang="en-us">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>Emscripten-Generated Code</title>
- <style>
- .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
- canvas.emscripten { border: 1px solid black; }
- textarea.emscripten { font-family: monospace; width: 80%; }
- div.emscripten { text-align: center; }
- </style>
- </head>
- <body>
- <hr/>
- <div class="emscripten" id="status">Downloading...</div>
- <div class="emscripten">
- <progress value="0" max="100" id="progress" hidden=1></progress>
- </div>
- <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
- <hr/>
- <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
- <hr/>
- <textarea class="emscripten" id="output" rows="8"></textarea>
- <hr>
- <script type='text/javascript'>
- // connect to canvas
- var Module = {
- preRun: [],
- postRun: [],
- print: (function() {
- var element = document.getElementById('output');
- element.value = ''; // clear browser cache
- return function(text) {
- // These replacements are necessary if you render to raw HTML
- //text = text.replace(/&/g, "&amp;");
- //text = text.replace(/</g, "&lt;");
- //text = text.replace(/>/g, "&gt;");
- //text = text.replace('\\n', '<br>', 'g');
- element.value += text + "\\n";
- element.scrollTop = element.scrollHeight; // focus on bottom
- };
- })(),
- printErr: function(text) {
- if (0) { // XXX disabled for safety typeof dump == 'function') {
- dump(text + '\\n'); // fast, straight to the real console
- } else {
- console.log(text);
- }
- },
- canvas: document.getElementById('canvas'),
- setStatus: function(text) {
- if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
- var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
- var statusElement = document.getElementById('status');
- var progressElement = document.getElementById('progress');
- if (m) {
- text = m[1];
- progressElement.value = parseInt(m[2])*100;
- progressElement.max = parseInt(m[4])*100;
- progressElement.hidden = false;
- } else {
- progressElement.value = null;
- progressElement.max = null;
- progressElement.hidden = true;
+ open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
+
+ <!doctype html>
+ <html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Emscripten-Generated Code</title>
+ <style>
+ .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
+ canvas.emscripten { border: 1px solid black; }
+ textarea.emscripten { font-family: monospace; width: 80%; }
+ div.emscripten { text-align: center; }
+ </style>
+ </head>
+ <body>
+ <hr/>
+ <div class="emscripten" id="status">Downloading...</div>
+ <div class="emscripten">
+ <progress value="0" max="100" id="progress" hidden=1></progress>
+ </div>
+ <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+ <hr/>
+ <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
+ <hr/>
+ <textarea class="emscripten" id="output" rows="8"></textarea>
+ <hr>
+ <script type='text/javascript'>
+ // connect to canvas
+ var Module = {
+ preRun: [],
+ postRun: [],
+ print: (function() {
+ var element = document.getElementById('output');
+ element.value = ''; // clear browser cache
+ return function(text) {
+ // These replacements are necessary if you render to raw HTML
+ //text = text.replace(/&/g, "&amp;");
+ //text = text.replace(/</g, "&lt;");
+ //text = text.replace(/>/g, "&gt;");
+ //text = text.replace('\\n', '<br>', 'g');
+ element.value += text + "\\n";
+ element.scrollTop = element.scrollHeight; // focus on bottom
+ };
+ })(),
+ printErr: function(text) {
+ if (0) { // XXX disabled for safety typeof dump == 'function') {
+ dump(text + '\\n'); // fast, straight to the real console
+ } else {
+ console.log(text);
+ }
+ },
+ canvas: document.getElementById('canvas'),
+ setStatus: function(text) {
+ if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
+ var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
+ var statusElement = document.getElementById('status');
+ var progressElement = document.getElementById('progress');
+ if (m) {
+ text = m[1];
+ progressElement.value = parseInt(m[2])*100;
+ progressElement.max = parseInt(m[4])*100;
+ progressElement.hidden = false;
+ } else {
+ progressElement.value = null;
+ progressElement.max = null;
+ progressElement.hidden = true;
+ }
+ statusElement.innerHTML = text;
+ },
+ totalDependencies: 0,
+ monitorRunDependencies: function(left) {
+ this.totalDependencies = Math.max(this.totalDependencies, left);
+ Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
- statusElement.innerHTML = text;
- },
- totalDependencies: 0,
- monitorRunDependencies: function(left) {
- this.totalDependencies = Math.max(this.totalDependencies, left);
- Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
- }
- };
- Module.setStatus('Downloading...');
- </script>''' + open(os.path.join(self.get_dir(), 'something.include.html')).read() + '''
- </body>
- </html>
- ''')
+ };
+ Module.setStatus('Downloading...');
+ </script>''' + open(os.path.join(self.get_dir(), 'something.include.html')).read() + '''
+ </body>
+ </html>
+ ''')
- self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
+ self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
+
+ nonfastcomp(nfc)
def test_split_in_source_filenames(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('no --split in fastcomp, deprecated')
-
- self.reftest(path_from_root('tests', 'htmltest.png'))
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '-g', '--split', '100', '--pre-js', 'reftest.js']).communicate()
- assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
- assert os.path.exists(os.path.join(self.get_dir(), 'something', 'hello_world_sdl.cpp.js')), 'must be functions js file'
- assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
-
- open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
-
- <!doctype html>
- <html lang="en-us">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>Emscripten-Generated Code</title>
- <style>
- .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
- canvas.emscripten { border: 1px solid black; }
- textarea.emscripten { font-family: monospace; width: 80%; }
- div.emscripten { text-align: center; }
- </style>
- </head>
- <body>
- <hr/>
- <div class="emscripten" id="status">Downloading...</div>
- <div class="emscripten">
- <progress value="0" max="100" id="progress" hidden=1></progress>
- </div>
- <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
- <hr/>
- <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
- <hr/>
- <textarea class="emscripten" id="output" rows="8"></textarea>
- <hr>
- <script type='text/javascript'>
- // connect to canvas
- var Module = {
- preRun: [],
- postRun: [],
- print: (function() {
- var element = document.getElementById('output');
- element.value = ''; // clear browser cache
- return function(text) {
- // These replacements are necessary if you render to raw HTML
- //text = text.replace(/&/g, "&amp;");
- //text = text.replace(/</g, "&lt;");
- //text = text.replace(/>/g, "&gt;");
- //text = text.replace('\\n', '<br>', 'g');
- element.value += text + "\\n";
- element.scrollTop = element.scrollHeight; // focus on bottom
- };
- })(),
- printErr: function(text) {
- if (0) { // XXX disabled for safety typeof dump == 'function') {
- dump(text + '\\n'); // fast, straight to the real console
- } else {
- console.log(text);
- }
- },
- canvas: document.getElementById('canvas'),
- setStatus: function(text) {
- if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
- var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
- var statusElement = document.getElementById('status');
- var progressElement = document.getElementById('progress');
- if (m) {
- text = m[1];
- progressElement.value = parseInt(m[2])*100;
- progressElement.max = parseInt(m[4])*100;
- progressElement.hidden = false;
- } else {
- progressElement.value = null;
- progressElement.max = null;
- progressElement.hidden = true;
+ def nfc():
+ self.reftest(path_from_root('tests', 'htmltest.png'))
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '-g', '--split', '100', '--pre-js', 'reftest.js']).communicate()
+ assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'something', 'hello_world_sdl.cpp.js')), 'must be functions js file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
+
+ open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
+
+ <!doctype html>
+ <html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Emscripten-Generated Code</title>
+ <style>
+ .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
+ canvas.emscripten { border: 1px solid black; }
+ textarea.emscripten { font-family: monospace; width: 80%; }
+ div.emscripten { text-align: center; }
+ </style>
+ </head>
+ <body>
+ <hr/>
+ <div class="emscripten" id="status">Downloading...</div>
+ <div class="emscripten">
+ <progress value="0" max="100" id="progress" hidden=1></progress>
+ </div>
+ <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+ <hr/>
+ <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
+ <hr/>
+ <textarea class="emscripten" id="output" rows="8"></textarea>
+ <hr>
+ <script type='text/javascript'>
+ // connect to canvas
+ var Module = {
+ preRun: [],
+ postRun: [],
+ print: (function() {
+ var element = document.getElementById('output');
+ element.value = ''; // clear browser cache
+ return function(text) {
+ // These replacements are necessary if you render to raw HTML
+ //text = text.replace(/&/g, "&amp;");
+ //text = text.replace(/</g, "&lt;");
+ //text = text.replace(/>/g, "&gt;");
+ //text = text.replace('\\n', '<br>', 'g');
+ element.value += text + "\\n";
+ element.scrollTop = element.scrollHeight; // focus on bottom
+ };
+ })(),
+ printErr: function(text) {
+ if (0) { // XXX disabled for safety typeof dump == 'function') {
+ dump(text + '\\n'); // fast, straight to the real console
+ } else {
+ console.log(text);
+ }
+ },
+ canvas: document.getElementById('canvas'),
+ setStatus: function(text) {
+ if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
+ var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
+ var statusElement = document.getElementById('status');
+ var progressElement = document.getElementById('progress');
+ if (m) {
+ text = m[1];
+ progressElement.value = parseInt(m[2])*100;
+ progressElement.max = parseInt(m[4])*100;
+ progressElement.hidden = false;
+ } else {
+ progressElement.value = null;
+ progressElement.max = null;
+ progressElement.hidden = true;
+ }
+ statusElement.innerHTML = text;
+ },
+ totalDependencies: 0,
+ monitorRunDependencies: function(left) {
+ this.totalDependencies = Math.max(this.totalDependencies, left);
+ Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
- statusElement.innerHTML = text;
- },
- totalDependencies: 0,
- monitorRunDependencies: function(left) {
- this.totalDependencies = Math.max(this.totalDependencies, left);
- Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
- }
- };
- Module.setStatus('Downloading...');
- </script>''' + open(os.path.join(self.get_dir(), 'something.include.html')).read() + '''
- </body>
- </html>
- ''')
+ };
+ Module.setStatus('Downloading...');
+ </script>''' + open(os.path.join(self.get_dir(), 'something.include.html')).read() + '''
+ </body>
+ </html>
+ ''')
- self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
+ self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
+
+ nonfastcomp(nfc)
def test_compression(self):
open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
@@ -1495,11 +1495,6 @@ keydown(100);keyup(100); // trigger the end
def test_sdl_resize(self):
self.btest('sdl_resize.c', '1')
- def test_gc(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('flaky in fastcomp and also non-fastcomp -O1, timing issues')
-
- self.btest('browser_gc.cpp', '1')
-
def test_glshaderinfo(self):
self.btest('glshaderinfo.cpp', '1')
@@ -1706,7 +1701,7 @@ void *getBindBuffer() {
self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js', '-s', 'LEGACY_GL_EMULATION=1'])
def test_aniso(self):
- if SPIDERMONKEY_ENGINE in JS_ENGINES and os.environ.get('EMCC_FAST_COMPILER') != '1':
+ if SPIDERMONKEY_ENGINE in JS_ENGINES:
# asm.js-ification check
Popen([PYTHON, EMCC, path_from_root('tests', 'aniso.c'), '-O2', '-g2', '-s', 'LEGACY_GL_EMULATION=1']).communicate()
Settings.ASM_JS = 1
@@ -1766,10 +1761,10 @@ void *getBindBuffer() {
self.btest('http.cpp', expected='0', args=['-I' + path_from_root('tests')])
def test_module(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
- Popen([PYTHON, EMCC, path_from_root('tests', 'browser_module.cpp'), '-o', 'module.js', '-O2', '-s', 'SIDE_MODULE=1', '-s', 'DLOPEN_SUPPORT=1', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two"]']).communicate()
- self.btest('browser_main.cpp', args=['-O2', '-s', 'MAIN_MODULE=1', '-s', 'DLOPEN_SUPPORT=1'], expected='8')
+ def nfc():
+ Popen([PYTHON, EMCC, path_from_root('tests', 'browser_module.cpp'), '-o', 'module.js', '-O2', '-s', 'SIDE_MODULE=1', '-s', 'DLOPEN_SUPPORT=1', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two"]']).communicate()
+ self.btest('browser_main.cpp', args=['-O2', '-s', 'MAIN_MODULE=1', '-s', 'DLOPEN_SUPPORT=1'], expected='8')
+ nonfastcomp(nfc)
def test_mmap_file(self):
open(self.in_dir('data.dat'), 'w').write('data from the file ' + ('.' * 9000))
diff --git a/tests/test_core.py b/tests/test_core.py
index c4bfcfa3..19bb9ca1 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -512,33 +512,45 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run(open(path_from_root('tests', 'cube2md5.cpp')).read(), open(path_from_root('tests', 'cube2md5.ok')).read())
def test_cube2hash(self):
- try:
- old_chunk_size = os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or ''
- os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = '1' # test splitting out each function to a chunk in emscripten.py (21 functions here)
-
- # A good test of i64 math
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing')
- self.do_run('', 'Usage: hashstring <seed>',
- libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None),
- includes=[path_from_root('tests', 'cube2hash')])
-
- for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
- ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'),
- ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]:
- self.do_run('', 'hash value: ' + output, [text], no_build=True)
- finally:
- os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = old_chunk_size
-
- assert 'asm1' in test_modes
- if self.run_name == 'asm1' and not os.environ.get('EMCC_FAST_COMPILER'):
- assert Settings.RELOOP
- generated = open('src.cpp.o.js').read()
- main = generated[generated.find('function _main'):]
- main = main[:main.find('\n}')]
- num_vars = 0
- for v in re.findall('var [^;]+;', main):
- num_vars += v.count(',') + 1
- assert num_vars == 10, 'no variable elimination should have been run, but seeing %d' % num_vars
+ # extra testing for various codegen modes
+ for x86 in [0, 1] if self.run_name == 'asm2' else [0]:
+ print 'x86', x86
+ try:
+ old_x86 = os.environ.get('EMCC_LLVM_TARGET') or ''
+ if x86:
+ os.environ['EMCC_LLVM_TARGET'] = "i386-pc-linux-gnu"
+ try:
+ old_fastcomp = os.environ.get('EMCC_FAST_COMPILER') or ''
+ if x86:
+ os.environ['EMCC_FAST_COMPILER'] = "0"
+ try:
+ old_chunk_size = os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or ''
+ os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = '1' # test splitting out each function to a chunk in emscripten.py (21 functions here)
+
+ # A good test of i64 math
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing')
+ self.do_run('', 'Usage: hashstring <seed>',
+ libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None, cache_name_extra=str(x86)),
+ includes=[path_from_root('tests', 'cube2hash')])
+
+ for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
+ ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'),
+ ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]:
+ self.do_run('', 'hash value: ' + output, [text], no_build=True)
+ finally:
+ os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = old_chunk_size
+ finally:
+ if x86:
+ if old_fastcomp:
+ os.environ['EMCC_FAST_COMPILER'] = old_fastcomp
+ else:
+ del os.environ['EMCC_FAST_COMPILER']
+ finally:
+ if x86:
+ if old_x86:
+ os.environ['EMCC_LLVM_TARGET'] = old_x86
+ else:
+ del os.environ['EMCC_LLVM_TARGET']
def test_unaligned(self):
if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1')
@@ -951,7 +963,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
for named in (0, 1):
print named
- if os.environ.get('EMCC_FAST_COMPILER') == '1' and named: continue # no named globals in fastcomp
+ if os.environ.get('EMCC_FAST_COMPILER') != '0' and named: continue # no named globals in fastcomp
Settings.NAMED_GLOBALS = named
self.do_run_from_file(src, output, ['wowie', 'too', '74'])
@@ -1138,7 +1150,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
def test_longjmp_repeat(self):
- if os.environ.get('EMCC_FAST_COMPILER') != '1': Settings.MAX_SETJMPS = 1 # todo: do this more strict thing in fastcomp too
+ if os.environ.get('EMCC_FAST_COMPILER') == '0': Settings.MAX_SETJMPS = 1 # todo: do this more strict thing in fastcomp too
test_path = path_from_root('tests', 'core', 'test_longjmp_repeat')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
@@ -1162,7 +1174,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
def test_setjmp_many(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp: make MAX_SETJMPS take effect')
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp: make MAX_SETJMPS take effect')
src = r'''
#include <stdio.h>
@@ -1930,7 +1942,7 @@ def process(filename):
def test_inlinejs(self):
if not self.is_le32(): return self.skip('le32 needed for inline js')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('fastcomp only supports EM_ASM')
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('fastcomp only supports EM_ASM')
test_path = path_from_root('tests', 'core', 'test_inlinejs')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -1943,7 +1955,7 @@ def process(filename):
def test_inlinejs2(self):
if not self.is_le32(): return self.skip('le32 needed for inline js')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('fastcomp only supports EM_ASM')
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('fastcomp only supports EM_ASM')
test_path = path_from_root('tests', 'core', 'test_inlinejs2')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -2749,7 +2761,7 @@ The current type of b is: 9
self.do_run(main, 'supp: 54,2\nmain: 56\nsupp see: 543\nmain see: 76\nok.')
def can_dlfcn(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1':
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
self.skip('todo in fastcomp')
return False
@@ -3171,7 +3183,7 @@ def process(filename):
def test_dlfcn_self(self):
if Settings.USE_TYPED_ARRAYS == 1: return self.skip('Does not work with USE_TYPED_ARRAYS=1')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp')
Settings.DLOPEN_SUPPORT = 1
def post(filename):
@@ -4673,25 +4685,6 @@ return malloc(size);
main = main[:main.find('\n}')]
assert main.count('\n') <= 7, ('must not emit too many postSets: %d' % main.count('\n')) + ' : ' + main
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('fastcomp always aliases pointers')
-
- assert 'asm2g' in test_modes
- if self.run_name == 'asm2g':
- results = {}
- original = open('src.cpp.o.js').read()
- results[Settings.ALIASING_FUNCTION_POINTERS] = len(original)
- Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS
- self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
- final = open('src.cpp.o.js').read()
- results[Settings.ALIASING_FUNCTION_POINTERS] = len(final)
- open('original.js', 'w').write(original)
- print results
- assert results[1] < 0.99*results[0]
- assert ' & 3]()' in original, 'small function table exists'
- assert ' & 3]()' not in final, 'small function table does not exist'
- assert ' & 255]()' not in original, 'big function table does not exist'
- assert ' & 255]()' in final, 'big function table exists'
-
def test_simd(self):
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate
@@ -4721,7 +4714,7 @@ return malloc(size);
self.do_run_from_file(src, output)
def test_gcc_unmangler(self):
- if os.environ.get('EMCC_FAST_COMPILER') != '1': Settings.NAMED_GLOBALS = 1 # test coverage for this; fastcomp never names globals
+ if os.environ.get('EMCC_FAST_COMPILER') == '0': Settings.NAMED_GLOBALS = 1 # test coverage for this; fastcomp never names globals
Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('third_party'), '-Wno-warn-absolute-paths']
@@ -4892,7 +4885,7 @@ def process(filename):
test()
assert 'asm2g' in test_modes
- if self.run_name == 'asm2g' and not use_cmake and os.environ.get('EMCC_FAST_COMPILER') != '1':
+ if self.run_name == 'asm2g' and not use_cmake and os.environ.get('EMCC_FAST_COMPILER') == '0':
# Test forced alignment
print >> sys.stderr, 'testing FORCE_ALIGNED_MEMORY'
old = open('src.cpp.o.js').read()
@@ -5125,7 +5118,7 @@ def process(filename):
for name in glob.glob(path_from_root('tests', 'cases', '*.ll')):
shortname = name.replace('.ll', '')
if '' not in shortname: continue
- if os.environ.get('EMCC_FAST_COMPILER') == '1' and os.path.basename(shortname) in [
+ if os.environ.get('EMCC_FAST_COMPILER') != '0' and os.path.basename(shortname) in [
'structparam', 'extendedprecision', 'issue_39', 'emptystruct', 'phinonexist', 'quotedlabel', 'oob_ta2', 'phientryimplicit', 'phiself', 'invokebitcast', 'funcptr', # invalid ir
'structphiparam', 'callwithstructural_ta2', 'callwithstructural64_ta2', 'structinparam', # pnacl limitations in ExpandStructRegs
'2xi40', # pnacl limitations in ExpandGetElementPtr
@@ -5141,7 +5134,7 @@ def process(filename):
if '_le32' in shortname and not self.is_le32():
print self.skip('case "%s" not relevant for non-le32 target' % shortname)
continue
- if '_fastcomp' in shortname and not os.environ.get('EMCC_FAST_COMPILER') == '1':
+ if '_fastcomp' in shortname and not os.environ.get('EMCC_FAST_COMPILER') != '0':
print self.skip('case "%s" not relevant for non-fastcomp' % shortname)
continue
self.emcc_args = emcc_args
@@ -5180,7 +5173,7 @@ def process(filename):
for name in glob.glob(path_from_root('tests', 'fuzz', '*.c')) + glob.glob(path_from_root('tests', 'fuzz', '*.cpp')):
#if os.path.basename(name) != '4.c': continue
if 'newfail' in name: continue
- if os.path.basename(name) == '18.cpp' and not os.environ.get('EMCC_FAST_COMPILER') == '1': continue # works only in fastcomp
+ if os.path.basename(name) == '18.cpp' and not os.environ.get('EMCC_FAST_COMPILER') != '0': continue # works only in fastcomp
print name
self.do_run(open(path_from_root('tests', 'fuzz', name)).read(),
@@ -5420,7 +5413,7 @@ def process(filename):
def test_asm_pgo(self):
if not Settings.ASM_JS: return self.skip('this is a test for PGO for asm (NB: not *in* asm)')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp')
src = open(path_from_root('tests', 'hello_libcxx.cpp')).read()
output = 'hello, world!'
@@ -5540,7 +5533,7 @@ def process(filename):
def test_embind(self):
if self.emcc_args is None: return self.skip('requires emcc')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp')
Building.COMPILER_TEST_OPTS += ['--bind']
src = r'''
@@ -5563,7 +5556,7 @@ def process(filename):
def test_embind_2(self):
if self.emcc_args is None: return self.skip('requires emcc')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp')
Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js']
open('post.js', 'w').write('''
Module.print('lerp ' + Module.lerp(1, 2, 0.66) + '.');
@@ -5637,8 +5630,6 @@ def process(filename):
# Way 2: use CppHeaderParser
- Settings.RUNTIME_TYPE_INFO = 1
-
header = '''
#include <stdio.h>
@@ -5879,6 +5870,8 @@ def process(filename):
self.do_run(src, '|hello|43|world|41|', post_build=post)
def test_typeinfo(self):
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('fastcomp does not support RUNTIME_TYPE_INFO')
+
if self.emcc_args is not None and self.emcc_args != []: return self.skip('full LLVM opts optimize out all the code that uses the type')
Settings.RUNTIME_TYPE_INFO = 1
@@ -6397,7 +6390,7 @@ def process(filename):
def test_minmax(self):
if self.emcc_args == None: return self.skip('needs emcc')
- if os.environ.get('EMCC_FAST_COMPILER') != '1': return self.skip('this test will not pass in the old compiler')
+ if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('this test will not pass in the old compiler')
self.do_run(open(path_from_root('tests', 'test_minmax.c')).read(), 'NAN != NAN\nSuccess!')
def test_locale(self):
@@ -6460,6 +6453,7 @@ def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0,
return
# TODO: Move much of these to a init() function in shared.py, and reuse that
+ Settings.ASM_JS = 0
Settings.USE_TYPED_ARRAYS = typed_arrays
Settings.INVOKE_RUN = 1
Settings.RELOOP = 0 # we only do them in the "o2" pass
@@ -6487,27 +6481,19 @@ def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0,
return TT
-# Make one run with the defaults
-default = make_run("default", compiler=CLANG, emcc_args=[] if os.environ.get('EMCC_FAST_COMPILER') != '1' else ['-s', 'ASM_JS=1'])
-
-# Make one run with -O1, with safe heap
-o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "ASM_JS=0", "-s", "SAFE_HEAP=1"])
-
-# Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow)
-o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0", "-s", "JS_CHUNK_SIZE=1024"])
-
-# asm.js
+# Main test modes
+default = make_run("default", compiler=CLANG, emcc_args=[])
asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1"])
asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2"])
asm3 = make_run("asm3", compiler=CLANG, emcc_args=["-O3"])
asm2f = make_run("asm2f", compiler=CLANG, emcc_args=["-O2", "-s", "PRECISE_F32=1"])
-if os.environ.get('EMCC_FAST_COMPILER') == '1':
- asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "SAFE_HEAP=1"])
-else:
- asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "CHECK_HEAP_ALIGN=1"])
-asm2x86 = make_run("asm2x86", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "CHECK_HEAP_ALIGN=1"], env={"EMCC_LLVM_TARGET": "i386-pc-linux-gnu"})
+asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "SAFE_HEAP=1"])
+
+# Legacy test modes -
+slow2 = make_run("slow2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0"], env={"EMCC_FAST_COMPILER": "0"})
+slow2asm = make_run("slow2asm", compiler=CLANG, emcc_args=["-O2"], env={"EMCC_FAST_COMPILER": "0"})
-# Make custom runs with various options
+# Legacy test modes - very old
for compiler, quantum, embetter, typed_arrays in [
(CLANG, 4, 0, 0),
(CLANG, 4, 1, 1),
@@ -6515,6 +6501,6 @@ for compiler, quantum, embetter, typed_arrays in [
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)
)
- locals()[fullname] = make_run(fullname, fullname, compiler, embetter, quantum, typed_arrays)
+ locals()[fullname] = make_run(fullname, fullname, compiler, embetter, quantum, typed_arrays, env={"EMCC_FAST_COMPILER": "0"})
del T # T is just a shape for the specific subclasses, we don't test it itself
diff --git a/tests/test_other.py b/tests/test_other.py
index 80461972..69f8d5c0 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -1,7 +1,7 @@
import multiprocessing, os, re, shutil, subprocess, sys
import tools.shared
from tools.shared import *
-from runner import RunnerCore, path_from_root, get_bullet_library
+from runner import RunnerCore, path_from_root, get_bullet_library, nonfastcomp
class other(RunnerCore):
def get_zlib_library(self):
@@ -207,7 +207,7 @@ Options that are modified or new in %s include:
]:
print params, text
self.clear()
- if os.environ.get('EMCC_FAST_COMPILER') == '1' and ['disable typed arrays', 'typed arrays 1 selected']: continue
+ if os.environ.get('EMCC_FAST_COMPILER') != '0' and ['disable typed arrays', 'typed arrays 1 selected']: continue
output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_loop.cpp'), '-o', 'a.out.js'] + params, stdout=PIPE, stderr=PIPE).communicate()
assert len(output[0]) == 0, output[0]
assert os.path.exists('a.out.js'), '\n'.join(output)
@@ -277,6 +277,9 @@ f.close()
# TODO: test normal project linking, static and dynamic: get_library should not need to be told what to link!
# TODO: deprecate llvm optimizations, dlmalloc, etc. in emscripten.py.
+ def test_emcc_nonfastcomp(self):
+ nonfastcomp(self.test_emcc)
+
def test_cmake(self):
# Test all supported generators.
if WINDOWS:
@@ -451,48 +454,48 @@ f.close()
self.assertContained('hello, world!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
def test_unaligned_memory(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
- open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
- #include <stdio.h>
- #include <stdarg.h>
+ def test():
+ open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ #include <stdarg.h>
- typedef unsigned char Bit8u;
- typedef unsigned short Bit16u;
- typedef unsigned int Bit32u;
+ typedef unsigned char Bit8u;
+ typedef unsigned short Bit16u;
+ typedef unsigned int Bit32u;
- int main()
- {
- va_list argp;
- va_arg(argp, char *); // check for compilation error, #1705
+ int main()
+ {
+ va_list argp;
+ va_arg(argp, char *); // check for compilation error, #1705
- Bit8u data[4] = {0x01,0x23,0x45,0x67};
+ Bit8u data[4] = {0x01,0x23,0x45,0x67};
- printf("data: %x\n", *(Bit32u*)data);
- printf("data[0,1] 16bit: %x\n", *(Bit16u*)data);
- printf("data[1,2] 16bit: %x\n", *(Bit16u*)(data+1));
- }
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
- self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ printf("data: %x\n", *(Bit32u*)data);
+ printf("data[0,1] 16bit: %x\n", *(Bit16u*)data);
+ printf("data[1,2] 16bit: %x\n", *(Bit16u*)(data+1));
+ }
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
+ self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ nonfastcomp(test)
def test_unaligned_memory_2(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
- open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
- #include <string>
- #include <stdio.h>
+ def test():
+ open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
+ #include <string>
+ #include <stdio.h>
- int main( int argc, char ** argv )
- {
- std::string testString( "Hello, World!" );
+ int main( int argc, char ** argv )
+ {
+ std::string testString( "Hello, World!" );
- printf( "testString = %s\n", testString.c_str() );
- return 0;
- }
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
- self.assertContained('testString = Hello, World!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ printf( "testString = %s\n", testString.c_str() );
+ return 0;
+ }
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
+ self.assertContained('testString = Hello, World!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ nonfastcomp(test)
def test_asm_minify(self):
def test(args):
@@ -542,7 +545,7 @@ f.close()
self.assertContained(expected, run_js(self.in_dir('a.out.js'), stderr=PIPE, full_output=True))
return open(self.in_dir('a.out.js')).read()
- if os.environ.get('EMCC_FAST_COMPILER') != '1':
+ if os.environ.get('EMCC_FAST_COMPILER') == '0':
test([], 'my func') # no asm, so casting func works
test(['-O2'], 'abort', ['Casting potentially incompatible function pointer i32 ()* to void (...)*, for my_func',
'Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these']) # asm, so failure
@@ -590,283 +593,285 @@ This pointer might make sense in another type signature: i: _my_func
assert not os.path.exists('a.out') and not os.path.exists('a.exe'), 'Must not leave unneeded linker stubs'
def test_static_link(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
- def test(name, header, main, side, expected, args=[], suffix='cpp', first=True):
- print name
- #t = main ; main = side ; side = t
- original_main = main
- original_side = side
- if header: open(os.path.join(self.get_dir(), 'header.h'), 'w').write(header)
- if type(main) == str:
- open(os.path.join(self.get_dir(), 'main.' + suffix), 'w').write(main)
- main = ['main.' + suffix]
- if type(side) == str:
- open(os.path.join(self.get_dir(), 'side.' + suffix), 'w').write(side)
- side = ['side.' + suffix]
- Popen([PYTHON, EMCC] + side + ['-o', 'side.js', '-s', 'SIDE_MODULE=1', '-O2'] + args).communicate()
- # TODO: test with and without DISABLE_GL_EMULATION, check that file sizes change
- Popen([PYTHON, EMCC] + main + ['-o', 'main.js', '-s', 'MAIN_MODULE=1', '-O2', '-s', 'DISABLE_GL_EMULATION=1'] + args).communicate()
- Popen([PYTHON, EMLINK, 'main.js', 'side.js', 'together.js'], stdout=PIPE).communicate()
- assert os.path.exists('together.js')
- for engine in JS_ENGINES:
- out = run_js('together.js', engine=engine, stderr=PIPE, full_output=True)
- self.assertContained(expected, out)
- if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
- if first:
- shutil.copyfile('together.js', 'first.js')
- test(name + ' (reverse)', header, original_side, original_main, expected, args, suffix, False) # test reverse order
-
- # test a simple call from one module to another. only one has a string (and constant memory initialization for it)
- test('basics', '', '''
- #include <stdio.h>
- extern int sidey();
- int main() {
- printf("other says %d.", sidey());
- return 0;
- }
- ''', '''
- int sidey() { return 11; }
- ''', 'other says 11.')
-
- # finalization of float variables should pass asm.js validation
- test('floats', '', '''
- #include <stdio.h>
- extern float sidey();
- int main() {
- printf("other says %.2f.", sidey()+1);
- return 0;
- }
- ''', '''
- float sidey() { return 11.5; }
- ''', 'other says 12.50')
+ def nonfc():
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp')
+
+ def test(name, header, main, side, expected, args=[], suffix='cpp', first=True):
+ print name
+ #t = main ; main = side ; side = t
+ original_main = main
+ original_side = side
+ if header: open(os.path.join(self.get_dir(), 'header.h'), 'w').write(header)
+ if type(main) == str:
+ open(os.path.join(self.get_dir(), 'main.' + suffix), 'w').write(main)
+ main = ['main.' + suffix]
+ if type(side) == str:
+ open(os.path.join(self.get_dir(), 'side.' + suffix), 'w').write(side)
+ side = ['side.' + suffix]
+ Popen([PYTHON, EMCC] + side + ['-o', 'side.js', '-s', 'SIDE_MODULE=1', '-O2'] + args).communicate()
+ # TODO: test with and without DISABLE_GL_EMULATION, check that file sizes change
+ Popen([PYTHON, EMCC] + main + ['-o', 'main.js', '-s', 'MAIN_MODULE=1', '-O2', '-s', 'DISABLE_GL_EMULATION=1'] + args).communicate()
+ Popen([PYTHON, EMLINK, 'main.js', 'side.js', 'together.js'], stdout=PIPE).communicate()
+ assert os.path.exists('together.js')
+ for engine in JS_ENGINES:
+ out = run_js('together.js', engine=engine, stderr=PIPE, full_output=True)
+ self.assertContained(expected, out)
+ if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
+ if first:
+ shutil.copyfile('together.js', 'first.js')
+ test(name + ' (reverse)', header, original_side, original_main, expected, args, suffix, False) # test reverse order
+
+ # test a simple call from one module to another. only one has a string (and constant memory initialization for it)
+ test('basics', '', '''
+ #include <stdio.h>
+ extern int sidey();
+ int main() {
+ printf("other says %d.", sidey());
+ return 0;
+ }
+ ''', '''
+ int sidey() { return 11; }
+ ''', 'other says 11.')
- # memory initialization in both
- test('multiple memory inits', '', r'''
- #include <stdio.h>
- extern void sidey();
- int main() {
- printf("hello from main\n");
- sidey();
- return 0;
- }
- ''', r'''
- #include <stdio.h>
- void sidey() { printf("hello from side\n"); }
- ''', 'hello from main\nhello from side\n')
+ # finalization of float variables should pass asm.js validation
+ test('floats', '', '''
+ #include <stdio.h>
+ extern float sidey();
+ int main() {
+ printf("other says %.2f.", sidey()+1);
+ return 0;
+ }
+ ''', '''
+ float sidey() { return 11.5; }
+ ''', 'other says 12.50')
- # function pointers
- test('fp1', 'typedef void (*voidfunc)();', r'''
- #include <stdio.h>
- #include "header.h"
- voidfunc sidey(voidfunc f);
- void a() { printf("hello from funcptr\n"); }
- int main() {
- sidey(a)();
- return 0;
- }
- ''', '''
- #include "header.h"
- voidfunc sidey(voidfunc f) { return f; }
- ''', 'hello from funcptr\n')
+ # memory initialization in both
+ test('multiple memory inits', '', r'''
+ #include <stdio.h>
+ extern void sidey();
+ int main() {
+ printf("hello from main\n");
+ sidey();
+ return 0;
+ }
+ ''', r'''
+ #include <stdio.h>
+ void sidey() { printf("hello from side\n"); }
+ ''', 'hello from main\nhello from side\n')
- # function pointers with 'return' in the name
- test('fp2', 'typedef void (*voidfunc)();', r'''
- #include <stdio.h>
- #include "header.h"
- int sidey(voidfunc f);
- void areturn0() { printf("hello 0\n"); }
- void areturn1() { printf("hello 1\n"); }
- void areturn2() { printf("hello 2\n"); }
- int main(int argc, char **argv) {
- voidfunc table[3] = { areturn0, areturn1, areturn2 };
- table[sidey(NULL)]();
- return 0;
- }
- ''', '''
- #include "header.h"
- int sidey(voidfunc f) { if (f) f(); return 1; }
- ''', 'hello 1\n')
+ # function pointers
+ test('fp1', 'typedef void (*voidfunc)();', r'''
+ #include <stdio.h>
+ #include "header.h"
+ voidfunc sidey(voidfunc f);
+ void a() { printf("hello from funcptr\n"); }
+ int main() {
+ sidey(a)();
+ return 0;
+ }
+ ''', '''
+ #include "header.h"
+ voidfunc sidey(voidfunc f) { return f; }
+ ''', 'hello from funcptr\n')
- # Global initializer
- test('global init', '', r'''
- #include <stdio.h>
- struct Class {
- Class() { printf("a new Class\n"); }
- };
- static Class c;
- int main() {
- return 0;
- }
- ''', r'''
- void nothing() {}
- ''', 'a new Class\n')
+ # function pointers with 'return' in the name
+ test('fp2', 'typedef void (*voidfunc)();', r'''
+ #include <stdio.h>
+ #include "header.h"
+ int sidey(voidfunc f);
+ void areturn0() { printf("hello 0\n"); }
+ void areturn1() { printf("hello 1\n"); }
+ void areturn2() { printf("hello 2\n"); }
+ int main(int argc, char **argv) {
+ voidfunc table[3] = { areturn0, areturn1, areturn2 };
+ table[sidey(NULL)]();
+ return 0;
+ }
+ ''', '''
+ #include "header.h"
+ int sidey(voidfunc f) { if (f) f(); return 1; }
+ ''', 'hello 1\n')
- # Multiple global initializers (LLVM generates overlapping names for them)
- test('global inits', r'''
- #include <stdio.h>
- struct Class {
- Class(const char *name) { printf("new %s\n", name); }
- };
- ''', r'''
- #include "header.h"
- static Class c("main");
- int main() {
- return 0;
- }
- ''', r'''
- #include "header.h"
- static Class c("side");
- ''', ['new main\nnew side\n', 'new side\nnew main\n'])
+ # Global initializer
+ test('global init', '', r'''
+ #include <stdio.h>
+ struct Class {
+ Class() { printf("a new Class\n"); }
+ };
+ static Class c;
+ int main() {
+ return 0;
+ }
+ ''', r'''
+ void nothing() {}
+ ''', 'a new Class\n')
- # Class code used across modules
- test('codecall', r'''
- #include <stdio.h>
- struct Class {
- Class(const char *name);
- };
- ''', r'''
- #include "header.h"
- int main() {
- Class c("main");
- return 0;
- }
- ''', r'''
- #include "header.h"
- Class::Class(const char *name) { printf("new %s\n", name); }
- ''', ['new main\n'])
-
- # malloc usage in both modules
- test('malloc', r'''
- #include <stdlib.h>
- #include <string.h>
- char *side(const char *data);
- ''', r'''
- #include <stdio.h>
- #include "header.h"
- int main() {
- char *temp = side("hello through side\n");
- char *ret = (char*)malloc(strlen(temp)+1);
- strcpy(ret, temp);
- temp[1] = 'x';
- puts(ret);
- return 0;
- }
- ''', r'''
- #include "header.h"
- char *side(const char *data) {
- char *ret = (char*)malloc(strlen(data)+1);
- strcpy(ret, data);
- return ret;
- }
- ''', ['hello through side\n'])
+ # Multiple global initializers (LLVM generates overlapping names for them)
+ test('global inits', r'''
+ #include <stdio.h>
+ struct Class {
+ Class(const char *name) { printf("new %s\n", name); }
+ };
+ ''', r'''
+ #include "header.h"
+ static Class c("main");
+ int main() {
+ return 0;
+ }
+ ''', r'''
+ #include "header.h"
+ static Class c("side");
+ ''', ['new main\nnew side\n', 'new side\nnew main\n'])
- # js library call
- open('lib.js', 'w').write(r'''
- mergeInto(LibraryManager.library, {
- test_lib_func: function(x) {
- return x + 17.2;
+ # Class code used across modules
+ test('codecall', r'''
+ #include <stdio.h>
+ struct Class {
+ Class(const char *name);
+ };
+ ''', r'''
+ #include "header.h"
+ int main() {
+ Class c("main");
+ return 0;
}
- });
- ''')
- test('js-lib', 'extern "C" { extern double test_lib_func(int input); }', r'''
- #include <stdio.h>
- #include "header.h"
- extern double sidey();
- int main2() { return 11; }
- int main() {
- int input = sidey();
- double temp = test_lib_func(input);
- printf("other says %.2f\n", temp);
- printf("more: %.5f, %d\n", temp, input);
- return 0;
- }
- ''', r'''
- #include <stdio.h>
- #include "header.h"
- extern int main2();
- double sidey() {
- int temp = main2();
- printf("main2 sed: %d\n", temp);
- printf("main2 sed: %u, %c\n", temp, temp/2);
- return test_lib_func(temp);
- }
- ''', 'other says 45.2', ['--js-library', 'lib.js'])
+ ''', r'''
+ #include "header.h"
+ Class::Class(const char *name) { printf("new %s\n", name); }
+ ''', ['new main\n'])
- # libc usage in one modules. must force libc inclusion in the main module if that isn't the one using mallinfo()
- try:
- os.environ['EMCC_FORCE_STDLIBS'] = 'libc'
- test('malloc-1', r'''
+ # malloc usage in both modules
+ test('malloc', r'''
+ #include <stdlib.h>
#include <string.h>
- int side();
+ char *side(const char *data);
''', r'''
#include <stdio.h>
#include "header.h"
int main() {
- printf("|%d|\n", side());
+ char *temp = side("hello through side\n");
+ char *ret = (char*)malloc(strlen(temp)+1);
+ strcpy(ret, temp);
+ temp[1] = 'x';
+ puts(ret);
return 0;
}
''', r'''
- #include <stdlib.h>
- #include <malloc.h>
#include "header.h"
- int side() {
- struct mallinfo m = mallinfo();
- return m.arena > 1;
+ char *side(const char *data) {
+ char *ret = (char*)malloc(strlen(data)+1);
+ strcpy(ret, data);
+ return ret;
}
- ''', ['|1|\n'])
- finally:
- del os.environ['EMCC_FORCE_STDLIBS']
-
- # iostream usage in one and std::string in both
- test('iostream', r'''
- #include <iostream>
- #include <string>
- std::string side();
- ''', r'''
- #include "header.h"
- int main() {
- std::cout << "hello from main " << side() << std::endl;
- return 0;
- }
- ''', r'''
- #include "header.h"
- std::string side() { return "and hello from side"; }
- ''', ['hello from main and hello from side\n'])
-
- # followup to iostream test: a second linking
- print 'second linking of a linking output'
- open('moar.cpp', 'w').write(r'''
- #include <iostream>
- struct Moar {
- Moar() { std::cout << "moar!" << std::endl; }
- };
- Moar m;
- ''')
- Popen([PYTHON, EMCC, 'moar.cpp', '-o', 'moar.js', '-s', 'SIDE_MODULE=1', '-O2']).communicate()
- Popen([PYTHON, EMLINK, 'together.js', 'moar.js', 'triple.js'], stdout=PIPE).communicate()
- assert os.path.exists('triple.js')
- for engine in JS_ENGINES:
- out = run_js('triple.js', engine=engine, stderr=PIPE, full_output=True)
- self.assertContained('moar!\nhello from main and hello from side\n', out)
- if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
-
- # zlib compression library. tests function pointers in initializers and many other things
- test('zlib', '', open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
- self.get_zlib_library(),
- open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
- args=['-I' + path_from_root('tests', 'zlib')], suffix='c')
-
- use_cmake = WINDOWS
- bullet_library = get_bullet_library(self, use_cmake)
-
- # bullet physics engine. tests all the things
- test('bullet', '', open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
- bullet_library,
- [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings
- open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(),
- open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()],
- args=['-I' + path_from_root('tests', 'bullet', 'src')])
+ ''', ['hello through side\n'])
+
+ # js library call
+ open('lib.js', 'w').write(r'''
+ mergeInto(LibraryManager.library, {
+ test_lib_func: function(x) {
+ return x + 17.2;
+ }
+ });
+ ''')
+ test('js-lib', 'extern "C" { extern double test_lib_func(int input); }', r'''
+ #include <stdio.h>
+ #include "header.h"
+ extern double sidey();
+ int main2() { return 11; }
+ int main() {
+ int input = sidey();
+ double temp = test_lib_func(input);
+ printf("other says %.2f\n", temp);
+ printf("more: %.5f, %d\n", temp, input);
+ return 0;
+ }
+ ''', r'''
+ #include <stdio.h>
+ #include "header.h"
+ extern int main2();
+ double sidey() {
+ int temp = main2();
+ printf("main2 sed: %d\n", temp);
+ printf("main2 sed: %u, %c\n", temp, temp/2);
+ return test_lib_func(temp);
+ }
+ ''', 'other says 45.2', ['--js-library', 'lib.js'])
+
+ # libc usage in one modules. must force libc inclusion in the main module if that isn't the one using mallinfo()
+ try:
+ os.environ['EMCC_FORCE_STDLIBS'] = 'libc'
+ test('malloc-1', r'''
+ #include <string.h>
+ int side();
+ ''', r'''
+ #include <stdio.h>
+ #include "header.h"
+ int main() {
+ printf("|%d|\n", side());
+ return 0;
+ }
+ ''', r'''
+ #include <stdlib.h>
+ #include <malloc.h>
+ #include "header.h"
+ int side() {
+ struct mallinfo m = mallinfo();
+ return m.arena > 1;
+ }
+ ''', ['|1|\n'])
+ finally:
+ del os.environ['EMCC_FORCE_STDLIBS']
+
+ # iostream usage in one and std::string in both
+ test('iostream', r'''
+ #include <iostream>
+ #include <string>
+ std::string side();
+ ''', r'''
+ #include "header.h"
+ int main() {
+ std::cout << "hello from main " << side() << std::endl;
+ return 0;
+ }
+ ''', r'''
+ #include "header.h"
+ std::string side() { return "and hello from side"; }
+ ''', ['hello from main and hello from side\n'])
+
+ # followup to iostream test: a second linking
+ print 'second linking of a linking output'
+ open('moar.cpp', 'w').write(r'''
+ #include <iostream>
+ struct Moar {
+ Moar() { std::cout << "moar!" << std::endl; }
+ };
+ Moar m;
+ ''')
+ Popen([PYTHON, EMCC, 'moar.cpp', '-o', 'moar.js', '-s', 'SIDE_MODULE=1', '-O2']).communicate()
+ Popen([PYTHON, EMLINK, 'together.js', 'moar.js', 'triple.js'], stdout=PIPE).communicate()
+ assert os.path.exists('triple.js')
+ for engine in JS_ENGINES:
+ out = run_js('triple.js', engine=engine, stderr=PIPE, full_output=True)
+ self.assertContained('moar!\nhello from main and hello from side\n', out)
+ if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
+
+ # zlib compression library. tests function pointers in initializers and many other things
+ test('zlib', '', open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
+ self.get_zlib_library(),
+ open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
+ args=['-I' + path_from_root('tests', 'zlib')], suffix='c')
+
+ use_cmake = WINDOWS
+ bullet_library = get_bullet_library(self, use_cmake)
+
+ # bullet physics engine. tests all the things
+ test('bullet', '', open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
+ bullet_library,
+ [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings
+ open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(),
+ open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()],
+ args=['-I' + path_from_root('tests', 'bullet', 'src')])
+ nonfastcomp(nonfc)
def test_outline(self):
def test(name, src, libs, expected, expected_ranges, args=[], suffix='cpp'):
@@ -918,7 +923,7 @@ This pointer might make sense in another type signature: i: _my_func
500: (250, 500),
1000: (230, 1000),
2000: (380, 2000),
- 5000: (800, 5000),
+ 5000: (500, 5000),
0: (1500, 5000)
}),
(['-O2'], {
@@ -1817,26 +1822,28 @@ This pointer might make sense in another type signature: i: _my_func
assert 'error' not in err, 'Unexpected stderr: ' + err
def test_chunking(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('not relevant for fastcomp, only checks js compiler chunking')
- if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
- if os.environ.get('EMCC_CORES'): return self.skip('cannot run if cores are altered')
- if multiprocessing.cpu_count() < 2: return self.skip('need multiple cores')
- try:
- os.environ['EMCC_DEBUG'] = '1'
- os.environ['EMCC_CORES'] = '2' # standardize over machines
- for asm, linkable, chunks in [
- (0, 0, 2), (0, 1, 2),
- (1, 0, 2), (1, 1, 2)
- ]:
- print asm, linkable, chunks
- output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1', '-s', 'LINKABLE=%d' % linkable, '-s', 'ASM_JS=%d' % asm] + (['-O2'] if asm else []), stdout=PIPE, stderr=PIPE).communicate()
- ok = False
- for c in range(chunks, chunks+2):
- ok = ok or ('phase 2 working on %d chunks' % c in err)
- assert ok, err
- finally:
- del os.environ['EMCC_DEBUG']
- del os.environ['EMCC_CORES']
+ def nonfc():
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('not relevant for fastcomp, only checks js compiler chunking')
+ if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
+ if os.environ.get('EMCC_CORES'): return self.skip('cannot run if cores are altered')
+ if multiprocessing.cpu_count() < 2: return self.skip('need multiple cores')
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ os.environ['EMCC_CORES'] = '2' # standardize over machines
+ for asm, linkable, chunks in [
+ (0, 0, 2), (0, 1, 2),
+ (1, 0, 2), (1, 1, 2)
+ ]:
+ print asm, linkable, chunks
+ output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1', '-s', 'LINKABLE=%d' % linkable, '-s', 'ASM_JS=%d' % asm] + (['-O2'] if asm else []), stdout=PIPE, stderr=PIPE).communicate()
+ ok = False
+ for c in range(chunks, chunks+2):
+ ok = ok or ('phase 2 working on %d chunks' % c in err)
+ assert ok, err
+ finally:
+ del os.environ['EMCC_DEBUG']
+ del os.environ['EMCC_CORES']
+ nonfastcomp(nonfc)
def test_debuginfo(self):
if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
@@ -1868,23 +1875,25 @@ This pointer might make sense in another type signature: i: _my_func
assert 'If you see this - the world is all right!' in output
def test_embind(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
- for args, fail in [
- ([], True), # without --bind, we fail
- (['--bind'], False),
- (['--bind', '-O1'], False),
- (['--bind', '-O2'], False),
- (['--bind', '-O1', '-s', 'ASM_JS=0'], False),
- (['--bind', '-O2', '-s', 'ASM_JS=0'], False)
- ]:
- print args, fail
- self.clear()
- try_delete(self.in_dir('a.out.js'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate()
- assert os.path.exists(self.in_dir('a.out.js')) == (not fail)
- if not fail:
- output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True)
- assert "FAIL" not in output, output
+ def nonfc():
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp')
+ for args, fail in [
+ ([], True), # without --bind, we fail
+ (['--bind'], False),
+ (['--bind', '-O1'], False),
+ (['--bind', '-O2'], False),
+ (['--bind', '-O1', '-s', 'ASM_JS=0'], False),
+ (['--bind', '-O2', '-s', 'ASM_JS=0'], False)
+ ]:
+ print args, fail
+ self.clear()
+ try_delete(self.in_dir('a.out.js'))
+ Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate()
+ assert os.path.exists(self.in_dir('a.out.js')) == (not fail)
+ if not fail:
+ output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True)
+ assert "FAIL" not in output, output
+ nonfastcomp(nonfc)
def test_llvm_nativizer(self):
try:
@@ -2362,7 +2371,7 @@ int main() {
assert '*** PCH/Modules Loaded:\nModule: header.h.gch' not in err[1], err[1]
def test_warn_unaligned(self):
- if os.environ.get('EMCC_FAST_COMPILER') != '1': return self.skip('need fastcomp')
+ if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('need fastcomp')
open('src.cpp', 'w').write(r'''
#include <stdio.h>
static const double grid[4][2] = {{-3 / 3., -1 / 3.},
diff --git a/tests/test_sanity.py b/tests/test_sanity.py
index 894f2192..5713c99c 100644
--- a/tests/test_sanity.py
+++ b/tests/test_sanity.py
@@ -196,9 +196,10 @@ class sanity(RunnerCore):
del os.environ['EM_IGNORE_SANITY']
def test_llvm_fastcomp(self):
- if os.environ.get('EMCC_FAST_COMPILER') != '1': return self.skip('not using fastcomp')
+ assert os.environ.get('EMCC_FAST_COMPILER') != '0', 'must be using fastcomp to test fastcomp'
WARNING = 'fastcomp in use, but LLVM has not been built with the JavaScript backend as a target'
+ WARNING2 = 'you can fall back to the older (pre-fastcomp) compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend'
restore()
@@ -206,6 +207,7 @@ class sanity(RunnerCore):
assert check_fastcomp()
output = self.check_working(EMCC)
assert WARNING not in output, output
+ assert WARNING2 not in output, output
# Fake incorrect llc output, no mention of js backend
restore()
@@ -222,6 +224,11 @@ class sanity(RunnerCore):
f.close()
os.chmod(path_from_root('tests', 'fake', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
output = self.check_working(EMCC, WARNING)
+ output = self.check_working(EMCC, WARNING2)
+
+ restore()
+
+ self.check_working([EMCC, 'tests/hello_world.cpp', '-s', 'INIT_HEAP=1'], '''Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend''')
def test_node(self):
NODE_WARNING = 'node version appears too old'
@@ -446,111 +453,34 @@ fi
try_delete(CANONICAL_TEMP_DIR)
def test_relooper(self):
- RELOOPER = Cache.get_path('relooper.js')
-
- restore()
- for phase in range(2): # 0: we wipe the relooper dir. 1: we have it, so should just update
- if phase == 0: Cache.erase()
- try_delete(RELOOPER)
-
- for i in range(4):
- print >> sys.stderr, phase, i
- opt = min(i, 2)
- try_delete('a.out.js')
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt), '-g'],
- stdout=PIPE, stderr=PIPE).communicate()
- self.assertContained('hello, world!', run_js('a.out.js'))
- output = '\n'.join(output)
- assert ('bootstrapping relooper succeeded' in output) == (i == 1), 'only bootstrap on first O2: ' + output
- assert os.path.exists(RELOOPER) == (i >= 1), 'have relooper on O2: ' + output
- src = open('a.out.js').read()
- main = src.split('function _main()')[1].split('\n}\n')[0]
- assert ('while (1) {' in main or 'while(1){' in main or 'while(1) {' in main or '} while ($' in main or '}while($' in main) == (i >= 1), 'reloop code on O2: ' + main
- assert ('switch' not in main) == (i >= 1), 'reloop code on O2: ' + main
-
- def test_jcache(self):
- PRE_LOAD_MSG = 'loading pre from jcache'
- PRE_SAVE_MSG = 'saving pre to jcache'
- FUNC_CHUNKS_LOAD_MSG = ' funcchunks from jcache'
- FUNC_CHUNKS_SAVE_MSG = ' funcchunks to jcache'
- JSFUNC_CHUNKS_LOAD_MSG = 'jsfuncchunks from jcache'
- JSFUNC_CHUNKS_SAVE_MSG = 'jsfuncchunks to jcache'
-
- restore()
- Cache.erase()
+ assert os.environ.get('EMCC_FAST_COMPILER') is None
try:
- os.environ['EMCC_DEBUG'] = '1'
- os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE'] = str(1024*512)
-
- self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp')
- if not os.path.exists(self.working_dir): os.makedirs(self.working_dir)
-
- assert not os.path.exists(JCache.get_cachename('emscript_files'))
-
- srcs = {}
- used_jcache = False
-
- for args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected in [
- ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []),
- (['--jcache'], 'hello_world_loop.cpp', True, False, True, False, True, False, []),
- (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []),
- ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []),
- # new
- ([], 'hello_world.cpp', False, False, False, False, False, False, []),
- (['--jcache'], 'hello_world.cpp', True, False, True, False, True, False, []),
- (['--jcache'], 'hello_world.cpp', False, True, False, True, False, True, []),
- ([], 'hello_world.cpp', False, False, False, False, False, False, []),
- # go back to old file, experience caching
- (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []),
- # new, large file
- ([], 'hello_malloc.cpp', False, False, False, False, False, False, []),
- (['--jcache'], 'hello_malloc.cpp', True, False, True, False, True, False, []),
- (['--jcache'], 'hello_malloc.cpp', False, True, False, True, False, True, []),
- ([], 'hello_malloc.cpp', False, False, False, False, False, False, []),
- # new, huge file
- ([], 'hello_libcxx.cpp', False, False, False, False, False, False, ('4 chunks',)),
- (['--jcache'], 'hello_libcxx.cpp', True, False, True, False, True, False, []),
- (['--jcache'], 'hello_libcxx.cpp', False, True, False, True, False, True, []),
- ([], 'hello_libcxx.cpp', False, False, False, False, False, False, []),
- # finally, build a file close to the previous, to see that some chunks are found in the cache and some not
- (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, True, True, True, True, []), # win on pre, mix on funcs, mix on jsfuncs
- (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, False, True, False, True, []),
- (None, None, None, None, None, None, None, None, None), # clear
- (['--jcache'], 'hello_libcxx_mod2.cpp', True, False, True, False, True, False, []), # load into cache
- (['--jcache'], 'hello_libcxx_mod2a.cpp', False, True, True, True, True, True, []) # add a printf, do not lose everything
- ]:
- self.clear()
- if args is None:
- Cache.erase()
- continue
-
- print >> sys.stderr, args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected
-
- out, err = Popen([PYTHON, EMCC, '-O2', '-g', path_from_root('tests', input_file)] + args, stdout=PIPE, stderr=PIPE).communicate()
- errtail = err.split('emcc invocation')[-1]
- self.assertContained('hello, world!', run_js('a.out.js'), errtail)
- assert (PRE_SAVE_MSG in err) == expect_pre_save, errtail
- assert (PRE_LOAD_MSG in err) == expect_pre_load, errtail
- assert (FUNC_CHUNKS_SAVE_MSG in err) == expect_funcs_save, errtail
- assert (FUNC_CHUNKS_LOAD_MSG in err) == expect_funcs_load, errtail
- assert (JSFUNC_CHUNKS_SAVE_MSG in err) == expect_jsfuncs_save, errtail
- assert (JSFUNC_CHUNKS_LOAD_MSG in err) == expect_jsfuncs_load, errtail
- for expect in expected: assert expect in err, expect + ' ? ' + errtail
- curr = open('a.out.js').read()
- if input_file not in srcs:
- srcs[input_file] = curr
- else:
- #open('/home/alon/Dev/emscripten/a', 'w').write(srcs[input_file])
- #open('/home/alon/Dev/emscripten/b', 'w').write(curr)
- assert abs(len(curr)/float(len(srcs[input_file]))-1)<0.01, 'contents may shift in order, but must remain the same size %d vs %d' % (len(curr), len(srcs[input_file])) + '\n' + errtail
- used_jcache = used_jcache or ('--jcache' in args)
- assert used_jcache == os.path.exists(JCache.get_cachename('emscript_files'))
- #print >> sys.stderr, errtail
+ os.environ['EMCC_FAST_COMPILER'] = '0'
+
+ RELOOPER = Cache.get_path('relooper.js')
+ restore()
+ for phase in range(2): # 0: we wipe the relooper dir. 1: we have it, so should just update
+ if phase == 0: Cache.erase()
+ try_delete(RELOOPER)
+
+ for i in range(4):
+ print >> sys.stderr, phase, i
+ opt = min(i, 2)
+ try_delete('a.out.js')
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt), '-g'],
+ stdout=PIPE, stderr=PIPE).communicate()
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ output = '\n'.join(output)
+ assert ('bootstrapping relooper succeeded' in output) == (i == 1), 'only bootstrap on first O2: ' + output
+ assert os.path.exists(RELOOPER) == (i >= 1), 'have relooper on O2: ' + output
+ src = open('a.out.js').read()
+ main = src.split('function _main()')[1].split('\n}\n')[0]
+ assert ('while (1) {' in main or 'while(1){' in main or 'while(1) {' in main or '} while ($' in main or '}while($' in main) == (i >= 1), 'reloop code on O2: ' + main
+ assert ('switch' not in main) == (i >= 1), 'reloop code on O2: ' + main
finally:
- del os.environ['EMCC_DEBUG']
- del os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE']
+ del os.environ['EMCC_FAST_COMPILER']
def test_nostdincxx(self):
restore()
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index fc195e03..240ee2bd 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -4525,10 +4525,10 @@ function outline(ast) {
var size = measureSize(func);
if (size <= extraInfo.sizeToOutline) {
sizeToOutline = Infinity;
- printErr(' no point in trying to reduce the size of ' + func[1] + ' which is ' + size + ' <= ' + extraInfo.sizeToOutline);
+ //printErr(' no point in trying to reduce the size of ' + func[1] + ' which is ' + size + ' <= ' + extraInfo.sizeToOutline);
} else {
sizeToOutline = Math.round(size/Math.max(2, asmData.intendedPieces--));
- printErr('trying to reduce the size of ' + func[1] + ' which is ' + size + ' (>=? ' + extraInfo.sizeToOutline + '), aim for ' + sizeToOutline);
+ //printErr('trying to reduce the size of ' + func[1] + ' which is ' + size + ' (>=? ' + extraInfo.sizeToOutline + '), aim for ' + sizeToOutline);
}
}
@@ -4753,7 +4753,7 @@ function outline(ast) {
}
}
outliningParents[newIdent] = func[1];
- printErr('performed outline ' + [func[1], newIdent, 'pre size', originalCodeSize, 'resulting size', measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned)), ' owned: ', setSize(owned), ' left: ', setSize(asmData.vars), setSize(asmData.params), ' loopsDepth: ', loops]);
+ //printErr('performed outline ' + [func[1], newIdent, 'pre size', originalCodeSize, 'resulting size', measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned)), ' owned: ', setSize(owned), ' left: ', setSize(asmData.vars), setSize(asmData.params), ' loopsDepth: ', loops]);
calculateThreshold(func, asmData);
return [newFunc];
}
@@ -4775,7 +4775,16 @@ function outline(ast) {
for (var i = minIndex; i < stats.length; i++) {
var stat = stats[i];
if (stat[0] == 'stat') stat = stat[1];
- if (stat[0] == 'assign' && stat[2][0] == 'name' && stat[2][1] == 'sp') minIndex = i+1; // cannot outline |sp = |
+ if (stat[0] == 'assign' && stat[2][0] == 'name' && stat[2][1] == 'sp') {
+ // cannot outline |sp = |
+ minIndex = i+1;
+ // When followed by a STACKTOP bump, preserve that too (we may need to replace it later)
+ stat = stats[i+1];
+ if (stat[0] == 'stat') stat = stat[1];
+ if (stat && stat[0] == 'assign' && stat[2][0] == 'name' && stat[2][1] == 'STACKTOP') {
+ minIndex = i+2;
+ }
+ }
}
}
}
@@ -4899,7 +4908,7 @@ function outline(ast) {
var maxTotalFunctions = Infinity; // debugging tool
- printErr('\n');
+ //printErr('\n');
var more = true;
while (more) {
@@ -4926,7 +4935,27 @@ function outline(ast) {
if ('sp' in asmData.vars) {
// find stack bump (STACKTOP = STACKTOP + X | 0) and add the extra space
var stackBumpNode = getStackBumpNode(stats);
- if (stackBumpNode) stackBumpNode[3][2][3][1] = asmData.totalStackSize;
+ if (stackBumpNode) {
+ stackBumpNode[3][2][3][1] = asmData.totalStackSize;
+ } else {
+ // sp exists, but no stack bump, so we need to add it
+ var found = false;
+ for (var i = 0; i < stats.length; i++) {
+ var stat = stats[i];
+ if (stat[0] === 'stat') stat = stat[1];
+ if (stat[0] === 'assign' && stat[2][0] === 'name' && stat[2][1] === 'sp') {
+ var newNode = ['stat', makeAssign(['name', 'STACKTOP'], ['binary', '|', ['binary', '+', ['name', 'STACKTOP'], ['num', asmData.totalStackSize]], ['num', 0]])];
+ if (i+1 < stats.length) {
+ stats.splice(i+1, 0, newNode);
+ } else {
+ stats.push(newNode);
+ }
+ found = true;
+ break;
+ }
+ }
+ assert(found);
+ }
} else if (!('sp' in asmData.params)) { // if sp is a param, then we are an outlined function, no need to add stack support for us
// add sp variable and stack bump
var index = getFirstIndexInNormalized(func, asmData);
@@ -4961,7 +4990,7 @@ function outline(ast) {
}
if (ret) {
ret.push(func);
- printErr('... resulting sizes of ' + func[1] + ' is ' + ret.map(measureSize) + '\n');
+ //printErr('... resulting sizes of ' + func[1] + ' is ' + ret.map(measureSize) + '\n');
}
}
denormalizeAsm(func, asmData);
diff --git a/tools/nativize_llvm.py b/tools/nativize_llvm.py
index b327bdfc..52dfdea1 100755
--- a/tools/nativize_llvm.py
+++ b/tools/nativize_llvm.py
@@ -25,9 +25,11 @@ Popen([LLVM_OPT, filename, '-strip-debug', '-o', filename + '.clean.bc']).commun
print 'bc => s'
for params in [['-march=x86'], ['-march=x86-64']]: # try x86, then x86-64 FIXME
print 'params', params
- Popen([LLVM_COMPILER] + params + [filename + '.clean.bc', '-o', filename + '.s']).communicate()[0]
- print 's => o'
- Popen(['as', filename + '.s', '-o', filename + '.o']).communicate()[0]
+ for triple in [['-mtriple=i386-pc-linux-gnu'], []]:
+ Popen([LLVM_COMPILER] + params + triple + [filename + '.clean.bc', '-o', filename + '.s']).communicate()[0]
+ print 's => o'
+ Popen(['as', filename + '.s', '-o', filename + '.o']).communicate()[0]
+ if os.path.exists(filename + '.o'): break
if os.path.exists(filename + '.o'): break
print 'o => runnable'
Popen(['g++', path_from_root('system', 'lib', 'debugging.cpp'), filename + '.o', '-o', filename + '.run'] + ['-l' + lib for lib in libs]).communicate()[0]
diff --git a/tools/shared.py b/tools/shared.py
index c4b01518..7a49f158 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -270,7 +270,7 @@ if EM_POPEN_WORKAROUND and os.name == 'nt':
# Expectations
-EXPECTED_LLVM_VERSION = (3,2)
+EXPECTED_LLVM_VERSION = (3,3)
actual_clang_version = None
@@ -303,6 +303,7 @@ def check_fastcomp():
print >> sys.stderr, '==========================================================================='
print >> sys.stderr, llc_version_info,
print >> sys.stderr, '==========================================================================='
+ logging.critical('you can fall back to the older (pre-fastcomp) compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend')
return False
return True
except Exception, e:
@@ -379,7 +380,7 @@ def check_sanity(force=False):
# some warning, mostly not fatal checks - do them even if EM_IGNORE_SANITY is on
check_llvm_version()
check_node_version()
- if os.environ.get('EMCC_FAST_COMPILER') == '1':
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
fastcomp_ok = check_fastcomp()
if os.environ.get('EM_IGNORE_SANITY'):
@@ -402,7 +403,7 @@ def check_sanity(force=False):
logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG))
sys.exit(1)
- if os.environ.get('EMCC_FAST_COMPILER') == '1':
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
if not fastcomp_ok:
logging.critical('failing sanity checks due to previous fastcomp failure')
sys.exit(1)
@@ -803,6 +804,8 @@ class Settings2(type):
@classmethod
def apply_opt_level(self, opt_level, noisy=False):
+ if opt_level == 0 and os.environ.get('EMCC_FAST_COMPILER') == '0':
+ self.attrs['ASM_JS'] = 0 # non-fastcomp has asm off in -O1
if opt_level >= 1:
self.attrs['ASM_JS'] = 1
self.attrs['ASSERTIONS'] = 0
@@ -1467,7 +1470,7 @@ class Building:
@staticmethod
def ensure_relooper(relooper):
if os.path.exists(relooper): return
- if os.environ.get('EMCC_FAST_COMPILER') == '1':
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
logging.debug('not building relooper to js, using it in c++ backend')
return
@@ -1542,7 +1545,7 @@ class Building:
text = m.groups(0)[0]
assert text.count('(') == 1 and text.count(')') == 1, 'must have simple expressions in emscripten_jcache_printf calls, no parens'
assert text.count('"') == 2, 'must have simple expressions in emscripten_jcache_printf calls, no strings as varargs parameters'
- if os.environ.get('EMCC_FAST_COMPILER') == '1': # fake it in fastcomp
+ if os.environ.get('EMCC_FAST_COMPILER') != '0': # fake it in fastcomp
return text.replace('emscripten_jcache_printf', 'printf')
start = text.index('(')
end = text.rindex(')')
diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js
index 27f93d8a..c4792c51 100644
--- a/tools/test-js-optimizer-asm-outline1-output.js
+++ b/tools/test-js-optimizer-asm-outline1-output.js
@@ -423,6 +423,32 @@ function switchh2() {
}
STACKTOP = sp;
}
+function stackSet(x1, x2, x3, x4, x5) {
+ x1 = x1 | 0;
+ x2 = x2 | 0;
+ x3 = x3 | 0;
+ x4 = x4 | 0;
+ x5 = x5 | 0;
+ var sp = 0;
+ sp = STACKTOP;
+ STACKTOP = STACKTOP + 282 | 0;
+ c(1);
+ c(2);
+ c(3);
+ c(4);
+ c(5);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ HEAP32[sp + 66 >> 2] = 0;
+ HEAP32[sp + 70 >> 2] = 0;
+ stackSet$1(sp);
+ HEAP32[sp + 58 >> 2] = 0;
+ HEAP32[sp + 62 >> 2] = 0;
+ stackSet$0(sp);
+}
function lin$0(sp) {
sp = sp | 0;
c(14);
@@ -926,4 +952,26 @@ function switchh2$2(sp) {
} while (0);
HEAP32[sp + 8 >> 2] = helper$0;
}
+function stackSet$0(sp) {
+ sp = sp | 0;
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
+}
+function stackSet$1(sp) {
+ sp = sp | 0;
+ c(11);
+ c(12);
+ c(13);
+ c(1);
+ c(2);
+ c(3);
+ c(4);
+ c(5);
+ c(6);
+}
diff --git a/tools/test-js-optimizer-asm-outline1.js b/tools/test-js-optimizer-asm-outline1.js
index b7ec9011..f640d11d 100644
--- a/tools/test-js-optimizer-asm-outline1.js
+++ b/tools/test-js-optimizer-asm-outline1.js
@@ -347,5 +347,42 @@ function switchh2() {
print(9);
}
}
+function stackSet(x1, x2, x3, x4, x5) {
+ x1 = x1 | 0;
+ x2 = x2 | 0;
+ x3 = x3 | 0;
+ x4 = x4 | 0;
+ x5 = x5 | 0;
+ var sp = 0, a = 0, b = 0, cc = 0, d = 0, e = 0, f = 0, g = 0;
+ var sp1 = 0, a1 = 0, b1 = 0, c1 = 0, d1 = 0, e1 = 0, f1 = 0, g1 = 0;
+ sp = STACKTOP;
+ STACKTOP = STACKTOP + 10 | 0;
+ c(1);
+ c(2);
+ c(3);
+ c(4);
+ c(5);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
+ c(1);
+ c(2);
+ c(3);
+ c(4);
+ c(5);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
+}
// EMSCRIPTEN_GENERATED_FUNCTIONS
// EXTRA_INFO: { "sizeToOutline": 30, "allowCostlyOutlines": 1 }
diff --git a/tools/test-js-optimizer-asm-outline2-output.js b/tools/test-js-optimizer-asm-outline2-output.js
index 2658fda0..923cd7df 100644
--- a/tools/test-js-optimizer-asm-outline2-output.js
+++ b/tools/test-js-optimizer-asm-outline2-output.js
@@ -25,6 +25,7 @@ function _free($mem) {
$mem = $mem | 0;
var $5 = 0, $10 = 0, $16 = 0, $21 = 0, $25 = 0, $26 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $194 = 0, sp = 0, helper$0 = 0;
sp = STACKTOP;
+ STACKTOP = STACKTOP + 864 | 0;
if (($mem | 0) == 0) {
STACKTOP = sp;
return;