aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/eliminator/asm-eliminator-test-output.js10
-rw-r--r--tools/eliminator/asm-eliminator-test.js10
-rw-r--r--tools/eliminator/eliminator-test-output.js11
-rw-r--r--tools/eliminator/eliminator-test.js17
-rw-r--r--tools/file_packager.py108
-rw-r--r--tools/js-optimizer.js55
-rw-r--r--tools/shared.py6
-rw-r--r--tools/test-js-optimizer-asm-pre-output.js8
-rw-r--r--tools/test-js-optimizer-asm-pre.js4
9 files changed, 162 insertions, 67 deletions
diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js
index 434fbaf9..a344fc35 100644
--- a/tools/eliminator/asm-eliminator-test-output.js
+++ b/tools/eliminator/asm-eliminator-test-output.js
@@ -280,9 +280,10 @@ function tempDouble2($46, $14, $28, $42, $20, $32, $45) {
$20 = $20 | 0;
$32 = $32 | 0;
$45 = $45 | 0;
- var $_sroa_06_0_insert_insert$1 = 0;
+ var $46 = 0, $_sroa_06_0_insert_insert$1 = 0;
+ $46 = (HEAPF32[tempDoublePtr >> 2] = ($14 < $28 ? $14 : $28) - $42, HEAP32[tempDoublePtr >> 2] | 0);
$_sroa_06_0_insert_insert$1 = (HEAPF32[tempDoublePtr >> 2] = ($20 < $32 ? $20 : $32) - $42, HEAP32[tempDoublePtr >> 2] | 0) | 0;
- HEAP32[$45 >> 2] = 0 | (HEAPF32[tempDoublePtr >> 2] = ($14 < $28 ? $14 : $28) - $42, HEAP32[tempDoublePtr >> 2] | 0);
+ HEAP32[$45 >> 2] = 0 | $46;
HEAP32[$45 + 4 >> 2] = $_sroa_06_0_insert_insert$1;
HEAP32[$45 + 8 >> 2] = $_sroa_06_0_insert_insert$1;
}
@@ -298,4 +299,9 @@ function select2($foundBase_0_off0) {
STACKTOP = sp;
return ($foundBase_0_off0 ? 0 : $call24) | 0;
}
+function binary(x) {
+ x = x | 0;
+ memset(f(x)) | 0;
+ +dmemset(f(x));
+}
diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js
index 7ec277d5..4b45e4d4 100644
--- a/tools/eliminator/asm-eliminator-test.js
+++ b/tools/eliminator/asm-eliminator-test.js
@@ -370,5 +370,13 @@ function select2($foundBase_0_off0) {
STACKTOP = sp;
return $retval_0 | 0;
}
-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2"]
+function binary(x) {
+ x = x | 0;
+ var y = 0, z = 0;
+ y = f(x);
+ memset(y) | 0;
+ z = f(x);
+ +dmemset(z);
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary"]
diff --git a/tools/eliminator/eliminator-test-output.js b/tools/eliminator/eliminator-test-output.js
index 0171e99b..4551fb34 100644
--- a/tools/eliminator/eliminator-test-output.js
+++ b/tools/eliminator/eliminator-test-output.js
@@ -6122,4 +6122,15 @@ function intoCond() {
function math(a, b, c, d) {
print(Math_imul(d) + (Math_fround(c) + (a + Math_abs(b))));
}
+function td(x, y) {
+ HEAP32[tempDoublePtr >> 2] = x;
+ var xf = HEAPF32[tempDoublePtr >> 2];
+ HEAP32[tempDoublePtr >> 2] = y;
+ func(xf, HEAPF32[tempDoublePtr >> 2]);
+ HEAPF64[tempDoublePtr >> 3] = x;
+ var xl = HEAP32[tempDoublePtr >> 2];
+ var xh = HEAP32[tempDoublePtr >> 2];
+ HEAPF64[tempDoublePtr >> 3] = y;
+ func(xl, xh, HEAP32[tempDoublePtr >> 2], HEAP32[tempDoublePtr >> 2]);
+}
diff --git a/tools/eliminator/eliminator-test.js b/tools/eliminator/eliminator-test.js
index ef17b388..e629d9f0 100644
--- a/tools/eliminator/eliminator-test.js
+++ b/tools/eliminator/eliminator-test.js
@@ -8860,5 +8860,20 @@ function math(a, b, c, d) {
w = Math_imul(d);
print(x + y + z + w);
}
-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "c", "f", "g", "h", "py", "r", "t", "f2", "f3", "llvm3_1", "_inflate", "_malloc", "_mallocNoU", "asm", "phi", "intoCond", "math"]
+function td(x, y) { // tempDoublePtr should invalidate each other
+ HEAP32[tempDoublePtr>>2] = x;
+ var xf = HEAPF32[tempDoublePtr>>2];
+ HEAP32[tempDoublePtr>>2] = y;
+ var yf = HEAPF32[tempDoublePtr>>2];
+ func(xf, yf);
+ //
+ HEAPF64[tempDoublePtr>>3] = x;
+ var xl = HEAP32[tempDoublePtr>>2];
+ var xh = HEAP32[tempDoublePtr>>2];
+ HEAPF64[tempDoublePtr>>3] = y;
+ var yl = HEAP32[tempDoublePtr>>2];
+ var yh = HEAP32[tempDoublePtr>>2];
+ func(xl, xh, yl, yh);
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "c", "f", "g", "h", "py", "r", "t", "f2", "f3", "llvm3_1", "_inflate", "_malloc", "_mallocNoU", "asm", "phi", "intoCond", "math", "td"]
diff --git a/tools/file_packager.py b/tools/file_packager.py
index 7d9344cd..8b65b219 100644
--- a/tools/file_packager.py
+++ b/tools/file_packager.py
@@ -11,7 +11,7 @@ data downloads.
Usage:
- file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--compress COMPRESSION_DATA] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--no-heap-copy]
+ file_packager.py TARGET [--preload A [B..]] [--embed C [D..]] [--exclude E [F..]] [--compress COMPRESSION_DATA] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--no-heap-copy]
--crunch=X Will compress dxt files to crn with quality level X. The crunch commandline tool must be present
and CRUNCH should be defined in ~/.emscripten that points to it. JS crunch decompressing code will
@@ -45,9 +45,10 @@ import posixpath
import shared
from shared import Compression, execute, suffix, unsuffixed
from subprocess import Popen, PIPE, STDOUT
+import fnmatch
if len(sys.argv) == 1:
- print '''Usage: file_packager.py TARGET [--preload A...] [--embed B...] [--compress COMPRESSION_DATA] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--no-heap-copy]
+ print '''Usage: file_packager.py TARGET [--preload A...] [--embed B...] [--exclude C...] [--compress COMPRESSION_DATA] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--no-heap-copy]
See the source for more details.'''
sys.exit(0)
@@ -66,10 +67,10 @@ DDS_HEADER_SIZE = 128
AV_WORKAROUND = 0 # Set to 1 to randomize file order and add some padding, to work around silly av false positives
data_files = []
-in_preload = False
-in_embed = False
+excluded_patterns = []
+leading = ''
has_preloaded = False
-in_compress = 0
+compress_cnt = 0
crunch = 0
plugins = []
jsoutput = None
@@ -81,45 +82,40 @@ use_preload_cache = False
# If set to False, the XHR blob is kept intact, and fread()s etc. are performed directly to that data. This optimizes for minimal memory usage and fread() performance.
no_heap_copy = True
-for arg in sys.argv[1:]:
+for arg in sys.argv[2:]:
if arg == '--preload':
- in_preload = True
- in_embed = False
has_preloaded = True
- in_compress = 0
+ leading = 'preload'
elif arg == '--embed':
- in_embed = True
- in_preload = False
- in_compress = 0
+ leading = 'embed'
+ elif arg == '--exclude':
+ leading = 'exclude'
elif arg == '--compress':
+ compress_cnt = 1
Compression.on = True
- in_compress = 1
- in_preload = False
- in_embed = False
+ leading = 'compress'
elif arg == '--no-force':
force = False
+ leading = ''
elif arg == '--use-preload-cache':
use_preload_cache = True
+ leading = ''
elif arg == '--no-heap-copy':
no_heap_copy = False
+ leading = ''
elif arg.startswith('--js-output'):
jsoutput = arg.split('=')[1] if '=' in arg else None
+ leading = ''
elif arg.startswith('--crunch'):
from shared import CRUNCH
crunch = arg.split('=')[1] if '=' in arg else '128'
- in_preload = False
- in_embed = False
- in_compress = 0
+ leading = ''
elif arg.startswith('--plugin'):
plugin = open(arg.split('=')[1], 'r').read()
eval(plugin) # should append itself to plugins
- in_preload = False
- in_embed = False
- in_compress = 0
- elif in_preload or in_embed:
- mode = 'preload'
- if in_embed:
- mode = 'embed'
+ leading = ''
+ elif leading == 'preload' or leading == 'embed':
+ mode = leading
if '@' in arg:
srcpath, dstpath = arg.split('@') # User is specifying destination filename explicitly.
else:
@@ -128,16 +124,21 @@ for arg in sys.argv[1:]:
data_files.append({ 'srcpath': srcpath, 'dstpath': dstpath, 'mode': mode })
else:
print >> sys.stderr, 'Warning: ' + arg + ' does not exist, ignoring.'
- elif in_compress:
- if in_compress == 1:
+ elif leading == 'exclude':
+ excluded_patterns.append(arg)
+ elif leading == 'compress':
+ if compress_cnt == 1:
Compression.encoder = arg
- in_compress = 2
- elif in_compress == 2:
+ compress_cnt = 2
+ elif compress_cnt == 2:
Compression.decoder = arg
- in_compress = 3
- elif in_compress == 3:
+ compress_cnt = 3
+ elif compress_cnt == 3:
Compression.js_name = arg
- in_compress = 0
+ compress_cnt = 0
+ else:
+ print >> sys.stderr, 'Unknown parameter:', arg
+ sys.exit(1)
if (not force) and len(data_files) == 0:
has_preloaded = False
@@ -172,16 +173,14 @@ def has_hidden_attribute(filepath):
result = False
return result
-# The packager should never preload/embed any directories that have a component starting with '.' in them,
-# or if the file is hidden (Win32). Note that this filter ONLY applies to directories. Explicitly specified single files
-# are always preloaded/embedded, even if they start with a '.'.
-def should_ignore(filename):
- if has_hidden_attribute(filename):
+# The packager should never preload/embed files if the file is hidden (Win32).
+# or it matches any pattern specified in --exclude
+def should_ignore(fullname):
+ if has_hidden_attribute(fullname):
return True
- components = filename.replace('\\\\', '/').replace('\\', '/').split('/')
- for c in components:
- if c.startswith('.') and c != '.' and c != '..':
+ for p in excluded_patterns:
+ if fnmatch.fnmatch(fullname, p):
return True
return False
@@ -190,20 +189,31 @@ def add(arg, dirname, names):
# rootpathsrc: The path name of the root directory on the local FS we are adding to emscripten virtual FS.
# rootpathdst: The name we want to make the source path available on the emscripten virtual FS.
mode, rootpathsrc, rootpathdst = arg
+ new_names = []
for name in names:
fullname = os.path.join(dirname, name)
- if not os.path.isdir(fullname):
- if should_ignore(fullname):
- if DEBUG:
- print >> sys.stderr, 'Skipping hidden file "' + fullname + '" from inclusion in the emscripten virtual file system.'
- else:
+ if should_ignore(fullname):
+ if DEBUG:
+ print >> sys.stderr, 'Skipping file "' + fullname + '" from inclusion in the emscripten virtual file system.'
+ else:
+ new_names.append(name)
+ if not os.path.isdir(fullname):
dstpath = os.path.join(rootpathdst, os.path.relpath(fullname, rootpathsrc)) # Convert source filename relative to root directory of target FS.
- data_files.append({ 'srcpath': fullname, 'dstpath': dstpath, 'mode': mode })
+ new_data_files.append({ 'srcpath': fullname, 'dstpath': dstpath, 'mode': mode })
+ del names[:]
+ names.extend(new_names)
+new_data_files = []
for file_ in data_files:
- if os.path.isdir(file_['srcpath']):
- os.path.walk(file_['srcpath'], add, [file_['mode'], file_['srcpath'], file_['dstpath']])
-data_files = filter(lambda file_: not os.path.isdir(file_['srcpath']), data_files)
+ if not should_ignore(file_['srcpath']):
+ if os.path.isdir(file_['srcpath']):
+ os.path.walk(file_['srcpath'], add, [file_['mode'], file_['srcpath'], file_['dstpath']])
+ else:
+ new_data_files.append(file_)
+data_files = filter(lambda file_: not os.path.isdir(file_['srcpath']), new_data_files)
+if len(data_files) == 0:
+ print >> sys.stderr, 'Nothing to do!'
+ sys.exit(1)
# Absolutize paths, and check that they make sense
curr_abspath = os.path.abspath(os.getcwd())
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 57ce0071..161ed59c 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -271,6 +271,16 @@ function isEmptyNode(node) {
return node.length === 2 && node[0] === 'toplevel' && node[1].length === 0;
}
+function clearEmptyNodes(list) {
+ for (var i = 0; i < list.length;) {
+ if (isEmptyNode(list[i]) || (list[i][0] === 'stat' && isEmptyNode(list[i][1]))) {
+ list.splice(i, 1);
+ } else {
+ i++;
+ }
+ }
+}
+
// Passes
// Dump the AST. Useful for debugging. For example,
@@ -585,12 +595,24 @@ function simplifyExpressions(ast) {
}
} else if (type === 'assign') {
// optimizations for assigning into HEAP32 specifically
- if (node[1] === true && node[2][0] === 'sub' && node[2][1][0] === 'name' && node[2][1][1] === 'HEAP32') {
- // HEAP32[..] = x | 0 does not need the | 0 (unless it is a mandatory |0 of a call)
- if (node[3][0] === 'binary' && node[3][1] === '|') {
- if (node[3][2][0] === 'num' && node[3][2][1] === 0 && node[3][3][0] != 'call') {
- node[3] = node[3][3];
- } else if (node[3][3][0] === 'num' && node[3][3][1] === 0 && node[3][2][0] != 'call') {
+ if (node[1] === true && node[2][0] === 'sub' && node[2][1][0] === 'name') {
+ if (node[2][1][1] === 'HEAP32') {
+ // HEAP32[..] = x | 0 does not need the | 0 (unless it is a mandatory |0 of a call)
+ if (node[3][0] === 'binary' && node[3][1] === '|') {
+ if (node[3][2][0] === 'num' && node[3][2][1] === 0 && node[3][3][0] != 'call') {
+ node[3] = node[3][3];
+ } else if (node[3][3][0] === 'num' && node[3][3][1] === 0 && node[3][2][0] != 'call') {
+ node[3] = node[3][2];
+ }
+ }
+ } else if (node[2][1][1] === 'HEAP8') {
+ // HEAP8[..] = x & 0xff does not need the & 0xff
+ if (node[3][0] === 'binary' && node[3][1] === '&' && node[3][3][0] == 'num' && node[3][3][1] == 0xff) {
+ node[3] = node[3][2];
+ }
+ } else if (node[2][1][1] === 'HEAP16') {
+ // HEAP16[..] = x & 0xffff does not need the & 0xffff
+ if (node[3][0] === 'binary' && node[3][1] === '&' && node[3][3][0] == 'num' && node[3][3][1] == 0xffff) {
node[3] = node[3][2];
}
}
@@ -2122,7 +2144,7 @@ function registerize(ast) {
// In memSafe mode, we are more careful and assume functions can replace HEAP and FUNCTION_TABLE, which
// can happen in ALLOW_MEMORY_GROWTH mode
-var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch'); // do is checked carefully, however
+var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch', 'binary', 'unary-prefix'); // do is checked carefully, however
var IGNORABLE_ELIMINATOR_SCAN_NODES = set('num', 'toplevel', 'string', 'break', 'continue', 'dot'); // dot can only be STRING_TABLE.*
var ABORTING_ELIMINATOR_SCAN_NODES = set('new', 'object', 'function', 'defun', 'for', 'while', 'array', 'throw'); // we could handle some of these, TODO, but nontrivial (e.g. for while, the condition is hit multiple times after the body)
@@ -2412,7 +2434,12 @@ function eliminate(ast, memSafe) {
if (allowTracking) track(name, node[3], node);
}
} else if (target[0] === 'sub') {
- if (!isTempDoublePtrAccess(target) && !memoryInvalidated) {
+ if (isTempDoublePtrAccess(target)) {
+ if (!globalsInvalidated) {
+ invalidateGlobals();
+ globalsInvalidated = true;
+ }
+ } else if (!memoryInvalidated) {
invalidateMemory();
memoryInvalidated = true;
}
@@ -2672,6 +2699,7 @@ function eliminate(ast, memSafe) {
}
if (ifTrue[1][0] && ifTrue[1][0][0] === 'break') {
var assigns = ifFalse[1];
+ clearEmptyNodes(assigns);
var loopers = [], helpers = [];
for (var i = 0; i < assigns.length; i++) {
if (assigns[i][0] === 'stat' && assigns[i][1][0] === 'assign') {
@@ -3097,6 +3125,17 @@ function outline(ast) {
parts = [];
var curr = node;
while (1) {
+ if (!curr[3]) {
+ // we normally expect ..if (cond) { .. } else [if (nextCond) {] (in [] is what we hope to see)
+ // but are now seeing ..if (cond) { .. } with no else. This might be
+ // ..if (cond) if (nextCond) {
+ // which vacuum can generate from if (cond) {} else if (nextCond), making it
+ // if (!cond) if (nextCond)
+ // so we undo that, in hopes of making it more flattenable
+ curr[3] = curr[2];
+ curr[2] = ['block', []];
+ curr[1] = simplifyNotCompsDirect(['unary-prefix', '!', curr[1]]);
+ }
parts.push({ condition: curr[1], body: curr[2] });
curr = curr[3];
if (!curr) break;
diff --git a/tools/shared.py b/tools/shared.py
index 443ff4c7..eb1c63be 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -322,7 +322,7 @@ def find_temp_directory():
# we re-check sanity when the settings are changed)
# We also re-check sanity and clear the cache when the version changes
-EMSCRIPTEN_VERSION = '1.7.8'
+EMSCRIPTEN_VERSION = '1.8.0'
def generate_sanity():
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT
@@ -682,7 +682,7 @@ def line_splitter(data):
return out
-def limit_size(string, MAX=12000*20):
+def limit_size(string, MAX=800*20):
if len(string) < MAX: return string
return string[0:MAX/2] + '\n[..]\n' + string[-MAX/2:]
@@ -1094,7 +1094,7 @@ class Building:
# 8k is a bit of an arbitrary limit, but a reasonable one
# for max command line size before we use a respose file
response_file = None
- if WINDOWS and len(' '.join(link_cmd)) > 8192:
+ if len(' '.join(link_cmd)) > 8192:
logging.debug('using response file for llvm-link')
[response_fd, response_file] = mkstemp(suffix='.response', dir=TEMP_DIR)
diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js
index 2e3db000..0fa81050 100644
--- a/tools/test-js-optimizer-asm-pre-output.js
+++ b/tools/test-js-optimizer-asm-pre-output.js
@@ -58,12 +58,14 @@ function b($this, $__n) {
_memset($38 + $23 | 0, 0, $__n | 0, 1, 1213141516);
$40 = $23 + $__n | 0;
if ((HEAP8[$4 & 16777215] & 1) == 0) {
- HEAP8[$4 & 16777215] = $40 << 1 & 255;
+ HEAP8[$4 & 16777215] = $40 << 1;
} else {
HEAP32[($this + 4 & 16777215) >> 2] = $40;
}
HEAP8[$38 + $40 & 16777215] = 0;
HEAP32[$4] = ~HEAP32[$5];
+ HEAP8[$4] = HEAP32[$5];
+ HEAP16[$4] = HEAP32[$5];
HEAP32[$4] = ~HEAP32[$5];
HEAP32[$4] = ~HEAP32[$5];
h(~~g ^ -1);
@@ -240,10 +242,10 @@ function _main($argc, $argv) {
}
if (($i_09_i_i | 0) > (HEAP32[9600 + ($j_08_i_i << 2) >> 2] | 0)) {
$34 = $j_08_i_i + 1 | 0;
- HEAP8[$i_09_i_i + 8952 | 0] = $34 & 255;
+ HEAP8[$i_09_i_i + 8952 | 0] = $34;
$j_1_i_i = $34;
} else {
- HEAP8[$i_09_i_i + 8952 | 0] = $j_08_i_i & 255;
+ HEAP8[$i_09_i_i + 8952 | 0] = $j_08_i_i;
$j_1_i_i = $j_08_i_i;
}
$38 = $i_09_i_i + 1 | 0;
diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js
index 9e6edf0f..dadeef53 100644
--- a/tools/test-js-optimizer-asm-pre.js
+++ b/tools/test-js-optimizer-asm-pre.js
@@ -66,6 +66,10 @@ function b($this, $__n) {
HEAP8[($38 + $40 | 0) & 16777215] = 0;
// Eliminate the |0.
HEAP32[$4] = ((~(HEAP32[$5]|0))|0);
+ // Eliminate the &255
+ HEAP8[$4] = HEAP32[$5]&255;
+ // Eliminate the &65535
+ HEAP16[$4] = HEAP32[$5]&65535;
// Rewrite to ~.
HEAP32[$4] = HEAP32[$5]^-1;
// Rewrite to ~ and eliminate the |0.