aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/asm_module.py4
-rwxr-xr-xtools/exec_llvm.py4
-rw-r--r--tools/file_packager.py15
-rw-r--r--tools/find_bigvars.py24
-rw-r--r--tools/js-optimizer.js73
-rwxr-xr-xtools/nativize_llvm.py4
-rw-r--r--tools/settings_template_readonly.py2
-rw-r--r--tools/shared.py206
-rw-r--r--tools/test-js-optimizer-asm-outline1-output.js304
-rw-r--r--tools/test-js-optimizer-asm-outline2-output.js576
10 files changed, 669 insertions, 543 deletions
diff --git a/tools/asm_module.py b/tools/asm_module.py
index bf7fa71d..226b66b8 100644
--- a/tools/asm_module.py
+++ b/tools/asm_module.py
@@ -84,7 +84,9 @@ class AsmModule():
for table in self.tables:
if table not in main.tables:
sig = table[table.rfind('_')+1:]
- all_sendings['invoke_%s' % sig] = shared.JS.make_invoke(sig, named=False)
+ func = 'invoke_%s' % sig
+ all_sendings[func] = func
+ main.pre_js += 'var %s = %s;\n' % (func, shared.JS.make_invoke(sig, named=False))
added_sending = True
# imports
diff --git a/tools/exec_llvm.py b/tools/exec_llvm.py
index 2685f9e4..ec7a8924 100755
--- a/tools/exec_llvm.py
+++ b/tools/exec_llvm.py
@@ -39,12 +39,12 @@ def path_from_root(*pathelems):
sys.path += [path_from_root('')]
from tools.shared import *
-Popen([LLVM_OPT, sys.argv[1], '-strip-debug', '-o=' + sys.argv[1]+'.clean.bc']).communicate()[0]
+Popen([LLVM_OPT, sys.argv[1], '-strip-debug', '-o', sys.argv[1]+'.clean.bc']).communicate()[0]
# Execute with empty environment - just like the JS script will have
Popen([LLVM_INTERPRETER, sys.argv[1]+'.clean.bc'] + sys.argv[2:], env={'HOME': '.'}).communicate()[0]
-#Popen([LLVM_COMPILER, '-march=c', sys.argv[1], '-o=' + sys.argv[1]+'.cbe.c']).communicate()[0]
+#Popen([LLVM_COMPILER, '-march=c', sys.argv[1], '-o', sys.argv[1]+'.cbe.c']).communicate()[0]
#Popen(['gcc', sys.argv[1]+'.cbe.c', '-lstdc++']).communicate()[0]
#Popen(['./a.out'] + sys.argv[2:]).communicate()[0]
diff --git a/tools/file_packager.py b/tools/file_packager.py
index 1a9d925b..33ccebad 100644
--- a/tools/file_packager.py
+++ b/tools/file_packager.py
@@ -40,7 +40,7 @@ TODO: You can also provide .crn files yourself, pre-crunched. With this o
'''
import os, sys, shutil, random, uuid, ctypes
-
+import posixpath
import shared
from shared import Compression, execute, suffix, unsuffixed
from subprocess import Popen, PIPE, STDOUT
@@ -216,7 +216,8 @@ for file_ in data_files:
file_['dstpath'] = file_['dstpath'].replace(os.path.sep, '/') # name in the filesystem, native and emulated
if file_['dstpath'].endswith('/'): # If user has submitted a directory name as the destination but omitted the destination filename, use the filename from source file
file_['dstpath'] = file_['dstpath'] + os.path.basename(file_['srcpath'])
- if file_['dstpath'].startswith('./'): file_['dstpath'] = file_['dstpath'][2:] # remove redundant ./ prefix
+ # make destination path always relative to the root
+ file_['dstpath'] = posixpath.normpath(os.path.join('/', file_['dstpath']))
if DEBUG:
print >> sys.stderr, 'Packaging file "' + file_['srcpath'] + '" to VFS in path "' + file_['dstpath'] + '".'
@@ -341,6 +342,8 @@ if has_preloaded:
counter = 0
for file_ in data_files:
filename = file_['dstpath']
+ dirname = os.path.dirname(filename)
+ basename = os.path.basename(filename)
if file_['mode'] == 'embed':
# Embed
data = map(ord, open(file_['srcpath'], 'rb').read())
@@ -356,7 +359,7 @@ for file_ in data_files:
str_data = str(chunk)
else:
str_data += '.concat(' + str(chunk) + ')'
- code += '''Module['FS_createDataFile']('/%s', '%s', %s, true, true);\n''' % (os.path.dirname(filename), os.path.basename(filename), str_data)
+ code += '''Module['FS_createDataFile']('%s', '%s', %s, true, true);\n''' % (dirname, basename, str_data)
elif file_['mode'] == 'preload':
# Preload
varname = 'filePreload%d' % counter
@@ -389,7 +392,7 @@ for file_ in data_files:
assert(arrayBuffer, 'Loading file %(filename)s failed.');
var byteArray = !arrayBuffer.subarray ? new Uint8Array(arrayBuffer) : arrayBuffer;
%(prepare)s
- Module['FS_createPreloadedFile']('/%(dirname)s', '%(basename)s', byteArray, true, true, function() {
+ Module['FS_createPreloadedFile']('%(dirname)s', '%(basename)s', byteArray, true, true, function() {
%(finish)s
}%(fail)s);
};
@@ -399,8 +402,8 @@ for file_ in data_files:
'request': 'DataRequest', # In the past we also supported XHRs here
'varname': varname,
'filename': filename,
- 'dirname': os.path.dirname(filename),
- 'basename': os.path.basename(filename),
+ 'dirname': dirname,
+ 'basename': basename,
'prepare': prepare,
'finish': finish,
'fail': '' if filename[-4:] not in AUDIO_SUFFIXES else ''', function() { Module['removeRunDependency']('fp %s') }''' % filename # workaround for chromium bug 124926 (still no audio with this, but at least we don't hang)
diff --git a/tools/find_bigvars.py b/tools/find_bigvars.py
new file mode 100644
index 00000000..6bee5dd4
--- /dev/null
+++ b/tools/find_bigvars.py
@@ -0,0 +1,24 @@
+'''
+Simple tool to find functions with lots of vars.
+'''
+
+import os, sys, re
+
+filename = sys.argv[1]
+i = 0
+curr = None
+data = []
+size = 0
+for line in open(filename):
+ i += 1
+ if line.startswith('function '):
+ size = len(line.split(',')) # params
+ curr = line
+ elif line.strip().startswith('var '):
+ size += len(line.split(',')) + 1 # vars
+ elif line.startswith('}') and curr:
+ data.append([curr, size])
+ curr = None
+data.sort(lambda x, y: x[1] - y[1])
+print ''.join(['%6d : %s' % (x[1], x[0]) for x in data])
+
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 4192ddd1..e61317af 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -801,7 +801,10 @@ function simplifyExpressions(ast) {
// HEAP[x >> 2]
// very often. We can in some cases do the shift on the variable itself when it is set,
// to greatly reduce the number of shift operations.
-// TODO: when shifting a variable, if there are other uses, keep an unshifted version too, to prevent slowdowns?
+// XXX this optimization is deprecated and currently invalid: does not handle overflows
+// or non-aligned (round numbers, x >> 2 is a multiple of 4). Both are ok to assume
+// for pointers (undefined behavior otherwise), but invalid in general, and we do
+// no sufficiently-well distinguish the cases.
function optimizeShiftsInternal(ast, conservative) {
var MAX_SHIFTS = 3;
traverseGeneratedFunctions(ast, function(fun) {
@@ -3001,7 +3004,7 @@ function outline(ast) {
// Try to flatten out code as much as possible, to make outlining more feasible.
function flatten(func, asmData) {
- var minSize = sizeToOutline;
+ var minSize = extraInfo.sizeToOutline/4;
var helperId = 0;
function getHelper() {
while (1) {
@@ -3106,7 +3109,9 @@ function outline(ast) {
// Reserve an extra two spots per possible outlining: one for control flow var, the other for control flow data
// The control variables are zeroed out when calling an outlined function, and after using
// the value after they return.
- asmData.maxOutlinings = Math.round(3*measureSize(func)/extraInfo.sizeToOutline);
+ var size = measureSize(func);
+ asmData.maxOutlinings = Math.round(3*size/extraInfo.sizeToOutline);
+ asmData.intendedPieces = Math.ceil(size/extraInfo.sizeToOutline);
asmData.totalStackSize = stackSize + (stack.length + 2*asmData.maxOutlinings)*8;
asmData.controlStackPos = function(i) { return stackSize + (stack.length + i)*8 };
asmData.controlDataStackPos = function(i) { return stackSize + (stack.length + i)*8 + 4 };
@@ -3211,16 +3216,18 @@ function outline(ast) {
var CONTROL_BREAK = 1, CONTROL_BREAK_LABEL = 2, CONTROL_CONTINUE = 3, CONTROL_CONTINUE_LABEL = 4, CONTROL_RETURN_VOID = 5, CONTROL_RETURN_INT = 6, CONTROL_RETURN_DOUBLE = 7;
var sizeToOutline = null; // customized per function and as we make progress
- function calculateThreshold(func) {
- sizeToOutline = extraInfo.sizeToOutline;
+ function calculateThreshold(func, asmData) {
var size = measureSize(func);
- //var desiredChunks = Math.ceil(size/extraInfo.sizeToOutline);
- ////sizeToOutline = Math.round((extraInfo.sizeToOutline + (2*size/desiredChunks))/3);
- //sizeToOutline = Math.round(size/desiredChunks);
- printErr('trying to reduce the size of ' + func[1] + ' which is ' + size + ' (>= ' + extraInfo.sizeToOutline + '), aim for ' + sizeToOutline);
+ if (size <= extraInfo.sizeToOutline) {
+ sizeToOutline = Infinity;
+ 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);
+ }
}
- var level = 0;
+ var level = 0, loops = 0;
var outliningParents = {}; // function name => parent it was outlined from
function doOutline(func, asmData, stats, start, end) {
@@ -3241,21 +3248,29 @@ function outline(ast) {
}
});
var reps = [];
- // wipe out control variable
- reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', 0])]);
- reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ['num', 0])]); // XXX not really needed
- // add spills and reads before and after the call to the outlined code, and in the outlined code itself
- keys(setUnion(codeInfo.reads, codeInfo.writes)).forEach(function(v) {
+ // add spills
+ function orderFunc(x, y) {
+ return (asmData.stackPos[x] - asmData.stackPos[y]) || x.localeCompare(y);
+ }
+ var sortedReadsAndWrites = keys(setUnion(codeInfo.reads, codeInfo.writes)).sort(orderFunc);
+ var sortedWrites = keys(codeInfo.writes).sort(orderFunc);
+ sortedReadsAndWrites.forEach(function(v) {
if (!(v in owned)) {
reps.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]);
}
});
+ // wipe out control variable
+ reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', 0])]);
+ reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ['num', 0])]); // XXX not really needed
+ // do the call
reps.push(['stat', ['call', ['name', newIdent], [['name', 'sp']]]]);
- for (var v in codeInfo.writes) {
+ // add unspills
+ sortedWrites.forEach(function(v) {
if (!(v in owned)) {
reps.push(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], getAsmType(v, asmData))]]);
}
- }
+ });
+
// Generate new function
if (codeInfo.hasReturn || codeInfo.hasReturnInt || codeInfo.hasReturnDouble || codeInfo.hasBreak || codeInfo.hasContinue) {
// we need to capture all control flow using a top-level labeled one-time loop in the outlined function
@@ -3389,16 +3404,17 @@ function outline(ast) {
}
}
// add spills and unspills in outlined code outside the OL loop
- keys(setUnion(codeInfo.reads, codeInfo.writes)).forEach(function(v) {
+ sortedReadsAndWrites.reverse();
+ sortedReadsAndWrites.forEach(function(v) {
if (!(v in owned)) {
code.unshift(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], getAsmType(v, asmData))]]);
}
});
- for (var v in codeInfo.writes) {
+ sortedWrites.forEach(function(v) {
if (!(v in owned)) {
code.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]);
}
- }
+ });
// finalize
var newFunc = ['defun', newIdent, ['sp'], code];
var newAsmData = { params: { sp: ASM_INT }, vars: {} };
@@ -3436,8 +3452,8 @@ function outline(ast) {
}
}
outliningParents[newIdent] = func[1];
- printErr('performed outline ' + [func[1], newIdent, 'code sizes (pre/post):', originalCodeSize, measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned))]);
- calculateThreshold(func);
+ printErr('performed outline ' + [func[1], newIdent, 'code sizes (pre/post):', originalCodeSize, 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];
}
@@ -3462,6 +3478,9 @@ function outline(ast) {
}
}
}
+ function done() {
+ return asmData.splitCounter >= asmData.maxOutlinings || measureSize(func) <= extraInfo.sizeToOutline;
+ }
while (1) {
i--;
calcMinIndex(); // TODO: optimize
@@ -3506,11 +3525,18 @@ function outline(ast) {
if (subRet && subRet.length > 0) ret.push.apply(ret, subRet);
}
return null; // do not recurse into children, outlineStatements will do so if necessary
+ } else if (type == 'while') {
+ loops++;
+ }
+ }, function(node, type) {
+ if (type == 'while') {
+ loops--;
}
});
if (ret.length > pre) {
// we outlined recursively, reset our state here
//printErr('successful outline in recursion ' + func[1] + ' due to recursive in level ' + level);
+ if (done()) break;
end = i-1;
sizeSeen = 0;
canRestart = true;
@@ -3550,6 +3576,7 @@ function outline(ast) {
if (newFuncs.length) {
ret.push.apply(ret, newFuncs);
}
+ if (done()) break;
sizeSeen = 0;
end = i-1;
canRestart = true;
@@ -3581,8 +3608,8 @@ function outline(ast) {
if (size >= extraInfo.sizeToOutline) {
aggressiveVariableElimination(func, asmData);
flatten(func, asmData);
- calculateThreshold(func);
analyzeFunction(func, asmData);
+ calculateThreshold(func, asmData);
var stats = getStatements(func);
var ret = outlineStatements(func, asmData, stats, 0.9*size);
assert(level == 0);
diff --git a/tools/nativize_llvm.py b/tools/nativize_llvm.py
index d9558c32..413c8d14 100755
--- a/tools/nativize_llvm.py
+++ b/tools/nativize_llvm.py
@@ -21,11 +21,11 @@ filename = sys.argv[1]
libs = sys.argv[2:] # e.g.: dl for dlopen/dlclose, util for openpty/forkpty
print 'bc => clean bc'
-Popen([LLVM_OPT, filename, '-strip-debug', '-o=' + filename + '.clean.bc']).communicate()[0]
+Popen([LLVM_OPT, filename, '-strip-debug', '-o', filename + '.clean.bc']).communicate()[0]
print 'bc => s'
for params in [[], ['-march=x86-64']]: # try x86, then x86-64 FIXME
print 'params', params
- Popen([LLVM_COMPILER] + params + [filename + '.clean.bc', '-o=' + filename + '.s']).communicate()[0]
+ Popen([LLVM_COMPILER] + params + [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
diff --git a/tools/settings_template_readonly.py b/tools/settings_template_readonly.py
index 7ab89b48..14b45a20 100644
--- a/tools/settings_template_readonly.py
+++ b/tools/settings_template_readonly.py
@@ -16,7 +16,7 @@ V8_ENGINE = os.path.expanduser(os.getenv('V8') or 'd8') # executable
JAVA = 'java' # executable
-TEMP_DIR = '/tmp' # You will need to modify this on Windows
+TEMP_DIR = '{{{ TEMP }}}'
#CLOSURE_COMPILER = '..' # define this to not use the bundled version
diff --git a/tools/shared.py b/tools/shared.py
index b80d9389..917f548e 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -200,18 +200,25 @@ if '\n' in EM_CONFIG:
else:
CONFIG_FILE = os.path.expanduser(EM_CONFIG)
if not os.path.exists(CONFIG_FILE):
+ # Note: repr is used to ensure the paths are escaped correctly on Windows.
+ # The full string is replaced so that the template stays valid Python.
config_file = open(path_from_root('tools', 'settings_template_readonly.py')).read().split('\n')
config_file = config_file[1:] # remove "this file will be copied..."
config_file = '\n'.join(config_file)
# autodetect some default paths
- config_file = config_file.replace('{{{ EMSCRIPTEN_ROOT }}}', __rootpath__)
+ config_file = config_file.replace('\'{{{ EMSCRIPTEN_ROOT }}}\'', repr(__rootpath__))
llvm_root = os.path.dirname(find_executable('llvm-dis') or '/usr/bin/llvm-dis')
- config_file = config_file.replace('{{{ LLVM_ROOT }}}', llvm_root)
+ config_file = config_file.replace('\'{{{ LLVM_ROOT }}}\'', repr(llvm_root))
node = find_executable('node') or find_executable('nodejs') or 'node'
- config_file = config_file.replace('{{{ NODE }}}', node)
+ config_file = config_file.replace('\'{{{ NODE }}}\'', repr(node))
python = find_executable('python2') or find_executable('python') or \
sys.executable or 'python'
- config_file = config_file.replace('{{{ PYTHON }}}', python)
+ config_file = config_file.replace('\'{{{ PYTHON }}}\'', repr(python))
+ if WINDOWS:
+ tempdir = os.environ.get('TEMP') or os.environ.get('TMP') or 'c:\\temp'
+ else:
+ tempdir = '/tmp'
+ config_file = config_file.replace('\'{{{ TEMP }}}\'', repr(tempdir))
# write
open(CONFIG_FILE, 'w').write(config_file)
@@ -283,7 +290,7 @@ def check_node_version():
# 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.5.3'
+EMSCRIPTEN_VERSION = '1.5.5'
def generate_sanity():
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT
@@ -333,7 +340,7 @@ def check_sanity(force=False):
logging.critical('Node.js (%s) does not seem to work, check the paths in %s' % (NODE_JS, EM_CONFIG))
sys.exit(1)
- for cmd in [CLANG, LLVM_LINK, LLVM_AR, LLVM_OPT, LLVM_AS, LLVM_DIS, LLVM_NM]:
+ for cmd in [CLANG, LINK_CMD[0], LLVM_AR, LLVM_OPT, LLVM_AS, LLVM_DIS, LLVM_NM]:
if not os.path.exists(cmd) and not os.path.exists(cmd + '.exe'): # .exe extension required for Windows
logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG))
sys.exit(1)
@@ -360,12 +367,31 @@ def check_sanity(force=False):
# Tools/paths
-LLVM_ADD_VERSION = os.getenv('LLVM_ADD_VERSION')
-CLANG_ADD_VERSION = os.getenv('CLANG_ADD_VERSION')
+try:
+ LLVM_ADD_VERSION
+except NameError:
+ LLVM_ADD_VERSION = os.getenv('LLVM_ADD_VERSION')
+
+try:
+ CLANG_ADD_VERSION
+except NameError:
+ CLANG_ADD_VERSION = os.getenv('CLANG_ADD_VERSION')
+
+USING_PNACL_TOOLCHAIN = os.path.exists(os.path.join(LLVM_ROOT, 'pnacl-clang'))
+
+def modify_prefix(tool):
+ if USING_PNACL_TOOLCHAIN:
+ if tool.startswith('llvm-'):
+ tool = tool[5:]
+ tool = 'pnacl-' + tool
+ if WINDOWS:
+ tool += '.bat'
+ return tool
# Some distributions ship with multiple llvm versions so they add
# the version to the binaries, cope with that
def build_llvm_tool_path(tool):
+ tool = modify_prefix(tool)
if LLVM_ADD_VERSION:
return os.path.join(LLVM_ROOT, tool + "-" + LLVM_ADD_VERSION)
else:
@@ -374,6 +400,7 @@ def build_llvm_tool_path(tool):
# Some distributions ship with multiple clang versions so they add
# the version to the binaries, cope with that
def build_clang_tool_path(tool):
+ tool = modify_prefix(tool)
if CLANG_ADD_VERSION:
return os.path.join(LLVM_ROOT, tool + "-" + CLANG_ADD_VERSION)
else:
@@ -382,7 +409,11 @@ def build_clang_tool_path(tool):
CLANG_CC=os.path.expanduser(build_clang_tool_path('clang'))
CLANG_CPP=os.path.expanduser(build_clang_tool_path('clang++'))
CLANG=CLANG_CPP
-LLVM_LINK=build_llvm_tool_path('llvm-link')
+if USING_PNACL_TOOLCHAIN:
+ # The PNaCl toolchain doesn't have llvm-link, but we can fake it
+ LINK_CMD = [build_llvm_tool_path('llvm-ld'), '-nostdlib', '-r']
+else:
+ LINK_CMD = [build_llvm_tool_path('llvm-link')]
LLVM_AR=build_llvm_tool_path('llvm-ar')
LLVM_OPT=os.path.expanduser(build_llvm_tool_path('opt'))
LLVM_AS=os.path.expanduser(build_llvm_tool_path('llvm-as'))
@@ -599,7 +630,7 @@ def line_splitter(data):
return out
-def limit_size(string, MAX=120*20):
+def limit_size(string, MAX=12000*20):
if len(string) < MAX: return string
return string[0:MAX/2] + '\n[..]\n' + string[-MAX/2:]
@@ -643,62 +674,89 @@ def expand_response(data):
# Settings. A global singleton. Not pretty, but nicer than passing |, settings| everywhere
-class Settings:
- @classmethod
- def reset(self):
- class Settings2:
- QUANTUM_SIZE = 4
- reset = Settings.reset
-
- # Given some emcc-type args (-O3, -s X=Y, etc.), fill Settings with the right settings
- @classmethod
- def load(self, args=[]):
- # Load the JS defaults into python
- settings = open(path_from_root('src', 'settings.js')).read().replace('var ', 'Settings.').replace('//', '#')
- exec settings in globals()
-
- # Apply additional settings. First -O, then -s
- for i in range(len(args)):
- if args[i].startswith('-O'):
- level = eval(args[i][2])
- Settings.apply_opt_level(level)
- for i in range(len(args)):
- if args[i] == '-s':
- exec 'Settings.' + args[i+1] in globals() # execute the setting
-
- # Transforms the Settings information into emcc-compatible args (-s X=Y, etc.). Basically
- # the reverse of load_settings, except for -Ox which is relevant there but not here
- @classmethod
- def serialize(self):
- ret = []
- for key, value in Settings.__dict__.iteritems():
- if key == key.upper(): # this is a hack. all of our settings are ALL_CAPS, python internals are not
- jsoned = json.dumps(value, sort_keys=True)
- ret += ['-s', key + '=' + jsoned]
- return ret
-
- @classmethod
- def apply_opt_level(self, opt_level, noisy=False):
- if opt_level >= 1:
- Settings.ASM_JS = 1
- Settings.ASSERTIONS = 0
- Settings.DISABLE_EXCEPTION_CATCHING = 1
- Settings.EMIT_GENERATED_FUNCTIONS = 1
- if opt_level >= 2:
- Settings.RELOOP = 1
- Settings.ALIASING_FUNCTION_POINTERS = 1
- if opt_level >= 3:
- # Aside from these, -O3 also runs closure compiler and llvm lto
- Settings.FORCE_ALIGNED_MEMORY = 1
- Settings.DOUBLE_MODE = 0
- Settings.PRECISE_I64_MATH = 0
- if noisy: logging.warning('Applying some potentially unsafe optimizations! (Use -O2 if this fails.)')
-
- global Settings
- Settings = Settings2
- Settings.load() # load defaults
-
-Settings.reset()
+class Settings2(type):
+ class __impl:
+ attrs = {}
+
+ def __init__(self):
+ self.reset()
+
+ @classmethod
+ def reset(self):
+ self.attrs = { 'QUANTUM_SIZE': 4 }
+ self.load()
+
+ # Given some emcc-type args (-O3, -s X=Y, etc.), fill Settings with the right settings
+ @classmethod
+ def load(self, args=[]):
+ # Load the JS defaults into python
+ settings = open(path_from_root('src', 'settings.js')).read().replace('//', '#')
+ settings = re.sub(r'var ([\w\d]+)', r'self.attrs["\1"]', settings)
+ exec settings
+
+ # Apply additional settings. First -O, then -s
+ for i in range(len(args)):
+ if args[i].startswith('-O'):
+ level = eval(args[i][2])
+ self.apply_opt_level(level)
+ for i in range(len(args)):
+ if args[i] == '-s':
+ declare = re.sub(r'([\w\d]+)\s*=\s*(.+)', r'self.attrs["\1"]=\2;', args[i+1])
+ exec declare
+
+ # Transforms the Settings information into emcc-compatible args (-s X=Y, etc.). Basically
+ # the reverse of load_settings, except for -Ox which is relevant there but not here
+ @classmethod
+ def serialize(self):
+ ret = []
+ for key, value in self.attrs.iteritems():
+ if key == key.upper(): # this is a hack. all of our settings are ALL_CAPS, python internals are not
+ jsoned = json.dumps(value, sort_keys=True)
+ ret += ['-s', key + '=' + jsoned]
+ return ret
+
+ @classmethod
+ def apply_opt_level(self, opt_level, noisy=False):
+ if opt_level >= 1:
+ self.attrs['ASM_JS'] = 1
+ self.attrs['ASSERTIONS'] = 0
+ self.attrs['DISABLE_EXCEPTION_CATCHING'] = 1
+ self.attrs['EMIT_GENERATED_FUNCTIONS'] = 1
+ if opt_level >= 2:
+ self.attrs['RELOOP'] = 1
+ self.attrs['ALIASING_FUNCTION_POINTERS'] = 1
+ if opt_level >= 3:
+ # Aside from these, -O3 also runs closure compiler and llvm lto
+ self.attrs['FORCE_ALIGNED_MEMORY'] = 1
+ self.attrs['DOUBLE_MODE'] = 0
+ self.attrs['PRECISE_I64_MATH'] = 0
+ if noisy: logging.warning('Applying some potentially unsafe optimizations! (Use -O2 if this fails.)')
+
+ def __getattr__(self, attr):
+ if attr in self.attrs:
+ return self.attrs[attr]
+ else:
+ raise AttributeError
+
+ def __setattr__(self, attr, value):
+ self.attrs[attr] = value
+
+ __instance = None
+
+ @staticmethod
+ def instance():
+ if Settings2.__instance is None:
+ Settings2.__instance = Settings2.__impl()
+ return Settings2.__instance
+
+ def __getattr__(self, attr):
+ return getattr(self.instance(), attr)
+
+ def __setattr__(self, attr, value):
+ return setattr(self.instance(), attr, value)
+
+class Settings(object):
+ __metaclass__ = Settings2
# Building
@@ -706,6 +764,7 @@ class Building:
COMPILER = CLANG
LLVM_OPTS = False
COMPILER_TEST_OPTS = [] # For use of the test runner
+ JS_ENGINE_OVERRIDE = None # Used to pass the JS engine override from runner.py -> test_benchmark.py
@staticmethod
def get_building_env(native=False):
@@ -947,7 +1006,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
logging.debug('emcc: llvm-linking: %s to %s', actual_files, target)
# check for too-long command line
- link_cmd = [LLVM_LINK] + actual_files + ['-o', target]
+ link_cmd = LINK_CMD + actual_files + ['-o', target]
# 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
@@ -955,7 +1014,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
logging.debug('using response file for llvm-link')
[response_fd, response_file] = mkstemp(suffix='.response', dir=TEMP_DIR)
- link_cmd = [LLVM_LINK, "@" + response_file]
+ link_cmd = LINK_CMD + ["@" + response_file]
response_fh = os.fdopen(response_fd, 'w')
for arg in actual_files:
@@ -999,7 +1058,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
opts = Building.pick_llvm_opts(opts)
#opts += ['-debug-pass=Arguments']
logging.debug('emcc: LLVM opts: ' + str(opts))
- output = Popen([LLVM_OPT, filename] + opts + ['-o=' + filename + '.opt.bc'], stdout=PIPE).communicate()[0]
+ output = Popen([LLVM_OPT, filename] + opts + ['-o', filename + '.opt.bc'], stdout=PIPE).communicate()[0]
assert os.path.exists(filename + '.opt.bc'), 'Failed to run llvm optimizations: ' + output
shutil.move(filename + '.opt.bc', filename)
@@ -1007,7 +1066,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
def llvm_opts(filename): # deprecated version, only for test runner. TODO: remove
if Building.LLVM_OPTS:
shutil.move(filename + '.o', filename + '.o.pre')
- output = Popen([LLVM_OPT, filename + '.o.pre'] + Building.LLVM_OPT_OPTS + ['-o=' + filename + '.o'], stdout=PIPE).communicate()[0]
+ output = Popen([LLVM_OPT, filename + '.o.pre'] + Building.LLVM_OPT_OPTS + ['-o', filename + '.o'], stdout=PIPE).communicate()[0]
assert os.path.exists(filename + '.o'), 'Failed to run llvm optimizations: ' + output
@staticmethod
@@ -1018,7 +1077,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
output_filename = input_filename + '.o.ll'
input_filename = input_filename + '.o'
try_delete(output_filename)
- output = Popen([LLVM_DIS, input_filename, '-o=' + output_filename], stdout=PIPE).communicate()[0]
+ output = Popen([LLVM_DIS, input_filename, '-o', output_filename], stdout=PIPE).communicate()[0]
assert os.path.exists(output_filename), 'Could not create .ll file: ' + output
return output_filename
@@ -1030,7 +1089,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
output_filename = input_filename + '.o'
input_filename = input_filename + '.o.ll'
try_delete(output_filename)
- output = Popen([LLVM_AS, input_filename, '-o=' + output_filename], stdout=PIPE).communicate()[0]
+ output = Popen([LLVM_AS, input_filename, '-o', output_filename], stdout=PIPE).communicate()[0]
assert os.path.exists(output_filename), 'Could not create bc file: ' + output
return output_filename
@@ -1051,6 +1110,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
for line in output.split('\n'):
if len(line) == 0: continue
parts = filter(lambda seg: len(seg) > 0, line.split(' '))
+ # pnacl-nm will print zero offsets for bitcode
+ if len(parts) == 3 and parts[0] == "00000000":
+ parts.pop(0)
if len(parts) == 2: # ignore lines with absolute offsets, these are not bitcode anyhow (e.g. |00000630 t d_source_name|)
status, symbol = parts
if status == 'U':
diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js
index 5027f680..d8ea9446 100644
--- a/tools/test-js-optimizer-asm-outline1-output.js
+++ b/tools/test-js-optimizer-asm-outline1-output.js
@@ -5,7 +5,6 @@ function lin() {
c(1);
c(2);
c(3);
- c(4);
HEAP32[sp + 16 >> 2] = 0;
HEAP32[sp + 20 >> 2] = 0;
lin$1(sp);
@@ -21,8 +20,6 @@ function lin2() {
while (1) {
c(1);
c(2);
- c(3);
- c(4);
HEAP32[sp + 16 >> 2] = 0;
HEAP32[sp + 20 >> 2] = 0;
lin2$1(sp);
@@ -42,9 +39,14 @@ function lin3() {
c(3);
c(4);
c(5);
- HEAP32[sp + 16 >> 2] = 0;
- HEAP32[sp + 20 >> 2] = 0;
- lin3$1(sp);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
HEAP32[sp + 8 >> 2] = 0;
HEAP32[sp + 12 >> 2] = 0;
lin3$0(sp);
@@ -70,9 +72,15 @@ function lin4() {
c(2);
c(3);
c(4);
- HEAP32[sp + 16 >> 2] = 0;
- HEAP32[sp + 20 >> 2] = 0;
- lin4$1(sp);
+ c(5);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
HEAP32[sp + 8 >> 2] = 0;
HEAP32[sp + 12 >> 2] = 0;
lin4$0(sp);
@@ -97,9 +105,15 @@ function lin5() {
c(2);
c(3);
c(4);
- HEAP32[sp + 16 >> 2] = 0;
- HEAP32[sp + 20 >> 2] = 0;
- lin5$1(sp);
+ c(5);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
HEAP32[sp + 8 >> 2] = 0;
HEAP32[sp + 12 >> 2] = 0;
lin5$0(sp);
@@ -120,13 +134,6 @@ function mix() {
sp = STACKTOP;
STACKTOP = STACKTOP + 168 | 0;
main : while (1) {
- c(1);
- c(2);
- c(3);
- c(4);
- c(5);
- c(6);
- c(7);
HEAP32[sp + 16 >> 2] = 0;
HEAP32[sp + 20 >> 2] = 0;
mix$1(sp);
@@ -170,15 +177,14 @@ function vars(x, y) {
var sp = 0;
sp = STACKTOP;
STACKTOP = STACKTOP + 152 | 0;
- HEAP32[sp + 32 >> 2] = 0;
- HEAP32[sp + 36 >> 2] = 0;
+ c(1 + (x + y));
+ c(2 + y * x);
+ c(3 + (x + y));
+ c(4 + y * x);
HEAP32[sp + 8 >> 2] = x;
HEAPF32[sp + 16 >> 2] = y;
- vars$1(sp);
HEAP32[sp + 24 >> 2] = 0;
HEAP32[sp + 28 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = x;
- HEAPF32[sp + 16 >> 2] = y;
vars$0(sp);
STACKTOP = sp;
}
@@ -192,10 +198,11 @@ function vars2(x, y) {
b = y * x;
a = c(1 + a);
b = c(2 + b);
- HEAP32[sp + 40 >> 2] = 0;
- HEAP32[sp + 44 >> 2] = 0;
+ a = c(3 + a);
HEAP32[sp + 24 >> 2] = a;
HEAPF32[sp + 32 >> 2] = b;
+ HEAP32[sp + 40 >> 2] = 0;
+ HEAP32[sp + 44 >> 2] = 0;
vars2$0(sp);
a = HEAP32[sp + 24 >> 2] | 0;
b = +HEAPF32[sp + 32 >> 2];
@@ -207,18 +214,16 @@ function vars3(x, y) {
var a = 0, sp = 0;
sp = STACKTOP;
STACKTOP = STACKTOP + 160 | 0;
- HEAP32[sp + 40 >> 2] = 0;
- HEAP32[sp + 44 >> 2] = 0;
- HEAP32[sp + 24 >> 2] = a;
+ a = x + y;
+ a = c(1 + a);
+ a = c(2 + y * x);
+ a = c(3 + a);
+ a = c(4 + y * x);
HEAP32[sp + 8 >> 2] = x;
HEAPF32[sp + 16 >> 2] = y;
- vars3$1(sp);
- a = HEAP32[sp + 24 >> 2] | 0;
+ HEAP32[sp + 24 >> 2] = a;
HEAP32[sp + 32 >> 2] = 0;
HEAP32[sp + 36 >> 2] = 0;
- HEAP32[sp + 24 >> 2] = a;
- HEAPF32[sp + 16 >> 2] = y;
- HEAP32[sp + 8 >> 2] = x;
vars3$0(sp);
a = HEAP32[sp + 24 >> 2] | 0;
STACKTOP = sp;
@@ -230,20 +235,16 @@ function vars4(x, y) {
sp = STACKTOP;
STACKTOP = STACKTOP + 168 | 0;
a = x + y;
- HEAP32[sp + 48 >> 2] = 0;
- HEAP32[sp + 52 >> 2] = 0;
- HEAPF32[sp + 16 >> 2] = y;
+ b = y * x;
+ a = c(1 + a);
+ a = c(2 + a);
+ a = c(3 + a);
+ a = c(4 + a);
HEAP32[sp + 8 >> 2] = x;
HEAP32[sp + 24 >> 2] = a;
HEAPF32[sp + 32 >> 2] = b;
- vars4$1(sp);
- b = +HEAPF32[sp + 32 >> 2];
- a = HEAP32[sp + 24 >> 2] | 0;
HEAP32[sp + 40 >> 2] = 0;
HEAP32[sp + 44 >> 2] = 0;
- HEAP32[sp + 24 >> 2] = a;
- HEAP32[sp + 8 >> 2] = x;
- HEAPF32[sp + 32 >> 2] = b;
vars4$0(sp);
a = HEAP32[sp + 24 >> 2] | 0;
b = +HEAPF32[sp + 32 >> 2];
@@ -255,20 +256,19 @@ function vars_w_stack(x, y) {
var a = 0, b = +0, sp = 0;
sp = STACKTOP;
STACKTOP = STACKTOP + 208 | 0;
- a = x + y;
- HEAP32[sp + 72 >> 2] = 0;
- HEAP32[sp + 76 >> 2] = 0;
- HEAPF32[sp + 32 >> 2] = y;
HEAP32[sp + 24 >> 2] = x;
+ HEAPF32[sp + 32 >> 2] = y;
HEAP32[sp + 40 >> 2] = a;
HEAPF32[sp + 48 >> 2] = b;
+ HEAP32[sp + 72 >> 2] = 0;
+ HEAP32[sp + 76 >> 2] = 0;
vars_w_stack$1(sp);
- b = +HEAPF32[sp + 48 >> 2];
a = HEAP32[sp + 40 >> 2] | 0;
- HEAP32[sp + 64 >> 2] = 0;
- HEAP32[sp + 68 >> 2] = 0;
+ b = +HEAPF32[sp + 48 >> 2];
HEAP32[sp + 40 >> 2] = a;
HEAPF32[sp + 48 >> 2] = b;
+ HEAP32[sp + 64 >> 2] = 0;
+ HEAP32[sp + 68 >> 2] = 0;
vars_w_stack$0(sp);
a = HEAP32[sp + 40 >> 2] | 0;
b = +HEAPF32[sp + 48 >> 2];
@@ -276,43 +276,53 @@ function vars_w_stack(x, y) {
function chain() {
var helper$0 = 0, sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 336 | 0;
+ STACKTOP = STACKTOP + 464 | 0;
helper$0 = 1;
- HEAP