aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemcc58
-rw-r--r--src/analyzer.js8
-rw-r--r--src/jsifier.js18
-rw-r--r--src/library.js28
-rw-r--r--src/library_browser.js7
-rw-r--r--src/library_fs.js84
-rw-r--r--src/library_memfs.js6
-rw-r--r--src/library_openal.js16
-rw-r--r--src/library_sdl.js7
-rw-r--r--src/parseTools.js2
-rw-r--r--src/settings.js19
-rw-r--r--src/shell.html2
-rw-r--r--system/include/emscripten/emscripten.h6
-rw-r--r--tests/aniso.c1
-rw-r--r--tests/cases/callwithstructural64_ta2.ll29
-rw-r--r--tests/cases/callwithstructural64_ta2.txt1
-rw-r--r--tests/cases/callwithstructural_ta2.ll29
-rw-r--r--tests/cases/callwithstructural_ta2.txt1
-rw-r--r--tests/cases/structinparam.ll36
-rw-r--r--tests/cases/structinparam.txt2
-rw-r--r--tests/cubegeom_color.c1
-rw-r--r--tests/cubegeom_pre.c1
-rw-r--r--tests/cubegeom_pre2.c1
-rw-r--r--tests/cubegeom_pre2_vao.c1
-rw-r--r--tests/cubegeom_pre2_vao2.c1
-rw-r--r--tests/cubegeom_pre3.c1
-rw-r--r--tests/cubegeom_pre_vao.c1
-rw-r--r--tests/cubegeom_texturematrix.c1
-rw-r--r--tests/file_db.cpp47
-rw-r--r--tests/float_tex.cpp2
-rw-r--r--tests/gl_matrix_identity.c1
-rw-r--r--tests/glshaderinfo.cpp2
-rw-r--r--tests/http.h1
-rw-r--r--tests/pthread/specific.c60
-rw-r--r--tests/pthread/specific.c.txt8
-rw-r--r--tests/s3tc.c1
-rw-r--r--tests/s3tc_crunch.c1
-rw-r--r--tests/sdl_canvas.c11
-rw-r--r--tests/sdl_headless.c65
-rw-r--r--tests/sdl_image_prepare_data.c2
-rw-r--r--tests/sdl_pumpevents.c16
-rw-r--r--tests/test_browser.py29
-rw-r--r--tests/test_core.py13
-rw-r--r--tests/test_other.py23
-rw-r--r--tests/test_sanity.py27
-rw-r--r--tests/tex_nonbyte.c1
-rw-r--r--tools/file_packager.py18
-rw-r--r--tools/js-optimizer.js12
-rw-r--r--tools/test-js-optimizer-asm-outline1-output.js64
-rw-r--r--tools/test-js-optimizer-asm-outline1.js2
51 files changed, 632 insertions, 143 deletions
diff --git a/AUTHORS b/AUTHORS
index 6afe0918..59eb27d3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -94,4 +94,5 @@ a license to everyone to use it as detailed in LICENSE.)
* Pin Zhang <zhangpin04@gmail.com>
* Nick Bray <ncbray@chromium.org> (copyright owned by Google, Inc.)
* Aidan Hobson Sayers <aidanhs@cantab.net>
+* Charlie Birks <admin@daftgames.net>
diff --git a/emcc b/emcc
index 0cd8ca2d..a07ce4f1 100755
--- a/emcc
+++ b/emcc
@@ -1577,6 +1577,35 @@ try:
js_transform_tempfiles = [final]
+ if memory_init_file:
+ if shared.Settings.USE_TYPED_ARRAYS != 2:
+ if type(memory_init_file) == int: logging.warning('memory init file requires typed arrays mode 2')
+ else:
+ memfile = target + '.mem'
+ shared.try_delete(memfile)
+ def repl(m):
+ # handle chunking of the memory initializer
+ s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0])
+ s = s.replace('concat', ',')
+ if s[-1] == ',': s = s[:-1]
+ open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(','))))
+ if DEBUG:
+ # Copy into temp dir as well, so can be run there too
+ temp_memfile = os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile))
+ if os.path.abspath(memfile) != os.path.abspath(memfile):
+ shutil.copyfile(memfile, temp_memfile)
+ return 'loadMemoryInitializer("%s");' % os.path.basename(memfile)
+ src = re.sub(shared.JS.memory_initializer_pattern, repl, open(final).read(), count=1)
+ open(final + '.mem.js', 'w').write(src)
+ final += '.mem.js'
+ js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings
+ if DEBUG:
+ if os.path.exists(memfile):
+ save_intermediate('meminit')
+ logging.debug('wrote memory initialization to %s' % memfile)
+ else:
+ logging.debug('did not see memory initialization')
+
# It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing
js_optimizer_queue = []
js_optimizer_extra_info = {}
@@ -1654,35 +1683,6 @@ try:
src = re.sub(r'\n+[ \n]*\n+', '\n', src)
open(final, 'w').write(src)
- if memory_init_file:
- if shared.Settings.USE_TYPED_ARRAYS != 2:
- if type(memory_init_file) == int: logging.warning('memory init file requires typed arrays mode 2')
- else:
- memfile = target + '.mem'
- shared.try_delete(memfile)
- def repl(m):
- # handle chunking of the memory initializer
- s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0])
- s = s.replace('concat', ',')
- if s[-1] == ',': s = s[:-1]
- open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(','))))
- if DEBUG:
- # Copy into temp dir as well, so can be run there too
- temp_memfile = os.path.join(shared.EMSCRIPTEN_TEMP_DIR, os.path.basename(memfile))
- if os.path.abspath(memfile) != os.path.abspath(memfile):
- shutil.copyfile(memfile, temp_memfile)
- return 'loadMemoryInitializer("%s");' % os.path.basename(memfile)
- src = re.sub(shared.JS.memory_initializer_pattern, repl, src, count=1)
- open(final + '.mem.js', 'w').write(src)
- final += '.mem.js'
- js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings
- if DEBUG:
- if os.path.exists(memfile):
- save_intermediate('meminit')
- logging.debug('wrote memory initialization to %s' % memfile)
- else:
- logging.debug('did not see memory initialization')
-
def generate_source_map(map_file_base_name, offset=0):
jsrun.run_js(shared.path_from_root('tools', 'source-maps', 'sourcemapper.js'),
shared.NODE_JS, js_transform_tempfiles +
diff --git a/src/analyzer.js b/src/analyzer.js
index 2a7d64f5..b20dedff 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -281,6 +281,14 @@ function analyzer(data, sidePass) {
Array.prototype.splice.apply(params, [i, 1].concat(toAdd));
i += toAdd.length;
continue;
+ } else if (param.intertype == 'structvalue') {
+ // 'flatten' out the struct into scalars
+ var toAdd = param.params;
+ toAdd.forEach(function(param) {
+ param.byval = 0;
+ });
+ Array.prototype.splice.apply(params, [i, 1].concat(toAdd));
+ continue; // do not increment i; proceed to process the new params
}
i++;
}
diff --git a/src/jsifier.js b/src/jsifier.js
index 179a910a..7273f54c 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -23,7 +23,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var mainPass = !functionsOnly;
if (mainPass) {
- var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB ? 'shell_sharedlib.js' : 'shell.js');
+ var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'shell_sharedlib.js' : 'shell.js');
if (phase == 'pre') {
// We will start to print out the data, but must do so carefully - we are
@@ -47,10 +47,11 @@ function JSify(data, functionsOnly, givenFunctions) {
var shellParts = read(shellFile).split('{{BODY}}');
print(processMacros(preprocess(shellParts[0])));
- var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js';
+ var preFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'preamble_sharedlib.js' : 'preamble.js';
var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime())));
print(pre);
+ // Populate implementedFunctions. Note that this is before types, and will be updated later.
data.unparsedFunctions.forEach(function(func) {
Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type }));
});
@@ -80,7 +81,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (phase == 'pre') {
var libFuncsToInclude;
if (INCLUDE_FULL_LIBRARY) {
- assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.')
+ assert(!(BUILD_AS_SHARED_LIB || SIDE_MODULE), 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB/SIDE_MODULE set.')
libFuncsToInclude = [];
for (var key in LibraryManager.library) {
if (!key.match(/__(deps|postset|inline|asm|sig)$/)) {
@@ -454,7 +455,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var postsetId = ident + '__postset';
var postset = LibraryManager.library[postsetId];
- if (postset && !addedLibraryItems[postsetId]) {
+ if (postset && !addedLibraryItems[postsetId] && !SIDE_MODULE) {
addedLibraryItems[postsetId] = true;
ret.push({
intertype: 'GlobalVariablePostSet',
@@ -497,6 +498,7 @@ function JSify(data, functionsOnly, givenFunctions) {
Functions.libraryFunctions[ident.substr(1)] = 2;
}
}
+ if (SIDE_MODULE) return ';'; // we import into the side module js library stuff from the outside parent
if ((!ASM_JS || phase == 'pre') &&
(EXPORT_ALL || (ident in EXPORTED_FUNCTIONS))) {
contentText += '\nModule["' + ident + '"] = ' + ident + ';';
@@ -1835,7 +1837,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print('Runtime.typeInfo = ' + JSON.stringify(Types.types));
print('Runtime.structMetadata = ' + JSON.stringify(Types.structMetadata));
}
- var postFile = BUILD_AS_SHARED_LIB ? 'postamble_sharedlib.js' : 'postamble.js';
+ var postFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'postamble_sharedlib.js' : 'postamble.js';
var postParts = processMacros(preprocess(read(postFile))).split('{{GLOBAL_VARS}}');
print(postParts[0]);
@@ -1871,6 +1873,12 @@ function JSify(data, functionsOnly, givenFunctions) {
// Data
if (mainPass) {
+ if (phase == 'pre') {
+ // types have been parsed, so we can figure out function signatures (which can use types)
+ data.unparsedFunctions.forEach(function(func) {
+ Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type }));
+ });
+ }
substrate.addItems(data.functionStubs, 'FunctionStub');
assert(data.functions.length == 0);
} else {
diff --git a/src/library.js b/src/library.js
index 9e78db13..3ba2f56b 100644
--- a/src/library.js
+++ b/src/library.js
@@ -6808,24 +6808,38 @@ LibraryManager.library = {
_pthread_once.seen[ptr] = 1;
},
+ $PTHREAD_SPECIFIC: {},
+ $PTHREAD_SPECIFIC_NEXT_KEY: 1,
+ pthread_key_create__deps: ['$PTHREAD_SPECIFIC', '$PTHREAD_SPECIFIC_NEXT_KEY', '$ERRNO_CODES'],
pthread_key_create: function(key, destructor) {
- if (!_pthread_key_create.keys) _pthread_key_create.keys = {};
+ if (key == 0) {
+ return ERRNO_CODES.EINVAL;
+ }
+ {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}}
// values start at 0
- _pthread_key_create.keys[key] = 0;
+ PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0;
+ PTHREAD_SPECIFIC_NEXT_KEY++;
+ return 0;
},
+ pthread_getspecific__deps: ['$PTHREAD_SPECIFIC'],
pthread_getspecific: function(key) {
- return _pthread_key_create.keys[key] || 0;
+ return PTHREAD_SPECIFIC[key] || 0;
},
+ pthread_setspecific__deps: ['$PTHREAD_SPECIFIC', '$ERRNO_CODES'],
pthread_setspecific: function(key, value) {
- _pthread_key_create.keys[key] = value;
+ if (value == 0) {
+ return ERRNO_CODES.EINVAL;
+ }
+ PTHREAD_SPECIFIC[key] = value;
+ return 0;
},
- pthread_key_delete: ['$ERRNO_CODES'],
+ pthread_key_delete__deps: ['$PTHREAD_SPECIFIC', '$ERRNO_CODES'],
pthread_key_delete: function(key) {
- if (_pthread_key_create.keys[key]) {
- delete _pthread_key_create.keys[key];
+ if (key in PTHREAD_SPECIFIC) {
+ delete PTHREAD_SPECIFIC[key];
return 0;
}
return ERRNO_CODES.EINVAL;
diff --git a/src/library_browser.js b/src/library_browser.js
index 558c9a59..591a3c11 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -821,6 +821,13 @@ mergeInto(LibraryManager.library, {
emscripten_set_canvas_size: function(width, height) {
Browser.setCanvasSize(width, height);
},
+
+ emscripten_get_canvas_size: function(width, height, isFullscreen) {
+ var canvas = Module['canvas'];
+ {{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}};
+ {{{ makeSetValue('height', '0', 'canvas.height', 'i32') }}};
+ {{{ makeSetValue('isFullscreen', '0', 'Browser.isFullScreen ? 1 : 0', 'i32') }}};
+ },
emscripten_get_now: function() {
if (ENVIRONMENT_IS_NODE) {
diff --git a/src/library_fs.js b/src/library_fs.js
index e1397356..9c8223ab 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -802,6 +802,90 @@ mergeInto(LibraryManager.library, {
}
},
+ indexedDB: function() {
+ return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+ },
+
+ DB_NAME: function() {
+ return 'EM_FS_' + window.location.pathname;
+ },
+ DB_VERSION: 20,
+ DB_STORE_NAME: 'FILE_DATA',
+
+ // asynchronously saves a list of files to an IndexedDB. The DB will be created if not already existing.
+ saveFilesToDB: function(paths, onload, onerror) {
+ onload = onload || function(){};
+ onerror = onerror || function(){};
+ var indexedDB = FS.indexedDB();
+ try {
+ var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+ } catch (e) {
+ return onerror(e);
+ }
+ openRequest.onupgradeneeded = function() {
+ console.log('creating db');
+ var db = openRequest.result;
+ db.createObjectStore(FS.DB_STORE_NAME);
+ };
+ openRequest.onsuccess = function() {
+ var db = openRequest.result;
+ var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+ var files = transaction.objectStore(FS.DB_STORE_NAME);
+ var ok = 0, fail = 0, total = paths.length;
+ function finish() {
+ if (fail == 0) onload(); else onerror();
+ }
+ paths.forEach(function(path) {
+ var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+ putRequest.onsuccess = function() { ok++; if (ok + fail == total) finish() };
+ putRequest.onerror = function() { fail++; if (ok + fail == total) finish() };
+ });
+ transaction.onerror = onerror;
+ };
+ openRequest.onerror = onerror;
+ },
+
+ // asychronously loads a file from IndexedDB.
+ loadFilesFromDB: function(paths, onload, onerror) {
+ onload = onload || function(){};
+ onerror = onerror || function(){};
+ var indexedDB = FS.indexedDB();
+ try {
+ var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+ } catch (e) {
+ return onerror(e);
+ }
+ openRequest.onupgradeneeded = onerror; // no database to load from
+ openRequest.onsuccess = function() {
+ var db = openRequest.result;
+ try {
+ var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+ } catch(e) {
+ onerror(e);
+ return;
+ }
+ var files = transaction.objectStore(FS.DB_STORE_NAME);
+ var ok = 0, fail = 0, total = paths.length;
+ function finish() {
+ if (fail == 0) onload(); else onerror();
+ }
+ paths.forEach(function(path) {
+ var getRequest = files.get(path);
+ getRequest.onsuccess = function() {
+ if (FS.analyzePath(path).exists) {
+ FS.unlink(path);
+ }
+ FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+ ok++;
+ if (ok + fail == total) finish();
+ };
+ getRequest.onerror = function() { fail++; if (ok + fail == total) finish() };
+ });
+ transaction.onerror = onerror;
+ };
+ openRequest.onerror = onerror;
+ },
+
//
// general
//
diff --git a/src/library_memfs.js b/src/library_memfs.js
index 63326c42..354f5e95 100644
--- a/src/library_memfs.js
+++ b/src/library_memfs.js
@@ -2,17 +2,13 @@ mergeInto(LibraryManager.library, {
$MEMFS__deps: ['$FS'],
$MEMFS: {
// content modes
- CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it - need to free() when no longer needed
+ CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it, without copying (note: someone else needs to free() it, if that is necessary)
CONTENT_FLEXIBLE: 2, // has been modified or never set to anything, and is a flexible js array that can grow/shrink
CONTENT_FIXED: 3, // contains some fixed-size content written into it, in a typed array
ensureFlexible: function(node) {
if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
var contents = node.contents;
node.contents = Array.prototype.slice.call(contents);
- if (node.contentMode === MEMFS.CONTENT_OWNING) {
- assert(contents.byteOffset);
- Module['_free'](contents.byteOffset);
- }
node.contentMode = MEMFS.CONTENT_FLEXIBLE;
}
},
diff --git a/src/library_openal.js b/src/library_openal.js
index 7f5d5df6..dea986f3 100644
--- a/src/library_openal.js
+++ b/src/library_openal.js
@@ -244,7 +244,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alDeleteSources called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
@@ -258,7 +257,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alGenSources called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
@@ -318,7 +316,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSourcei called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -387,7 +384,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSourcef called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -440,7 +436,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSource3f called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -481,7 +476,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSourceQueueBuffers called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -518,7 +512,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSourceUnqueueBuffers called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -557,7 +550,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alDeleteBuffers called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
if (count > AL.currentContext.buf.length) {
@@ -601,7 +593,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alGenBuffers called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
@@ -615,7 +606,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alBufferData called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
if (buffer > AL.currentContext.buf.length) {
@@ -680,7 +670,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSourcePlay called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -700,7 +689,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSourceStop called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -720,7 +708,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSourcePause called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -740,7 +727,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alGetSourcei called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -804,7 +790,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alGetSourcef called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
var src = AL.currentContext.src[source - 1];
@@ -865,7 +850,6 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alListenerfv called without a valid context");
#endif
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
switch (param) {
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 7b1837e8..d6cb6d18 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -567,7 +567,12 @@ var LibrarySDL = {
switch (event.type) {
case 'keydown': case 'keyup': {
var down = event.type === 'keydown';
- var code = SDL.keyCodes[event.keyCode] || event.keyCode;
+ var code = event.keyCode;
+ if (code >= 65 && code <= 90) {
+ code += 32; // make lowercase for SDL
+ } else {
+ code = SDL.keyCodes[event.keyCode] || event.keyCode;
+ }
{{{ makeSetValue('SDL.keyboardState', 'code', 'down', 'i8') }}};
// TODO: lmeta, rmeta, numlock, capslock, KMOD_MODE, KMOD_RESERVED
diff --git a/src/parseTools.js b/src/parseTools.js
index 046dac1b..66354dca 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -430,6 +430,8 @@ function parseParamTokens(params) {
ret.push(parseLLVMFunctionCall(segment));
} else if (segment[1].text === 'blockaddress') {
ret.push(parseBlockAddress(segment));
+ } else if (segment[1].type && segment[1].type == '{') {
+ ret.push(parseLLVMSegment(segment));
} else {
if (segment[2] && segment[2].text == 'to') { // part of bitcast params
segment = segment.slice(0, 2);
diff --git a/src/settings.js b/src/settings.js
index cb64bfd9..03b4ed64 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -6,6 +6,11 @@
// emcc -s OPTION1=VALUE1 -s OPTION2=VALUE2 [..other stuff..]
//
// See https://github.com/kripken/emscripten/wiki/Code-Generation-Modes/
+//
+// Note that the values here are the defaults in -O0, that is, unoptimized
+// mode. See apply_opt_level in tools/shared.py for how -O1,2,3 affect these
+// flags.
+//
// Tuning
var QUANTUM_SIZE = 4; // This is the size of an individual field in a structure. 1 would
@@ -131,6 +136,16 @@ var OUTLINING_LIMIT = 0; // A function size above which we try to automatically
// large functions (JS engines often compile them very slowly,
// compile them with lower optimizations, or do not optimize them
// at all). If 0