diff options
-rw-r--r-- | AUTHORS | 4 | ||||
-rwxr-xr-x | emcc | 21 | ||||
-rw-r--r-- | src/compiler.js | 1 | ||||
-rw-r--r-- | src/intertyper.js | 147 | ||||
-rw-r--r-- | src/jsifier.js | 5 | ||||
-rw-r--r-- | src/library_fs.js | 34 | ||||
-rw-r--r-- | src/library_gl.js | 6 | ||||
-rw-r--r-- | src/library_glut.js | 37 | ||||
-rw-r--r-- | src/library_sdl.js | 2 | ||||
-rw-r--r-- | src/preamble.js | 25 | ||||
-rw-r--r-- | src/proxyClient.js | 10 | ||||
-rw-r--r-- | tests/cases/ctors_cast.ll | 49 | ||||
-rw-r--r-- | tests/cases/ctors_cast.txt | 3 | ||||
-rw-r--r-- | tests/glut_wheelevents.c | 68 | ||||
-rw-r--r-- | tests/sdl_rotozoom.c | 2 | ||||
-rw-r--r-- | tests/sdl_rotozoom.png | bin | 431168 -> 711242 bytes | |||
-rw-r--r-- | tests/test_browser.py | 5 | ||||
-rw-r--r-- | tests/test_core.py | 10 | ||||
-rw-r--r-- | tests/test_other.py | 27 | ||||
-rw-r--r-- | tools/autodebugger.py | 4 |
20 files changed, 347 insertions, 113 deletions
@@ -99,4 +99,8 @@ a license to everyone to use it as detailed in LICENSE.) * Tobias Vrinssen <tobias@vrinssen.de> * Patrick R. Martin <patrick.martin.r@gmail.com> * Richard Quirk <richard.quirk@gmail.com> +* Marcos Scriven <marcos@scriven.org> +* Antoine Lambert <antoine.lambert33@gmail.com> +* Daniel Aquino <mr.danielaquino@gmail.com> * Remi Papillie <remi.papillie@gmail.com> + @@ -127,7 +127,11 @@ Most normal gcc/g++ options will work, for example: --version Display compiler version information Options that are modified or new in %s include: - -O0 No optimizations (default) + + -O0 No optimizations (default). This is the recommended + setting for starting to port a project, as it + includes various assertions. + -O1 Simple optimizations, including asm.js, LLVM -O1 optimizations, relooping, and no runtime assertions or C++ exception catching (to re-enable @@ -136,11 +140,20 @@ Options that are modified or new in %s include: -s ALIASING_FUNCTION_POINTERS=1 - (For details on the affects of different + This is the recommended setting when you want a + reasonably optimized build that is generated as + quickly as possible (it is much faster than -O2). + + (Note: for details on the affects of different opt levels, see apply_opt_level() in tools/shared.py and also src/settings.js.) + -O2 As -O1, plus various js-level optimizations and - LLVM -O3 optimizations + LLVM -O3 optimizations. This is the recommended + setting for a release build: slower compilation + time in return for the smallest and fastest + output. + -O3 As -O2, plus dangerous optimizations that may break the generated code! This adds @@ -1231,7 +1244,7 @@ try: file_suffix = filename_type_suffix(input_file) if file_suffix.endswith(SOURCE_SUFFIXES): temp_file = temp_files[i] - logging.debug('optimizing %s with -O%d' % (input_file, llvm_opts)) + logging.debug('optimizing %s with -O%s' % (input_file, llvm_opts)) shared.Building.llvm_opt(temp_file, llvm_opts) # If we were just asked to generate bitcode, stop there diff --git a/src/compiler.js b/src/compiler.js index d490f454..ac1b0ec8 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -318,4 +318,5 @@ if (ll_file) { //var M = keys(tokenCacheMisses).map(function(m) { return [m, misses[m]] }).sort(function(a, b) { return a[1] - b[1] }); //printErr(dump(M.slice(M.length-10))); +//printErr('hits: ' + hits); diff --git a/src/intertyper.js b/src/intertyper.js index 781c8187..9414a1d4 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -6,12 +6,12 @@ var fastPaths = 0, slowPaths = 0; var tokenCache = {}; -['=', 'i32', 'label', ';', '4', '0', '1', '2', '255', 'align', 'i8*', 'i8', 'i16', 'getelementptr', 'inbounds', 'unnamed_addr', 'x', 'load', 'preds', 'br', 'i32*', 'i1', 'store', '<label>', 'constant', 'c', 'private', 'null', 'internal', 'to', 'bitcast', 'define', 'nounwind', 'nocapture', '%this', 'call', '...'].forEach(function(text) { tokenCache[text] = { text: text } }); +[',', 'i32', 'label', ';', '4', '0', '1', '2', '255', 'align', 'i8*', 'i8', 'i16', 'getelementptr', 'inbounds', 'unnamed_addr', 'x', 'load', 'preds', 'br', 'i32*', 'i1', 'store', '<label>', 'constant', 'c', 'private', 'null', 'internal', 'to', 'bitcast', 'define', 'nounwind', 'nocapture', '%this', 'call', '...'].forEach(function(text) { tokenCache[text] = { text: text } }); //var tokenCacheMisses = {}; // Line tokenizer -function tokenize(text, lineNum) { +function tokenize(text, lineNum, indent) { var tokens = []; var quotes = 0; var lastToken = null; @@ -63,12 +63,7 @@ function tokenize(text, lineNum) { tokens.splice(openBrace, tokens.length-openBrace+1); tokens.push(token); token.type = '{'; - token.text = '{ ' + token.text + ' }'; - var pointingLevelsToAdd = pointingLevels(text) - pointingLevels(token.text); - while (pointingLevelsToAdd > 0) { - token.text += '*'; - pointingLevelsToAdd--; - } + token.text = '{ ' + token.text + ' ' + text; lastToken = token; } else { tokens.push(token); @@ -82,78 +77,67 @@ function tokenize(text, lineNum) { segments.pop(); var len = segments.length; var i = -1; - var curr = ''; + var start = 0; var segment, letter; for (var s = 0; s < len; s++) { segment = segments[s]; i += segment.length + 1; letter = lineText[i]; - curr += segment; switch (letter) { case ' ': if (totalEnclosing == 0 && quotes == 0) { - makeToken(curr); - curr = ''; + makeToken(lineText.substring(start, i)); + start = i+1; } else { - curr += ' '; } break; case '"': if (totalEnclosing == 0) { if (quotes == 0) { - if (curr == '@' || curr == '%') { - curr += '"'; + if (start === i-1 && (lineText[start] == '@' || lineText[start] == '%')) { } else { - makeToken(curr); - curr = '"'; + makeToken(lineText.substring(start, i)); + start = i; } } else { - makeToken(curr + '"'); - curr = ''; + makeToken(lineText.substring(start, i+1)); + start = i+1; } - } else { - curr += '"'; } quotes = 1-quotes; break; case ',': if (totalEnclosing == 0 && quotes == 0) { - makeToken(curr); - curr = ''; - tokens.push({ text: ',' }); - } else { - curr += ','; + makeToken(lineText.substring(start, i)); + start = i+1; + tokens.push(tokenCache[',']); } break; default: assert(letter in enclosers); if (quotes) { - curr += letter; break; } if (letter in ENCLOSER_STARTERS) { if (totalEnclosing == 0) { - makeToken(curr); - curr = ''; + makeToken(lineText.substring(start, i)); + start = i; } - curr += letter; enclosers[letter]++; totalEnclosing++; } else { enclosers[enclosers[letter]]--; totalEnclosing--; if (totalEnclosing == 0) { - makeToken(curr + letter); - curr = ''; - } else { - curr += letter; + makeToken(lineText.substring(start, i+1)); + start = i+1; } } } } var newItem = { tokens: tokens, - indent: lineText.search(/[^ ]/), + indent: indent || lineText.search(/[^ ]/), lineNum: lineNum || 0 }; return newItem; @@ -291,10 +275,6 @@ function intertyper(lines, sidePass, baseLineNums) { function triager(item) { assert(!item.intertype); - if (item.indent == 2 && (eq = findTokenText(item, '=')) >= 0) { - item.assignTo = toNiceIdent(combineTokens(item.tokens.slice(0, eq)).text); - item.tokens = item.tokens.slice(eq+1); - } var token0Text = item.tokens[0].text; var token1Text = item.tokens[1] ? item.tokens[1].text : null; var tokensLength = item.tokens.length; @@ -345,7 +325,7 @@ function intertyper(lines, sidePass, baseLineNums) { return labelHandler(item); if (tokensLength >= 4 && token0Text == 'declare') return externalHandler(item); - if (tokensLength >= 3 && token1Text == '=') + if (item.assignTo) return globalHandler(item); if (tokensLength >= 4 && token0Text == 'define' && item.tokens.slice(-1)[0].text == '{') @@ -458,15 +438,15 @@ function intertyper(lines, sidePass, baseLineNums) { } } - cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 2); - if (item.tokens[2].text == 'alias') { - cleanOutTokens(LLVM.LINKAGES, item.tokens, 3); - cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 3); + cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 0); + if (item.tokens[0].text == 'alias') { + cleanOutTokens(LLVM.LINKAGES, item.tokens, 1); + cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 1); var last = getTokenIndexByText(item.tokens, ';'); var ret = { intertype: 'alias', - ident: toNiceIdent(item.tokens[0].text), - value: parseLLVMSegment(item.tokens.slice(3, last)), + ident: item.assignTo, + value: parseLLVMSegment(item.tokens.slice(1, last)), lineNum: item.lineNum }; ret.type = ret.value.type; @@ -476,18 +456,18 @@ function intertyper(lines, sidePass, baseLineNums) { } return ret; } - if (item.tokens[2].text == 'type') { + if (item.tokens[0].text == 'type') { var fields = []; var packed = false; - if (Runtime.isNumberType(item.tokens[3].text)) { + if (Runtime.isNumberType(item.tokens[1].text)) { // Clang sometimes has |= i32| instead of |= { i32 }| - fields = [item.tokens[3].text]; - } else if (item.tokens[3].text != 'opaque') { - if (item.tokens[3].type == '<') { + fields = [item.tokens[1].text]; + } else if (item.tokens[1].text != 'opaque') { + if (item.tokens[1].type == '<') { packed = true; - item.tokens[3] = item.tokens[3].item.tokens[0]; + item.tokens[1] = item.tokens[1].item.tokens[0]; } - var subTokens = item.tokens[3].tokens; + var subTokens = item.tokens[1].tokens; if (subTokens) { subTokens.push({text:','}); while (subTokens[0]) { @@ -500,38 +480,40 @@ function intertyper(lines, sidePass, baseLineNums) { } return { intertype: 'type', - name_: item.tokens[0].text, + name_: item.assignTo, fields: fields, packed: packed, lineNum: item.lineNum }; } else { // variable - var ident = item.tokens[0].text; + var ident = item.assignTo; var private_ = findTokenText(item, 'private') >= 0 || findTokenText(item, 'internal') >= 0; var named = findTokenText(item, 'unnamed_addr') < 0; - cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [2, 3]); + cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [0, 1]); var external = false; - if (item.tokens[2].text === 'external') { + if (item.tokens[0].text === 'external') { external = true; - item.tokens.splice(2, 1); + item.tokens.splice(0, 1); } var ret = { intertype: 'globalVariable', - ident: toNiceIdent(ident), - type: item.tokens[2].text, + ident: ident, + type: item.tokens[0].text, external: external, private_: private_, named: named, lineNum: item.lineNum }; noteGlobalVariable(ret); - if (ident == '@llvm.global_ctors') { + if (ident == '_llvm_global_ctors') { ret.ctors = []; - if (item.tokens[3].item) { - var subTokens = item.tokens[3].item.tokens; + if (item.tokens[1].item) { + var subTokens = item.tokens[1].item.tokens; splitTokenList(subTokens).forEach(function(segment) { - var ctor = toNiceIdent(segment[1].tokens.slice(-1)[0].text); + var parsed = parseLLVMSegment(segment); + assert(parsed.intertype === 'structvalue'); + var ctor = toNiceIdent(parsed.params[1].ident); ret.ctors.push(ctor); if (ASM_JS) { // must export the global constructors from asm.js module, so mark as implemented and exported Functions.implementedFunctions[ctor] = 'v'; @@ -540,14 +522,14 @@ function intertyper(lines, sidePass, baseLineNums) { }); } } else if (!external) { - if (item.tokens[3] && item.tokens[3].text != ';') { - if (item.tokens[3].text == 'c') { - item.tokens.splice(3, 1); + if (item.tokens[1] && item.tokens[1].text != ';') { + if (item.tokens[1].text == 'c') { + item.tokens.splice(1, 1); } - if (item.tokens[3].text in PARSABLE_LLVM_FUNCTIONS) { - ret.value = parseLLVMFunctionCall(item.tokens.slice(2)); + if (item.tokens[1].text in PARSABLE_LLVM_FUNCTIONS) { + ret.value = parseLLVMFunctionCall(item.tokens); } else { - ret.value = scanConst(item.tokens[3], ret.type); + ret.value = scanConst(item.tokens[1], ret.type); } } else { ret.value = { intertype: 'value', ident: '0', value: '0', type: ret.type }; @@ -1131,7 +1113,27 @@ function intertyper(lines, sidePass, baseLineNums) { //var time = Date.now(); - var t = tokenize(line.lineText, line.lineNum); + // parse out the assignment + var indent = 0, assignTo = null; + if (phase === 'pre') { + var m = /^([%@\w\d\._\-]+|[%@]"[^"]+") = (.*)/.exec(line.lineText); + if (m) { + assignTo = m[1]; + line.lineText = m[2]; + } + } else if (phase === 'funcs') { + var m = /^ ([%@\w\d\._\-]+|[%@]"[^"]+") = (.*)/.exec(line.lineText); + if (m) { + indent = 2; + assignTo = m[1]; + line.lineText = m[2]; + } + } + + var t = tokenize(line.lineText, line.lineNum, indent); + if (assignTo) { + t.assignTo = t.tokens[0].text !== 'type' ? toNiceIdent(assignTo) : assignTo; + } item = triager(t); /* @@ -1148,7 +1150,7 @@ function intertyper(lines, sidePass, baseLineNums) { return finalResults; } -// intertyper profiler +// intertyper profiling /* var interProf = {}; @@ -1156,4 +1158,5 @@ function dumpInterProf() { printErr('\nintertyper/' + phase + ' (ms | n): ' + JSON.stringify(keys(interProf).sort(function(x, y) { return interProf[y].ms - interProf[x].ms }).map(function(x) { return x + ' : ' + interProf[x].ms + ' | ' + interProf[x].n }), null, ' ') + '\n'); } */ +//var hits = 0; diff --git a/src/jsifier.js b/src/jsifier.js index a126994b..e84de3ee 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -407,6 +407,9 @@ function JSify(data, functionsOnly, givenFunctions) { var snippet = LibraryManager.library[ident]; var redirectedIdent = null; var deps = LibraryManager.library[ident + '__deps'] || []; + deps.forEach(function(dep) { + if (typeof snippet === 'string' && !(dep in LibraryManager.library)) warn('missing library dependency ' + dep + ', make sure you are compiling with the right options (see #ifdefs in src/library*.js)'); + }); var isFunction = false; if (typeof snippet === 'string') { @@ -1372,7 +1375,7 @@ function JSify(data, functionsOnly, givenFunctions) { // store current list offset in tempInt, advance list offset by STACK_ALIGN, return list entry stored at tempInt return '(tempInt=' + makeGetValue(ident, Runtime.QUANTUM_SIZE, '*') + ',' + - makeSetValue(ident, Runtime.QUANTUM_SIZE, 'tempInt + ' + move, '*') + ',' + + makeSetValue(ident, Runtime.QUANTUM_SIZE, 'tempInt + ' + move, '*', null, null, null, null, ',') + ',' + makeGetValue(makeGetValue(ident, 0, '*'), 'tempInt', item.type) + ')'; } diff --git a/src/library_fs.js b/src/library_fs.js index 5adbe6b7..bd1522a8 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -1,5 +1,5 @@ mergeInto(LibraryManager.library, { - $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$VFS', '$PATH', '$TTY', '$MEMFS', '$IDBFS', '$NODEFS', 'stdin', 'stdout', 'stderr', 'fflush'], + $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$PATH', '$TTY', '$MEMFS', '$IDBFS', '$NODEFS', 'stdin', 'stdout', 'stderr', 'fflush'], $FS__postset: 'FS.staticInit();' + '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' + '__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });' + @@ -1064,19 +1064,8 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue(makeGlobalUse('_stderr'), 0, 'stderr.fd', 'void*') }}}; assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')'); }, - staticInit: function() { - FS.nameTable = new Array(4096); - - FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0); - FS.mount(MEMFS, {}, '/'); - - FS.createDefaultDirectories(); - FS.createDefaultDevices(); - }, - init: function(input, output, error) { - assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'); - FS.init.initialized = true; - + ensureErrnoError: function() { + if (FS.ErrnoError) return; FS.ErrnoError = function ErrnoError(errno) { this.errno = errno; for (var key in ERRNO_CODES) { @@ -1090,6 +1079,23 @@ mergeInto(LibraryManager.library, { }; FS.ErrnoError.prototype = new Error(); FS.ErrnoError.prototype.constructor = FS.ErrnoError; + }, + staticInit: function() { + FS.ensureErrnoError(); + + FS.nameTable = new Array(4096); + + FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0); + FS.mount(MEMFS, {}, '/'); + + FS.createDefaultDirectories(); + FS.createDefaultDevices(); + }, + init: function(input, output, error) { + assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'); + FS.init.initialized = true; + + FS.ensureErrnoError(); // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here Module['stdin'] = input || Module['stdin']; diff --git a/src/library_gl.js b/src/library_gl.js index 6e0e04dc..1ea8efc2 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -4047,7 +4047,10 @@ var LibraryGL = { _glColor4f({{{ makeGetValue('p', '0', 'float') }}}, {{{ makeGetValue('p', '4', 'float') }}}, {{{ makeGetValue('p', '8', 'float') }}}, {{{ makeGetValue('p', '12', 'float') }}}); }, - glColor4ubv: function() { throw 'glColor4ubv not implemented' }, + glColor4ubv__deps: ['glColor4ub'], + glColor4ubv: function(p) { + _glColor4ub({{{ makeGetValue('p', '0', 'i8') }}}, {{{ makeGetValue('p', '1', 'i8') }}}, {{{ makeGetValue('p', '2', 'i8') }}}, {{{ makeGetValue('p', '3', 'i8') }}}); + }, glFogf: function(pname, param) { // partial support, TODO switch(pname) { @@ -4470,6 +4473,7 @@ var LibraryGL = { return 1 /* GL_TRUE */; }, + gluOrtho2D__deps: ['glOrtho'], gluOrtho2D: function(left, right, bottom, top) { _glOrtho(left, right, bottom, top, -1, 1); }, diff --git a/src/library_glut.js b/src/library_glut.js index 79c586c6..722ea85c 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -190,12 +190,12 @@ var LibraryGLUT = { } }, - onMouseButtonDown: function(event){ + onMouseButtonDown: function(event) { Browser.calculateMouseEvent(event); GLUT.buttons |= (1 << event['button']); - if(event.target == Module["canvas"] && GLUT.mouseFunc){ + if (event.target == Module["canvas"] && GLUT.mouseFunc) { try { event.target.setCapture(); } catch (e) {} @@ -205,21 +205,40 @@ var LibraryGLUT = { } }, - onMouseButtonUp: function(event){ + onMouseButtonUp: function(event) { Browser.calculateMouseEvent(event); GLUT.buttons &= ~(1 << event['button']); - if(GLUT.mouseFunc) { + if (GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); Runtime.dynCall('viiii', GLUT.mouseFunc, [event['button'], 1/*GLUT_UP*/, Browser.mouseX, Browser.mouseY]); } }, + onMouseWheel: function(event) { + Browser.calculateMouseEvent(event); + + // cross-browser wheel delta + var e = window.event || event; // old IE support + var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); + + var button = 3; // wheel up + if (delta < 0) { + button = 4; // wheel down + } + + if (GLUT.mouseFunc) { + event.preventDefault(); + GLUT.saveModifiers(event); + Runtime.dynCall('viiii', GLUT.mouseFunc, [button, 0/*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY]); + } + }, + // TODO add fullscreen API ala: // http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/ - onFullScreenEventChange: function(event){ + onFullScreenEventChange: function(event) { var width; var height; if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) { @@ -280,6 +299,10 @@ var LibraryGLUT = { window.addEventListener("mousemove", GLUT.onMousemove, true); window.addEventListener("mousedown", GLUT.onMouseButtonDown, true); window.addEventListener("mouseup", GLUT.onMouseButtonUp, true); + // IE9, Chrome, Safari, Opera + window.addEventListener("mousewheel", GLUT.onMouseWheel, true); + // Firefox + window.addEventListener("DOMMouseScroll", GLUT.onMouseWheel, true); } Browser.resizeListeners.push(function(width, height) { @@ -299,6 +322,10 @@ var LibraryGLUT = { window.removeEventListener("mousemove", GLUT.onMousemove, true); window.removeEventListener("mousedown", GLUT.onMouseButtonDown, true); window.removeEventListener("mouseup", GLUT.onMouseButtonUp, true); + // IE9, Chrome, Safari, Opera + window.removeEventListener("mousewheel", GLUT.onMouseWheel, true); + // Firefox + window.removeEventListener("DOMMouseScroll", GLUT.onMouseWheel, true); } Module["canvas"].width = Module["canvas"].height = 1; } }); diff --git a/src/library_sdl.js b/src/library_sdl.js index bb7e9264..a0689343 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1149,7 +1149,7 @@ var LibrarySDL = { var ret = SDL.makeSurface(diagonal, diagonal, srcData.flags, false, 'rotozoomSurface'); var dstData = SDL.surfaces[ret]; dstData.ctx.translate(diagonal / 2, diagonal / 2); - dstData.ctx.rotate(angle * Math.PI / 180); + dstData.ctx.rotate(-angle * Math.PI / 180); dstData.ctx.drawImage(srcData.canvas, -w / 2, -h / 2, w, h); return ret; }, diff --git a/src/preamble.js b/src/preamble.js index 33e80217..ee273f6a 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -656,7 +656,16 @@ function demangle(func) { 'i': 'int', 'l': 'long', 'f': 'float', - 'd': 'double' + 'd': 'double', + 'w': 'wchar_t', + 'a': 'signed char', + 'h': 'unsigned char', + 't': 'unsigned short', + 'j': 'unsigned int', + 'm': 'unsigned long', + 'x': 'long long', + 'y': 'unsigned long long', + 'z': '...' }; function dump(x) { //return; @@ -729,6 +738,7 @@ function demangle(func) { } else { switch (c) { case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer + case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference case 'L': { // literal i++; // skip basic type var end = func.indexOf('E', i); @@ -737,6 +747,14 @@ function demangle(func) { i += size + 2; // size + 'EE' break; } + case 'A': { // array + var size = parseInt(func.substr(i)); + i += size.toString().length; + if (func[i] !== '_') throw '?'; + i++; // skip _ + list.push(parse(true, 1, true)[0] + ' [' + size + ']'); + break; + } case 'E': break paramLoop; default: ret += '?' + c; break paramLoop; } @@ -752,11 +770,12 @@ function demangle(func) { } function demangleAll(text) { - return text.replace(/__Z[\w\d_]+/, function(x) { var y = demangle(x); return x === y ? x : (x + ' (' + y + ')') }); + return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') }); } function stackTrace() { - return demangleAll(new Error().stack); + var stack = new Error().stack; + return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6. } // Memory management diff --git a/src/proxyClient.js b/src/proxyClient.js index 04f7ed11..38ea5771 100644 --- a/src/proxyClient.js +++ b/src/proxyClient.js @@ -30,7 +30,15 @@ worker.onmessage = function(event) { break; } case 'render': { - Module.canvasData.data.set(data.image.data); + var src = data.image.data; + var dst = Module.canvasData.data; + if (dst.set) { + dst.set(src); + } else { + for (var i = 0; i < src.length; i++) { + dst[i] = src[i]; + } + } Module.ctx.putImageData(Module.canvasData, 0, 0); break; } diff --git a/tests/cases/ctors_cast.ll b/tests/cases/ctors_cast.ll new file mode 100644 index 00000000..d94b1d63 --- /dev/null +++ b/tests/cases/ctors_cast.ll @@ -0,0 +1,49 @@ +; ModuleID = '/tmp/tmpHcVUBJ/a.out.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" + +%struct.Other = type { i8 } + +@.str = private unnamed_addr constant [17 x i8] c"autorun called!\0A\00", align 1 +@other = internal global %struct.Other zeroinitializer, align 1 +@.str1 = private unnamed_addr constant [14 x i8] c"main called!\0A\00", align 1 +@.str2 = private unnamed_addr constant [7 x i8] c"Other\0A\00", align 1 +@llvm.global_ctors = appending global [2 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* bitcast (i32 ()* @_Z7autorunv to void ()*) }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] + +define internal i32 @_Z7autorunv() { + %1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([17 x i8]* @.str, i32 0, i32 0)) + ret i32 0 +} + +declare i32 @printf(i8*, ...) + +define internal void @__cxx_global_var_init() { + call void @_ZN5OtherC1Ev(%struct.Other* @other) + ret void +} + +define internal void @_ZN5OtherC1Ev(%struct.Other* %this) unnamed_addr align 2 { + %1 = alloca %struct.Other*, align 4 + store %struct.Other* %this, %struct.Other** %1, align 4 + %2 = load %struct.Other** %1 + call void @_ZN5OtherC2Ev(%struct.Other* %2) + ret void +} + +define i32 @main() { + %1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([14 x i8]* @.str1, i32 0, i32 0)) + ret i32 0 +} + +define internal void @_ZN5OtherC2Ev(%struct.Other* %this) unnamed_addr align 2 { + %1 = alloca %struct.Other*, align 4 + store %struct.Other* %this, %struct.Other** %1, align 4 + %2 = load %struct.Other** %1 + %3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([7 x i8]* @.str2, i32 0, i32 0)) + ret void +} + +define internal void @_GLOBAL__I_a() { + call void @__cxx_global_var_init() + ret void +} diff --git a/tests/cases/ctors_cast.txt b/tests/cases/ctors_cast.txt new file mode 100644 index 00000000..8a3f62a7 --- /dev/null +++ b/tests/cases/ctors_cast.txt @@ -0,0 +1,3 @@ +autorun called! +Other +main called! diff --git a/tests/glut_wheelevents.c b/tests/glut_wheelevents.c new file mode 100644 index 00000000..7be01636 --- /dev/null +++ b/tests/glut_wheelevents.c @@ -0,0 +1,68 @@ +#include <stdio.h> +#include <stdlib.h> +#include <GL/glut.h> +#include <EGL/egl.h> +#include <emscripten.h> + +#define MULTILINE(...) #__VA_ARGS__ + +int wheel_up = 0; +int wheel_down = 0; + +int result = 0; + +void mouseCB(int button, int state, int x, int y) +{ + if(button == 3) + { + wheel_up = 1; + } + else if (button == 4) + { + wheel_down = 1; + } +} + +int main(int argc, char *argv[]) +{ + emscripten_run_script(MULTILINE( + Module.injectWheelEvent = function(x, y, delta) { + var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; + var event = document.createEvent("MouseEvents"); + if (!isFirefox) { + // mouse wheel event for IE9, Chrome, Safari, Opera + event.initMouseEvent('mousewheel', true, true, window, + 0, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, + 0, 0, 0, 0, 0, null); + event.wheelDelta = delta; + } else { + // mouse wheel event for Firefox, the delta sign is inversed for that browser and is stored in the detail property of the mouse event + event.initMouseEvent('DOMMouseScroll', true, true, window, + -delta, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, + 0, 0, 0, 0, 0, null); + } + Module['canvas'].dispatchEvent(event); + } + )); + + + glutInit(&argc, argv); + + glutMouseFunc(&mouseCB); + + // inject wheel up event (delta > 0) + emscripten_run_script("Module.injectWheelEvent(100, 100, 1)"); + if (wheel_up) { + printf("%s\n", "mouse wheel up event received"); + } + // inject wheel down event (delta < 0) + emscripten_run_script("Module.injectWheelEvent(100, 100, -1)"); + if (wheel_down) { + printf("%s\n", "mouse wheel down event received"); + } + + result = wheel_up && wheel_down; + + REPORT_RESULT(); + return 0; +} diff --git a/tests/sdl_rotozoom.c b/tests/sdl_rotozoom.c index cdbdcc6f..2c0d35df 100644 --- a/tests/sdl_rotozoom.c +++ b/tests/sdl_rotozoom.c @@ -38,7 +38,7 @@ int main(int argc, char **argv) { sprite[2] = zoomSurface(sprite[0], 0.5, 0.5, SMOOTHING_ON); sprite[3] = zoomSurface(sprite[1], 0.5, 0.5, SMOOTHING_ON); sprite[4] = rotozoomSurface(sprite[0], -20, 0.3, SMOOTHING_ON); - sprite[5] = rotozoomSurface(sprite[1], 45, 0.5, SMOOTHING_ON); + sprite[5] = rotozoomSurface(sprite[1], 20, 1, SMOOTHING_ON); sprite[6] = zoomSurface(sprite[0], -0.5, 0.5, SMOOTHING_ON); sprite[7] = zoomSurface(sprite[0], -0.5, -0.5, SMOOTHING_ON); sprite[8] = rotozoomSurface(sprite[1], 0, 0.5, SMOOTHING_ON); diff --git a/tests/sdl_rotozoom.png b/tests/sdl_rotozoom.png Binary files differindex 5933754f..ebde79f2 100644 --- a/tests/sdl_rotozoom.png +++ b/tests/sdl_rotozoom.png diff --git a/tests/test_browser.py b/tests/test_browser.py index 24113511..ecd331fd 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -866,6 +866,9 @@ keydown(100);keyup(100); // trigger the end def test_glut_touchevents(self): self.btest('glut_touchevents.c', '1') + def test_glut_wheelevents(self): + self.btest('glut_wheelevents.c', '1') + def test_emscripten_get_now(self): self.btest('emscripten_get_now.cpp', '1') @@ -1389,7 +1392,7 @@ keydown(100);keyup(100); // trigger the end def test_sdl_rotozoom(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('sdl_rotozoom.c', reference='sdl_rotozoom.png', args=['--preload-file', 'screenshot.png'], reference_slack=5) + self.btest('sdl_rotozoom.c', reference='sdl_rotozoom.png', args=['--preload-file', 'screenshot.png']) def test_sdl_gfx_primitives(self): self.btest('sdl_gfx_primitives.c', reference='sdl_gfx_primitives.png', reference_slack=1) diff --git a/tests/test_core.py b/tests/test_core.py index 87925082..8ba9295a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -7274,6 +7274,7 @@ date: 18.07.2013w; day 18, month 7, year 2013, extra: 201, 3 self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/langinfo.h']) def test_files(self): + self.banned_js_engines = [SPIDERMONKEY_ENGINE] # closure can generate variables called 'gc', which pick up js shell stuff 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) @@ -7826,6 +7827,7 @@ def process(filename): self.do_run(src, expected) def test_unistd_unlink(self): + self.clear() if self.emcc_args is None: return self.skip('requires emcc') if not self.is_le32(): return self.skip('le32 needed for inline js') for fs in ['MEMFS', 'NODEFS']: @@ -7834,6 +7836,7 @@ def process(filename): self.do_run(src, 'success', force_c=True, js_engines=[NODE_JS]) def test_unistd_links(self): + self.clear() if not self.is_le32(): return self.skip('le32 needed for inline js') for fs in ['MEMFS', 'NODEFS']: src = open(path_from_root('tests', 'unistd', 'links.c'), 'r').read() @@ -7847,6 +7850,7 @@ def process(filename): self.do_run(src, expected) def test_unistd_io(self): + self.clear() if not self.is_le32(): return self.skip('le32 needed for inline js') if self.run_name == 'o2': return self.skip('non-asm optimized builds can fail with inline js') if self.emcc_args is None: return self.skip('requires emcc') @@ -8091,11 +8095,7 @@ int main(int argc, char **argv) { def test_iostream(self): if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") - - if self.emcc_args is None: - if Building.LLVM_OPTS: return self.skip('optimizing bitcode before emcc can confuse libcxx inclusion') - self.emcc_args = [] # libc++ auto-inclusion is only done if we use emcc - Settings.SAFE_HEAP = 0 # Some spurious warnings from libc++ internals + if self.emcc_args is None: return self.skip('needs ta2 and emcc') src = ''' #include <iostream> diff --git a/tests/test_other.py b/tests/test_other.py index 2d3dde3f..c8b6d4b1 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -31,8 +31,8 @@ Most normal gcc/g++ options will work, for example: --version Display compiler version information Options that are modified or new in %s include: - -O0 No optimizations (default) -''' % (shortcompiler, shortcompiler), output[0].replace('\r', ''), output[1].replace('\r', '')) + + -O0 No optimizations (default)''' % (shortcompiler, shortcompiler), output[0].replace('\r', ''), output[1].replace('\r', '')) # emcc src.cpp ==> writes a.out.js self.clear() @@ -388,6 +388,7 @@ f.close() def test_unaligned_memory(self): open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r''' #include <stdio.h> + #include <stdarg.h> typedef unsigned char Bit8u; typedef unsigned short Bit16u; @@ -395,6 +396,9 @@ f.close() int main() { + va_list argp; + va_arg(argp, char *); // check for compilation error, #1705 + Bit8u data[4] = {0x01,0x23,0x45,0x67}; printf("data: %x\n", *(Bit32u*)data); @@ -1910,6 +1914,12 @@ done. open('src.cpp', 'w').write(''' #include <stdio.h> #include <emscripten.h> + void two(char c) { + EM_ASM(Module.print(stackTrace())); + } + void one(int x) { + two(x % 17); + } int main() { EM_ASM(Module.print(demangle('__Znwj'))); // check for no aborts EM_ASM(Module.print(demangle('_main'))); @@ -1922,11 +1932,16 @@ done. EM_ASM(Module.print(demangle('__Z3FooIidEvi'))); EM_ASM(Module.print(demangle('__ZN3Foo3BarILi5EEEvv'))); EM_ASM(Module.print(demangle('__ZNK10__cxxabiv120__si_class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib'))); + EM_ASM(Module.print(demangle('__Z9parsewordRPKciRi'))); + EM_ASM(Module.print(demangle('__Z5multiwahtjmxyz'))); + EM_ASM(Module.print(demangle('__Z1aA32_iPA5_c'))); + one(17); return 0; } ''') Popen([PYTHON, EMCC, 'src.cpp', '-s', 'LINKABLE=1']).communicate() + output = run_js('a.out.js') self.assertContained('''main f2() abcdabcdabcd(int) @@ -1937,5 +1952,11 @@ void Foo<int>() void Foo<int, double>(int) void Foo::Bar<5>() __cxxabiv1::__si_class_type_info::search_below_dst(__cxxabiv1::__dynamic_cast_info*, void*, int, bool) -''', run_js('a.out.js')) +parseword(char*&, int, int&) +multi(wchar_t, signed char, unsigned char, unsigned short, unsigned int, unsigned long, long long, unsigned long long, ...) +a(int [32], char [5]*) +''', output) + # test for multiple functions in one stack trace + assert 'one(int)' in output + assert 'two(char)' in output diff --git a/tools/autodebugger.py b/tools/autodebugger.py index c74e56d2..df9594b3 100644 --- a/tools/autodebugger.py +++ b/tools/autodebugger.py @@ -282,7 +282,9 @@ for i in range(len(lines)): lines_added += 1 f = open(ofilename, 'w') -f.write('\n'.join(lines) + '\n' + POSTAMBLE + '\n') +ll = '\n'.join(lines) +meta_start = ll.find('\n!') +f.write(ll[:meta_start] + '\n' + POSTAMBLE + '\n' + ll[meta_start:]) f.close() print 'Success.' |