summaryrefslogtreecommitdiff
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_memmove_p0i8_p0i8_i64: 'memmove',
+ wmemmove: function() { throw 'wmemmove not implemented' },
+
memset__inline: function(ptr, value, num, align) {
return makeSetValues(ptr, 0, value, 'null', num, align);
},
@@ -4272,8 +4288,17 @@ LibraryManager.library = {
llvm_memset_p0i8_i32: 'memset',
llvm_memset_p0i8_i64: 'memset',
+ wmemset: function() { throw 'wmemset not implemented' },
+
+ strlen__asm: 'ii',
strlen: function(ptr) {
- return String_len(ptr);
+ ptr = ptr|0;
+ var curr = 0;
+ curr = ptr;
+ while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}|0 != 0) {
+ curr = (curr + 1)|0;
+ }
+ return (curr - ptr)|0;
},
// TODO: Implement when we have real unicode support.
@@ -4281,6 +4306,13 @@ LibraryManager.library = {
return 1;
},
+ wcslen: function() { throw 'wcslen not implemented' },
+ mbrlen: function() { throw 'mbrlen not implemented' },
+ mbsrtowcs: function() { throw 'mbsrtowcs not implemented' },
+ wcsnrtombs: function() { throw 'wcsnrtombs not implemented' },
+ mbsnrtowcs: function() { throw 'mbsnrtowcs not implemented' },
+ mbrtowc: function() { throw 'mbrtowc not implemented' },
+
strspn: function(pstr, pset) {
var str = pstr, set, strcurr, setcurr;
while (1) {
@@ -4497,17 +4529,18 @@ LibraryManager.library = {
},
rindex: 'strrchr',
+ strdup__deps: ['strlen'],
strdup: function(ptr) {
- var len = String_len(ptr);
+ var len = _strlen(ptr);
var newStr = _malloc(len + 1);
{{{ makeCopyValues('newStr', 'ptr', 'len', 'null', null, 1) }}};
{{{ makeSetValue('newStr', 'len', '0', 'i8') }}};
return newStr;
},
- strndup__deps: ['strdup'],
+ strndup__deps: ['strdup', 'strlen'],
strndup: function(ptr, size) {
- var len = String_len(ptr);
+ var len = _strlen(ptr);
if (size >= len) {
return _strdup(ptr);
@@ -4898,12 +4931,12 @@ LibraryManager.library = {
} else {
__ZSt18uncaught_exceptionv.uncaught_exception++;
}
- throw ptr;
+ {{{ makeThrow('ptr') }}};
},
__cxa_rethrow__deps: ['llvm_eh_exception', '__cxa_end_catch'],
__cxa_rethrow: function() {
___cxa_end_catch.rethrown = true;
- throw {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
+ {{{ makeThrow(makeGetValue('_llvm_eh_exception.buf', '0', 'void*')) }}};
},
llvm_eh_exception__postset: '_llvm_eh_exception.buf = allocate(12, "void*", ALLOC_STATIC);',
llvm_eh_exception: function() {
@@ -4966,11 +4999,10 @@ LibraryManager.library = {
},
_Unwind_Resume_or_Rethrow: function(ptr) {
- throw ptr;
+ {{{ makeThrow('ptr') }}};
},
- _Unwind_RaiseException__deps: ['llvm_eh_exception', '__cxa_find_matching_catch'],
_Unwind_RaiseException: function(ptr) {
- throw ptr;
+ {{{ makeThrow('ptr') }}};
},
_Unwind_DeleteException: function(ptr) {},
@@ -5074,6 +5106,8 @@ LibraryManager.library = {
_ZNSt9exceptionD2Ev: function(){}, // XXX a dependency of dlmalloc, but not actually needed if libcxx is not anyhow included
+ _ZNSt9type_infoD2Ev: function(){},
+
// RTTI hacks for exception handling, defining type_infos for common types.
// The values are dummies. We simply use the addresses of these statically
// allocated variables as unique identifiers.
@@ -6130,6 +6164,8 @@ LibraryManager.library = {
return me.ret;
},
+ __locale_mb_cur_max: function() { throw '__locale_mb_cur_max not implemented' },
+
// ==========================================================================
// langinfo.h
// ==========================================================================
@@ -6310,6 +6346,10 @@ LibraryManager.library = {
return me.ret;
},
+ _Z7catopenPKci: function() { throw 'catopen not implemented' },
+ _Z7catgetsP8_nl_catdiiPKc: function() { throw 'catgets not implemented' },
+ _Z8catcloseP8_nl_catd: function() { throw 'catclose not implemented' },
+
// ==========================================================================
// errno.h
// ==========================================================================
@@ -6553,6 +6593,7 @@ LibraryManager.library = {
pthread_cond_init: function() {},
pthread_cond_destroy: function() {},
pthread_cond_broadcast: function() {},
+ pthread_cond_wait: function() {},
pthread_self: function() {
//FIXME: assumes only a single thread
return 0;
diff --git a/src/library_gl.js b/src/library_gl.js
index 267a6185..2a6ec92f 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -2462,6 +2462,10 @@ var LibraryGL = {
{{{ makeSetValue('objZ', '0', 'result[2]', 'double') }}};
return 1 /* GL_TRUE */;
+ },
+
+ gluOrtho2D: function(left, right, bottom, top) {
+ _glOrtho(left, right, bottom, top, -1, 1);
}
};
diff --git a/src/modules.js b/src/modules.js
index b5a30866..a08d6f1a 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -13,8 +13,10 @@ var LLVM = {
ACCESS_OPTIONS: set('volatile', 'atomic'),
INVOKE_MODIFIERS: set('alignstack', 'alwaysinline', 'inlinehint', 'naked', 'noimplicitfloat', 'noinline', 'alwaysinline attribute.', 'noredzone', 'noreturn', 'nounwind', 'optsize', 'readnone', 'readonly', 'ssp', 'sspreq'),
SHIFTS: set('ashr', 'lshr', 'shl'),
- PHI_REACHERS: set('branch', 'switch', 'invoke'),
+ PHI_REACHERS: set('branch', 'switch', 'invoke', 'indirectbr'),
EXTENDS: set('sext', 'zext'),
+ COMPS: set('icmp', 'fcmp'),
+ CONVERSIONS: set('inttoptr', 'ptrtoint', 'uitofp', 'sitofp', 'fptosi', 'fptoui'),
INTRINSICS_32: set('_llvm_memcpy_p0i8_p0i8_i64', '_llvm_memmove_p0i8_p0i8_i64', '_llvm_memset_p0i8_i64'), // intrinsics that need args converted to i32 in USE_TYPED_ARRAYS == 2
};
LLVM.GLOBAL_MODIFIERS = set(keys(LLVM.LINKAGES).concat(['constant', 'global', 'hidden']));
@@ -263,7 +265,7 @@ var Functions = {
function emptyTable(sig) {
return zeros(total);
}
- var tables = {};
+ var tables = { pre: '' };
if (ASM_JS) {
['v', 'vi', 'ii', 'iii'].forEach(function(sig) { // add some default signatures that are used in the library
tables[sig] = emptyTable(sig); // TODO: make them compact
@@ -276,7 +278,9 @@ var Functions = {
tables[sig][this.indexedFunctions[ident]] = ident;
}
var generated = false;
+ var wrapped = {};
for (var t in tables) {
+ if (t == 'pre') continue;
generated = true;
var table = tables[t];
for (var i = 0; i < table.length; i++) {
@@ -293,6 +297,22 @@ var Functions = {
table[i] = (libName.indexOf('.') < 0 ? '_' : '') + libName;
}
}
+ var curr = table[i];
+ if (curr && Functions.unimplementedFunctions[table[i]]) {
+ // This is a library function, we can't just put it in the function table, need a wrapper
+ if (!wrapped[curr]) {
+ var args = '', arg_coercions = '', call = curr + '(', ret = t[0] == 'v' ? '' : ('return ' + (t[0] == 'f' ? '+0' : '0'));
+ for (var i = 1; i < t.length; i++) {
+ args += (i > 1 ? ',' : '') + 'a' + i;
+ arg_coercions += 'a' + i + '=' + asmCoercion('a' + i, t[i] == 'f' ? 'float' : 'i32') + ';';
+ call += (i > 1 ? ',' : '') + asmCoercion('a' + i, t[i] == 'f' ? 'float' : 'i32');
+ }
+ call += ')';
+ tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + call + ' ; ' + ret + ' }\n';
+ wrapped[curr] = 1;
+ }
+ table[i] = curr + '__wrapper';
+ }
}
var indices = table.toString().replace('"', '');
if (BUILD_AS_SHARED_LIB) {
diff --git a/src/parseTools.js b/src/parseTools.js
index 32bf70e9..5f8797b0 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -974,7 +974,7 @@ if (ASM_JS) {
var memoryMask = hexMemoryMask.length <= decMemoryMask.length ? hexMemoryMask : decMemoryMask;
}
-function getHeapOffset(offset, type) {
+function getHeapOffset(offset, type, forceAsm) {
if (USE_TYPED_ARRAYS !== 2) {
return offset;
} else {
@@ -983,7 +983,7 @@ function getHeapOffset(offset, type) {
}
var shifts = Math.log(Runtime.getNativeTypeSize(type))/Math.LN2;
offset = '(' + offset + ')';
- if (ASM_JS && phase == 'funcs') offset = '(' + offset + '&' + memoryMask + ')';
+ if (ASM_JS && (phase == 'funcs' || forceAsm)) offset = '(' + offset + '&' + memoryMask + ')';
if (shifts != 0) {
return '(' + offset + '>>' + shifts + ')';
} else {
@@ -1019,14 +1019,18 @@ function asmCoercion(value, type, signedness) {
if (type == 'void') {
return value;
} else if (type in Runtime.FLOAT_TYPES) {
- if (signedness) {
- if (signedness == 'u') {
- value = '(' + value + ')>>>0';
- } else {
- value = '(' + value + ')|0';
+ if (isNumber(value)) {
+ return asmEnsureFloat(value, type);
+ } else {
+ if (signedness) {
+ if (signedness == 'u') {
+ value = '(' + value + ')>>>0';
+ } else {
+ value = '(' + value + ')|0';
+ }
}
+ return '(+(' + value + '))';
}
- return '(+(' + value + '))';
} else {
return '((' + value + ')|0)';
}
@@ -1041,7 +1045,7 @@ function asmMultiplyI32(a, b) {
return '(~~(+((' + a + ')|0) * +((' + b + ')|0)))';
}
-function makeGetTempDouble(i, type) { // get an aliased part of the tempDouble temporary storage
+function makeGetTempDouble(i, type, forSet) { // get an aliased part of the tempDouble temporary storage
// Cannot use makeGetValue because it uses us
// this is a unique case where we *can* use HEAPF64
var slab = type == 'double' ? 'HEAPF64' : makeGetSlabs(null, type)[0];
@@ -1053,11 +1057,17 @@ function makeGetTempDouble(i, type) { // get an aliased part of the tempDouble t
} else {
offset = getHeapOffset(ptr, type);
}
- return slab + '[' + offset + ']';
+ var ret = slab + '[' + offset + ']';
+ if (!forSet) ret = asmCoercion(ret, type);
+ return ret;
+}
+
+function makeSetTempDouble(i, type, value) {
+ return makeGetTempDouble(i, type, true) + '=' + asmEnsureFloat(value, type);
}
// See makeSetValue
-function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) {
+function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe, forceAsm) {
if (UNALIGNED_MEMORY) align = 1;
if (isStructType(type)) {
var typeData = Types.types[type];
@@ -1069,8 +1079,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
}
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
- return '(' + makeGetTempDouble(0, 'i32') + '=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
- makeGetTempDouble(1, 'i32') + '=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
+ return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align)) + ',' +
+ makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align)) + ',' +
makeGetTempDouble(0, 'double') + ')';
}
@@ -1110,7 +1120,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
if (type[0] === '#') type = type.substr(1);
return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
} else {
- var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']';
+ var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']';
if (ASM_JS && phase == 'funcs') {
ret = asmCoercion(ret, type);
}
@@ -1118,6 +1128,10 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
}
}
+function makeGetValueAsm(ptr, pos, type) {
+ return makeGetValue(ptr, pos, type, null, null, null, null, null, true);
+}
+
function indexizeFunctions(value, type) {
assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing');
assert(value !== type, 'Type set to value');
@@ -1165,7 +1179,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
}
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
- return '(' + makeGetTempDouble(0, 'double') + '=' + value + ',' +
+ return '(' + makeSetTempDouble(0, 'double', value) + ',' +
makeSetValue(ptr, pos, makeGetTempDouble(0, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), makeGetTempDouble(1, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
} else if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
@@ -1191,7 +1205,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
ret += 'tempBigInt=' + value + sep;
for (var i = 0; i < bytes; i++) {
ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1);
- if (i < bytes-1) ret += sep + 'tempBigInt>>=8' + sep;
+ if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep;
}
}
} else {
@@ -1236,7 +1250,7 @@ function makeSetValues(ptr, pos, value, type, num, align) {
// If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset
// TODO: optimize the case of numeric num but non-numeric value
if (!isNumber(num) || !isNumber(value) || (align < 4 && parseInt(num) >= SEEK_OPTIMAL_ALIGN_MIN)) {
- return '_memset(' + getFastValue(ptr, '+', pos) + ', ' + value + ', ' + num + ', ' + align + ')';
+ return '_memset(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + ', ' + asmCoercion(value, 'i32') + ', ' + asmCoercion(num, 'i32') + ', ' + align + ')';
}
num = parseInt(num);
value = parseInt(value);
@@ -1426,8 +1440,18 @@ var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP');
function makePointer(slab, pos, allocator, type, ptr) {
assert(type, 'makePointer requires type info');
- if (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP)) return pos;
+ if (typeof slab == 'string' && (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP))) return pos;
var types = generateStructTypes(type);
+ if (typeof slab == 'object') {
+ for (var i = 0; i < slab.length; i++) {
+ var curr = slab[i];
+ if (isNumber(curr)) {
+ slab[i] = parseFloat(curr); // fix "5" to 5 etc.
+ } else if (curr == 'undef') {
+ slab[i] = 0;
+ }
+ }
+ }
// compress type info and data if possible
var de;
try {
@@ -1435,25 +1459,68 @@ function makePointer(slab, pos, allocator, type, ptr) {
// note that we cannot always eval the slab, e.g., if it contains ident,0,0 etc. In that case, no compression TODO: ensure we get arrays here, not str
var evaled = typeof slab === 'string' ? eval(slab) : slab;
de = dedup(evaled);
- if (de.length === 1 && de[0] === 0) {
+ if (de.length === 1 && de[0] == 0) {
slab = types.length;
- if (USE_TYPED_ARRAYS == 2) {
- types = ['i8']; // if data is zeros, we don't need type info
- }
}
// TODO: if not all zeros, at least filter out items with type === 0. requires cleverness to know how to skip at runtime though. also
// be careful of structure padding
} catch(e){}
- de = dedup(types);
- if (de.length === 1) {
- types = de[0];
- } else if (de.length === 2 && typeof slab === 'number') {
- // If slab is all zeros, we can compress types even if we have i32,0,0,0,i32,0,0,0 etc. - we do not need the zeros
- de = de.filter(function(x) { return x !== 0 });
+ if (USE_TYPED_ARRAYS != 2) {
+ de = dedup(types);
if (de.length === 1) {
types = de[0];
+ } else if (de.length === 2 && typeof slab === 'number') {
+ // If slab is all zeros, we can compress types even if we have i32,0,0,0,i32,0,0,0 etc. - we do not need the zeros
+ de = de.filter(function(x) { return x !== 0 });
+ if (de.length === 1) {
+ types = de[0];
+ }
+ }
+ } else { // USE_TYPED_ARRAYS == 2
+ var fail = false;
+ if (typeof slab === 'object') {
+ // flatten out into i8 values, so we can just to typed array .set()
+ for (var i = 0; i < slab.length; i++) {
+ if (!isNumber(slab[i])) { fail = true; break }
+ }
+ if (!fail) {
+ // XXX This heavily assumes the target endianness is the same as our current endianness! XXX
+ var i = 0;
+ var temp64f = new Float64Array(1);
+ var temp32f = new Float32Array(temp64f.buffer);
+ var temp32 = new Uint32Array(temp64f.buffer);
+ var temp16 = new Uint16Array(temp64f.buffer);
+ var temp8 = new Uint8Array(temp64f.buffer);
+ while (i < slab.length) {
+ var currType = types[i];
+ if (!currType) { i++; continue }
+ var currSize = 0, currValue = slab[i];
+ switch (currType) {
+ case 'i8': i++; continue;
+ case 'i16': temp16[0] = currValue; currSize = 2; break;
+ case 'i64': // fall through, i64 is two i32 chunks
+ case 'i32': temp32[0] = currValue; currSize = 4; break;
+ case 'float': temp32f[0] = currValue; currSize = 4; break;
+ case 'double': temp64f[0] = currValue; currSize = 8; break;
+ default: {
+ if (currType[currType.length-1] == '*') {
+ temp32[0] = currValue;
+ currSize = 4;
+ } else {
+ throw 'what? ' + types[i];
+ }
+ }
+ }
+ for (var j = 0; j < currSize; j++) {
+ slab[i+j] = temp8[j];
+ }
+ i += currSize;
+ }
+ }
}
+ if (!fail) types = 'i8';
}
+ if (typeof slab == 'object') slab = '[' + slab.join(',') + ']';
// JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime
var chunkSize = 10240;
function chunkify(array) {
@@ -1466,7 +1533,7 @@ function makePointer(slab, pos, allocator, type, ptr) {
}
return ret;
}
- if (typeof slab == 'string' && evaled && evaled.length > chunkSize) {
+ if (typeof slab == 'string' && evaled && evaled.length > chunkSize && slab.length > chunkSize) {
slab = chunkify(evaled);
}
if (typeof types != 'string' && types.length > chunkSize) {
@@ -1666,6 +1733,10 @@ function makeStructuralAccess(ident, i) {
}
}
+function makeThrow(what) {
+ return 'throw ' + what + (DISABLE_EXCEPTION_CATCHING == 1 ? ' + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch."' : '') + ';';
+}
+
// From parseLLVMSegment
function finalizeLLVMParameter(param, noIndexizeFunctions) {
var ret;
@@ -1876,8 +1947,8 @@ function processMathop(item) {
}
function i64PreciseOp(type, lastArg) {
Types.preciseI64MathUsed = true;
- return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 +
- (lastArg ? ',' + lastArg : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]);
+ return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + asmCoercion(low1, 'i32') + ',' + asmCoercion(high1, 'i32') + ',' + asmCoercion(low2, 'i32') + ',' + asmCoercion(high2, 'i32') +
+ (lastArg ? ',' + asmCoercion(+lastArg, 'i32') : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]);
}
switch (op) {
// basic integer ops
@@ -1894,7 +1965,7 @@ function processMathop(item) {
case 'ashr':
case 'lshr': {
if (!isNumber(idents[1])) {
- return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],"' + op + '",' + stripCorrections(idents[1]) + '[0]|0),' +
+ return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],' + Runtime['BITSHIFT64_' + op.toUpperCase()] + ',' + stripCorrections(idents[1]) + '[0]|0),' +
'[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])';
}
bits = parseInt(idents[1]);
@@ -1935,24 +2006,24 @@ function processMathop(item) {
case 'fptoui': case 'fptosi': return finish(splitI64(idents[0]));
case 'icmp': {
switch (variant) {
- case 'uge': return '(' + high1 + '>>>0) >= (' + high2 + '>>>0) && ((' + high1 + '>>>0) > (' + high2 + '>>>0) || ' +
- '(' + low1 + '>>>0) >= (' + low2 + '>>>0))';
- case 'sge': return '(' + high1 + '|0) >= (' + high2 + '|0) && ((' + high1 + '|0) > (' + high2 + '|0) || ' +
- '(' + low1 + '>>>0) >= (' + low2 + '>>>0))';
- case 'ule': return '(' + high1 + '>>>0) <= (' + high2 + '>>>0) && ((' + high1 + '>>>0) < (' + high2 + '>>>0) || ' +
- '(' + low1 + '>>>0) <= (' + low2 + '>>>0))';
- case 'sle': return '(' + high1 + '|0) <= (' + high2 + '|0) && ((' + high1 + '|0) < (' + high2 + '|0) || ' +
- '(' + low1 + '>>>0) <= (' + low2 + '>>>0))';
- case 'ugt': return '(' + high1 + '>>>0) > (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' +
- '(' + low1 + '>>>0) > (' + low2 + '>>>0))';
- case 'sgt': return '(' + high1 + '|0) > (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' +
- '(' + low1 + '>>>0) > (' + low2 + '>>>0))';
- case 'ult': return '(' + high1 + '>>>0) < (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' +
- '(' + low1 + '>>>0) < (' + low2 + '>>>0))';
- case 'slt': return '(' + high1 + '|0) < (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' +
- '(' + low1 + '>>>0) < (' + low2 + '>>>0))';
- case 'ne': return low1 + ' != ' + low2 + ' || ' + high1 + ' != ' + high2 + '';
- case 'eq': return low1 + ' == ' + low2 + ' && ' + high1 + ' == ' + high2 + '';
+ case 'uge': return '((' + high1 + '>>>0) >= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) > (' + high2 + '>>>0)) | ' +
+ '(' + low1 + '>>>0) >= (' + low2 + '>>>0)))';
+ case 'sge': return '((' + high1 + '|0) >= (' + high2 + '|0)) & ((((' + high1 + '|0) > (' + high2 + '|0)) | ' +
+ '(' + low1 + '>>>0) >= (' + low2 + '>>>0)))';
+ case 'ule': return '((' + high1 + '>>>0) <= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) < (' + high2 + '>>>0)) | ' +
+ '(' + low1 + '>>>0) <= (' + low2 + '>>>0)))';
+ case 'sle': return '((' + high1 + '|0) <= (' + high2 + '|0)) & ((((' + high1 + '|0) < (' + high2 + '|0)) | ' +
+ '(' + low1 + '>>>0) <= (' + low2 + '>>>0)))';
+ case 'ugt': return '((' + high1 + '>>>0) > (' + high2 + '>>>0)) | ((((' + high1 + '>>>0) == (' + high2 + '>>>0) & ' +
+ '(' + low1 + '>>>0) > (' + low2 + '>>>0))))';
+ case 'sgt': return '((' + high1 + '|0) > (' + high2 + '|0)) | ((((' + high1 + '|0) == (' + high2 + '|0) & ' +
+ '(' + low1 + '>>>0) > (' + low2 + '>>>0))))';
+ case 'ult': return '((' + high1 + '>>>0) < (' + high2 + '>>>0)) | ((((' + high1 + '>>>0) == (' + high2 + '>>>0) & ' +
+ '(' + low1 + '>>>0) < (' + low2 + '>>>0))))';
+ case 'slt': return '((' + high1 + '|0) < (' + high2 + '|0)) | ((((' + high1 + '|0) == (' + high2 + '|0) & ' +
+ '(' + low1 + '>>>0) < (' + low2 + '>>>0))))';
+ case 'ne': return '((' + low1 + '|0) != (' + low2 + '|0)) | ((' + high1 + '|0) != (' + high2 + '|0))';
+ case 'eq': return '((' + low1 + '|0) == (' + low2 + '|0)) & ((' + high1 + '|0) == (' + high2 + '|0))';
default: throw 'Unknown icmp variant: ' + variant;
}
}
@@ -2012,15 +2083,15 @@ function processMathop(item) {
var outType = item.type;
if (inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) {
if (legalizedI64s) {
- return '(' + makeGetTempDouble(0, 'i32') + '=' + idents[0] + '$0, ' + makeGetTempDouble(1, 'i32') + '=' + idents[0] + '$1, ' + makeGetTempDouble(0, 'double') + ')';
+ return '(' + makeSetTempDouble(0, 'i32', idents[0] + '$0') + ', ' + makeSetTempDouble(1, 'i32', idents[0] + '$1') + ', ' + makeGetTempDouble(0, 'double') + ')';
} else {
- return makeInlineCalculation(makeGetTempDouble(0, 'i32') + '=VALUE[0],' + makeGetTempDouble(1, 'i32') + '=VALUE[1],' + makeGetTempDouble(0, 'double'), idents[0], 'tempI64');
+ return makeInlineCalculation(makeSetTempDouble(0, 'i32', 'VALUE[0]') + ',' + makeSetTempDouble(1, 'i32', 'VALUE[1]') + ',' + makeGetTempDouble(0, 'double'), idents[0], 'tempI64');
}
} else if (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES) {
if (legalizedI64s) {
- return makeGetTempDouble(0, 'double') + '=' + idents[0] + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]);
+ return makeSetTempDouble(0, 'double', idents[0]) + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]);
} else {
- return '(' + makeGetTempDouble(0, 'double') + '=' + idents[0] + ',[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])';
+ return '(' + makeSetTempDouble(0, 'double', idents[0]) + ',[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])';
}
} else {
throw 'Invalid USE_TYPED_ARRAYS == 2 bitcast: ' + dump(item) + ' : ' + item.params[0].type;
@@ -2038,7 +2109,7 @@ function processMathop(item) {
case 'mul': {
if (bits == 32 && PRECISE_I32_MUL) {
Types.preciseI64MathUsed = true;
- return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + idents[0] + ',0,' + idents[1] + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')';
+ return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + asmCoercion(idents[0], 'i32') + ',0,' + asmCoercion(idents[1], 'i32') + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')';
} else {
return handleOverflow(getFastValue(idents[0], '*', idents[1], item.type), bits);
}
@@ -2159,9 +2230,9 @@ function processMathop(item) {
(inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES)) {
assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2');
if (inType in Runtime.INT_TYPES) {
- return '(' + makeGetTempDouble(0, 'i32') + '=' + idents[0] + ',' + makeGetTempDouble(0, 'float') + ')';
+ return '(' + makeSetTempDouble(0, 'i32', idents[0]) + ',' + makeGetTempDouble(0, 'float') + ')';
} else {
- return '(' + makeGetTempDouble(0, 'float') + '=' + idents[0] + ',' + makeGetTempDouble(0, 'i32') + ')';
+ return '(' + makeSetTempDouble(0, 'float', idents[0]) + ',' + makeGetTempDouble(0, 'i32') + ')';
}
}
return idents[0];
diff --git a/src/preamble.js b/src/preamble.js
index cb01994f..c66146ac 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -506,10 +506,17 @@ function allocate(slab, types, allocator, ptr) {
}
if (zeroinit) {
- _memset(ret, 0, size);
- return ret;
+ _memset(ret, 0, size);
+ return ret;
+ }
+
+#if USE_TYPED_ARRAYS == 2
+ if (singleType === 'i8') {
+ HEAPU8.set(new Uint8Array(slab), ret);
+ return ret;
}
-
+#endif
+
var i = 0, type;
while (i < size) {
var curr = slab[i];
@@ -750,17 +757,6 @@ function exitRuntime() {
CorrectionsMonitor.print();
}
-function String_len(ptr) {
- var i = ptr;
- while ({{{ makeGetValue('i++', '0', 'i8') }}}) { // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds
-#if ASSERTIONS
- assert(i < TOTAL_MEMORY);
-#endif
- }
- return i - ptr - 1;
-}
-Module['String_len'] = String_len;
-
// Tools
// This processes a JS string into a C-line array of numbers, 0-terminated.
diff --git a/src/runtime.js b/src/runtime.js
index 9d5e5e1f..feeeca38 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -46,7 +46,7 @@ var RuntimeGenerator = {
ret += '; assert(STACKTOP < STACK_MAX)';
}
if (INIT_STACK) {
- ret += '; _memset(__stackBase__, 0, ' + initial + ')';
+ ret += '; _memset(' + asmCoercion('__stackBase__', 'i32') + ', 0, ' + initial + ')';
}
return ret;
},
@@ -123,42 +123,45 @@ var Runtime = {
FLOAT_TYPES: set('float', 'double'),
// Mirrors processMathop's treatment of constants (which we optimize directly)
+ BITSHIFT64_SHL: 0,
+ BITSHIFT64_ASHR: 1,
+ BITSHIFT64_LSHR: 2,
bitshift64: function(low, high, op, bits) {
var ret;
var ander = Math.pow(2, bits)-1;
if (bits < 32) {
switch (op) {
- case 'shl':
+ case Runtime.BITSHIFT64_SHL:
ret = [low << bits, (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits))];
break;
- case 'ashr':
+ case Runtime.BITSHIFT64_ASHR:
ret = [(((low >>> bits ) | ((high&ander) << (32 - bits))) >> 0) >>> 0, (high >> bits) >>> 0];
break;
- case 'lshr':
+ case Runtime.BITSHIFT64_LSHR:
ret = [((low >>> bits) | ((high&ander) << (32 - bits))) >>> 0, high >>> bits];
break;
}
} else if (bits == 32) {
switch (op) {
- case 'shl':
+ case Runtime.BITSHIFT64_SHL:
ret = [0, low];
break;
- case 'ashr':
+ case Runtime.BITSHIFT64_ASHR:
ret = [high, (high|0) < 0 ? ander : 0];
break;
- case 'lshr':
+ case Runtime.BITSHIFT64_LSHR:
ret = [high, 0];
break;
}
} else { // bits > 32
switch (op) {
- case 'shl':
+ case Runtime.BITSHIFT64_SHL:
ret = [0, low << (bits - 32)];
break;
- case 'ashr':
+ case Runtime.BITSHIFT64_ASHR:
ret = [(high >> (bits - 32)) >>> 0, (high|0) < 0 ? ander : 0];
break;
- case 'lshr':
+ case Runtime.BITSHIFT64_LSHR:
ret = [high >>> (bits - 32) , 0];
break;
}
diff --git a/src/settings.js b/src/settings.js
index 8ae287f9..ccf2a25b 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -158,8 +158,16 @@ var DISABLE_EXCEPTION_CATCHING = 0; // Disables generating code to actually catc
// then this can make it much faster. If an exception actually happens,
// it will not be caught and the program will halt (so this will not
// introduce silent failures, which is good).
+ // DISABLE_EXCEPTION_CATCHING = 0 - generate code to actually catch exceptions
+ // DISABLE_EXCEPTION_CATCHING = 1 - disable exception catching at all
+ // DISABLE_EXCEPTION_CATCHING = 2 - disable exception catching, but enables
+ // catching in whitelist
// TODO: Make this also remove cxa_begin_catch etc., optimize relooper
// for it, etc. (perhaps do all of this as preprocessing on .ll?)
+
+var EXCEPTION_CATCHING_WHITELIST = []; // Enables catching exception in listed functions if
+ // DISABLE_EXCEPTION_CATCHING = 2 set
+
var EXECUTION_TIMEOUT = -1; // Throw an exception after X seconds - useful to debug infinite loops
var CHECK_OVERFLOWS = 0; // Add code that checks for overflows in integer math operations.
// There is currently not much to do to handle overflows if they occur.
diff --git a/system/include/libc/sys/_types.h b/system/include/libc/sys/_types.h
index c56fbd58..0511602c 100644
--- a/system/include/libc/sys/_types.h
+++ b/system/include/libc/sys/_types.h
@@ -27,9 +27,15 @@ typedef unsigned __dev_t; /* XXX Emscripten */
#ifndef __uid_t_defined
typedef unsigned __uid_t; /* XXX Emscripten */
+#define __uid_t_defined 1
#endif
#ifndef __gid_t_defined
typedef unsigned __gid_t; /* XXX Emscripten */
+#define __gid_t_defined 1
+#endif
+#ifndef __id_t_defined
+typedef unsigned __id_t; /* can hold a gid_t, pid_t, or uid_t XXX EMSCRIPTEN specific*/
+#define __id_t_defined 1
#endif
#ifndef __off64_t_defined
diff --git a/system/include/libc/sys/types.h b/system/include/libc/sys/types.h
index 4bf41a34..e90a74ac 100644
--- a/system/include/libc/sys/types.h
+++ b/system/include/libc/sys/types.h
@@ -162,6 +162,7 @@ typedef _off_t off_t;
typedef __dev_t dev_t;
typedef __uid_t uid_t;
typedef __gid_t gid_t;
+typedef __id_t id_t ; /* can hold a uid_t or pid_t */
#endif
#if defined(__XMK__)
diff --git a/tests/cases/extendedprecision.ll b/tests/cases/extendedprecision.ll
index 2ab74d58..6f1b2626 100644
--- a/tests/cases/extendedprecision.ll
+++ b/tests/cases/extendedprecision.ll
@@ -5,7 +5,7 @@ target triple = "i386-pc-linux-gnu"
@.str = private constant [14 x i8] c"hello, world!\00", align 1 ; [#uses=1]
; [#uses=2]
-define void @"\01_Z5hellov"() {
+define void @"\01_Z5hellov"(x86_fp80 %waka) {
entry:
%0 = call i32 bitcast (i32 (i8*)* @puts to i32 (i32*)*)(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
br label %return
diff --git a/tests/openjpeg/codec/convert.h b/tests/openjpeg/codec/convert.h
index 1dc58d72..73ad6fb7 100644
--- a/tests/openjpeg/codec/convert.h
+++ b/tests/openjpeg/codec/convert.h
@@ -57,7 +57,7 @@ int imagetobmp(opj_image_t *image, const char *outfile);
/* TIFF conversion*/
opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters);
-int imagetotif(opj_image_t *image, const char *outfile);
+static int imagetotif(opj_image_t *image, const char *outfile) { return 0; } // XXX EMSCRIPTEN
/**
Load a single image component encoded in PGX file format
@param filename Name of the PGX file to load
@@ -75,7 +75,7 @@ int imagetoraw(opj_image_t * image, const char *outfile);
opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters, raw_cparameters_t *raw_cp);
/* PNG conversion*/
-extern int imagetopng(opj_image_t *image, const char *write_idf);
+static int imagetopng(opj_image_t *image, const char *write_idf) { return 0; } // XXX EMSCRIPTEN
extern opj_image_t* pngtoimage(const char *filename, opj_cparameters_t *parameters);
#endif /* __J2K_CONVERT_H */
diff --git a/tests/runner.py b/tests/runner.py
index 106389a9..a33bf133 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -276,6 +276,11 @@ process(sys.argv[1])
os.chdir(cwd)
out = open(stdout, 'r').read()
err = open(stderr, 'r').read()
+ if engine == SPIDERMONKEY_ENGINE and Settings.ASM_JS:
+ if 'Successfully compiled asm.js code' in err and 'asm.js link error' not in err:
+ print >> sys.stderr, "[was asm.js'ified]"
+ else:
+ print >> sys.stderr, "[did NOT asm.js'ify]"
if output_nicerizer:
ret = output_nicerizer(out, err)
else:
@@ -1161,6 +1166,8 @@ m_divisor is 1091269979
def test_llvm_intrinsics(self):
if self.emcc_args == None: return self.skip('needs ta2')
+ Settings.PRECISE_I64_MATH = 2 # for bswap64
+
src = r'''
#include <stdio.h>
#include <sys/types.h>
@@ -1188,6 +1195,10 @@ m_divisor is 1091269979
printf("%d\n", llvm_expect_i32(x % 27, 3));
+ int64_t a = 1;
+ a = __builtin_bswap64(a);
+ printf("%lld\n", a);
+
return 0;
}
'''
@@ -1197,6 +1208,7 @@ c8,ef
c5,de,15,8a
23,21
13
+72057594037927936
''')
def test_bswap64(self):
@@ -2277,6 +2289,7 @@ Exception execution path of first function! 1
''')
def test_exceptions(self):
+ if Settings.ASM_JS: return self.skip('no exceptions support in asm')
if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
Settings.EXCEPTION_DEBUG = 1
@@ -2316,8 +2329,8 @@ Exception execution path of first function! 1
self.do_run(src, '*throw...caught!infunc...done!*')
Settings.DISABLE_EXCEPTION_CATCHING = 1
- self.do_run(src, 'Compiled code throwing an exception')
-
+ self.do_run(src, 'Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0')
+
src = '''
#include <iostream>
@@ -2367,7 +2380,41 @@ Exception execution path of first function! 1
Settings.DISABLE_EXCEPTION_CATCHING = 0
self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...')
+ def test_white_list_exception(self):
+ if Settings.ASM_JS: return self.skip('no exceptions support in asm')
+ Settings.DISABLE_EXCEPTION_CATCHING = 2
+ Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
+
+ src = '''
+ #include <stdio.h>
+
+ void thrower() {
+ printf("infunc...");
+ throw(99);
+ printf("FAIL");
+ }
+
+ void somefunction() {
+ try {
+ thrower();
+ } catch(...) {
+ printf("done!*\\n");
+ }
+ }
+
+ int main() {
+ somefunction();
+ return 0;
+ }
+ '''
+ self.do_run(src, 'infunc...done!*')
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ Settings.EXCEPTION_CATCHING_WHITELIST = []
+
+
def test_uncaught_exception(self):
+ if Settings.ASM_JS: return self.skip('no exceptions support in asm')
if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
if '-O2' in self.emcc_args:
self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
@@ -2409,6 +2456,7 @@ Exception execution path of first function! 1
self.do_run(src, 'success')
def test_typed_exceptions(self):
+ if Settings.ASM_JS: return self.skip('no exceptions support in asm')
Settings.DISABLE_EXCEPTION_CATCHING = 0
Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read()
@@ -2416,6 +2464,7 @@ Exception execution path of first function! 1
self.do_run(src, expected)
def test_multiexception(self):
+ if Settings.ASM_JS: return self.skip('no exceptions support in asm')
Settings.DISABLE_EXCEPTION_CATCHING = 0
src = r'''
#include <stdio.h>
@@ -3195,6 +3244,7 @@ def process(filename):
self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check)
def test_inlinejs(self):
+ if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm')
src = r'''
#include <stdio.h>
@@ -3348,6 +3398,8 @@ def process(filename):
self.do_run(src, '*96,97,98,-14,-14,101*')
def test_bigswitch(self):
+ if Settings.RELOOP: return self.skip('TODO: switch in relooper, issue #781')
+
src = open(path_from_root('tests', 'bigswitch.cpp')).read()
self.do_run(src, '''34962: GL_ARRAY_BUFFER (0x8892)
26214: what?
@@ -3782,6 +3834,7 @@ The current type of b is: 9
self.do_run(src, '*0\n')
def test_intentional_fault(self):
+ if Settings.ASM_JS: return self.skip('no throw support in asm')
# Some programs intentionally segfault themselves, we should compile that into a throw
src = r'''
int main () {
@@ -4721,7 +4774,7 @@ at function.:blag
'''
self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
- def test_snprintf0(self):
+ def test_printf_cases(self):
src = r'''
#include <stdio.h>
int main() {
@@ -4729,10 +4782,13 @@ at function.:blag
char buf[size];
snprintf(buf, size, "%s %d %.2f\n", "me and myself", 25, 1.345);
printf("%d : %s\n", size, buf);
+ char *buff = NULL;
+ asprintf(&buff, "%d waka %d\n", 21, 95);
+ puts(buff);
return 0;
}
'''
- self.do_run(src, '22 : me and myself 25 1.34\n')
+ self.do_run(src, '22 : me and myself 25 1.34\n21 waka 95\n')
def test_atoX(self):
if self.emcc_args is None: return self.skip('requires ta2')
@@ -5513,7 +5569,7 @@ def process(filename):
int main() {
char *c = "μ†ℱ ╋ℯ╳╋";
printf("%d %d %d %d %s\n", c[0]&0xff, c[1]&0xff, c[2]&0xff, c[3]&0xff, c);
- emscripten_run_script("cheez = Module._malloc(100);"
+ emscripten_run_script("cheez = _malloc(100);"
"Module.writeStringToMemory(\"μ†ℱ ╋ℯ╳╋\", cheez);"
"Module.print([Pointer_stringify(cheez), Module.getValue(cheez, 'i8')&0xff, Module.getValue(cheez+1, 'i8')&0xff, Module.getValue(cheez+2, 'i8')&0xff, Module.getValue(cheez+3, 'i8')&0xff, ]);");
}
@@ -10552,7 +10608,8 @@ elif 'benchmark' in str(sys.argv):
try_delete(final_filename)
output = Popen([PYTHON, EMCC, filename, #'-O3',
- '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',# '-s', 'ASM_JS=1',
+ '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',
+ #'-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1',
'-s', 'TOTAL_MEMORY=128*1024*1024', '-s', 'FAST_MEMORY=10*1024*1024',
'-o', final_filename] + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate()
assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0]
@@ -10562,7 +10619,7 @@ elif 'benchmark' in str(sys.argv):
times = []
for i in range(TEST_REPS):
start = time.time()
- js_output = self.run_generated_code(JS_ENGINE, final_filename, args, check_timeout=False)
+ js_output = run_js(final_filename, engine=JS_ENGINE, args=args, stderr=PIPE, full_output=True)
if i == 0 and 'Successfully compiled asm.js code' in js_output:
print "[%s was asm.js'ified]" % name
curr = time.time()-start
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 8db40bc6..69abe23a 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -428,12 +428,13 @@ function simplifyExpressionsPre(ast) {
if (stack[i] == 1) {
// we will replace ourselves with the non-zero side. Recursively process that node.
var result = jsonCompare(node[2], ZERO) ? node[3] : node[2], other;
- // Great, we can eliminate
- rerun = true;
- while (other = process(result, result[0], stack)) {
- result = other;
+ // replace node in-place
+ node.length = result.length;
+ for (var j = 0; j < result.length; j++) {
+ node[j] = result[j];
}
- return result;
+ rerun = true;
+ return process(result, result[0], stack);
} else if (stack[i] == -1) {
break; // Too bad, we can't
} else if (asm) {
@@ -473,6 +474,12 @@ function simplifyExpressionsPre(ast) {
if (!unsigned) {
input[1][1] = 'HEAPU' + bits; // make unsigned
}
+ if (asm) {
+ // we cannot return HEAPU8 without a coercion, but at least we do HEAP8 & 255 => HEAPU8 | 0
+ node[1] = '|';
+ node[3][1] = 0;
+ return node;
+ }
return input;
}
}
@@ -1316,6 +1323,14 @@ function normalizeAsm(func) {
while (i < stats.length) {
traverse(stats[i], function(node, type) {
if (type == 'var') {
+ for (var j = 0; j < node[1].length; j++) {
+ var v = node[1][j];
+ var name = v[0];
+ var value = v[1];
+ if (!(name in data.vars)) {
+ data.vars[name] = detectAsmCoercion(value);
+ }
+ }
unVarify(node[1], node);
} else if (type == 'dot') {
if (node[1][0] == 'name' && node[1][1] == 'Math') {
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index b72a2084..f2e610d0 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -18,6 +18,7 @@ DEBUG = os.environ.get('EMCC_DEBUG')
def run_on_chunk(command):
filename = command[2] # XXX hackish
+ #print >> sys.stderr, 'running js optimizer command', ' '.join(command), '""""', open(filename).read()
output = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0]
assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + output
filename = temp_files.get(os.path.basename(filename) + '.jo.js').name
diff --git a/tools/shared.py b/tools/shared.py
index a78db8e0..f94bb263 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -344,10 +344,12 @@ try:
except:
COMPILER_OPTS = []
# Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms
+# -fno-ms-compatibility is passed, since on Windows, Clang enables a 'MS compatibility mode' by default, that disables char16_t and char32_t
+# to be MSVC header -compatible. This would cause build errors in libcxx file __config.
COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__x86_64__', '-U__i386', '-U__x86_64', '-Ui386', '-Ux86_64', '-U__SSE__', '-U__SSE2__', '-U__MMX__',
'-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87', '-DEMSCRIPTEN', '-U__STRICT_ANSI__', '-U__CYGWIN__',
- '-D__STDC__', '-Xclang', '-triple=i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno']
-
+ '-D__STDC__', '-Xclang', '-triple=i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno',
+ '-fno-ms-compatibility']
USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK')
diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js
index afd43893..84c95360 100644
--- a/tools/test-js-optimizer-asm-pre-output.js
+++ b/tools/test-js-optimizer-asm-pre-output.js
@@ -5,4 +5,48 @@ function a() {
f(351);
f(8);
}
+function b($this, $__n) {
+ $this = $this | 0;
+ $__n = $__n | 0;
+ var $4 = 0, $5 = 0, $10 = 0, $13 = 0, $14 = 0, $15 = 0, $23 = 0, $30 = 0, $38 = 0, $40 = 0;
+ if (($__n | 0) == 0) {
+ return;
+ }
+ $4 = $this;
+ $5 = HEAP8[$4 & 16777215] | 0;
+ if (($5 & 1) << 24 >> 24 == 0) {
+ $14 = 10;
+ $13 = $5;
+ } else {
+ $10 = HEAP32[($this & 16777215) >> 2] | 0;
+ $14 = ($10 & -2) - 1 | 0;
+ $13 = $10 & 255;
+ }
+ $15 = $13 & 255;
+ if (($15 & 1 | 0) == 0) {
+ $23 = $15 >>> 1;
+ } else {
+ $23 = HEAP32[($this + 4 & 16777215) >> 2] | 0;
+ }
+ if (($14 - $23 | 0) >>> 0 < $__n >>> 0) {
+ __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__grow_byEjjjjjj($this, $14, ($__n - $14 | 0) + $23 | 0, $23, $23);
+ $30 = HEAP8[$4 & 16777215] | 0;
+ } else {
+ $30 = $13;
+ }
+ if (($30 & 1) << 24 >> 24 == 0) {
+ $38 = $this + 1 | 0;
+ } else {
+ $38 = HEAP32[($this + 8 & 16777215) >> 2] | 0;
+ }
+ _memset($38 + $23 | 0, 0, $__n | 0, 1, 1213141516);
+ $40 = $23 + $__n | 0;
+ if ((HEAP8[$4 & 16777215] & 1) << 24 >> 24 == 0) {
+ HEAP8[$4 & 16777215] = $40 << 1 & 255;
+ } else {
+ HEAP32[($this + 4 & 16777215) >> 2] = $40;
+ }
+ HEAP8[$38 + $40 & 16777215] = 0;
+ return;
+}
diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js
index 6c9e64c1..3042ef66 100644
--- a/tools/test-js-optimizer-asm-pre.js
+++ b/tools/test-js-optimizer-asm-pre.js
@@ -5,4 +5,48 @@ function a() {
f(347 | 12);
f(347 & 12);
}
-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a"]
+function b($this, $__n) {
+ $this = $this | 0;
+ $__n = $__n | 0;
+ var $4 = 0, $5 = 0, $10 = 0, $13 = 0, $14 = 0, $15 = 0, $23 = 0, $30 = 0, $38 = 0, $40 = 0;
+ if (($__n | 0) == 0) {
+ return;
+ }
+ $4 = $this;
+ $5 = HEAP8[$4 & 16777215] | 0;
+ if (($5 & 1) << 24 >> 24 == 0) {
+ $14 = 10;
+ $13 = $5;
+ } else {
+ $10 = HEAP32[(($this | 0) & 16777215) >> 2] | 0;
+ $14 = ($10 & -2) - 1 | 0;
+ $13 = $10 & 255;
+ }
+ $15 = $13 & 255;
+ if (($15 & 1 | 0) == 0) {
+ $23 = $15 >>> 1;
+ } else {
+ $23 = HEAP32[(($this + 4 | 0) & 16777215) >> 2] | 0;
+ }
+ if (($14 - $23 | 0) >>> 0 < $__n >>> 0) {
+ __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__grow_byEjjjjjj($this, $14, ($__n - $14 | 0) + $23 | 0, $23, $23);
+ $30 = HEAP8[$4 & 16777215] | 0;
+ } else {
+ $30 = $13;
+ }
+ if (($30 & 1) << 24 >> 24 == 0) {
+ $38 = $this + 1 | 0;
+ } else {
+ $38 = HEAP32[(($this + 8 | 0) & 16777215) >> 2] | 0;
+ }
+ _memset($38 + $23 | 0 | 0 | 0, 0 | 0 | 0, $__n | 0 | 0, 1 | 0 | 0, 1213141516);
+ $40 = $23 + $__n | 0;
+ if (((HEAP8[$4 & 16777215] | 0) & 1) << 24 >> 24 == 0) {
+ HEAP8[$4 & 16777215] = $40 << 1 & 255;
+ } else {
+ HEAP32[(($this + 4 | 0) & 16777215) >> 2] = $40;
+ }
+ HEAP8[($38 + $40 | 0) & 16777215] = 0;
+ return;
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b"]