summaryrefslogtreecommitdiff
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, we do not perform outlining at all.
+ // To see which funcs are large, you can inspect the source
+ // in a debug build (-g2 or -g for example), and can run
+ // tools/find_bigfuncs.py on that to get a sorted list by size.
+ // Another possibility is to look in the web console in firefox,
+ // which will note slowly-compiling functions.
+ // You will probably want to experiment with various values to
+ // see the impact on compilation time, code size and runtime
+ // throughput. It is hard to say what values to start testing
+ // with, but something around 20,000 to 100,000 might make sense.
+ // (The unit size is number of AST nodes.)
// Generated code debugging options
var SAFE_HEAP = 0; // Check each write to the heap, for example, this will give a clear
@@ -380,9 +395,7 @@ var HEADLESS = 0; // If 1, will include shim code that tries to 'fake' a browser
var BENCHMARK = 0; // If 1, will just time how long main() takes to execute, and not
// print out anything at all whatsoever. This is useful for benchmarking.
-var ASM_JS = 0; // If 1, generate code in asm.js format. XXX This is highly experimental,
- // and will not work on most codebases yet. It is NOT recommended that you
- // try this yet.
+var ASM_JS = 0; // If 1, generate code in asm.js format.
var PGO = 0; // Enables profile-guided optimization in the form of runtime checks for
// which functions are actually called. Emits a list during shutdown that you
diff --git a/src/shell.html b/src/shell.html
index 22bc9de9..ff5f6e35 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -87,6 +87,6 @@
};
Module.setStatus('Downloading...');
</script>
- <script type='text/javascript'>{{{ SCRIPT_CODE }}}</script>
+ <script async type='text/javascript'>{{{ SCRIPT_CODE }}}</script>
</body>
</html>
diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h
index 1ed4c721..1b9a8f25 100644
--- a/system/include/emscripten/emscripten.h
+++ b/system/include/emscripten/emscripten.h
@@ -170,6 +170,12 @@ void emscripten_hide_mouse();
void emscripten_set_canvas_size(int width, int height);
/*
+ * Get the current pixel width and height of the <canvas> element
+ * as well as whether the canvas is fullscreen or not.
+ */
+void emscripten_get_canvas_size(int *width, int *height, int *isFullscreen);
+
+/*
* Returns the highest-precision representation of the
* current time that the browser provides. This uses either
* Date.now or performance.now. The result is *not* an
diff --git a/tests/aniso.c b/tests/aniso.c
index f210e5a5..e8d7bd3f 100644
--- a/tests/aniso.c
+++ b/tests/aniso.c
@@ -27,6 +27,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#include "SDL/SDL_opengl.h"
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/cases/callwithstructural64_ta2.ll b/tests/cases/callwithstructural64_ta2.ll
new file mode 100644
index 00000000..d16b0e87
--- /dev/null
+++ b/tests/cases/callwithstructural64_ta2.ll
@@ -0,0 +1,29 @@
+; ModuleID = 'foo.bc'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32"
+target triple = "le32-unknown-nacl"
+
+%ac = type { i8*, i64 }
+
+@0 = constant [9 x i8] c"func %s\0A\00"
+@1 = constant [4 x i8] c"foo\00"
+
+declare void @llvm.trap() noreturn nounwind
+
+define void @direct(%ac) {
+entry:
+ %str = alloca %ac
+ store %ac %0, %ac* %str
+ %1 = getelementptr inbounds %ac* %str, i32 0, i32 0
+ %2 = load i8** %1
+ call void (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @0, i32 0, i32 0), i8* %2)
+ ret void
+}
+
+declare void @printf(i8*, ...)
+
+define i32 @main() {
+entry:
+ call void @direct(%ac { i8* getelementptr inbounds ([4 x i8]* @1, i32 0, i32 0), i64 3 })
+ ret i32 0
+}
+
diff --git a/tests/cases/callwithstructural64_ta2.txt b/tests/cases/callwithstructural64_ta2.txt
new file mode 100644
index 00000000..51a6ac7c
--- /dev/null
+++ b/tests/cases/callwithstructural64_ta2.txt
@@ -0,0 +1 @@
+func foo
diff --git a/tests/cases/callwithstructural_ta2.ll b/tests/cases/callwithstructural_ta2.ll
new file mode 100644
index 00000000..bc6f852a
--- /dev/null
+++ b/tests/cases/callwithstructural_ta2.ll
@@ -0,0 +1,29 @@
+; ModuleID = 'foo.bc'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32"
+target triple = "le32-unknown-nacl"
+
+%ac = type { i8*, i32 }
+
+@0 = constant [9 x i8] c"func %s\0A\00"
+@1 = constant [4 x i8] c"foo\00"
+
+declare void @llvm.trap() noreturn nounwind
+
+define void @direct(%ac) {
+entry:
+ %str = alloca %ac
+ store %ac %0, %ac* %str
+ %1 = getelementptr inbounds %ac* %str, i32 0, i32 0
+ %2 = load i8** %1
+ call void (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @0, i32 0, i32 0), i8* %2)
+ ret void
+}
+
+declare void @printf(i8*, ...)
+
+define i32 @main() {
+entry:
+ call void @direct(%ac { i8* getelementptr inbounds ([4 x i8]* @1, i32 0, i32 0), i32 3 })
+ ret i32 0
+}
+
diff --git a/tests/cases/callwithstructural_ta2.txt b/tests/cases/callwithstructural_ta2.txt
new file mode 100644
index 00000000..51a6ac7c
--- /dev/null
+++ b/tests/cases/callwithstructural_ta2.txt
@@ -0,0 +1 @@
+func foo
diff --git a/tests/cases/structinparam.ll b/tests/cases/structinparam.ll
new file mode 100644
index 00000000..d81f5e67
--- /dev/null
+++ b/tests/cases/structinparam.ll
@@ -0,0 +1,36 @@
+; ModuleID = 'min.bc'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32"
+target triple = "le32-unknown-nacl"
+
+%ac = type { i8*, i32 }
+
+@0 = constant [9 x i8] c"func %s\0A\00"
+@1 = constant [4 x i8] c"foo\00"
+@2 = constant [9 x i8] c"main %s\0A\00"
+
+declare void @llvm.trap() noreturn nounwind
+
+define void @direct(%ac) {
+entry:
+ %str = alloca %ac
+ store %ac %0, %ac* %str
+ %1 = getelementptr inbounds %ac* %str, i32 0, i32 0
+ %2 = load i8** %1
+ call void (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @0, i32 0, i32 0), i8* %2)
+ ret void
+}
+
+declare void @printf(i8*, ...)
+
+define i32 @main() {
+entry:
+ %str = alloca %ac
+ store %ac { i8* getelementptr inbounds ([4 x i8]* @1, i32 0, i32 0), i32 3 }, %ac* %str
+ %0 = getelementptr inbounds %ac* %str, i32 0, i32 0
+ %1 = load i8** %0
+ call void (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @2, i32 0, i32 0), i8* %1)
+ %2 = load %ac* %str
+ call void @direct(%ac %2)
+ ret i32 0
+}
+
diff --git a/tests/cases/structinparam.txt b/tests/cases/structinparam.txt
new file mode 100644
index 00000000..785191e7
--- /dev/null
+++ b/tests/cases/structinparam.txt
@@ -0,0 +1,2 @@
+main foo
+func foo
diff --git a/tests/cubegeom_color.c b/tests/cubegeom_color.c
index 7d384324..ff30e1a9 100644
--- a/tests/cubegeom_color.c
+++ b/tests/cubegeom_color.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/cubegeom_pre.c b/tests/cubegeom_pre.c
index fb1a5e02..40b03cf7 100644
--- a/tests/cubegeom_pre.c
+++ b/tests/cubegeom_pre.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/cubegeom_pre2.c b/tests/cubegeom_pre2.c
index 51961bf7..df04ae31 100644
--- a/tests/cubegeom_pre2.c
+++ b/tests/cubegeom_pre2.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/cubegeom_pre2_vao.c b/tests/cubegeom_pre2_vao.c
index cba262ff..733c8fc6 100644
--- a/tests/cubegeom_pre2_vao.c
+++ b/tests/cubegeom_pre2_vao.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/cubegeom_pre2_vao2.c b/tests/cubegeom_pre2_vao2.c
index 3784006c..69096833 100644
--- a/tests/cubegeom_pre2_vao2.c
+++ b/tests/cubegeom_pre2_vao2.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/cubegeom_pre3.c b/tests/cubegeom_pre3.c
index 4ba2a779..ceaa757e 100644
--- a/tests/cubegeom_pre3.c
+++ b/tests/cubegeom_pre3.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/cubegeom_pre_vao.c b/tests/cubegeom_pre_vao.c
index cae68cfc..8c598143 100644
--- a/tests/cubegeom_pre_vao.c
+++ b/tests/cubegeom_pre_vao.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/cubegeom_texturematrix.c b/tests/cubegeom_texturematrix.c
index 99a4469e..abb667eb 100644
--- a/tests/cubegeom_texturematrix.c
+++ b/tests/cubegeom_texturematrix.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/file_db.cpp b/tests/file_db.cpp
new file mode 100644
index 00000000..ebb3bb30
--- /dev/null
+++ b/tests/file_db.cpp
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <emscripten.h>
+
+void later(void *) {}
+
+int main() {
+#if FIRST
+ FILE *f = fopen("waka.txt", "w");
+ fputc('a', f);
+ fputc('z', f);
+ fclose(f);
+
+ EM_ASM(
+ FS.saveFilesToDB(['waka.txt', 'moar.txt'], function() {
+ Module.print('save ok');
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://localhost:8888/report_result?1');
+ xhr.send();
+ setTimeout(function() { window.close() }, 1000);
+ }, function(e) {
+ abort('saving should succeed ' + e);
+ });
+ );
+#else
+ EM_ASM(
+ FS.loadFilesFromDB(['waka.txt', 'moar.txt'], function() {
+ function stringy(arr) {
+ return Array.prototype.map.call(arr, function(x) { return String.fromCharCode(x) }).join('');
+ }
+ assert(stringy(FS.analyzePath('waka.txt').object.contents) == 'az');
+ var secret = stringy(FS.analyzePath('moar.txt').object.contents);
+ Module.print('load: ' + secret);
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://localhost:8888/report_result?' + secret);
+ xhr.send();
+ setTimeout(function() { window.close() }, 1000);
+ }, function() {
+ abort('loading should succeed');
+ });
+ );
+#endif
+
+ emscripten_async_call(later, NULL, 100); // keep runtime alive
+
+ return 0;
+}
+
diff --git a/tests/float_tex.cpp b/tests/float_tex.cpp
index 61531124..c40ff786 100644
--- a/tests/float_tex.cpp
+++ b/tests/float_tex.cpp
@@ -113,7 +113,7 @@ static void gl_init(void) {
/* Store the vertices in a vertex buffer object (VBO) */
glGenBuffers(1, &indicesVBO);
glBindBuffer(GL_ARRAY_BUFFER, indicesVBO);
- glBufferData(GL_ARRAY_BUFFER, elements.size() * sizeof(uint), &elements[0], GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, elements.size() * sizeof(float), &elements[0], GL_STATIC_DRAW);
/* Get the locations of the uniforms so we can access them */
nodeSamplerLocation = glGetUniformLocation(program, "nodeInfo");
glBindAttribLocation(program, 0, "indices");
diff --git a/tests/gl_matrix_identity.c b/tests/gl_matrix_identity.c
index 98b1c21f..9f990a77 100644
--- a/tests/gl_matrix_identity.c
+++ b/tests/gl_matrix_identity.c
@@ -26,6 +26,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/glshaderinfo.cpp b/tests/glshaderinfo.cpp
index 8ec393a8..56da2414 100644
--- a/tests/glshaderinfo.cpp
+++ b/tests/glshaderinfo.cpp
@@ -1,8 +1,6 @@
#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
-#define _GNU_SOURCE
-
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/tests/http.h b/tests/http.h
index 7eff7013..d20f012b 100644
--- a/tests/http.h
+++ b/tests/http.h
@@ -8,6 +8,7 @@
#ifndef __HTTP_H__
#define __HTTP_H__
+#include <stdarg.h>
#include <string>
diff --git a/tests/pthread/specific.c b/tests/pthread/specific.c
new file mode 100644
index 00000000..914884e7
--- /dev/null
+++ b/tests/pthread/specific.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+
+static void destr_function(void *arg)
+{
+ // Not implemented yet in Emscripten
+}
+
+int main(void)
+{
+ pthread_key_t key = 0;
+ int rv;
+ int data = 123;
+ int *data2;
+
+ assert(pthread_key_delete(key) != 0);
+ assert(pthread_getspecific(key) == NULL);
+
+ rv = pthread_key_create(&key, &destr_function);
+ printf("pthread_key_create = %d\n", rv);
+ assert(rv == 0);
+
+ assert(pthread_getspecific(key) == NULL);
+
+ rv = pthread_setspecific(key, (void*) &data);
+ printf("pthread_setspecific = %d\n", rv);
+ assert(rv == 0);
+
+ data2 = pthread_getspecific(key);
+ assert(data2 != NULL);
+ printf("pthread_getspecific = %d\n", *data2);
+ assert(*data2 == 123);
+
+ rv = pthread_key_create(&key, &destr_function);
+ data2 = pthread_getspecific(key);
+ printf("pthread_getspecific after key recreate = %p\n", data2);
+ assert(data2 == NULL);
+
+ rv = pthread_key_delete(key);
+ printf("pthread_key_delete = %d\n", rv);
+ assert(rv == 0);
+
+ rv = pthread_key_delete(key);
+ printf("pthread_key_delete repeated = %d\n", rv);
+ assert(rv == EINVAL);
+
+ rv = pthread_setspecific(key, NULL);
+ printf("pthread_setspecific for value NULL = %d\n", rv);
+ assert(rv == EINVAL);
+
+ rv = pthread_key_create(&key, &destr_function);
+ assert(rv == 0);
+ rv = pthread_key_delete(key);
+ printf("pthread_key_delete just after created = %d\n", rv);
+ assert(rv == 0);
+
+ return 0;
+}
diff --git a/tests/pthread/specific.c.txt b/tests/pthread/specific.c.txt
new file mode 100644
index 00000000..ad122b3d
--- /dev/null
+++ b/tests/pthread/specific.c.txt
@@ -0,0 +1,8 @@
+pthread_key_create = 0
+pthread_setspecific = 0
+pthread_getspecific = 123
+pthread_getspecific after key recreate = (nil)
+pthread_key_delete = 0
+pthread_key_delete repeated = 22
+pthread_setspecific for value NULL = 22
+pthread_key_delete just after created = 0
diff --git a/tests/s3tc.c b/tests/s3tc.c
index 16ee783f..5f7bee83 100644
--- a/tests/s3tc.c
+++ b/tests/s3tc.c
@@ -27,6 +27,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#include "SDL/SDL_opengl.h"
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/s3tc_crunch.c b/tests/s3tc_crunch.c
index 90ed02d9..c2606c8f 100644
--- a/tests/s3tc_crunch.c
+++ b/tests/s3tc_crunch.c
@@ -27,6 +27,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#include "SDL/SDL_opengl.h"
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tests/sdl_canvas.c b/tests/sdl_canvas.c
index 10044ff4..6bd659b8 100644
--- a/tests/sdl_canvas.c
+++ b/tests/sdl_canvas.c
@@ -1,4 +1,5 @@
#include <stdio.h>
+#include <stdlib.h>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include <emscripten.h>
@@ -43,6 +44,16 @@ int main(int argc, char **argv) {
SDL_Flip(screen);
SDL_LockSurface(screen);
+
+ int width, height, isFullscreen;
+ emscripten_get_canvas_size(&width, &height, &isFullscreen);
+
+ if (width != 600 && height != 450)
+ {
+ printf("error: wrong width/height\n");
+ abort();
+ }
+
int sum = 0;
for (int i = 0; i < screen->h; i++) {
sum += *((char*)screen->pixels + i*screen->w*4 + i*4 + 0);
diff --git a/tests/sdl_headless.c b/tests/sdl_headless.c
new file mode 100644
index 00000000..349c5e26
--- /dev/null
+++ b/tests/sdl_headless.c
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_ttf.h>
+#include <emscripten.h>
+
+
+int main(int argc, char **argv) {
+#if EMSCRIPTEN
+ // include GL stuff, to check that we can compile hybrid 2d/GL apps
+ extern void glBegin(int mode);
+ extern void glBindBuffer(int target, int buffer);
+ if (argc == 9876) {
+ glBegin(0);
+ glBindBuffer(0, 0);
+ }
+#endif
+
+ SDL_Init(SDL_INIT_VIDEO);
+ SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE);
+
+ printf("Init: %d\n", TTF_Init());
+
+ TTF_Font *font = TTF_OpenFont("sans-serif", 40);
+ printf("Font: %p\n", font);
+
+ SDL_Color color = { 0xff, 0x99, 0x00, 0xff };
+
+ SDL_Surface *text = TTF_RenderText_Solid(font, "hello orange world", color);
+
+ SDL_Color color2 = { 0xbb, 0, 0xff, 0xff };
+ SDL_Surface *text2 = TTF_RenderText_Solid(font, "a second line, purple", color2);
+
+ // render
+ SDL_Rect dest = { 0, 50, 0, 0 };
+ SDL_BlitSurface (text, NULL, screen, NULL);
+ dest.y = 100;
+ SDL_BlitSurface (text2, NULL, screen, &dest);
+
+ // fill stuff
+ SDL_Rect rect = { 200, 200, 175, 125 };
+ SDL_FillRect(screen, &rect, SDL_MapRGBA(screen->format, 0x22, 0x22, 0xff, 0xff));
+
+ SDL_Flip(screen);
+
+ SDL_LockSurface(screen);
+
+ int sum = 0;
+ for (int i = 0; i < screen->h; i++) {
+ sum += *((char*)screen->pixels + i*screen->w*4 + i*4 + 0);
+ }
+ printf("Sum: %d\n", sum);
+
+ printf("you should see two lines of text in different colors and a blue rectangle\n");
+
+ SDL_Quit();
+
+ printf("done.\n");
+
+ int result = sum > 3000 && sum < 5000; // varies a little on different browsers, font differences?
+ REPORT_RESULT();
+
+ return 0;
+}
+
diff --git a/tests/sdl_image_prepare_data.c b/tests/sdl_image_prepare_data.c
index d45a2e60..043ace47 100644
--- a/tests/sdl_image_prepare_data.c
+++ b/tests/sdl_image_prepare_data.c
@@ -58,7 +58,7 @@ int main() {
printf("prepare..\n");
#define SIZE 203164
- FILE *f = open("screenshot.not", "rb");
+ FILE *f = fopen("screenshot.not", "rb");
char *buffer = malloc(SIZE);
fread(buffer, SIZE, 1, f);
fclose(f);
diff --git a/tests/sdl_pumpevents.c b/tests/sdl_pumpevents.c
index 64becaad..e765d285 100644
--- a/tests/sdl_pumpevents.c
+++ b/tests/sdl_pumpevents.c
@@ -40,6 +40,20 @@ int loop2()
return r;
}
+int alphakey()
+{
+ unsigned i;
+ int r = 0;
+
+ SDL_PumpEvents();
+
+ const Uint8 *keys = SDL_GetKeyState(NULL);
+ if (keys[SDLK_a])
+ r = 4;
+
+ return r;
+}
+
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
@@ -49,6 +63,8 @@ int main(int argc, char *argv[])
result += loop1();
emscripten_run_script("keydown(39);"); // right
result += loop2();
+ emscripten_run_script("keydown(65);"); // A
+ result += alphakey();
REPORT_RESULT();
return 0;
}
diff --git a/tests/test_browser.py b/tests/test_browser.py
index 7c387071..32b29966 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -38,8 +38,6 @@ class browser(BrowserCore):
message='You should see "hello, world!" and a colored cube.')
def test_html_source_map(self):
- if 'test_html_source_map' not in str(sys.argv): return self.skip('''This test
-requires manual intervention; will not be run unless explicitly requested''')
cpp_file = os.path.join(self.get_dir(), 'src.cpp')
html_file = os.path.join(self.get_dir(), 'src.html')
# browsers will try to 'guess' the corresponding original line if a
@@ -64,14 +62,20 @@ requires manual intervention; will not be run unless explicitly requested''')
''')
# use relative paths when calling emcc, because file:// URIs can only load
# sourceContent when the maps are relative paths
+ try_delete(html_file)
+ try_delete(html_file + '.map')
Popen([PYTHON, EMCC, 'src.cpp', '-o', 'src.html', '-g4'],
cwd=self.get_dir()).communicate()
+ assert os.path.exists(html_file)
+ assert os.path.exists(html_file + '.map')
+ import webbrowser, time
webbrowser.open_new('file://' + html_file)
+ time.sleep(1)
print '''
-Set the debugger to pause on exceptions
-You should see an exception thrown at src.cpp:7.
-Press any key to continue.'''
- raw_input()
+If manually bisecting:
+ Check that you see src.cpp among the page sources.
+ Even better, add a breakpoint, e.g. on the printf, then reload, then step through and see the print (best to run with EM_SAVE_DIR=1 for the reload).
+'''
def build_native_lzma(self):
lzma_native = path_from_root('third_party', 'lzma.js', 'lzma-native')
@@ -790,6 +794,17 @@ Press any key to continue.'''
def test_glut_touchevents(self):
self.btest('glut_touchevents.c', '1')
+ def test_file_db(self):
+ secret = str(time.time())
+ open('moar.txt', 'w').write(secret)
+ self.btest('file_db.cpp', '1', args=['--preload-file', 'moar.txt', '-DFIRST'])
+ shutil.copyfile('test.html', 'first.html')
+ self.btest('file_db.cpp', secret)
+ shutil.copyfile('test.html', 'second.html')
+ open('moar.txt', 'w').write('aliantha')
+ self.btest('file_db.cpp', secret, args=['--preload-file', 'moar.txt']) # even with a file there, we load over it
+ shutil.move('test.html', 'third.html')
+
def test_sdl_pumpevents(self):
# key events should be detected using SDL_PumpEvents
open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
@@ -801,7 +816,7 @@ Press any key to continue.'''
document.dispatchEvent(event);
}
''')
- self.btest('sdl_pumpevents.c', expected='3', args=['--pre-js', 'pre.js'])
+ self.btest('sdl_pumpevents.c', expected='7', args=['--pre-js', 'pre.js'])
def test_sdl_audio(self):
shutil.copyfile(path_from_root('tests', 'sounds', 'alarmvictory_1.ogg'), os.path.join(self.get_dir(), 'sound.ogg'))
diff --git a/tests/test_core.py b/tests/test_core.py
index 142d6df4..7c5b651f 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -4664,6 +4664,12 @@ The current type of b is: 9
'''
self.do_run(src, 'BA')
+ def test_pthread_specific(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = open(path_from_root('tests', 'pthread', 'specific.c'), 'r').read()
+ expected = open(path_from_root('tests', 'pthread', 'specific.c.txt'), 'r').read()
+ self.do_run(src, expected, force_c=True)
+
def test_time(self):
# XXX Not sure what the right output is here. Looks like the test started failing with daylight savings changes. Modified it to pass again.
src = open(path_from_root('tests', 'time', 'src.c'), 'r').read()
@@ -5567,7 +5573,6 @@ The current type of b is: 9
if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
Settings.NAMED_GLOBALS = 1
- Settings.LINKABLE = 1
lib_src = '''
#include <cstdio>
@@ -6762,6 +6767,7 @@ date: 18.07.2013w; day 18, month 7, year 2013, extra: 201, 3
def test_files(self):
if self.emcc_args is not None and '-O2' in self.emcc_args:
self.emcc_args += ['--closure', '1'] # Use closure here, to test we don't break FS stuff
+ self.emcc_args = filter(lambda x: x != '-g', self.emcc_args) # ensure we test --closure 1 --memory-init-file 1 (-g would disable closure)
Settings.CORRECT_SIGNS = 1 # Just so our output is what we expect. Can flip them both.
post = '''
@@ -6788,8 +6794,13 @@ def process(filename):
other.close()
src = open(path_from_root('tests', 'files.cpp'), 'r').read()
+
+ mem_file = 'src.cpp.o.js.mem'
+ try_delete(mem_file)
self.do_run(src, ('size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\ntexte\n', 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\n'),
post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+ if self.emcc_args and '--memory-init-file' in self.emcc_args:
+ assert os.path.exists(mem_file)
def test_files_m(self):
# Test for Module.stdin etc.
diff --git a/tests/test_other.py b/tests/test_other.py
index d6e67e59..a6813b07 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -330,27 +330,6 @@ f.close()
os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove.
shutil.rmtree(tempdirname)
- def test_nostdincxx(self):
- try:
- old = os.environ.get('EMCC_LLVM_TARGET') or ''
- for compiler in [EMCC, EMXX]:
- for target in ['i386-pc-linux-gnu', 'le32-unknown-nacl']:
- print compiler, target
- os.environ['EMCC_LLVM_TARGET'] = target
- out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v'], stdout=PIPE, stderr=PIPE).communicate()
- out2, err2 = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v', '-nostdinc++'], stdout=PIPE, stderr=PIPE).communicate()
- assert out == out2
- def focus(e):
- assert 'search starts here:' in e, e
- assert e.count('End of search list.') == 1, e
- return e[e.index('search starts here:'):e.index('End of search list.')+20]
- err = focus(err)
- err2 = focus(err2)
- assert err == err2, err + '\n\n\n\n' + err2
- finally:
- if old:
- os.environ['EMCC_LLVM_TARGET'] = old
-
def test_failure_error_code(self):
for compiler in [EMCC, EMXX]:
# Test that if one file is missing from the build, then emcc shouldn't succeed, and shouldn't try to produce an output file.
@@ -1902,7 +1881,7 @@ seeked= file.
if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey due to node limitations (Uint8ClampedArray etc.)')
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'example.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_canvas.c'), '-s', 'HEADLESS=1']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_headless.c'), '-s', 'HEADLESS=1']).communicate()
output = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, stderr=PIPE)
assert '''Init: 0
Font: 0x1
diff --git a/tests/test_sanity.py b/tests/test_sanity.py
index 931645e2..4188afff 100644
--- a/tests/test_sanity.py
+++ b/tests/test_sanity.py
@@ -519,4 +519,29 @@ fi
finally:
del os.environ['EMCC_DEBUG']
- del os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE'] \ No newline at end of file
+ del os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE']
+
+ def test_nostdincxx(self):
+ restore()
+ Cache.erase()
+
+ try:
+ old = os.environ.get('EMCC_LLVM_TARGET') or ''
+ for compiler in [EMCC, EMXX]:
+ for target in ['i386-pc-linux-gnu', 'le32-unknown-nacl']:
+ print compiler, target
+ os.environ['EMCC_LLVM_TARGET'] = target
+ out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v'], stdout=PIPE, stderr=PIPE).communicate()
+ out2, err2 = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v', '-nostdinc++'], stdout=PIPE, stderr=PIPE).communicate()
+ assert out == out2
+ def focus(e):
+ assert 'search starts here:' in e, e
+ assert e.count('End of search list.') == 1, e
+ return e[e.index('search starts here:'):e.index('End of search list.')+20]
+ err = focus(err)
+ err2 = focus(err2)
+ assert err == err2, err + '\n\n\n\n' + err2
+ finally:
+ if old:
+ os.environ['EMCC_LLVM_TARGET'] = old
+
diff --git a/tests/tex_nonbyte.c b/tests/tex_nonbyte.c
index 8f2ec162..960d0efb 100644
--- a/tests/tex_nonbyte.c
+++ b/tests/tex_nonbyte.c
@@ -37,6 +37,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <assert.h>
diff --git a/tools/file_packager.py b/tools/file_packager.py
index bb62e905..8a1f1ba5 100644
--- a/tools/file_packager.py
+++ b/tools/file_packager.py
@@ -344,14 +344,7 @@ if has_preloaded:
},
send: function() {},
onload: function() {
- var data = this.byteArray.subarray(this.start, this.end);
- var size = this.end - this.start;
- var ptr = Module['_malloc'](size); // XXX leaked if a preload plugin replaces with new data
- Module['HEAPU8'].set(data, ptr);
- var arrayBuffer = Module['HEAPU8'].subarray(ptr, ptr + size);
- assert(arrayBuffer, 'Loading file ' + name + ' failed');
- var byteArray = !arrayBuffer.subarray ? new Uint8Array(arrayBuffer) : arrayBuffer;
-
+ var byteArray = this.byteArray.subarray(this.start, this.end);
if (this.crunched) {
var ddsHeader = byteArray.subarray(0, 128);
var that = this;
@@ -375,7 +368,7 @@ if has_preloaded:
} else {
Runtime.warn('Preloading file ' + that.name + ' failed');
}
- });
+ }, false, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change
this.requests[this.name] = null;
},
};
@@ -419,7 +412,12 @@ for file_ in data_files:
if has_preloaded:
# Get the big archive and split it up
- use_data = ' DataRequest.prototype.byteArray = byteArray;\n'
+ use_data = '''
+ // copy the entire loaded file into a spot in the heap. Files will refer to slices in that. They cannot be freed though.
+ var ptr = Module['_malloc'](byteArray.length);
+ Module['HEAPU8'].set(byteArray, ptr);
+ DataRequest.prototype.byteArray = Module['HEAPU8'].subarray(ptr, ptr+byteArray.length);
+'''
for file_ in data_files:
if file_['mode'] == 'preload':
use_data += ' DataRequest.prototype.requests["%s"].onload();\n' % (file_['dstpath'])
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 9a5104bf..b42164f9 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -135,6 +135,7 @@ var ASSIGN_OR_ALTER = set('assign', 'unary-postfix', 'unary-prefix');
var CONTROL_FLOW = set('do', 'while', 'for', 'if', 'switch');
var NAME_OR_NUM = set('name', 'num');
var ASSOCIATIVE_BINARIES = set('+', '*', '|', '&', '^');
+var ALTER_FLOW = set('break', 'continue', 'return');
var BREAK_CAPTURERS = set('do', 'while', 'for', 'switch');
var CONTINUE_CAPTURERS = LOOP;
@@ -3070,10 +3071,10 @@ function outline(ast) {
currSize += size;
if (!isIf) {
var last = part.body;
- last = last[stats.length-1];
+ last = last[last.length-1];
if (last && last[0] === 'block') last = last[1][last[1].length-1];
if (last && last[0] === 'stat') last = last[1];
- force = !last || last[0] !== 'break';
+ force = !last || !(last[0] in ALTER_FLOW);
}
});
assert(currSize);
@@ -3487,7 +3488,7 @@ function outline(ast) {
}
}
outliningParents[newIdent] = func[1];
- printErr('performed outline ' + [func[1], newIdent, 'code sizes (pre/post):', originalCodeSize, measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned)), ' owned: ', setSize(owned), ' left: ', setSize(asmData.vars), setSize(asmData.params), ' loopsDepth: ', loops]);
+ printErr('performed outline ' + [func[1], newIdent, 'pre size', originalCodeSize, 'resulting size', measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned)), ' owned: ', setSize(owned), ' left: ', setSize(asmData.vars), setSize(asmData.params), ' loopsDepth: ', loops]);
calculateThreshold(func, asmData);
return [newFunc];
}
@@ -3633,6 +3634,8 @@ function outline(ast) {
var maxTotalFunctions = Infinity; // debugging tool
+ printErr('\n');
+
var more = true;
while (more) {
more = false;
@@ -3691,7 +3694,8 @@ function outline(ast) {
}
}
}
- printErr('... resulting size of ' + func[1] + ' is ' + measureSize(func));
+ ret.push(func);
+ printErr('... resulting sizes of ' + func[1] + ' is ' + ret.map(measureSize) + '\n');
}
denormalizeAsm(func, asmData);
});
diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js
index 895004d8..612da16a 100644
--- a/tools/test-js-optimizer-asm-outline1-output.js
+++ b/tools/test-js-optimizer-asm-outline1-output.js
@@ -348,6 +348,15 @@ function switchh() {
HEAP32[sp + 44 >> 2] = 0;
switchh$2(sp);
helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ tempValue = HEAP32[sp + 40 >> 2] | 0;
+ tempInt = HEAP32[sp + 44 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 44 >> 2];
+ HEAP32[sp + 40 >> 2] = 0;
+ HEAP32[sp + 44 >> 2] = 0;
+ if ((tempValue | 0) == 5) {
+ STACKTOP = sp;
+ return;
+ }
HEAP32[sp + 8 >> 2] = helper$0;
HEAP32[sp + 16 >> 2] = helper$1;
HEAP32[sp + 32 >> 2] = 0;
@@ -749,36 +758,39 @@ function switchh$2(sp) {
var helper$0 = 0, helper$1 = 0;
helper$0 = HEAP32[sp + 8 >> 2] | 0;
helper$1 = HEAP32[sp + 16 >> 2] | 0;
- if (helper$0) {
- helper$0 = 0;
- switch (helper$1 | 0) {
- case 1:
- {
- f(1);
- g();
- break;
- }
- default:
- {
- helper$0 = 1;
+ OL : do {
+ if (helper$0) {
+ helper$0 = 0;
+ switch (helper$1 | 0) {
+ case 1:
+ {
+ f(1);
+ g();
+ HEAP32[sp + 40 >> 2] = 5;
+ break OL;
+ }
+ default:
+ {
+ helper$0 = 1;
+ }
}
}
- }
- if (helper$0) {
- helper$0 = 0;
- switch (helper$1 | 0) {
- case 2:
- {
- f(2);
- g();
- break;
- }
- default:
- {
- helper$0 = 1;
+ if (helper$0) {
+ helper$0 = 0;
+ switch (helper$1 | 0) {
+ case 2:
+ {
+ f(2);
+ g();
+ break;
+ }
+ default:
+ {
+ helper$0 = 1;
+ }
}
}
- }
+ } while (0);
HEAP32[sp + 8 >> 2] = helper$0;
}
diff --git a/tools/test-js-optimizer-asm-outline1.js b/tools/test-js-optimizer-asm-outline1.js
index 3c454182..4282ec8e 100644
--- a/tools/test-js-optimizer-asm-outline1.js
+++ b/tools/test-js-optimizer-asm-outline1.js
@@ -269,7 +269,7 @@ function switchh() {
case 1: {
f(1);
g();
- break;
+ return;
}
case 2: {
f(2);