aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-rw-r--r--README.markdown2
-rw-r--r--cmake/Platform/Emscripten.cmake17
-rwxr-xr-xemscripten.py95
-rw-r--r--src/analyzer.js15
-rw-r--r--src/compiler.js1
-rw-r--r--src/intertyper.js10
-rw-r--r--src/jsifier.js103
-rw-r--r--src/library.js65
-rw-r--r--src/library_gl.js4
-rw-r--r--src/modules.js24
-rw-r--r--src/parseTools.js185
-rw-r--r--src/preamble.js24
-rw-r--r--src/runtime.js23
-rw-r--r--src/settings.js8
-rw-r--r--system/include/libc/sys/_types.h6
-rw-r--r--system/include/libc/sys/types.h1
-rw-r--r--tests/cases/extendedprecision.ll2
-rw-r--r--tests/openjpeg/codec/convert.h4
-rwxr-xr-xtests/runner.py71
-rw-r--r--tools/js-optimizer.js25
-rw-r--r--tools/js_optimizer.py1
-rw-r--r--tools/shared.py6
-rw-r--r--tools/test-js-optimizer-asm-pre-output.js44
-rw-r--r--tools/test-js-optimizer-asm-pre.js46
25 files changed, 599 insertions, 187 deletions
diff --git a/AUTHORS b/AUTHORS
index 9a0fa20d..f491acc0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -44,5 +44,9 @@ a license to everyone to use it as detailed in LICENSE.)
* Dominic Wong <dom@slowbunyip.org>
* Alan Kligman <alan.kligman@gmail.com> (copyright owned by Mozilla Foundation)
* Anthony Liot <wolfviking0@yahoo.com>
+* Michael Riss <Michael.Riss@gmx.de>
+* Jasper St. Pierre <jstpierre@mecheye.net>
* Manuel Schölling <manuel.schoelling@gmx.de>
+
+
diff --git a/README.markdown b/README.markdown
index dadbf3a4..81a95141 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,4 +1,6 @@
+![logo](http://dl.dropbox.com/u/80664946/emscripten_logo.jpg)
+
Emscripten
==========
diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Platform/Emscripten.cmake
index 532e5d99..4b9c6572 100644
--- a/cmake/Platform/Emscripten.cmake
+++ b/cmake/Platform/Emscripten.cmake
@@ -42,3 +42,20 @@ set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER} -o <TARGET> -emit-llvm <LINK_FLA
# Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten.
# There seems to be some kind of bug with CMake, so you might need to define this manually on the command line with "-DEMSCRIPTEN=1".
set(EMSCRIPTEN 1)
+
+set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE")
+set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO")
+set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELEASE")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_MINSIZEREL")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELWITHDEBINFO")
+
+set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELEASE")
+set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_MINSIZEREL")
+set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO")
+set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELEASE")
+set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL")
+set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO")
+set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELEASE")
+set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL")
+set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO")
diff --git a/emscripten.py b/emscripten.py
index ac13f7a3..9c3fedef 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -248,6 +248,11 @@ def emscript(infile, settings, outfile, libraries=[]):
for key, value in curr_forwarded_json['Functions']['unimplementedFunctions'].iteritems():
forwarded_json['Functions']['unimplementedFunctions'][key] = value
+ if settings.get('ASM_JS'):
+ parts = pre.split('// ASM_LIBRARY FUNCTIONS\n')
+ if len(parts) > 1:
+ pre = parts[0]
+ outputs.append([parts[1]])
funcs_js = ''.join([output[0] for output in outputs])
outputs = None
@@ -295,24 +300,36 @@ def emscript(infile, settings, outfile, libraries=[]):
simple = os.environ.get('EMCC_SIMPLE_ASM')
class Counter:
i = 0
+ pre_tables = last_forwarded_json['Functions']['tables']['pre']
+ del last_forwarded_json['Functions']['tables']['pre']
+
+ # Find function table calls without function tables generated for them
+ for use in set(re.findall(r'{{{ FTM_[\w\d_$]+ }}}', funcs_js)):
+ sig = use[8:len(use)-4]
+ if sig not in last_forwarded_json['Functions']['tables']:
+ if DEBUG: print >> sys.stderr, 'add empty function table', sig
+ last_forwarded_json['Functions']['tables'][sig] = 'var FUNCTION_TABLE_' + sig + ' = [0,0];\n'
+
def make_table(sig, raw):
i = Counter.i
Counter.i += 1
bad = 'b' + str(i)
params = ','.join(['p%d' % p for p in range(len(sig)-1)])
- coercions = ';'.join(['p%d = %sp%d%s' % (p, '+' if sig[p+1] == 'd' else '', p, '' if sig[p+1] == 'd' else '|0') for p in range(len(sig)-1)]) + ';'
- ret = '' if sig[0] == 'v' else ('return %s0' % ('+' if sig[0] == 'd' else ''))
- return 'function %s(%s) { %s abort(%d); %s };\n' % (bad, params, coercions, i, ret) + raw.replace('[0,', '[' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0]', ',' + bad + ']').replace(',0]', ',' + bad + ']')
- function_tables_defs = '\n'.join([make_table(sig, raw) for sig, raw in last_forwarded_json['Functions']['tables'].iteritems()])
-
- maths = ['Runtime.bitshift64', 'Math.floor', 'Math.min', 'Math.abs', 'Math.sqrt', 'Math.pow', 'Math.cos', 'Math.sin', 'Math.tan', 'Math.acos', 'Math.asin', 'Math.atan', 'Math.atan2', 'Math.exp', 'Math.log', 'Math.ceil']
+ coercions = ';'.join(['p%d = %sp%d%s' % (p, '+' if sig[p+1] == 'f' else '', p, '' if sig[p+1] == 'f' else '|0') for p in range(len(sig)-1)]) + ';'
+ ret = '' if sig[0] == 'v' else ('return %s0' % ('+' if sig[0] == 'f' else ''))
+ return ('function %s(%s) { %s abort(%d); %s };' % (bad, params, coercions, i, ret), raw.replace('[0,', '[' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0]', ',' + bad + ']').replace(',0]', ',' + bad + ']'))
+ infos = [make_table(sig, raw) for sig, raw in last_forwarded_json['Functions']['tables'].iteritems()]
+ function_tables_defs = '\n'.join([info[0] for info in infos] + [info[1] for info in infos])
+ maths = ['Math.' + func for func in ['floor', 'abs', 'sqrt', 'pow', 'cos', 'sin', 'tan', 'acos', 'asin', 'atan', 'atan2', 'exp', 'log', 'ceil']]
if settings['USE_MATH_IMUL']:
maths += ['Math.imul']
- asm_setup = '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in maths])
fundamentals = ['buffer', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array']
- basic_funcs = ['abort', 'assert'] + [m.replace('.', '_') for m in maths]
+ math_envs = ['Runtime.bitshift64', 'Math.min'] # TODO: move min to maths
+ asm_setup = '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs])
+ basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs]
basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT']
+ basic_float_vars = ['NaN', 'Infinity']
if forwarded_json['Types']['preciseI64MathUsed']:
basic_funcs += ['i64Math_' + op for op in ['add', 'subtract', 'multiply', 'divide', 'modulo']]
asm_setup += '''
@@ -324,18 +341,25 @@ var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) };
'''
asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)]
# function tables
+ def asm_coerce(value, sig):
+ if sig == 'v': return value
+ return ('+' if sig == 'f' else '') + value + ('|0' if sig == 'i' else '')
+
function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']]
function_tables_impls = []
for sig in last_forwarded_json['Functions']['tables'].iterkeys():
args = ','.join(['a' + str(i) for i in range(1, len(sig))])
- arg_coercions = ' '.join(['a' + str(i) + '=' + ('+' if sig[i] == 'd' else '') + 'a' + str(i) + ('|0' if sig[i] == 'i' else '') + ';' for i in range(1, len(sig))])
+ arg_coercions = ' '.join(['a' + str(i) + '=' + asm_coerce('a' + str(i), sig[i]) + ';' for i in range(1, len(sig))])
+ coerced_args = ','.join([asm_coerce('a' + str(i), sig[i]) for i in range(1, len(sig))])
+ ret = ('return ' if sig[0] != 'v' else '') + asm_coerce('FUNCTION_TABLE_%s[index&{{{ FTM_%s }}}](%s)' % (sig, sig, coerced_args), sig[0])
function_tables_impls.append('''
function dynCall_%s(index%s%s) {
index = index|0;
%s
- %sFUNCTION_TABLE_%s[index&{{{ FTM_%s }}}](%s);
+ %s;
}
-''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, 'return ' if sig[0] != 'v' else '', sig, sig, args))
+''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, ret))
+
# calculate exports
exported_implemented_functions = list(exported_implemented_functions)
exports = []
@@ -353,10 +377,14 @@ var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) };
# If no named globals, only need externals
global_vars = map(lambda g: g['name'], filter(lambda g: settings['NAMED_GLOBALS'] or g.get('external') or g.get('unIndexable'), forwarded_json['Variables']['globals'].values()))
global_funcs = ['_' + x for x in forwarded_json['Functions']['libraryFunctions'].keys()]
- asm_global_funcs = ''.join([' var ' + g + '=env.' + g + ';\n' for g in basic_funcs + global_funcs])
- asm_global_vars = ''.join([' var ' + g + '=env.' + g + '|0;\n' for g in basic_vars + global_vars])
+ def math_fix(g):
+ return g if not g.startswith('Math_') else g.split('_')[1];
+ asm_global_funcs = ''.join([' var ' + g.replace('.', '_') + '=global.' + g + ';\n' for g in maths]) + \
+ ''.join([' var ' + g + '=env.' + math_fix(g) + ';\n' for g in basic_funcs + global_funcs])
+ asm_global_vars = ''.join([' var ' + g + '=env.' + g + '|0;\n' for g in basic_vars + global_vars]) + \
+ ''.join([' var ' + g + '=+env.' + g + ';\n' for g in basic_float_vars])
# sent data
- sending = '{ ' + ', '.join([s + ': ' + s for s in fundamentals + basic_funcs + global_funcs + basic_vars + global_vars]) + ' }'
+ sending = '{ ' + ', '.join([math_fix(s) + ': ' + s for s in fundamentals + basic_funcs + global_funcs + basic_vars + basic_float_vars + global_vars]) + ' }'
# received
if not simple:
receiving = ';\n'.join(['var ' + s + ' = Module["' + s + '"] = asm.' + s for s in exported_implemented_functions + function_tables])
@@ -365,20 +393,26 @@ var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) };
# finalize
funcs_js = '''
%s
-var asmPre = (function(env, buffer) {
+function asmPrintInt(x) {
+ Module.print('int ' + x);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x) {
+ Module.print('float ' + x);// + ' ' + new Error().stack);
+}
+var asm = (function(global, env, buffer) {
'use asm';
- var HEAP8 = new env.Int8Array(buffer);
- var HEAP16 = new env.Int16Array(buffer);
- var HEAP32 = new env.Int32Array(buffer);
- var HEAPU8 = new env.Uint8Array(buffer);
- var HEAPU16 = new env.Uint16Array(buffer);
- var HEAPU32 = new env.Uint32Array(buffer);
- var HEAPF32 = new env.Float32Array(buffer);
- var HEAPF64 = new env.Float64Array(buffer);
+ var HEAP8 = new global.Int8Array(buffer);
+ var HEAP16 = new global.Int16Array(buffer);
+ var HEAP32 = new global.Int32Array(buffer);
+ var HEAPU8 = new global.Uint8Array(buffer);
+ var HEAPU16 = new global.Uint16Array(buffer);
+ var HEAPU32 = new global.Uint32Array(buffer);
+ var HEAPF32 = new global.Float32Array(buffer);
+ var HEAPF64 = new global.Float64Array(buffer);
''' % (asm_setup,) + '\n' + asm_global_vars + '''
var __THREW__ = 0;
var undef = 0;
- var tempInt = 0, tempValue = 0;
+ var tempInt = 0, tempBigInt = 0, tempValue = 0;
''' + ''.join(['''
var tempRet%d = 0;''' % i for i in range(10)]) + '\n' + asm_global_funcs + '''
function stackAlloc(size) {
@@ -410,18 +444,12 @@ var asmPre = (function(env, buffer) {
%s
return %s;
-});
-if (asmPre.toSource) { // works in sm but not v8, so we get full coverage between those two
- asmPre = asmPre.toSource();
- asmPre = asmPre.substr(25, asmPre.length-28);
- asmPre = new Function('env', 'buffer', asmPre);
-}
-var asm = asmPre(%s, buffer); // pass through Function to prevent seeing outside scope
+})(this, %s, buffer);
%s;
Runtime.stackAlloc = function(size) { return asm.stackAlloc(size) };
Runtime.stackSave = function() { return asm.stackSave() };
Runtime.stackRestore = function(top) { asm.stackRestore(top) };
-''' % (function_tables_defs.replace('\n', '\n ') + '\n' + '\n'.join(function_tables_impls), exports, sending, receiving)
+''' % (pre_tables + '\n'.join(function_tables_impls) + '\n' + function_tables_defs.replace('\n', '\n '), exports, sending, receiving)
# Set function table masks
def function_table_maskize(js):
@@ -432,9 +460,6 @@ Runtime.stackRestore = function(top) { asm.stackRestore(top) };
default = sig
def fix(m):
sig = m.groups(0)[0]
- if not sig in masks:
- print >> sys.stderr, 'warning: function table use without functions for it!', sig
- return masks[default] # TODO: generate empty function tables for this case, even though it would fail at runtime if used
return masks[sig]
return re.sub(r'{{{ FTM_([\w\d_$]+) }}}', lambda m: fix(m), js) # masks[m.groups(0)[0]]
funcs_js = function_table_maskize(funcs_js)
diff --git a/src/analyzer.js b/src/analyzer.js
index 8146c75c..60ef5ba8 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -617,8 +617,8 @@ function analyzer(data, sidePass) {
for (var i = 0; i < targetElements.length; i++) {
if (i > 0) {
switch(value.variant) {
- case 'eq': ident += '&&'; break;
- case 'ne': ident += '||'; break;
+ case 'eq': ident += '&'; break;
+ case 'ne': ident += '|'; break;
default: throw 'unhandleable illegal icmp: ' + value.variant;
}
}
@@ -635,7 +635,7 @@ function analyzer(data, sidePass) {
break;
}
case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem':
- case 'uitofp': case 'sitofp': {
+ case 'uitofp': case 'sitofp': case 'fptosi': case 'fptoui': {
// We cannot do these in parallel chunks of 32-bit operations. We will handle these in processMathop
i++;
continue;
@@ -654,9 +654,12 @@ function analyzer(data, sidePass) {
// We can't statically legalize this, do the operation at runtime TODO: optimize
assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits');
value.intertype = 'value';
- value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + sourceElements[0].ident + ', ' +
- sourceElements[1].ident + ',"' + value.op + '",' + value.params[1].ident + '$0);' +
- 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0, 'i32') + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1, 'i32') + ';';
+ value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' +
+ asmCoercion(sourceElements[0].ident, 'i32') + ',' +
+ asmCoercion(sourceElements[1].ident, 'i32') + ',' +
+ Runtime['BITSHIFT64_' + value.op.toUpperCase()] + ',' +
+ asmCoercion(value.params[1].ident + '$0', 'i32') + ');' +
+ 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0, 'i32') + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1, 'i32') + ';';
value.assignTo = null;
i++;
continue;
diff --git a/src/compiler.js b/src/compiler.js
index 118ca83a..25c306cf 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -168,6 +168,7 @@ if (PGO) { // by default, correct everything during PGO
EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS);
EXPORTED_GLOBALS = set(EXPORTED_GLOBALS);
+EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST);
RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG;
diff --git a/src/intertyper.js b/src/intertyper.js
index 5bca9236..c1a98354 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -725,7 +725,7 @@ function intertyper(data, sidePass, baseLineNums) {
substrate.addActor('Invoke', {
processItem: function(item) {
var result = makeCall.call(this, item, 'invoke');
- if (DISABLE_EXCEPTION_CATCHING) {
+ if (DISABLE_EXCEPTION_CATCHING == 1) {
result.item.intertype = 'call';
result.ret.push({
intertype: 'branch',
@@ -834,15 +834,17 @@ function intertyper(data, sidePass, baseLineNums) {
item.params[i-1] = parseLLVMSegment(segments[i-1]);
}
}
+ var setParamTypes = true;
if (item.op === 'select') {
assert(item.params[1].type === item.params[2].type);
item.type = item.params[1].type;
- } else if (item.op === 'inttoptr' || item.op === 'ptrtoint') {
+ } else if (item.op in LLVM.CONVERSIONS) {
item.type = item.params[1].type;
+ setParamTypes = false;
} else {
item.type = item.params[0].type;
}
- if (item.op != 'ptrtoint') {
+ if (setParamTypes) {
for (var i = 0; i < 4; i++) {
if (item.params[i]) item.params[i].type = item.type; // All params have the same type, normally
}
@@ -851,6 +853,8 @@ function intertyper(data, sidePass, baseLineNums) {
item.type = item.params[1].ident;
item.params[0].type = item.params[1].type;
// TODO: also remove 2nd param?
+ } else if (item.op in LLVM.COMPS) {
+ item.type = 'i1';
}
if (USE_TYPED_ARRAYS == 2) {
// Some specific corrections, since 'i64' is special
diff --git a/src/jsifier.js b/src/jsifier.js
index 44d9cc53..08b6d4f6 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -10,6 +10,7 @@ var UNDERSCORE_OPENPARENS = set('_', '(');
var RELOOP_IGNORED_LASTS = set('return', 'unreachable', 'resume');
var addedLibraryItems = {};
+var asmLibraryFunctions = [];
// JSifier
function JSify(data, functionsOnly, givenFunctions) {
@@ -76,7 +77,7 @@ function JSify(data, functionsOnly, givenFunctions) {
assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.')
libFuncsToInclude = [];
for (var key in LibraryManager.library) {
- if (!key.match(/__(deps|postset|inline)$/)) {
+ if (!key.match(/__(deps|postset|inline|asm)$/)) {
libFuncsToInclude.push(key);
}
}
@@ -292,7 +293,7 @@ function JSify(data, functionsOnly, givenFunctions) {
padding = makeEmptyStruct(item.type);
}
var padded = val.concat(padding.slice(val.length));
- var js = item.ident + '=' + makePointer(JSON.stringify(padded), null, allocator, item.type, index) + ';'
+ var js = item.ident + '=' + makePointer(padded, null, allocator, item.type, index) + ';'
if (LibraryManager.library[shortident + '__postset']) {
js += '\n' + LibraryManager.library[shortident + '__postset'];
}
@@ -332,7 +333,6 @@ function JSify(data, functionsOnly, givenFunctions) {
constant[i] = '0';
}
});
- constant = '[' + constant.join(', ') + ']';
}
// NOTE: This is the only place that could potentially create static
// allocations in a shared library.
@@ -346,7 +346,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (index !== null) {
index = getFastValue(index, '+', Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type)));
}
- js += '\n' + makePointer('[0]', null, allocator, ['void*'], index) + ';';
+ js += '\n' + makePointer([0], null, allocator, ['void*'], index) + ';';
}
if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) {
js += '\nModule["' + item.ident + '"] = ' + item.ident + ';';
@@ -477,13 +477,25 @@ function JSify(data, functionsOnly, givenFunctions) {
} else {
ident = '_' + ident;
}
- var text = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : '');
+ var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : '');
// redirected idents just need a var, but no value assigned to them - it would be unused
- text += isFunction ? snippet : ('var ' + ident + (redirectedIdent ? '' : '=' + snippet) + ';');
- if (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS)) {
- text += '\nModule["' + ident + '"] = ' + ident + ';';
+ var contentText = isFunction ? snippet : ('var ' + ident + (redirectedIdent ? '' : '=' + snippet) + ';');
+ if (ASM_JS) {
+ var asmSig = LibraryManager.library[ident.substr(1) + '__asm'];
+ if (isFunction && asmSig) {
+ // asm library function, add it as generated code alongside the generated code
+ Functions.implementedFunctions[ident] = asmSig;
+ asmLibraryFunctions.push(contentText);
+ contentText = ' ';
+ EXPORTED_FUNCTIONS[ident] = 1;
+ delete Functions.libraryFunctions[ident.substr(1)];
+ }
+ } else {
+ if (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS)) {
+ contentText += '\nModule["' + ident + '"] = ' + ident + ';';
+ }
}
- return text;
+ return depsText + contentText;
}
var ret = [item];
@@ -606,10 +618,12 @@ function JSify(data, functionsOnly, givenFunctions) {
}
for (i = 0; i < chunks.length; i++) {
func.JS += ' var ' + chunks[i].map(function(v) {
- if (v.type != 'i64') {
+ if (!isIllegalType(v.type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal
return v.ident + ' = ' + asmInitializer(v.type); //, func.variables[v.ident].impl);
} else {
- return v.ident + '$0 = 0, ' + v.ident + '$1 = 1';
+ return range(Math.ceil(getBits(v.type)/32)).map(function(i) {
+ return v.ident + '$' + i + '= 0';
+ }).join(',');
}
}).join(', ') + ';\n';
}
@@ -720,12 +734,13 @@ function JSify(data, functionsOnly, givenFunctions) {
if (func.setjmpTable) {
ret += 'try { ';
}
- ret += 'switch(label) {\n';
+ ret += 'switch(' + asmCoercion('label', 'i32') + ') {\n';
ret += block.labels.map(function(label) {
return indent + ' case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
+ getLabelLines(label, indent + ' ');
}).join('\n');
- ret += '\n' + indent + ' default: assert(0, "bad label: " + label);\n' + indent + '}';
+ if (ASSERTIONS) ret += '\n' + indent + ' default: assert(0, "bad label: " + label);\n';
+ ret += indent + '}';
if (func.setjmpTable) {
ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](e.value) }';
}
@@ -783,10 +798,10 @@ function JSify(data, functionsOnly, givenFunctions) {
func.JS += walkBlock(func.block, ' ');
// Finalize function
if (LABEL_DEBUG && functionNameFilterTest(func.ident)) func.JS += " INDENT = INDENT.substr(0, INDENT.length-2);\n";
- // Add an unneeded return, needed for strict mode to not throw warnings in some cases.
- // If we are not relooping, then switches make it unimportant to have this (and, we lack hasReturn anyhow)
- if (RELOOP && func.lines.length > 0 && func.labels.filter(function(label) { return label.hasReturn }).length > 0) {
- func.JS += ' return' + (func.returnType !== 'void' ? ' null' : '') + ';\n';
+ // Ensure a return in a function with a type that returns, even if it lacks a return (e.g., if it aborts())
+ if (RELOOP && func.lines.length > 0 && func.returnType != 'void') {
+ var returns = func.labels.filter(function(label) { return label.lines[label.lines.length-1].intertype == 'return' }).length;
+ if (returns == 0) func.JS += ' return ' + asmCoercion('0', func.returnType);
}
func.JS += '}\n';
@@ -1091,7 +1106,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (useIfs) {
value = targetLabels[targetLabel].map(function(value) {
return makeComparison(signedIdent, makeSignOp(value, item.type, 're'), item.type)
- }).join(' || ');
+ }).join(' | ');
ret += 'if (' + value + ') {\n';
} else {
value = targetLabels[targetLabel].map(function(value) {
@@ -1150,20 +1165,29 @@ function JSify(data, functionsOnly, givenFunctions) {
var ptr = makeStructuralAccess(item.ident, 0);
return (EXCEPTION_DEBUG ? 'Module.print("Resuming exception");' : '') +
'if (' + makeGetValue('_llvm_eh_exception.buf', 0, 'void*') + ' == 0) { ' + makeSetValue('_llvm_eh_exception.buf', 0, ptr, 'void*') + ' } ' +
- 'throw ' + ptr + ';';
+ makeThrow(ptr) + ';';
});
makeFuncLineActor('invoke', function(item) {
// Wrapping in a function lets us easily return values if we are
// in an assignment
var phiSets = calcPhiSets(item);
var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type);
- var ret = '(function() { try { __THREW__ = 0; return '
- + call_ + ' '
- + '} catch(e) { '
- + 'if (typeof e != "number") throw e; '
- + 'if (ABORT) throw e; __THREW__ = 1; '
- + (EXCEPTION_DEBUG ? 'Module.print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '')
- + 'return null } })();';
+
+ var ret;
+
+ if (DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST)) {
+ ret = call_ + ';';
+ } else {
+ ret = '(function() { try { __THREW__ = 0; return '
+ + call_ + ' '
+ + '} catch(e) { '
+ + 'if (typeof e != "number") throw e; '
+ + 'if (ABORT) throw e; __THREW__ = 1; '
+ + (EXCEPTION_DEBUG ? 'Module.print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '')
+ + 'return null } })();';
+ }
+
+
if (item.assignTo) {
ret = 'var ' + item.assignTo + ' = ' + ret;
if (USE_TYPED_ARRAYS == 2 && isIllegalType(item.type)) {
@@ -1191,7 +1215,7 @@ function JSify(data, functionsOnly, givenFunctions) {
case 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type, null, null, null, null, ',') + ',tempValue)';
case 'cmpxchg': {
var param3 = finalizeLLVMParameter(item.params[2]);
- return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' && (' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ')),tempValue)';
+ return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' ? ' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ' : 0),tempValue)';
}
default: throw 'unhandled atomic op: ' + item.op;
}
@@ -1240,7 +1264,12 @@ function JSify(data, functionsOnly, givenFunctions) {
return ret + item.ident + '.f' + item.indexes[0][0].text + ' = ' + finalizeLLVMParameter(item.value) + ', ' + item.ident + ')';
});
makeFuncLineActor('indirectbr', function(item) {
- return makeBranch(finalizeLLVMParameter(item.value), item.currLabelId, true);
+ var phiSets = calcPhiSets(item);
+ var js = 'var ibr = ' + finalizeLLVMParameter(item.value) + ';\n';
+ for (var targetLabel in phiSets) {
+ js += 'if (ibr == ' + targetLabel + ') { ' + getPhiSetsForLabel(phiSets, targetLabel) + ' }\n';
+ }
+ return js + makeBranch('ibr', item.currLabelId, true);
});
makeFuncLineActor('alloca', function(item) {
if (typeof item.allocatedIndex === 'number') {
@@ -1311,8 +1340,12 @@ function JSify(data, functionsOnly, givenFunctions) {
});
args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) });
- if (ASM_JS && shortident in Functions.libraryFunctions) {
- args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) });
+ if (ASM_JS) {
+ if (shortident in Functions.libraryFunctions) {
+ args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) });
+ } else {
+ args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) });
+ }
}
varargs = varargs.map(function(vararg, i) {
@@ -1471,6 +1504,16 @@ function JSify(data, functionsOnly, givenFunctions) {
generated.forEach(function(item) { print(indentify(item.JS || '', 2)); });
legalizedI64s = legalizedI64sDefault;
+
+ if (asmLibraryFunctions.length > 0) {
+ print('// ASM_LIBRARY FUNCTIONS');
+ function fix(f) { // fix indenting to not confuse js optimizer
+ f = f.substr(f.indexOf('f')); // remove initial spaces before 'function'
+ f = f.substr(0, f.lastIndexOf('\n')+1); // remove spaces and last }
+ return f + '}'; // add unindented } to match function
+ }
+ print(asmLibraryFunctions.map(fix).join('\n'));
+ }
} else {
if (singlePhase) {
assert(data.unparsedGlobalss[0].lines.length == 0, dump([phase, data.unparsedGlobalss]));
diff --git a/src/library.js b/src/library.js
index 3b229dfa..9268edd5 100644
--- a/src/library.js
+++ b/src/library.js
@@ -52,7 +52,7 @@ LibraryManager.library = {
streams: [null],
#if ASSERTIONS
checkStreams: function() {
- for (var i in FS.streams) assert(i >= 0 && i < FS.streams.length); // no keys not in dense span
+ for (var i in FS.streams) if (FS.streams.hasOwnProperty(i)) assert(i >= 0 && i < FS.streams.length); // no keys not in dense span
for (var i = 0; i < FS.streams.length; i++) assert(typeof FS.streams[i] == 'object'); // no non-null holes in dense span
},
#endif
@@ -2611,6 +2611,7 @@ LibraryManager.library = {
// format: A pointer to the format string.
// varargs: A pointer to the start of the arguments list.
// Returns the resulting string string as a character array.
+ _formatString__deps: ['strlen'],
_formatString: function(format, varargs) {
var textIndex = format;
var argIndex = 0;
@@ -2937,7 +2938,7 @@ LibraryManager.library = {
} else if (next == 's'.charCodeAt(0)) {
// String.
var arg = getNextArg('i8*') || nullString;
- var argLength = String_len(arg);
+ var argLength = _strlen(arg);
if (precisionSet) argLength = Math.min(argLength, precision);
if (!flagLeftAlign) {
while (argLength < width--) {
@@ -3500,6 +3501,12 @@ LibraryManager.library = {
var result = __formatString(format, varargs);
var limit = (n === undefined) ? result.length
: Math.min(result.length, Math.max(n - 1, 0));
+ if (s < 0) {
+ s = -s;
+ var buf = _malloc(limit+1);
+ {{{ makeSetValue('s', '0', 'buf', 'i8*') }}};
+ s = buf;
+ }
for (var i = 0; i < limit; i++) {
{{{ makeSetValue('s', 'i', 'result[i]', 'i8') }}};
}
@@ -3529,10 +3536,15 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
return _snprintf(s, undefined, format, varargs);
},
+ asprintf__deps: ['sprintf'],
+ asprintf: function(s, format, varargs) {
+ return _sprintf(-s, format, varargs);
+ },
vfprintf: 'fprintf',
vsnprintf: 'snprintf',
vprintf: 'printf',
vsprintf: 'sprintf',
+ vasprintf: 'asprintf',
vscanf: 'scanf',
vfscanf: 'fscanf',
vsscanf: 'sscanf',
@@ -3617,7 +3629,7 @@ LibraryManager.library = {
* implementation (replaced by dlmalloc normally) so
* not an issue.
*/
- ptr = Runtime.staticAlloc(bytes + 8);
+ var ptr = Runtime.staticAlloc(bytes + 8);
return (ptr+8) & 0xFFFFFFF8;
},
free: function(){},
@@ -4213,6 +4225,8 @@ LibraryManager.library = {
}
},
+ wmemcpy: function() { throw 'wmemcpy not implemented' },
+
llvm_memcpy_i32: 'memcpy',
llvm_memcpy_i64: 'memcpy',
llvm_memcpy_p0i8_p0i8_i32: 'memcpy',
@@ -4238,6 +4252,8 @@ LibraryManager.library = {
llvm_memmove_p0i8_p0i8_i32: 'memmove',
llvm_m