aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
11 files changed, 159 insertions, 38 deletions
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>