aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc15
-rw-r--r--src/analyzer.js2
-rw-r--r--src/experimental/sdl_key_forwarding.diff57
-rw-r--r--src/library_browser.js25
-rw-r--r--src/library_sdl.js41
-rw-r--r--src/settings.js12
-rwxr-xr-xtests/runner.py50
-rw-r--r--tests/sdl_quit.c33
8 files changed, 194 insertions, 41 deletions
diff --git a/emcc b/emcc
index ace14ece..aa8827da 100755
--- a/emcc
+++ b/emcc
@@ -285,6 +285,17 @@ Options that are modified or new in %s include:
llvm-link's behavior is not as permissive
as ld is.
+ --clear-cache Manually clears the cache of compiled
+ emscripten system libraries (libc++,
+ libc++abi, dlmalloc). This is normally
+ handled automatically, but if you update
+ llvm in-place (instead of having a different
+ directory for a new version), the caching
+ mechanism can get confused. Clearing the
+ cache can fix weird problems related to
+ cache incompatibilities, like clang failing
+ to link with library files.
+
The target file, if specified (-o <target>), defines what will
be generated:
@@ -519,6 +530,10 @@ try:
elif newargs[i] == '--remove-duplicates':
remove_duplicates = True
newargs[i] = ''
+ elif newargs[i] == '--clear-cache':
+ newargs[i] = ''
+ print >> sys.stderr, 'emcc: clearing cache'
+ shared.Cache.erase()
elif newargs[i].startswith(('-I/', '-L/')):
print >> sys.stderr, 'emcc: warning: -I or -L of an absolute path encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' # Of course an absolute path to a non-system-specific library or header is fine, and you can ignore this warning. The danger are system headers that are e.g. x86 specific and nonportable. The emscripten bundled headers are modified to be portable, local system ones are generally not
newargs = [ arg for arg in newargs if arg is not '' ]
diff --git a/src/analyzer.js b/src/analyzer.js
index 9bf93c86..69b811f0 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -561,7 +561,7 @@ function analyzer(data, sidePass) {
var whole = shifts >= 0 ? Math.floor(shifts/32) : Math.ceil(shifts/32);
var fraction = Math.abs(shifts % 32);
if (signed) {
- var signedFill = '((' + sourceElements[sourceElements.length-1].ident + '|0) < 0 ? -1 : 0)';
+ var signedFill = '(' + makeSignOp(sourceElements[sourceElements.length-1].ident, 'i' + sourceElements[sourceElements.length-1].bits, 're', 1, 1) + ' < 0 ? -1 : 0)';
var signedKeepAlive = { intertype: 'value', ident: sourceElements[sourceElements.length-1].ident, type: 'i32' };
}
for (var j = 0; j < targetElements.length; j++) {
diff --git a/src/experimental/sdl_key_forwarding.diff b/src/experimental/sdl_key_forwarding.diff
new file mode 100644
index 00000000..395dc110
--- /dev/null
+++ b/src/experimental/sdl_key_forwarding.diff
@@ -0,0 +1,57 @@
+diff --git a/src/library_sdl.js b/src/library_sdl.js
+index 8cb8db7..d46a089 100644
+--- a/src/library_sdl.js
++++ b/src/library_sdl.js
+@@ -43,6 +43,7 @@ var LibrarySDL = {
+ DOMButtons: [0, 0, 0],
+
+ DOMEventToSDLEvent: {},
++ forwardedDOMKeys: {},
+
+ keyCodes: { // DOM code ==> SDL code. See https://developer.mozilla.org/en/Document_Object_Model_%28DOM%29/KeyboardEvent and SDL_keycode.h
+ 46: 127, // SDLK_DEL == '\177'
+@@ -372,6 +373,11 @@ var LibrarySDL = {
+ if (!SDL.DOMButtons[event.button]) return false; // ignore extra ups, can happen if we leave the canvas while pressing down, then return,
+ // since we add a mouseup in that case
+ SDL.DOMButtons[event.button] = 0;
++ } else if (event.type == 'keydown' || event.type == 'keyup') {
++ // whitelist a few keycodes that we do want to let the browser handle
++ if (event.keyCode in SDL.forwardedDOMKeys) {
++ return true;
++ }
+ }
+
+ SDL.events.push(event);
+@@ -399,6 +405,10 @@ var LibrarySDL = {
+ // Force-run a main event loop, since otherwise this event will never be caught!
+ Browser.mainLoop.runner();
+ return true;
++ case 'keypress':
++ if (event.ctrlKey) {
++ return true; // forward control-X events, see SDL.forwardedDOMKeys
++ }
+ }
+ return false;
+ },
+@@ -569,13 +579,20 @@ var LibrarySDL = {
+ window.onunload = SDL.receiveEvent;
+ SDL.keyboardState = _malloc(0x10000);
+ _memset(SDL.keyboardState, 0, 0x10000);
+- // Initialize this structure carefully for closure
++ // Initialize these structures carefully for closure
+ SDL.DOMEventToSDLEvent['keydown'] = 0x300 /* SDL_KEYDOWN */;
+ SDL.DOMEventToSDLEvent['keyup'] = 0x301 /* SDL_KEYUP */;
+ SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */;
+ SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */;
+ SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */;
+ SDL.DOMEventToSDLEvent['unload'] = 0x100 /* SDL_QUIT */;
++ SDL.forwardedDOMKeys[17] = 1; // control - forward control-X to keep the page responsive
++ SDL.forwardedDOMKeys[173] = 1; // minus (shrink view)
++ SDL.forwardedDOMKeys[61] = 1; // plus (expand view)
++ SDL.forwardedDOMKeys[48] = 1; // 0 (return view to normal)
++ SDL.forwardedDOMKeys[84] = 1; // t (new tab)
++ SDL.forwardedDOMKeys[87] = 1; // w (close tab)
++ SDL.forwardedDOMKeys[82] = 1; // r (reload)
+ return 0; // success
+ },
+
diff --git a/src/library_browser.js b/src/library_browser.js
index f3654f81..51c0cf78 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -133,8 +133,18 @@ mergeInto(LibraryManager.library, {
Module["preloadedAudios"][name] = audio;
if (onload) onload(byteArray);
}
+ function fail() {
+ if (done) return;
+ done = true;
+ Module["preloadedAudios"][name] = new Audio(); // empty shim
+ if (onerror) onerror();
+ }
if (Browser.hasBlobConstructor) {
- var b = new Blob([byteArray], { type: getMimetype(name) });
+ try {
+ var b = new Blob([byteArray], { type: getMimetype(name) });
+ } catch(e) {
+ return fail();
+ }
var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
var audio = new Audio();
audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
@@ -174,8 +184,7 @@ mergeInto(LibraryManager.library, {
finish(audio); // try to use it even though it is not necessarily ready to play
}, 10000);
} else {
- Module["preloadedAudios"][name] = new Audio(); // empty shim
- if (onerror) onerror();
+ return fail();
}
};
Module['preloadPlugins'].push(audioPlugin);
@@ -252,7 +261,7 @@ mergeInto(LibraryManager.library, {
},
requestFullScreen: function() {
- var canvas = Module.canvas;
+ var canvas = Module['canvas'];
function fullScreenChange() {
var isFullScreen = false;
if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
@@ -375,7 +384,7 @@ mergeInto(LibraryManager.library, {
Module['noExitRuntime'] = true;
var jsFunc = FUNCTION_TABLE[func];
- var wrapper = function() {
+ Browser.mainLoop.runner = function() {
if (Browser.mainLoop.queue.length > 0) {
var start = Date.now();
var blocker = Browser.mainLoop.queue.shift();
@@ -393,7 +402,7 @@ mergeInto(LibraryManager.library, {
}
console.log('main loop blocker "' + blocker.name + '" took ' + (Date.now() - start) + ' ms'); //, left: ' + Browser.mainLoop.remainingBlockers);
Browser.mainLoop.updateStatus();
- setTimeout(wrapper, 0);
+ setTimeout(Browser.mainLoop.runner, 0);
return;
}
if (Browser.mainLoop.shouldPause) {
@@ -427,11 +436,11 @@ mergeInto(LibraryManager.library, {
}
if (fps && fps > 0) {
Browser.mainLoop.scheduler = function() {
- setTimeout(wrapper, 1000/fps); // doing this each time means that on exception, we stop
+ setTimeout(Browser.mainLoop.runner, 1000/fps); // doing this each time means that on exception, we stop
}
} else {
Browser.mainLoop.scheduler = function() {
- Browser.requestAnimationFrame(wrapper);
+ Browser.requestAnimationFrame(Browser.mainLoop.runner);
}
}
Browser.mainLoop.scheduler();
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 580330e8..8cb8db72 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -350,11 +350,19 @@ var LibrarySDL = {
event['movementX'] = event['mozMovementX'];
event['movementY'] = event['mozMovementY'];
// fall through
- case 'keydown': case 'keyup': case 'mousedown': case 'mouseup': case 'DOMMouseScroll':
- if (event.type == 'DOMMouseScroll') {
- event = {
+ case 'keydown': case 'keyup': case 'mousedown': case 'mouseup': case 'DOMMouseScroll': case 'mousewheel':
+ if (event.type == 'DOMMouseScroll' || event.type == 'mousewheel') {
+ var button = (event.type == 'DOMMouseScroll' ? event.detail : -event.wheelDelta) > 0 ? 4 : 3;
+ var event2 = {
type: 'mousedown',
- button: event.detail > 0 ? 4 : 3,
+ button: button,
+ pageX: event.pageX,
+ pageY: event.pageY
+ };
+ SDL.events.push(event2);
+ event = {
+ type: 'mouseup',
+ button: button,
pageX: event.pageX,
pageY: event.pageY
};
@@ -371,11 +379,6 @@ var LibrarySDL = {
Module.printErr('SDL event queue full, dropping earliest event');
SDL.events.shift();
}
- if ((event.keyCode >= 37 && event.keyCode <= 40) || // arrow keys
- event.keyCode == 32 || // space
- event.keyCode == 33 || event.keyCode == 34) { // page up/down
- event.preventDefault();
- }
break;
case 'mouseout':
// Un-press all pressed mouse buttons, because we might miss the release outside of the canvas
@@ -391,6 +394,11 @@ var LibrarySDL = {
}
}
break;
+ case 'unload':
+ SDL.events.push(event);
+ // Force-run a main event loop, since otherwise this event will never be caught!
+ Browser.mainLoop.runner();
+ return true;
}
return false;
},
@@ -485,6 +493,10 @@ var LibrarySDL = {
SDL.mouseY = y;
break;
}
+ case 'unload': {
+ {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ break;
+ }
default: throw 'Unhandled SDL event: ' + event.type;
}
},
@@ -550,9 +562,11 @@ var LibrarySDL = {
SDL_Init: function(what) {
SDL.startTime = Date.now();
- ['keydown', 'keyup'].forEach(function(event) {
- addEventListener(event, SDL.receiveEvent, true);
- });
+ // capture all key events. we just keep down and up, but also capture press to prevent default actions
+ document.onkeydown = SDL.receiveEvent;
+ document.onkeyup = SDL.receiveEvent;
+ document.onkeypress = SDL.receiveEvent;
+ window.onunload = SDL.receiveEvent;
SDL.keyboardState = _malloc(0x10000);
_memset(SDL.keyboardState, 0, 0x10000);
// Initialize this structure carefully for closure
@@ -561,6 +575,7 @@ var LibrarySDL = {
SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */;
SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */;
SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */;
+ SDL.DOMEventToSDLEvent['unload'] = 0x100 /* SDL_QUIT */;
return 0; // success
},
@@ -619,7 +634,7 @@ var LibrarySDL = {
},
SDL_SetVideoMode: function(width, height, depth, flags) {
- ['mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mouseout'].forEach(function(event) {
+ ['mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'mouseout'].forEach(function(event) {
Module['canvas'].addEventListener(event, SDL.receiveEvent, true);
});
Module['canvas'].width = width;
diff --git a/src/settings.js b/src/settings.js
index cf329568..9f63622d 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -5,6 +5,7 @@
//
// emcc -s OPTION1=VALUE1 -s OPTION2=VALUE2 [..other stuff..]
//
+// See https://github.com/kripken/emscripten/wiki/Code-Generation-Modes/
// Tuning
var QUANTUM_SIZE = 4; // This is the size of an individual field in a structure. 1 would
@@ -51,15 +52,10 @@ var FAST_MEMORY = 2*1024*1024; // The amount of memory to initialize to 0. This
// Code embetterments
var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables
var RELOOP = 0; // Recreate js native loops from llvm data
-var USE_TYPED_ARRAYS = 2; // Use typed arrays for the heap
+var USE_TYPED_ARRAYS = 2; // Use typed arrays for the heap. See https://github.com/kripken/emscripten/wiki/Code-Generation-Modes/
// 1 has two heaps, IHEAP (int32) and FHEAP (double),
- // and addresses there are a match for normal addresses. This wastes memory but can be fast.
- // 2 is a single heap, accessible through views as int8, int32, etc. This saves memory but
- // has more overhead of pointer calculations. It also is limited to storing doubles as floats,
- // simply because double stores are not necessarily 64-bit aligned, and we can only access
- // 64-bit aligned values with a 64-bit typed array. Likewise int64s are stored as int32's,
- // which is potentially very dangerous!
- // TODO: require compiling with -malign-double, which does align doubles
+ // and addresses there are a match for normal addresses.
+ // 2 is a single heap, accessible through views as int8, int32, etc.
var USE_FHEAP = 1; // Relevant in USE_TYPED_ARRAYS == 1. If this is disabled, only IHEAP will be used, and FHEAP
// not generated at all. This is useful if your code is 100% ints without floats or doubles
var DOUBLE_MODE = 1; // How to load and store 64-bit doubles. Without typed arrays or in typed array mode 1,
diff --git a/tests/runner.py b/tests/runner.py
index 563f6bc1..54ae5a49 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -953,6 +953,22 @@ m_divisor is 1091269979
'''
self.do_run(src, 'zero 2, 104', ['hallo'])
+ def test_i64_i16(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+ int main(int argc, char ** argv){
+ int y=-133;
+ __int64_t x= ((__int64_t)((short)(y)))*(100 + argc);
+ if(x>0)
+ printf(">0\n");
+ else
+ printf("<=0\n");
+ }
+ '''
+ self.do_run(src, '<=0')
+
def test_i32_mul_precise(self):
if self.emcc_args == None: return self.skip('needs ta2')
@@ -4023,7 +4039,7 @@ at function.:blag
self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
def test_atoX(self):
- if Settings.QUANTUM_SIZE != 4: return self.skip('need q4 for atoll')
+ if self.emcc_args is None: return self.skip('requires ta2')
src = r'''
#include <stdio.h>
@@ -7633,15 +7649,17 @@ elif 'browser' in str(sys.argv):
print '(moving on..)'
def with_report_result(self, code):
- return code.replace('REPORT_RESULT();', '''
- char output[1000];
- sprintf(output,
- "xhr = new XMLHttpRequest();"
- "xhr.open('GET', 'http://localhost:8888/report_result?%d');"
- "xhr.send();", result);
- emscripten_run_script(output);
+ return '''
+ #define REPORT_RESULT_INTERNAL(sync) \
+ char output[1000]; \
+ sprintf(output, \
+ "xhr = new XMLHttpRequest();" \
+ "xhr.open('GET', 'http://localhost:8888/report_result?%d'%s);" \
+ "xhr.send();", result, sync ? ", false" : ""); \
+ emscripten_run_script(output); \
emscripten_run_script("setTimeout(function() { window.close() }, 1000)");
-''')
+ #define REPORT_RESULT() REPORT_RESULT_INTERNAL(0)
+''' + code
def reftest(self, expected):
basename = os.path.basename(expected)
@@ -7917,12 +7935,12 @@ elif 'browser' in str(sys.argv):
event.initKeyEvent("keydown", true, true, window,
0, 0, 0, 0,
c, c);
- dispatchEvent(event);
+ document.dispatchEvent(event);
var event2 = document.createEvent("KeyboardEvent");
event2.initKeyEvent("keyup", true, true, window,
0, 0, 0, 0,
c, c);
- dispatchEvent(event2);
+ document.dispatchEvent(event2);
}
''')
open(os.path.join(self.get_dir(), 'sdl_key.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_key.c')).read()))
@@ -8141,6 +8159,9 @@ elif 'browser' in str(sys.argv):
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) # preloaded *after* run
self.btest('emscripten_fs_api_browser.cpp', '1')
+ def test_sdl_quit(self):
+ self.btest('sdl_quit.c', '1')
+
def test_gc(self):
self.btest('browser_gc.cpp', '1')
@@ -8782,6 +8803,7 @@ elif 'sanity' in str(sys.argv):
def test_emcc_caching(self):
INCLUDING_MESSAGE = 'emcc: including X'
BUILDING_MESSAGE = 'emcc: building X for cache'
+ ERASING_MESSAGE = 'emcc: clearing cache'
EMCC_CACHE = Cache.dirname
@@ -8829,6 +8851,12 @@ elif 'sanity' in str(sys.argv):
if emcc_debug:
os.environ['EMCC_DEBUG'] = emcc_debug
+ # Manual cache clearing
+ assert os.path.exists(EMCC_CACHE)
+ output = self.do([EMCC, '--clear-cache'])
+ assert ERASING_MESSAGE in output
+ assert not os.path.exists(EMCC_CACHE)
+
else:
raise Exception('Test runner is confused: ' + str(sys.argv))
diff --git a/tests/sdl_quit.c b/tests/sdl_quit.c
new file mode 100644
index 00000000..1a07526f
--- /dev/null
+++ b/tests/sdl_quit.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_ttf.h>
+#include <assert.h>
+#include <emscripten.h>
+
+int result = 0;
+
+void one() {
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ switch(event.type) {
+ case SDL_QUIT: {
+ if (!result) { // prevent infinite recursion since REPORT_RESULT does window.close too.
+ result = 1;
+ REPORT_RESULT_INTERNAL(1);
+ }
+ }
+ }
+ }
+}
+
+void main_2();
+
+int main() {
+ SDL_Init(SDL_INIT_VIDEO);
+ SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE);
+
+ emscripten_set_main_loop(one, 0);
+
+ emscripten_run_script("setTimeout(function() { window.close() }, 2000)");
+}
+