diff options
53 files changed, 1829 insertions, 880 deletions
@@ -137,7 +137,7 @@ Options that are modified or new in %s include: opt levels, see apply_opt_level() in tools/shared.py and also src/settings.js.) -O2 As -O1, plus the relooper (loop recreation), - LLVM -O2 optimizations, and + LLVM -O3 optimizations, and -s ALIASING_FUNCTION_POINTERS=1 @@ -1621,9 +1621,6 @@ try: js_optimizer_queue += [get_eliminate(), 'simplifyExpressions'] - if shared.Settings.RELOOP and not shared.Settings.ASM_JS: - js_optimizer_queue += ['optimizeShiftsAggressive', get_eliminate()] # aggressive shifts optimization requires loops, it breaks on switches - if closure and not shared.Settings.ASM_JS: flush_js_optimizer_queue() diff --git a/emscripten.py b/emscripten.py index 1b1284c7..a156ca73 100755 --- a/emscripten.py +++ b/emscripten.py @@ -190,6 +190,11 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, open(forwarded_file, 'w').write(forwarded_data) if DEBUG: print >> sys.stderr, ' emscript: phase 1 took %s seconds' % (time.time() - t) + indexed_functions = set() + forwarded_json = json.loads(forwarded_data) + for key in forwarded_json['Functions']['indexedFunctions'].iterkeys(): + indexed_functions.add(key) + # Phase 2 - func cores = int(os.environ.get('EMCC_CORES') or multiprocessing.cpu_count()) @@ -203,8 +208,6 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, chunk_size = MAX_CHUNK_SIZE # if 1 core, just use the max chunk size if DEBUG: t = time.time() - forwarded_json = json.loads(forwarded_data) - indexed_functions = set() if settings.get('ASM_JS'): settings['EXPORTED_FUNCTIONS'] = forwarded_json['EXPORTED_FUNCTIONS'] save_settings() diff --git a/src/analyzer.js b/src/analyzer.js index 931ce421..2a7d64f5 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -953,9 +953,23 @@ function analyzer(data, sidePass) { if (type[0] == '{' || type[0] == '<') { type = nonPointing; var packed = type[0] == '<'; + var internal = type; + if (packed) { + if (internal[internal.length-1] != '>') { + warnOnce('ignoring type ' + internal); + return; // function pointer or such + } + internal = internal.substr(1, internal.length-2); + } + assert(internal[0] == '{', internal); + if (internal[internal.length-1] != '}') { + warnOnce('ignoring type ' + internal); + return; // function pointer or such + } + internal = internal.substr(2, internal.length-4); Types.types[type] = { name_: type, - fields: splitTokenList(tokenize(type.substr(2 + packed, type.length - 4 - 2*packed)).tokens).map(function(segment) { + fields: splitTokenList(tokenize(internal).tokens).map(function(segment) { return segment[0].text; }), packed: packed, diff --git a/src/compiler.js b/src/compiler.js index 365ff32f..0baec95e 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -185,8 +185,7 @@ if (ASM_JS) { assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap'); assert((TOTAL_MEMORY&(TOTAL_MEMORY-1)) == 0, 'asm.js heap must be power of 2'); } -assert(!BUILD_AS_SHARED_LIB, 'shared libs are deprecated'); -//assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals'); +assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals'); // Output some info and warnings based on settings @@ -203,6 +202,8 @@ if (phase == 'pre') { } } +if (VERBOSE) printErr('VERBOSE is on, this generates a lot of output and can slow down compilation'); + // Load compiler code load('framework.js'); diff --git a/src/headless.js b/src/headless.js index 097a42f7..1c7b8945 100644 --- a/src/headless.js +++ b/src/headless.js @@ -23,6 +23,7 @@ var window = { return '%s'; }, search: '?%s', + pathname: '%s', }, fakeNow: 0, // we don't use Date.now() rafs: [], @@ -84,6 +85,7 @@ var window = { }, revokeObjectURL: function(x) {}, }, + encodeURIComponent: function(x) { return x }, }; var setTimeout = window.setTimeout; var document = { diff --git a/src/intertyper.js b/src/intertyper.js index 3fc840c4..31e97bd0 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -365,8 +365,17 @@ function intertyper(data, sidePass, baseLineNums) { } if (tokensLength >= 3 && (token0Text == 'call' || token1Text == 'call')) return 'Call'; - if (token0Text == 'target') + if (token0Text == 'target') { + if (token1Text == 'triple') { + var triple = item.tokens[3].text; + triple = triple.substr(1, triple.length-2); + var expected = TARGET_LE32 ? 'le32-unknown-nacl' : 'i386-pc-linux-gnu'; + if (triple !== expected) { + warn('using an unexpected LLVM triple: ' + [triple, ' !== ', expected] + ' (are you using emcc for everything and not clang?)'); + } + } return '/dev/null'; + } if (token0Text == ';') return '/dev/null'; if (tokensLength >= 3 && token0Text == 'invoke') diff --git a/src/jsifier.js b/src/jsifier.js index c92526d2..c7742288 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -16,6 +16,8 @@ var SETJMP_LABEL = -1; var INDENTATION = ' '; +var functionStubSigs = {}; + // JSifier function JSify(data, functionsOnly, givenFunctions) { var mainPass = !functionsOnly; @@ -278,7 +280,7 @@ function JSify(data, functionsOnly, givenFunctions) { // they would shadow similarly-named globals in the parent. item.JS = ''; } else { - item.JS = makeGlobalDef(item.ident); + item.JS = makeGlobalDef(item.ident); } if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) { @@ -407,6 +409,11 @@ function JSify(data, functionsOnly, givenFunctions) { // functionStub substrate.addActor('FunctionStub', { processItem: function(item) { + // note the signature + if (item.returnType && item.params) { + functionStubSigs[item.ident] = Functions.getSignature(item.returnType.text, item.params.map(function(arg) { return arg.type }), false); + } + function addFromLibrary(ident) { if (ident in addedLibraryItems) return ''; addedLibraryItems[ident] = true; @@ -1537,7 +1544,7 @@ function JSify(data, functionsOnly, givenFunctions) { // This is a call through an invoke_*, either a forced one, or a setjmp-required one // note: no need to update argsTypes at this point if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig; - args.unshift(byPointerForced ? Functions.getIndex(callIdent, undefined, sig) : asmCoercion(callIdent, 'i32')); + args.unshift(byPointerForced ? Functions.getIndex(callIdent, sig) : asmCoercion(callIdent, 'i32')); callIdent = 'invoke_' + sig; } } else if (SAFE_DYNCALLS) { @@ -1628,7 +1635,7 @@ function JSify(data, functionsOnly, givenFunctions) { // if (!mainPass) { - if (phase == 'pre' && !Variables.generatedGlobalBase) { + if (phase == 'pre' && !Variables.generatedGlobalBase && !BUILD_AS_SHARED_LIB) { Variables.generatedGlobalBase = true; // Globals are done, here is the rest of static memory assert((TARGET_LE32 && Runtime.GLOBAL_BASE == 8) || (TARGET_X86 && Runtime.GLOBAL_BASE == 4)); // this is assumed in e.g. relocations for linkable modules @@ -1672,24 +1679,26 @@ function JSify(data, functionsOnly, givenFunctions) { print('}\n'); if (USE_TYPED_ARRAYS == 2) { - print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n'); - print('assert(tempDoublePtr % 8 == 0);\n'); - print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n'); - print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n'); - print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n'); - print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n'); - print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n'); - print('}\n'); - print('function copyTempDouble(ptr) {\n'); - print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n'); - print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n'); - print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n'); - print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n'); - print(' HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n'); - print(' HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n'); - print(' HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n'); - print(' HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n'); - print('}\n'); + if (!BUILD_AS_SHARED_LIB) { + print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n'); + print('assert(tempDoublePtr % 8 == 0);\n'); + print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n'); + print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n'); + print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n'); + print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n'); + print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n'); + print('}\n'); + print('function copyTempDouble(ptr) {\n'); + print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n'); + print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n'); + print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n'); + print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n'); + print(' HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n'); + print(' HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n'); + print(' HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n'); + print(' HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n'); + print('}\n'); + } } } @@ -1724,11 +1733,13 @@ function JSify(data, functionsOnly, givenFunctions) { legalizedI64s = legalizedI64sDefault; - print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n'); - print('staticSealed = true; // seal the static portion of memory\n'); - print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n'); - print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n'); - print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n'); + if (!BUILD_AS_SHARED_LIB) { + print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n'); + print('staticSealed = true; // seal the static portion of memory\n'); + print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n'); + print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n'); + print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n'); + } if (asmLibraryFunctions.length > 0) { print('// ASM_LIBRARY FUNCTIONS'); @@ -1795,7 +1806,7 @@ function JSify(data, functionsOnly, givenFunctions) { } if (HEADLESS) { print('if (!ENVIRONMENT_IS_WEB) {'); - print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace('%s,', 'null,').replace('%d', '0')); + print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace("'?%s'", "'/'").replace('%s,', 'null,').replace('%d', '0')); print('}'); } if (RUNTIME_TYPE_INFO) { diff --git a/src/library.js b/src/library.js index 815badc1..9e78db13 100644 --- a/src/library.js +++ b/src/library.js @@ -100,7 +100,7 @@ LibraryManager.library = { } var entries; try { - entries = FS.readdir(stream); + entries = FS.readdir(stream.path); } catch (e) { return FS.handleFSError(e); } @@ -478,8 +478,6 @@ LibraryManager.library = { open: function(path, oflag, varargs) { // int open(const char *path, int oflag, ...); // http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html - // NOTE: This implementation tries to mimic glibc rather than strictly - // following the POSIX standard. var mode = {{{ makeGetValue('varargs', 0, 'i32') }}}; path = Pointer_stringify(path); try { @@ -7237,7 +7235,7 @@ LibraryManager.library = { socket__deps: ['$FS', '$Sockets'], socket: function(family, type, protocol) { var INCOMING_QUEUE_LENGTH = 64; - var stream = FS.createStream({ + var info = FS.createStream({ addr: null, port: null, inQueue: new CircularBuffer(INCOMING_QUEUE_LENGTH), @@ -7246,7 +7244,7 @@ LibraryManager.library = { socket: true, stream_ops: {} }); - assert(stream.fd < 64); // select() assumes socket fd values are in 0..63 + assert(info.fd < 64); // select() assumes socket fd values are in 0..63 var stream = type == {{{ cDefine('SOCK_STREAM') }}}; if (protocol) { assert(stream == (protocol == {{{ cDefine('IPPROTO_TCP') }}})); // if stream, must be tcp @@ -7359,8 +7357,7 @@ LibraryManager.library = { } }; }; - - return stream.fd; + return info.fd; }, mkport__deps: ['$Sockets'], @@ -7454,6 +7451,7 @@ LibraryManager.library = { buffer.set(data, info.header.byteLength); connection.send('unreliable', buffer.buffer); + return ret; }, recvmsg__deps: ['$FS', '$Sockets', 'bind', '__setErrNo', '$ERRNO_CODES', 'htons'], diff --git a/src/library_browser.js b/src/library_browser.js index f65791e4..558c9a59 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -6,6 +6,7 @@ mergeInto(LibraryManager.library, { $Browser__deps: ['$PATH'], $Browser__postset: 'Module["requestFullScreen"] = function(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports 'Module["requestAnimationFrame"] = function(func) { Browser.requestAnimationFrame(func) };\n' + + 'Module["setCanvasSize"] = function(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };\n' + 'Module["pauseMainLoop"] = function() { Browser.mainLoop.pause() };\n' + 'Module["resumeMainLoop"] = function() { Browser.mainLoop.resume() };\n' + 'Module["getUserMedia"] = function() { Browser.getUserMedia() }', @@ -451,8 +452,21 @@ mergeInto(LibraryManager.library, { // Otherwise, calculate the movement based on the changes // in the coordinates. var rect = Module["canvas"].getBoundingClientRect(); - var x = event.pageX - (window.scrollX + rect.left); - var y = event.pageY - (window.scrollY + rect.top); + var x, y; + if (event.type == 'touchstart' || + event.type == 'touchend' || + event.type == 'touchmove') { + var t = event.touches.item(0); + if (t) { + x = t.pageX - (window.scrollX + rect.left); + y = t.pageY - (window.scrollY + rect.top); + } else { + return; + } + } else { + x = event.pageX - (window.scrollX + rect.left); + y = event.pageY - (window.scrollY + rect.top); + } // the canvas might be CSS-scaled compared to its backbuffer; // SDL-using content will want mouse coordinates in terms diff --git a/src/library_egl.js b/src/library_egl.js index 0e96e92f..ff912ed2 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -489,6 +489,11 @@ var LibraryEGL = { eglSwapBuffers: function() { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); }, + + eglGetProcAddress__deps: ['emscripten_GetProcAddress'], + eglGetProcAddress: function(name_) { + return _emscripten_GetProcAddress(Pointer_stringify(name_)); + }, }; autoAddDeps(LibraryEGL, '$EGL'); diff --git a/src/library_fs.js b/src/library_fs.js index 9c83fcad..9d1f0cfd 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -18,7 +18,7 @@ mergeInto(LibraryManager.library, { devices: [null], streams: [null], nextInode: 1, - name_table: new Array(4096), + name_table: null, currentPath: '/', initialized: false, // Whether we are currently ignoring permissions. Useful when preparing the @@ -27,16 +27,21 @@ mergeInto(LibraryManager.library, { // to modify the filesystem freely before run() is called. ignorePermissions: true, - ErrnoError: function(errno) { - this.errno = errno; - for (var key in ERRNO_CODES) { - if (ERRNO_CODES[key] === errno) { - this.code = key; - break; + ErrnoError: (function() { + function ErrnoError(errno) { + this.errno = errno; + for (var key in ERRNO_CODES) { + if (ERRNO_CODES[key] === errno) { + this.code = key; + break; + } } - } - this.message = ERRNO_MESSAGES[errno] + ' : ' + new Error().stack; - }, + this.message = ERRNO_MESSAGES[errno]; + }; + ErrnoError.prototype = new Error(); + ErrnoError.prototype.constructor = ErrnoError; + return ErrnoError; + }()), handleFSError: function(e) { if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + new Error().stack; @@ -51,7 +56,7 @@ mergeInto(LibraryManager.library, { for (var i = 0; i < name.length; i++) { hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; } - return (parentid + hash) % FS.name_table.length; + return ((parentid + hash) >>> 0) % FS.name_table.length; }, hashAddNode: function(node) { var hash = FS.hashName(node.parent.id, node.name); @@ -730,6 +735,9 @@ mergeInto(LibraryManager.library, { }); // use a custom read function stream_ops.read = function(stream, buffer, offset, length, position) { + if (!FS.forceLoadFile(node)) { + throw new FS.ErrnoError(ERRNO_CODES.EIO); + } var contents = stream.node.contents; var size = Math.min(contents.length - position, length); if (contents.slice) { // normal array @@ -860,6 +868,8 @@ mergeInto(LibraryManager.library, { assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')'); }, staticInit: function() { + FS.name_table = new Array(4096); + FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0); FS.mount(MEMFS, {}, '/'); @@ -1035,7 +1045,7 @@ mergeInto(LibraryManager.library, { FS.hashRemoveNode(old_node); // do the underlying fs rename try { - old_node.node_ops.rename(old_node, new_dir, new_name); + old_dir.node_ops.rename(old_node, new_dir, new_name); } catch (e) { throw e; } finally { @@ -1062,6 +1072,14 @@ mergeInto(LibraryManager.library, { parent.node_ops.rmdir(parent, name); FS.destroyNode(node); }, + readdir: function(path) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + if (!node.node_ops.readdir) { + throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR); + } + return node.node_ops.readdir(node); + }, unlink: function(path) { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; @@ -1202,6 +1220,7 @@ mergeInto(LibraryManager.library, { open: function(path, flags, mode, fd_start, fd_end) { path = PATH.normalize(path); flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags; + mode = typeof mode === 'undefined' ? 0666 : mode; if ((flags & {{{ cDefine('O_CREAT') }}})) { mode = (mode & {{{ cDefine('S_IALLUGO') }}}) | {{{ cDefine('S_IFREG') }}}; } else { @@ -1280,12 +1299,6 @@ mergeInto(LibraryManager.library, { } return stream.stream_ops.llseek(stream, offset, whence); }, - readdir: function(stream) { - if (!stream.stream_ops.readdir) { - throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR); - } - return stream.stream_ops.readdir(stream); - }, read: function(stream, buffer, offset, length, position) { if (length < 0 || position < 0) { throw new FS.ErrnoError(ERRNO_CODES.EINVAL); diff --git a/src/library_gl.js b/src/library_gl.js index 8c724245..c134ad97 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -1285,10 +1285,11 @@ var LibraryGL = { return Module.ctx.isFramebuffer(fb); }, -#if DISABLE_GL_EMULATION == 0 +#if LEGACY_GL_EMULATION // GL emulation: provides misc. functionality not present in OpenGL ES 2.0 or WebGL + $GLEmulation__deps: ['$GLImmediateSetup', 'glEnable', 'glDisable', 'glIsEnabled', 'glGetBooleanv', 'glGetIntegerv', 'glGetString', 'glCreateShader', 'glShaderSource', 'glCompileShader', 'glAttachShader', 'glDetachShader', 'glUseProgram', 'glDeleteProgram', 'glBindAttribLocation', 'glLinkProgram', 'glBindBuffer', 'glGetFloatv', 'glHint', 'glEnableVertexAttribArray', 'glDisableVertexAttribArray', 'glVertexAttribPointer', 'glActiveTexture'], $GLEmulation__postset: 'GLEmulation.init();', $GLEmulation: { // Fog support. Partial, we assume shaders are used that implement fog. We just pass them uniforms @@ -1323,7 +1324,7 @@ var LibraryGL = { GLEmulation.fogColor = new Float32Array(4); // Add some emulation workarounds - Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work. (If you do not want this, build with -s DISABLE_GL_EMULATION=1)'); + Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work.'); #if GL_UNSAFE_OPTS == 0 Module.printErr('WARNING: using emscripten GL emulation unsafe opts. If weirdness happens, try -s GL_UNSAFE_OPTS=0'); #endif @@ -1618,17 +1619,15 @@ var LibraryGL = { var glCompileShader = _glCompileShader; _glCompileShader = function(shader) { Module.ctx.compileShader(GL.shaders[shader]); +#if GL_DEBUG if (!Module.ctx.getShaderParameter(GL.shaders[shader], Module.ctx.COMPILE_STATUS)) { Module.printErr('Failed to compile shader: ' + Module.ctx.getShaderInfoLog(GL.shaders[shader])); Module.printErr('Info: ' + JSON.stringify(GL.shaderInfos[shader])); -#if GL_DEBUG Module.printErr('Original source: ' + GL.shaderOriginalSources[shader]); Module.printErr('Source: ' + GL.shaderSources[shader]); throw 'Shader compilation halt'; -#else - Module.printErr('Enable GL_DEBUG to see shader source'); -#endif } +#endif }; GL.programShaders = {}; @@ -1775,170 +1774,6 @@ var LibraryGL = { } return attrib; }, - - getProcAddress: function(name) { - name = name.replace('EXT', '').replace('ARB', ''); - // Do the translation carefully because of closure - var ret = 0; - switch (name) { - case 'glCreateShaderObject': case 'glCreateShader': ret = {{{ Functions.getIndex('_glCreateShader', true) }}}; break; - case 'glCreateProgramObject': case 'glCreateProgram': ret = {{{ Functions.getIndex('_glCreateProgram', true) }}}; break; - case 'glAttachObject': case 'glAttachShader': ret = {{{ Functions.getIndex('_glAttachShader', true) }}}; break; - case 'glUseProgramObject': case 'glUseProgram': ret = {{{ Functions.getIndex('_glUseProgram', true) }}}; break; - case 'glDetachObject': case 'glDetachShader': ret = {{{ Functions.getIndex('_glDetachShader', true) }}}; break; - case 'glDeleteObject': ret = {{{ Functions.getIndex('_glDeleteObject', true) }}}; break; - case 'glGetObjectParameteriv': ret = {{{ Functions.getIndex('_glGetObjectParameteriv', true) }}}; break; - case 'glGetInfoLog': ret = {{{ Functions.getIndex('_glGetInfoLog', true) }}}; break; - case 'glBindProgram': ret = {{{ Functions.getIndex('_glBindProgram', true) }}}; break; - case 'glDrawRangeElements': ret = {{{ Functions.getIndex('_glDrawRangeElements', true) }}}; break; - case 'glShaderSource': ret = {{{ Functions.getIndex('_glShaderSource', true) }}}; break; - case 'glCompileShader': ret = {{{ Functions.getIndex('_glCompileShader', true) }}}; break; - case 'glLinkProgram': ret = {{{ Functions.getIndex('_glLinkProgram', true) }}}; break; - case 'glGetUniformLocation': ret = {{{ Functions.getIndex('_glGetUniformLocation', true) }}}; break; - case 'glUniform1f': ret = {{{ Functions.getIndex('_glUniform1f', true) }}}; break; - case 'glUniform2f': ret = {{{ Functions.getIndex('_glUniform2f', true) }}}; break; - case 'glUniform3f': ret = {{{ Functions.getIndex('_glUniform3f', true) }}}; break; - case 'glUniform4f': ret = {{{ Functions.getIndex('_glUniform4f', true) }}}; break; - case 'glUniform1fv': ret = {{{ Functions.getIndex('_glUniform1fv', true) }}}; break; - case 'glUniform2fv': ret = {{{ Functions.getIndex('_glUniform2fv', true) }}}; break; - case 'glUniform3fv': ret = {{{ Functions.getIndex('_glUniform3fv', true) }}}; break; - case 'glUniform4fv': ret = {{{ Functions.getIndex('_glUniform4fv', true) }}}; break; - case 'glUniform1i': ret = {{{ Functions.getIndex('_glUniform1i', true) }}}; break; - case 'glUniform2i': ret = {{{ Functions.getIndex('_glUniform2i', true) }}}; break; - case 'glUniform3i': ret = {{{ Functions.getIndex('_glUniform3i', true) }}}; break; - case 'glUniform4i': ret = {{{ Functions.getIndex('_glUniform4i', true) }}}; break; - case 'glUniform1iv': ret = {{{ Functions.getIndex('_glUniform1iv', true) }}}; break; - case 'glUniform2iv': ret = {{{ Functions.getIndex('_glUniform2iv', true) }}}; break; - case 'glUniform3iv': ret = {{{ Functions.getIndex('_glUniform3iv', true) }}}; break; - case 'glUniform4iv': ret = {{{ Functions.getIndex('_glUniform4iv', true) }}}; break; - case 'glBindAttribLocation': ret = {{{ Functions.getIndex('_glBindAttribLocation', true) }}}; break; - case 'glGetActiveUniform': ret = {{{ Functions.getIndex('_glGetActiveUniform', true) }}}; break; - case 'glGenBuffers': ret = {{{ Functions.getIndex('_glGenBuffers', true) }}}; break; - case 'glBindBuffer': ret = {{{ Functions.getIndex('_glBindBuffer', true) }}}; break; - case 'glBufferData': ret = {{{ Functions.getIndex('_glBufferData', true) }}}; break; - case 'glBufferSubData': ret = {{{ Functions.getIndex('_glBufferSubData', true) }}}; break; - case 'glDeleteBuffers': ret = {{{ Functions.getIndex('_glDeleteBuffers', true) }}}; break; - case 'glActiveTexture': ret = {{{ Functions.getIndex('_glActiveTexture', true) }}}; break; - case 'glClientActiveTexture': ret = {{{ Functions.getIndex('_glClientActiveTexture', true) }}}; break; - case 'glGetProgramiv': ret = {{{ Functions.getIndex('_glGetProgramiv', true) }}}; break; - case 'glEnableVertexAttribArray': ret = {{{ Functions.getIndex('_glEnableVertexAttribArray', true) }}}; break; - case 'glDisableVertexAttribArray': ret = {{{ Functions.getIndex('_glDisableVertexAttribArray', true) }}}; break; - case 'glVertexAttribPointer': ret = {{{ Functions.getIndex('_glVertexAttribPointer', true) }}}; break; - case 'glVertexAttrib1f': ret = {{{ Functions.getIndex('_glVertexAttrib1f', true) }}}; break; - case 'glVertexAttrib2f': ret = {{{ Functions.getIndex('_glVertexAttrib2f', true) }}}; break; - case 'glVertexAttrib3f': ret = {{{ Functions.getIndex('_glVertexAttrib3f', true) }}}; break; - case 'glVertexAttrib4f': ret = {{{ Functions.getIndex('_glVertexAttrib4f', true) }}}; break; - case 'glVertexAttrib1fv': ret = {{{ Functions.getIndex('_glVertexAttrib1fv', true) }}}; break; - case 'glVertexAttrib2fv': ret = {{{ Functions.getIndex('_glVertexAttrib2fv', true) }}}; break; - case 'glVertexAttrib3fv': ret = {{{ Functions.getIndex('_glVertexAttrib3fv', true) }}}; break; - case 'glVertexAttrib4fv': ret = {{{ Functions.getIndex('_glVertexAttrib4fv', true) }}}; break; - case 'glGetVertexAttribfv': ret = {{{ Functions.getIndex('_glGetVertexAttribfv', true) }}}; break; - case 'glGetVertexAttribiv': ret = {{{ Functions.getIndex('_glGetVertexAttribiv', true) }}}; break; - case 'glGetVertexAttribPointerv': ret = {{{ Functions.getIndex('_glGetVertexAttribPointerv', true) }}}; break; - case 'glGetAttribLocation': ret = {{{ Functions.getIndex('_glGetAttribLocation', true) }}}; break; - case 'glGetActiveAttrib': ret = {{{ Functions.getIndex('_glGetActiveAttrib', true) }}}; break; - case 'glBindRenderbuffer': ret = {{{ Functions.getIndex('_glBindRenderbuffer', true) }}}; break; - case 'glDeleteRenderbuffers': ret = {{{ Functions.getIndex('_glDeleteRenderbuffers', true) }}}; break; - case 'glGenRenderbuffers': ret = {{{ Functions.getIndex('_glGenRenderbuffers', true) }}}; break; - case 'glCompressedTexImage2D': ret = {{{ Functions.getIndex('_glCompressedTexImage2D', true) }}}; break; - case 'glCompressedTexSubImage2D': ret = {{{ Functions.getIndex('_glCompressedTexSubImage2D', true) }}}; break; - case 'glBindFramebuffer': ret = {{{ Functions.getIndex('_glBindFramebuffer', true) }}}; break; - case 'glGenFramebuffers': ret = {{{ Functions.getIndex('_glGenFramebuffers', true) }}}; break; - case 'glDeleteFramebuffers': ret = {{{ Functions.getIndex('_glDeleteFramebuffers', true) }}}; break; - case 'glFramebufferRenderbuffer': ret = {{{ Functions.getIndex('_glFramebufferRenderbuffer', true) }}}; break; - case 'glFramebufferTexture2D': ret = {{{ Functions.getIndex('_glFramebufferTexture2D', true) }}}; break; - case 'glGetFramebufferAttachmentParameteriv': ret = {{{ Functions.getIndex('_glGetFramebufferAttachmentParameteriv', true) }}}; break; - case 'glIsFramebuffer': ret = {{{ Functions.getIndex('_glIsFramebuffer', true) }}}; break; - case 'glCheckFramebufferStatus': ret = {{{ Functions.getIndex('_glCheckFramebufferStatus', true) }}}; break; - case 'glRenderbufferStorage': ret = {{{ Functions.getIndex('_glRenderbufferStorage', true) }}}; break; - case 'glGenVertexArrays': ret = {{{ Functions.getIndex('_glGenVertexArrays', true) }}}; break; - case 'glDeleteVertexArrays': ret = {{{ Functions.getIndex('_glDeleteVertexArrays', true) }}}; break; - case 'glBindVertexArray': ret = {{{ Functions.getIndex('_glBindVertexArray', true) }}}; break; - case 'glGetString': ret = {{{ Functions.getIndex('_glGetString', true) }}}; break; - case 'glBindTexture': ret = {{{ Functions.getIndex('_glBindTexture', true) }}}; break; - case 'glGetBufferParameteriv': ret = {{{ Functions.getIndex('_glGetBufferParameteriv', true) }}}; break; - case 'glIsBuffer': ret = {{{ Functions.getIndex('_glIsBuffer', true) }}}; break; - case 'glDeleteShader': ret = {{{ Functions.getIndex('_glDeleteShader', true) }}}; break; - case 'glUniformMatrix2fv': ret = {{{ Functions.getIndex('_glUniformMatrix2fv', true) }}}; break; - case 'glUniformMatrix3fv': ret = {{{ Functions.getIndex('_glUniformMatrix3fv', true) }}}; break; - case 'glUniformMatrix4fv': ret = {{{ Functions.getIndex('_glUniformMatrix4fv', true) }}}; break; - case 'glIsRenderbuffer': ret = {{{ Functions.getIndex('_glIsRenderbuffer', true) }}}; break; - case 'glBlendEquation': ret = {{{ Functions.getIndex('_glBlendEquation', true) }}}; break; - case 'glBlendFunc': ret = {{{ Functions.getIndex('_glBlendFunc', true) }}}; break; - case 'glBlendFuncSeparate': ret = {{{ Functions.getIndex('_glBlendFuncSeparate', true) }}}; break; - case 'glBlendEquationSeparate': ret = {{{ Functions.getIndex('_glBlendEquationSeparate', true) }}}; break; - case 'glDepthRangef': ret = {{{ Functions.getIndex('_glDepthRangef', true) }}}; break; - case 'glClear': ret = {{{ Functions.getIndex('_glClear', true) }}}; break; - case 'glGenerateMipmap': ret = {{{ Functions.getIndex('_glGenerateMipmap', true) }}}; break; - case 'glBlendColor': ret = {{{ Functions.getIndex('_glBlendColor', true) }}}; break; - case 'glClearDepthf': ret = {{{ Functions.getIndex('_glClearDepthf', true) }}}; break; - case 'glDeleteProgram': ret = {{{ Functions.getIndex('_glDeleteProgram', true) }}}; break; - case 'glUniformMatrix3fv': ret = {{{ Functions.getIndex('_glUniformMatrix3fv', true) }}}; break; - case 'glClearColor': ret = {{{ Functions.getIndex('_glClearColor', true) }}}; break; - case 'glGetRenderbufferParameteriv': ret = {{{ Functions.getIndex('_glGetRenderbufferParameteriv', true) }}}; break; - case 'glGetShaderInfoLog': ret = {{{ Functions.getIndex('_glGetShaderInfoLog', true) }}}; break; - case 'glUniformMatrix4fv': ret = {{{ Functions.getIndex('_glUniformMatrix4fv', true) }}}; break; - case 'glClearStencil': ret = {{{ Functions.getIndex('_glClearStencil', true) }}}; break; - case 'glGetProgramInfoLog': ret = {{{ Functions.getIndex('_glGetProgramInfoLog', true) }}}; break; - case 'glGetUniformfv': ret = {{{ Functions.getIndex('_glGetUniformfv', true) }}}; break; - case 'glStencilFuncSeparate': ret = {{{ Functions.getIndex('_glStencilFuncSeparate', true) }}}; break; - case 'glSampleCoverage': ret = {{{ Functions.getIndex('_glSampleCoverage', true) }}}; break; - case 'glColorMask': ret = {{{ Functions.getIndex('_glColorMask', true) }}}; break; - case 'glGetShaderiv': ret = {{{ Functions.getIndex('_glGetShaderiv', true) }}}; break; - case 'glGetUniformiv': ret = {{{ Functions.getIndex('_glGetUniformiv', true) }}}; break; - case 'glCopyTexSubImage2D': ret = {{{ Functions.getIndex('_glCopyTexSubImage2D', true) }}}; break; - case 'glDetachShader': ret = {{{ Functions.getIndex('_glDetachShader', true) }}}; break; - case 'glGetShaderSource': ret = {{{ Functions.getIndex('_glGetShaderSource', true) }}}; break; - case 'glDeleteTextures': ret = {{{ Functions.getIndex('_glDeleteTextures', true) }}}; break; - case 'glGetAttachedShaders': ret = {{{ Functions.getIndex('_glGetAttachedShaders', true) }}}; break; - case 'glValidateProgram': ret = {{{ Functions.getIndex('_glValidateProgram', true) }}}; break; - case 'glDepthFunc': ret = {{{ Functions.getIndex('_glDepthFunc', true) }}}; break; - case 'glIsShader': ret = {{{ Functions.getIndex('_glIsShader', true) }}}; break; - case 'glDepthMask': ret = {{{ Functions.getIndex('_glDepthMask', true) }}}; break; - case 'glStencilMaskSeparate': ret = {{{ Functions.getIndex('_glStencilMaskSeparate', true) }}}; break; - case 'glIsProgram': ret = {{{ Functions.getIndex('_glIsProgram', true) }}}; break; - case 'glDisable': ret = {{{ Functions.getIndex('_glDisable', true) }}}; break; - case 'glStencilOpSeparate': ret = {{{ Functions.getIndex('_glStencilOpSeparate', true) }}}; break; - case 'glDrawArrays': ret = {{{ Functions.getIndex('_glDrawArrays', true) }}}; break; - case 'glDrawElements': ret = {{{ Functions.getIndex('_glDrawElements', true) }}}; break; - case 'glEnable': ret = {{{ Functions.getIndex('_glEnable', true) }}}; break; - case 'glFinish': ret = {{{ Functions.getIndex('_glFinish', true) }}}; break; - case 'glFlush': ret = {{{ Functions.getIndex('_glFlush', true) }}}; break; - case 'glFrontFace': ret = {{{ Functions.getIndex('_glFrontFace', true) }}}; break; - case 'glCullFace': ret = {{{ Functions.getIndex('_glCullFace', true) }}}; break; - case 'glGenTextures': ret = {{{ Functions.getIndex('_glGenTextures', true) }}}; break; - case 'glGetError': ret = {{{ Functions.getIndex('_glGetError', true) }}}; break; - case 'glGetIntegerv': ret = {{{ Functions.getIndex('_glGetIntegerv', true) }}}; break; - case 'glGetBooleanv': ret = {{{ Functions.getIndex('_glGetBooleanv', true) }}}; break; - case 'glGetFloatv': ret = {{{ Functions.getIndex('_glGetFloatv', true) }}}; break; - case 'glHint': ret = {{{ Functions.getIndex('_glHint', true) }}}; break; - case 'glIsTexture': ret = {{{ Functions.getIndex('_glIsTexture', true) }}}; break; - case 'glPixelStorei': ret = {{{ Functions.getIndex('_glPixelStorei', true) }}}; break; - case 'glReadPixels': ret = {{{ Functions.getIndex('_glReadPixels', true) }}}; break; - case 'glScissor': ret = {{{ Functions.getIndex('_glScissor', true) }}}; break; - case 'glStencilFunc': ret = {{{ Functions.getIndex('_glStencilFunc', true) }}}; break; - case 'glStencilMask': ret = {{{ Functions.getIndex('_glStencilMask', true) }}}; break; - case 'glStencilOp': ret = {{{ Functions.getIndex('_glStencilOp', true) }}}; break; - case 'glTexImage2D': ret = {{{ Functions.getIndex('_glTexImage2D', true) }}}; break; - case 'glTexParameterf': ret = {{{ Functions.getIndex('_glTexParameterf', true) }}}; break; - case 'glTexParameterfv': ret = {{{ Functions.getIndex('_glTexParameterfv', true) }}}; break; - case 'glTexParameteri': ret = {{{ Functions.getIndex('_glTexParameteri', true) }}}; break; - case 'glTexParameteriv': ret = {{{ Functions.getIndex('_glTexParameteriv', true) }}}; break; - case 'glGetTexParameterfv': ret = {{{ Functions.getIndex('_glGetTexParameterfv', true) }}}; break; - case 'glGetTexParameteriv': ret = {{{ Functions.getIndex('_glGetTexParameteriv', true) }}}; break; - case 'glTexSubImage2D': ret = {{{ Functions.getIndex('_glTexSubImage2D', true) }}}; break; - case 'glCopyTexImage2D': ret = {{{ Functions.getIndex('_glCopyTexImage2D', true) }}}; break; - case 'glViewport': ret = {{{ Functions.getIndex('_glViewport', true) }}}; break; - case 'glIsEnabled': ret = {{{ Functions.getIndex('_glIsEnabled', true) }}}; break; - case 'glLineWidth': ret = {{{ Functions.getIndex('_glLineWidth', true) }}}; break; - case 'glPolygonOffset': ret = {{{ Functions.getIndex('_glPolygonOffset', true) }}}; break; - case 'glReleaseShaderCompiler': ret = {{{ Functions.getIndex('_glReleaseShaderCompiler', true) }}}; break; - case 'glGetShaderPrecisionFormat': ret = {{{ Functions.getIndex('_glGetShaderPrecisionFormat', true) }}}; break; - case 'glShaderBinary': ret = {{{ Functions.getIndex('_glShaderBinary', true) }}}; break; - } - if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name); - return ret; - } }, glGetShaderPrecisionFormat__sig: 'v', @@ -4202,7 +4037,43 @@ var LibraryGL = { glBindVertexArrayOES: 'glBindVertexArray', glFramebufferTexture2DOES: 'glFramebufferTexture2D', -#endif // DISABLE_GL_EMULATION == 0 +#else // LEGACY_GL_EMULATION + + // Warn if code tries to use various emulation stuff, when emulation is disabled + // (do not warn if INCLUDE_FULL_LIBRARY is one, because then likely the gl code will + // not be called anyhow, leave only the runtime aborts) + glVertexPointer__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glVertexPointer) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glVertexPointer: function(){ throw 'Legacy GL function (glVertexPointer) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + glGenVertexArrays__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glGenVertexArrays) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glGenVertexArrays: function(){ throw 'Legacy GL function (glGenVertexArrays) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + glMatrixMode__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glMatrixMode) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glMatrixMode: function(){ throw 'Legacy GL function (glMatrixMode) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + glBegin__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glBegin) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glBegin: function(){ throw 'Legacy GL function (glBegin) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + glLoadIdentity__deps: [function() { +#if INCLUDE_FULL_LIBRARY == 0 + warn('Legacy GL function (glLoadIdentity) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'); +#endif + }], + glLoadIdentity: function(){ throw 'Legacy GL function (glLoadIdentity) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; }, + +#endif // LEGACY_GL_EMULATION // GLU @@ -4438,28 +4309,60 @@ var LibraryGL = { autoAddDeps(LibraryGL, '$GL'); -if (!DISABLE_GL_EMULATION) { - // Emulation requires everything else, potentially - LibraryGL.$GLEmulation__deps = LibraryGL.$GLEmulation__deps.slice(0); // the __deps object is shared - var glFuncs = []; - for (var item in LibraryGL) { - if (item != '$GLEmulation' && item.substr(-6) != '__deps' && item.substr(-9) != '__postset' && item.substr(-5) != '__sig' && item.substr(0, 2) == 'gl') { - glFuncs.push(item); +// Legacy GL emulation +if (LEGACY_GL_EMULATION) { + DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('$GLEmulation'); +} + +// GL proc address retrieval +LibraryGL.emscripten_GetProcAddress__deps = [function() { + // ProcAddress is used, so include everything in GL. This runs before we go to the $ProcAddressTable object, + // and we fill its deps just in time, and create the lookup table + var table = {}; + LibraryManager.library.emscripten_procAddressTable__deps = keys(LibraryGL).map(function(x) { + if (x.substr(-6) == '__deps' || x.substr(-9) == '__postset' || x.substr(-5) == '__sig' || x.substr(-5) == '__asm' || x.substr(0, 2) != 'gl') return null; + var original = x; + if (('_' + x) in Functions.implementedFunctions) { + // a user-implemented function aliases this one, but we still want it to be accessible by name, so rename it + var y = x + '__procTable'; + LibraryManager.library[y] = LibraryManager.library[x]; + LibraryManager.library[y + '__deps'] = LibraryManager.library[x + '__deps']; + LibraryManager.library[y + '__postset'] = LibraryManager.library[x + '__postset']; + LibraryManager.library[y + '__sig'] = LibraryManager.library[x + '__sig'];//|| Functions.implementedFunctions['_' + x]; + LibraryManager.library[y + '__asm'] = LibraryManager.library[x + '__asm']; + x = y; + assert(!(y in Functions.implementedFunctions) && !Functions.unimplementedFunctions['_' + y]); } - } - LibraryGL.$GLEmulation__deps = LibraryGL.$GLEmulation__deps.concat(glFuncs); - LibraryGL.$GLEmulation__deps.push(function() { - for (var func in Functions.getIndex.tentative) { - Functions.getIndex(func); - Functions.unimplementedFunctions[func] = LibraryGL[func.substr(1) + '__sig']; + var longX = '_' + x; + var sig = LibraryManager.library[x + '__sig'] || functionStubSigs[longX]; + if (sig) { + table[original] = Functions.getIndex(longX, sig); + if (!(longX in Functions.implementedFunctions)) Functions.unimplementedFunctions[longX] = sig; } - }); - - if (FORCE_GL_EMULATION) { - LibraryGL.glDrawElements__deps = LibraryGL.glDrawElements__deps.concat('$GLEmulation'); - LibraryGL.glDrawArrays__deps = LibraryGL.glDrawArrays__deps.concat('$GLEmulation'); + return x; + }).filter(function(x) { return x !== null }); + // convert table into function with switch, to not confuse closure compiler + var tableImpl = 'switch(name) {\n'; + for (var x in table) tableImpl += 'case "' + x + '": return ' + table[x] + '; break;\n'; + tableImpl += '}\nreturn 0;'; + LibraryManager.library.emscripten_procAddressTable = new Function('name', tableImpl); +}, 'emscripten_procAddressTable']; +LibraryGL.emscripten_GetProcAddress = function(name) { + name = name.replace('EXT', '').replace('ARB', ''); + switch(name) { // misc renamings + case 'glCreateProgramObject': name = 'glCreateProgram'; break; + case 'glUseProgramObject': name = 'glUseProgram'; break; + case 'glCreateShaderObject': name = 'glCreateShader'; break; + case 'glAttachObject': name = 'glAttachShader'; break; + case 'glDetachObject': name = 'glDetachShader'; break; } + var ret = _emscripten_procAddressTable(name); + if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name); + return ret; } +// Final merge mergeInto(LibraryManager.library, LibraryGL); +assert(!(FULL_ES2 && LEGACY_GL_EMULATION), 'cannot emulate both ES2 and legacy GL'); + diff --git a/src/library_glut.js b/src/library_glut.js index 29957e6f..60dc6540 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -267,11 +267,19 @@ var LibraryGLUT = { // Ignore arguments GLUT.initTime = Date.now(); + var isTouchDevice = 'ontouchstart' in document.documentElement; + window.addEventListener("keydown", GLUT.onKeydown, true); window.addEventListener("keyup", GLUT.onKeyup, true); - window.addEventListener("mousemove", GLUT.onMousemove, true); - window.addEventListener("mousedown", GLUT.onMouseButtonDown, true); - window.addEventListener("mouseup", GLUT.onMouseButtonUp, true); + if (isTouchDevice) { + window.addEventListener("touchmove", GLUT.onMousemove, true); + window.addEventListener("touchstart", GLUT.onMouseButtonDown, true); + window.addEventListener("touchend", GLUT.onMouseButtonUp, true); + } else { + window.addEventListener("mousemove", GLUT.onMousemove, true); + window.addEventListener("mousedown", GLUT.onMouseButtonDown, true); + window.addEventListener("mouseup", GLUT.onMouseButtonUp, true); + } Browser.resizeListeners.push(function(width, height) { if (GLUT.reshapeFunc) { @@ -282,9 +290,15 @@ var LibraryGLUT = { __ATEXIT__.push({ func: function() { window.removeEventListener("keydown", GLUT.onKeydown, true); window.removeEventListener("keyup", GLUT.onKeyup, true); - window.removeEventListener("mousemove", GLUT.onMousemove, true); - window.removeEventListener("mousedown", GLUT.onMouseButtonDown, true); - window.removeEventListener("mouseup", GLUT.onMouseButtonUp, true); + if (isTouchDevice) { + window.removeEventListener("touchmove", GLUT.onMousemove, true); + window.removeEventListener("touchstart", GLUT.onMouseButtonDown, true); + window.removeEventListener("touchend", GLUT.onMouseButtonUp, true); + } else { + window.removeEventListener("mousemove", GLUT.onMousemove, true); + window.removeEventListener("mousedown", GLUT.onMouseButtonDown, true); + window.removeEventListener("mouseup", GLUT.onMouseButtonUp, true); + } Module["canvas"].width = Module["canvas"].height = 1; } }); }, diff --git a/src/library_memfs.js b/src/library_memfs.js index a044e0c6..0fa6cdfb 100644 --- a/src/library_memfs.js +++ b/src/library_memfs.js @@ -10,16 +10,48 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(ERRNO_CODES.EPERM); } var node = FS.createNode(parent, name, mode, dev); - node.node_ops = MEMFS.node_ops; if (FS.isDir(node.mode)) { - node.stream_ops = MEMFS.stream_ops; + node.node_ops = { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + lookup: MEMFS.node_ops.lookup, + mknod: MEMFS.node_ops.mknod, + mknod: MEMFS.node_ops.mknod, + rename: MEMFS.node_ops.rename, + unlink: MEMFS.node_ops.unlink, + rmdir: MEMFS.node_ops.rmdir, + readdir: MEMFS.node_ops.readdir, + symlink: MEMFS.node_ops.symlink + }; + node.stream_ops = { + llseek: MEMFS.stream_ops.llseek + }; node.contents = {}; } else if (FS.isFile(node.mode)) { - node.stream_ops = MEMFS.stream_ops; + node.node_ops = { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }; + node.stream_ops = { + llseek: MEMFS.stream_ops.llseek, + read: MEMFS.stream_ops.read, + write: MEMFS.stream_ops.write, + allocate: MEMFS.stream_ops.allocate, + mmap: MEMFS.stream_ops.mmap + }; node.contents = []; } else if (FS.isLink(node.mode)) { - node.stream_ops = MEMFS.stream_ops; + node.node_ops = { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + readlink: MEMFS.node_ops.readlink + }; + node.stream_ops = {}; } else if (FS.isChrdev(node.mode)) { + node.node_ops = { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }; node.stream_ops = FS.chrdev_stream_ops; } node.timestamp = Date.now(); @@ -106,6 +138,16 @@ mergeInto(LibraryManager.library, { } delete parent.contents[name]; }, + readdir: function(node) { + var entries = ['.', '..'] + for (var key in node.contents) { + if (!node.contents.hasOwnProperty(key)) { + continue; + } + entries.push(key); + } + return entries; + }, symlink: function(parent, newname, oldpath) { var node = MEMFS.create_node(parent, newname, 0777 | {{{ cDefine('S_IFLNK') }}}, 0); node.link = oldpath; @@ -119,19 +161,6 @@ mergeInto(LibraryManager.library, { }, }, stream_ops: { - open: function(stream) { - if (FS.isDir(stream.node.mode)) { - // cache off the directory entries when open'd - var entries = ['.', '..'] - for (var key in stream.node.contents) { - if (!stream.node.contents.hasOwnProperty(key)) { - continue; - } - entries.push(key); - } - stream.entries = entries; - } - }, read: function(stream, buffer, offset, length, position) { var contents = stream.node.contents; var size = Math.min(contents.length - position, length); @@ -172,9 +201,6 @@ mergeInto(LibraryManager.library, { stream.position = position; return position; }, - readdir: function(stream) { - return stream.entries; - }, allocate: function(stream, offset, length) { var contents = stream.node.contents; var limit = offset + length; diff --git a/src/library_sdl.js b/src/library_sdl.js index 92cfc7e5..5b2f8379 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -258,7 +258,7 @@ var LibrarySDL = { makeSurface: function(width, height, flags, usePageCanvas, source, rmask, gmask, bmask, amask) { flags = flags || 0; - var surf = _malloc(14*Runtime.QUANTUM_SIZE); // SDL_Surface has 14 fields of quantum size + var surf = _malloc(15*Runtime.QUANTUM_SIZE); // SDL_Surface has 15 fields of quantum size var buffer = _malloc(width*height*4); // TODO: only allocate when locked the first time var pixelFormat = _malloc(18*Runtime.QUANTUM_SIZE); flags |= 1; // SDL_HWSURFACE - this tells SDL_MUSTLOCK that this needs to be locked @@ -379,7 +379,8 @@ var LibrarySDL = { SDL.surfaces[surf] = null; }, - touchX:0, touchY: 0, + touchX: 0, touchY: 0, + savedKeydown: null, receiveEvent: function(event) { switch(event.type) { @@ -466,11 +467,29 @@ var LibrarySDL = { SDL.DOMButtons[event.button] = 0; } - if (event.type == 'keypress' && !SDL.textInput) { - break; + // SDL expects a unicode character to be passed to its keydown events. + // Unfortunately, the browser APIs only provide a charCode property on + // keypress events, so we must backfill in keydown events with their + // subsequent keypress event's charCode. + if (event.type === 'keypress' && SDL.savedKeydown) { + // charCode is read-only + SDL.savedKeydown.keypressCharCode = event.charCode; + SDL.savedKeydown = null; + } else if (event.type === 'keydown') { + SDL.savedKeydown = event; + } + + // If we preventDefault on keydown events, the subsequent keypress events + // won't fire. However, it's fine (and in some cases necessary) to + // preventDefault for keys that don't generate a character. + if (event.type !== 'keydown' || (event.keyCode === 8 /* backspace */ || event.keyCode === 9 /* tab */)) { + event.preventDefault(); + } + + // Don't push keypress events unless SDL_StartTextInput has been called. + if (event.type !== 'keypress' || SDL.textInput) { + SDL.events.push(event); } - - SDL.events.push(event); break; case 'mouseout': // Un-press all pressed mouse buttons, because we might miss the release outside of the canvas @@ -485,6 +504,7 @@ var LibrarySDL = { SDL.DOMButtons[i] = 0; } } + event.preventDefault(); break; case 'blur': case 'visibilitychange': { @@ -495,6 +515,7 @@ var LibrarySDL = { keyCode: SDL.keyboardMap[code] }); } + event.preventDefault(); break; } case 'unload': @@ -506,16 +527,16 @@ var LibrarySDL = { return; case 'resize': SDL.events.push(event); + // manually triggered resize event doesn't have a preventDefault member + if (event.preventDefault) { + event.preventDefault(); + } break; } if (SDL.events.length >= 10000) { Module.printErr('SDL event queue full, dropping events'); SDL.events = SDL.events.slice(0, 10000); } - // manually triggered resize event doesn't have a preventDefault member - if (event.preventDefault) { - event.preventDefault(); - } return; }, @@ -590,8 +611,9 @@ var LibrarySDL = { {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.repeat', '0', 'i8') }}} // TODO {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.scancode', 'scan', 'i32') }}} {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.sym', 'key', 'i32') }}} - {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.mod', 'SDL.modState', 'i32') }}} - {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.unicode', 'key', 'i32') }}} + {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.mod', 'SDL.modState', 'i16') }}} + // some non-character keys (e.g. backspace and tab) won't have keypressCharCode set, fill in with the keyCode. + {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.unicode', 'event.keypressCharCode || key', 'i32') }}} break; } @@ -755,6 +777,11 @@ var LibrarySDL = { return depth; // all modes are ok. }, + SDL_AudioDriverName__deps: ['SDL_VideoDriverName'], + SDL_AudioDriverName: function(buf, max_size) { + return _SDL_VideoDriverName(buf, max_size); + }, + SDL_VideoDriverName: function(buf, max_size) { if (SDL.startTime === null) { return 0; //return NULL @@ -2062,9 +2089,9 @@ var LibrarySDL = { console.log('TODO: SDL_GL_SetAttribute'); }, - SDL_GL_GetProcAddress__deps: ['$GLEmulation'], + SDL_GL_GetProcAddress__deps: ['emscripten_GetProcAddress'], SDL_GL_GetProcAddress: function(name_) { - return GLEmulation.getProcAddress(Pointer_stringify(name_)); + return _emscripten_GetProcAddress(Pointer_stringify(name_)); }, SDL_GL_SwapBuffers: function() {}, diff --git a/src/modules.js b/src/modules.js index 13561777..fa6c0983 100644 --- a/src/modules.js +++ b/src/modules.js @@ -275,20 +275,15 @@ var Functions = { }, // Mark a function as needing indexing. Python will coordinate them all - getIndex: function(ident, doNotCreate, sig) { - if (doNotCreate && !(ident in this.indexedFunctions)) { - if (!Functions.getIndex.tentative) Functions.getIndex.tentative = {}; // only used by GL emulation; TODO: generalize when needed - Functions.getIndex.tentative[ident] = 0; - } + getIndex: function(ident, sig) { var ret; if (phase != 'post' && singlePhase) { - if (!doNotCreate) this.indexedFunctions[ident] = 0; // tell python we need this indexized ret = "'{{ FI_" + toNiceIdent(ident) + " }}'"; // something python will replace later + this.indexedFunctions[ident] = 0; } else { if (!singlePhase) return 'NO_INDEX'; // Should not index functions in post ret = this.indexedFunctions[ident]; if (!ret) { - if (doNotCreate) return '0'; ret = this.nextIndex; this.nextIndex += 2; // Need to have indexes be even numbers, see |polymorph| test this.indexedFunctions[ident] = ret; @@ -326,7 +321,7 @@ var Functions = { tables[sig][index] = ident; } var generated = false; - var wrapped = {}; + var wrapped = {}; // whether we wrapped a lib func var maxTable = 0; for (var t in tables) { if (t == 'pre') continue; @@ -349,10 +344,11 @@ var Functions = { if (ASM_JS) { var curr = table[i]; if (curr && curr != '0' && !Functions.implementedFunctions[curr]) { - curr = toNiceIdent(curr); // fix Math.* to Math_* + var short = toNiceIdent(curr); // fix Math.* to Math_* + curr = t + '_' + short; // libfuncs can alias with different sigs, wrap each separately // This is a library function, we can't just put it in the function table, need a wrapper if (!wrapped[curr]) { - var args = '', arg_coercions = '', call = curr + '(', retPre = '', retPost = ''; + var args = '', arg_coercions = '', call = short + '(', retPre = '', retPost = ''; if (t[0] != 'v') { if (t[0] == 'i') { retPre = 'return '; @@ -367,7 +363,7 @@ var Functions = { call += (j > 1 ? ',' : '') + asmCoercion('a' + j, t[j] != 'i' ? 'float' : 'i32'); } call += ')'; - if (curr == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things'); + if (short == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things'); tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + retPre + call + retPost + ' }\n'; wrapped[curr] = 1; } diff --git a/src/parseTools.js b/src/parseTools.js index f11c867a..046dac1b 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -727,15 +727,37 @@ function makeI64(low, high) { // Splits a number (an integer in a double, possibly > 32 bits) into an USE_TYPED_ARRAYS == 2 i64 value. // Will suffer from rounding. mergeI64 does the opposite. function splitI64(value, floatConversion) { - // We need to min here, since our input might be a double, and large values are rounded, so they can + // general idea: + // + // $1$0 = ~~$d >>> 0; + // $1$1 = Math_abs($d) >= 1 ? ( + // $d > 0 ? Math.min(Math_floor(($d)/ 4294967296.0), 4294967295.0) + // : Math_ceil(Math.min(-4294967296.0, $d - $1$0)/ 4294967296.0) + // ) : 0; + // + // We need to min on positive values here, since our input might be a double, and large values are rounded, so they can // be slightly higher than expected. And if we get 4294967296, that will turn into a 0 if put into a // HEAP32 or |0'd, etc. + // + // For negatives, we need to ensure a -1 if the value is overall negative, even if not significant negative component + var lowInput = legalizedI64s ? value : 'VALUE'; if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput); + var low = lowInput + '>>>0'; + var high = makeInlineCalculation( + asmCoercion('Math.abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' + + '(VALUE > ' + asmEnsureFloat('0', 'double') + ' ? ' + + asmCoercion('Math.min(' + asmCoercion('Math.floor((VALUE)/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0' + + ' : ' + asmFloatToInt(asmCoercion('Math.ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'float') + ')', 'double')) + '>>>0' + + ')' + + ' : 0', + value, + 'tempDouble' + ); if (legalizedI64s) { - return [lowInput + '>>>0', asmCoercion('Math.min(' + asmCoercion('Math.floor((' + value + ')/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0']; + return [low, high]; } else { - return makeInlineCalculation(makeI64(lowInput + '>>>0', asmCoercion('Math.min(' + asmCoercion('Math.floor(VALUE/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0'), value, 'tempBigIntP'); + return makeI64(low, high); } } function mergeI64(value, unsigned) { @@ -1244,7 +1266,7 @@ function indexizeFunctions(value, type) { if (!sig) { sig = Functions.unimplementedFunctions[value] = Functions.getSignature(out.returnType, out.segments ? out.segments.map(function(segment) { return segment[0].text }) : [], isVarArgsFunctionType(type)); } - return Functions.getIndex(value, undefined, sig); + return Functions.getIndex(value, sig); } return value; } diff --git a/src/postamble.js b/src/postamble.js index c4ca3aae..df844121 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -11,12 +11,18 @@ ExitStatus.prototype.constructor = ExitStatus; var initialStackTop; +var preloadStartTime = null; + Module['callMain'] = Module.callMain = function callMain(args) { assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)'); assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called'); args = args || []; + if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) { + Module.printErr('preload time: ' + (Date.now() - preloadStartTime) + ' ms'); + } + ensureInitRuntime(); var argc = args.length+1; @@ -72,6 +78,8 @@ Module['callMain'] = Module.callMain = function callMain(args) { function run(args) { args = args || Module['arguments']; + if (preloadStartTime === null) preloadStartTime = Date.now(); + if (runDependencies > 0) { Module.printErr('run() called, but dependencies remain, so not running'); return; @@ -127,6 +135,7 @@ Module['exit'] = Module.exit = exit; function abort(text) { if (text) { Module.print(text); + Module.printErr(text); } ABORT = true; diff --git a/src/settings.js b/src/settings.js index 3ecac040..cb64bfd9 100644 --- a/src/settings.js +++ b/src/settings.js @@ -191,9 +191,8 @@ var GL_TESTING = 0; // When enabled, sets preserveDrawingBuffer in the context, var GL_MAX_TEMP_BUFFER_SIZE = 2097152; // How large GL emulation temp buffers are var GL_UNSAFE_OPTS = 1; // Enables some potentially-unsafe optimizations in GL emulation code var FULL_ES2 = 0; // Forces support for all GLES2 features, not just the WebGL-friendly subset. -var FORCE_GL_EMULATION = 0; // Forces inclusion of full GL emulation code. -var DISABLE_GL_EMULATION = 0; // Disable inclusion of full GL emulation code. Useful when you don't want emulation - // but do need INCLUDE_FULL_LIBRARY or MAIN_MODULE. +var LEGACY_GL_EMULATION = 0; // Includes code to emulate various desktop GL features. Incomplete but useful + // in some cases, see https://github.com/kripken/emscripten/wiki/OpenGL-support var STB_IMAGE = 0; // Enables building of stb-image, a tiny public-domain library for decoding images, allowing // decoding of images without using the browser's built-in decoders. The benefit is that this @@ -316,11 +315,12 @@ var SIDE_MODULE = 0; // Corresponds to MAIN_MODULE var BUILD_AS_SHARED_LIB = 0; // Whether to build the code as a shared library // 0 here means this is not a shared lib: It is a main file. - // All shared library options (1 and 2) are currently deprecated XXX // 1 means this is a normal shared lib, load it with dlopen() // 2 means this is a shared lib that will be linked at runtime, // which means it will insert its functions into // the global namespace. See STATIC_LIBS_TO_LOAD. + // + // Value 2 is currently deprecated. var RUNTIME_LINKED_LIBS = []; // If this is a main file (BUILD_AS_SHARED_LIB == 0), then // we will link these at runtime. They must have been built with // BUILD_AS_SHARED_LIB == 2. diff --git a/src/shell.js b/src/shell.js index bac4eaa3..f91aa96a 100644 --- a/src/shell.js +++ b/src/shell.js @@ -74,7 +74,12 @@ else if (ENVIRONMENT_IS_SHELL) { Module['print'] = print; if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm - Module['read'] = read; + if (typeof read != 'undefined') { + Module['read'] = read; + } else { + Module['read'] = function() { throw 'no read() available (jsc?)' }; + } + Module['readBinary'] = function(f) { return read(f, 'binary'); }; diff --git a/system/include/compat/math.h b/system/include/compat/math.h new file mode 100644 index 00000000..089cf66b --- /dev/null +++ b/system/include/compat/math.h @@ -0,0 +1,14 @@ +#ifndef _COMPAT_MATH_H_ +#define _COMPAT_MATH_H_ + +#ifndef isinff + #define isinff isinf +#endif + +#ifndef isnanf + #define isnanf isnan +#endif + +#include_next <math.h> + +#endif /* _COMPAT_MATH_H_ */ diff --git a/system/include/compat/stdlib.h b/system/include/compat/stdlib.h new file mode 100644 index 00000000..dc01947d --- /dev/null +++ b/system/include/compat/stdlib.h @@ -0,0 +1,16 @@ +#ifndef _COMPAT_STDLIB_H +#define _COMPAT_STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +int getloadavg(double loadavg[], int nelem); + +#ifdef __cplusplus +} +#endif + +#include_next <stdlib.h> + +#endif diff --git a/system/include/compat/string.h b/system/include/compat/string.h new file mode 100644 index 00000000..880089cc --- /dev/null +++ b/system/include/compat/string.h @@ -0,0 +1,17 @@ +#ifndef _COMPAT_STRING_H +#define _COMPAT_STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char* strlwr(char *); +extern char* strupr(char *); + +#ifdef __cplusplus +} +#endif + +#include_next <string.h> + +#endif diff --git a/system/include/compat/sys/stat.h b/system/include/compat/sys/stat.h new file mode 100644 index 00000000..731502ea --- /dev/null +++ b/system/include/compat/sys/stat.h @@ -0,0 +1,20 @@ +#ifndef _COMPAT_STAT_H +#define _COMPAT_STAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include_next <sys/stat.h> + +#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) +#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) +#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) +#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) +#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/libc/sys/timeb.h b/system/include/compat/sys/timeb.h index 0a2c3de8..0a2c3de8 100644 --- a/system/include/libc/sys/timeb.h +++ b/system/include/compat/sys/timeb.h diff --git a/system/include/compat/unistd.h b/system/include/compat/unistd.h new file mode 100644 index 00000000..07c3afde --- /dev/null +++ b/system/include/compat/unistd.h @@ -0,0 +1,16 @@ +#ifndef _COMPAT_UNISTD_H +#define _COMPAT_UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +char * getwd(char *__buf ); + +#ifdef __cplusplus +} +#endif + +#include_next <unistd.h> + +#endif diff --git a/system/include/compat/xlocale.h b/system/include/compat/xlocale.h new file mode 100644 index 00000000..4bafa27d --- /dev/null +++ b/system/include/compat/xlocale.h @@ -0,0 +1,21 @@ +#ifndef _COMPAT_XLOCALE_H_ +#define _COMPAT_XLOCALE_H_ + +#include <locale.h> + +#ifdef __cplusplus +extern "C" { +#endif + +long long strtoll_l(const char *start, char **end, int base, locale_t loc); +unsigned long long strtoull_l(const char *start, char **end, int base, locale_t loc); +double strtold_l(const char *start, char **end, locale_t loc); + +#ifdef __cplusplus +} +#endif + +#include_next <xlocale.h> + +#endif /* _COMPAT_XLOCALE_H_ */ + diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index 28e6063c..f0df8dca 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -20,14 +20,13 @@ extern "C" { /* * Forces LLVM to not dead-code-eliminate a function. Note that - * closure may still eliminate it at the JS level, for which you - * should use EXPORTED_FUNCTIONS (see settings.js). - * - * **DEPRECATED**: Use EXPORTED_FUNCTIONS instead, which will work - * with closure, asm.js, etc. For example - * -s EXPORTED_FUNCTIONS=["_main", "myfunc"] + * you still need to use EXPORTED_FUNCTIONS so it stays alive + * in JS, e.g. + * emcc -s EXPORTED_FUNCTIONS=["_main", "_myfunc"] + * and in the source file + * void EMSCRIPTEN_KEEPALIVE myfunc() {..} */ -/* #define EMSCRIPTEN_KEEPALIVE __attribute__((used)) */ +#define EMSCRIPTEN_KEEPALIVE __attribute__((used)) /* * Interface to the underlying JS engine. This function will diff --git a/system/include/libc/stdlib.h b/system/include/libc/stdlib.h index 888b6041..6fdef40b 100644 --- a/system/include/libc/stdlib.h +++ b/system/include/libc/stdlib.h @@ -223,8 +223,6 @@ extern long double strtold (const char *, char **); extern long double wcstold (const wchar_t *, wchar_t **); #endif /* _LDBL_EQ_DBL */ -int getloadavg(double loadavg[], int nelem); /* XXX Emscripten */ - _END_STD_C #endif /* _STDLIB_H_ */ diff --git a/system/include/libc/string.h b/system/include/libc/string.h index 515c71a7..8fd9ea43 100644 --- a/system/include/libc/string.h +++ b/system/include/libc/string.h @@ -72,8 +72,6 @@ size_t _EXFUN(strlcpy,(char *, const char *, size_t)); int _EXFUN(strncasecmp,(const char *, const char *, size_t)); size_t _EXFUN(strnlen,(const char *, size_t)); char *_EXFUN(strsep,(char **, const char *)); -char *_EXFUN(strlwr,(char *)); -char *_EXFUN(strupr,(char *)); #if defined(__CYGWIN__) || defined(EMSCRIPTEN) #ifndef DEFS_H /* Kludge to work around problem compiling in gdb */ char *_EXFUN(strsignal, (int __signo)); diff --git a/system/include/libc/sys/unistd.h b/system/include/libc/sys/unistd.h index 1a414b3c..a4219d4d 100644 --- a/system/include/libc/sys/unistd.h +++ b/system/include/libc/sys/unistd.h @@ -102,7 +102,6 @@ uid_t _EXFUN(getuid, (void )); #endif #if defined(EMSCRIPTEN) || defined(__CYGWIN__) char * _EXFUN(getusershell, (void)); -char * _EXFUN(getwd, (char *__buf )); int _EXFUN(iruserok, (unsigned long raddr, int superuser, const char *ruser, const char *luser)); #endif int _EXFUN(isatty, (int __fildes )); diff --git a/system/include/xlocale.h b/system/include/xlocale.h index bb3b50e5..6867d25f 100644 --- a/system/include/xlocale.h +++ b/system/include/xlocale.h @@ -1,4 +1,3 @@ - #ifndef _XLOCALE_H_ #define _XLOCALE_H_ @@ -9,10 +8,6 @@ extern "C" { #endif -long long strtoll_l(const char *start, char **end, int base, locale_t loc); -unsigned long long strtoull_l(const char *start, char **end, int base, locale_t loc); -double strtold_l(const char *start, char **end, locale_t loc); - int strcoll_l(const char *s1, const char *s2, locale_t locale); int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale); @@ -43,5 +38,5 @@ size_t strftime_l(char *s, size_t maxsize, const char *format, const struct tm * } #endif -#endif /* _LOCALE_H_ */ +#endif /* _XLOCALE_H_ */ diff --git a/tests/aniso.c b/tests/aniso.c index 1126265e..f210e5a5 100644 --- a/tests/aniso.c +++ b/tests/aniso.c @@ -161,7 +161,7 @@ int main(int argc, char *argv[]) for (int x = 0; x < n; x++) { int start = x*w*2; glBegin( GL_TRIANGLES ); - glTexCoord2i( 1, 0 ); glVertex3f( start , 0, 0 ); + glTexCoord2i( 1, 0 ); glVertex2i( start , 0 ); glTexCoord2i( 0, 0 ); glVertex3f( start+w, 300, 0 ); glTexCoord2i( 1, 1 ); glVertex3f( start-w, 300, 0 ); glEnd(); @@ -209,5 +209,11 @@ int main(int argc, char *argv[]) SDL_Quit(); - return 0; + // check for asm compilation bug with aliased functions with different sigs + void (*f)(int, int) = glVertex2i; + if ((int)f % 16 == 4) f(5, 7); + void (*g)(int, int) = glVertex3f; + if ((int)g % 16 == 4) g(5, 7); + return (int)f + (int)g; } + diff --git a/tests/cases/phi24_ta2.ll b/tests/cases/phi24_ta2.ll index 4894d5e6..2d9b6646 100644 --- a/tests/cases/phi24_ta2.ll +++ b/tests/cases/phi24_ta2.ll @@ -252,6 +252,7 @@ target triple = "i386-pc-linux-gnu" @g_287 = internal constant i32 -1, align 4 define i32 @main(i32 %argc, i8** nocapture %argv) nounwind { + %msgdummy = alloca { i8*, { i64, i8* } (i8*)* } ; test for parsing of this kind of stuff, compilation-only test %p_6.i.i = alloca %union.U3, align 8 %1 = icmp eq i32 %argc, 2 br i1 %1, label %2, label %7 diff --git a/tests/glut_touchevents.c b/tests/glut_touchevents.c new file mode 100644 index 00000000..1f097895 --- /dev/null +++ b/tests/glut_touchevents.c @@ -0,0 +1,64 @@ +#include <stdio.h> +#include <stdlib.h> +#include <GL/glut.h> +#include <EGL/egl.h> +#include <emscripten.h> + +#define MULTILINE(...) #__VA_ARGS__ + +int touch_started = 0; +int touch_ended = 0; + +int result = 0; + +void mouseCB(int button, int state, int x, int y) +{ + if(button == GLUT_LEFT_BUTTON) + { + if(state == GLUT_DOWN) + { + touch_started = 1; + } + else if(state == GLUT_UP) + { + touch_ended = 1; + } + } +} + +int main(int argc, char *argv[]) +{ + emscripten_run_script(MULTILINE( + Module.injectEvent = function(eventType, x, y) { + // Desktop browsers do not have the event types for touch events, + // so we fake them by creating a plain-vanilla UIEvent and then + // filling in the fields that we look for with appropriate values. + var touch = { + pageX: x, + pageY: y + }; + var touches = [ touch ]; + touches.item = function(i) { return this[i]; }; + + var event = document.createEvent('UIEvent'); + event.target = Module['canvas']; + event.button = 0; + event.touches = touches; + event.initUIEvent(eventType, true, true); + Module['canvas'].dispatchEvent(event); + } + )); + + // Fake a touch device so that glut sets up the appropriate event handlers. + emscripten_run_script("document.documentElement['ontouchstart'] = 1"); + glutInit(&argc, argv); + + glutMouseFunc(&mouseCB); + + emscripten_run_script("Module.injectEvent('touchend', 100, 100)"); + emscripten_run_script("Module.injectEvent('touchstart', 100, 100)"); + result = touch_started && touch_ended; + + REPORT_RESULT(); + return 0; +} diff --git a/tests/runner.py b/tests/runner.py index 41fd5b90..bbbc23e5 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -48,6 +48,9 @@ class RunnerCore(unittest.TestCase): env = {} + def skipme(self): # used by tests we ask on the commandline to be skipped, see right before call to unittest.main + return self.skip('requested to be skipped') + def setUp(self): Settings.reset() self.banned_js_engines = [] @@ -272,6 +275,18 @@ process(sys.argv[1]) print "Output: " + output[0] return output[0] + # Tests that the given two paths are identical, modulo path delimiters. E.g. "C:/foo" is equal to "C:\foo". + def assertPathsIdentical(self, path1, path2): + path1 = path1.replace('\\', '/') + path2 = path2.replace('\\', '/') + return self.assertIdentical(path1, path2) + + # Tests that the given two multiline text content are identical, modulo line ending differences (\r\n on Windows, \n on Unix). + def assertTextDataIdentical(self, text1, text2): + text1 = text1.replace('\r\n', '\n') + text2 = text2.replace('\r\n', '\n') + return self.assertIdentical(text1, text2) + def assertIdentical(self, values, y): if type(values) not in [list, tuple]: values = [values] for x in values: @@ -477,7 +492,7 @@ def server_func(dir, q): if 'report_' in s.path: q.put(s.path) else: - filename = s.path[1:] + filename = s.path.split('?')[0][1:] if os.path.exists(filename): s.send_response(200) s.send_header("Content-type", "text/html") @@ -646,6 +661,7 @@ class BrowserCore(RunnerCore): self.reftest(path_from_root('tests', reference)) args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1'] Popen([PYTHON, EMCC, temp_filepath, '-o', outfile] + args).communicate() + assert os.path.exists(outfile) if type(expected) is str: expected = [expected] self.run_browser(outfile, message, ['/report_result?' + e for e in expected]) @@ -660,9 +676,55 @@ if __name__ == '__main__': elif len(JS_ENGINES) < total_engines: print 'WARNING: Not all the JS engines in JS_ENGINES appears to work, ignoring those.' + # Create a list of modules to load tests from + modules = [] + for filename in glob.glob(os.path.join(os.path.dirname(__file__), 'test*.py')): + module_dir, module_file = os.path.split(filename) + module_name, module_ext = os.path.splitext(module_file) + __import__(module_name) + modules.append(sys.modules[module_name]) + + # Extract the JS engine override from the arguments (used by benchmarks) + for i in range(1, len(sys.argv)): + arg = sys.argv[i] + if arg.isupper(): + print 'Interpreting all capital argument "%s" as JS_ENGINE override' % arg + Building.JS_ENGINE_OVERRIDE = eval(arg) + sys.argv[i] = None + sys.argv = filter(lambda arg: arg is not None, sys.argv) + # If an argument comes in as test_*, treat it as a test of the default suite sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv) + # If a test (e.g. test_html) is specified as ALL.test_html, add an entry for each test_mode + if len(sys.argv) == 2 and sys.argv[1].startswith('ALL.'): + ignore, test = sys.argv[1].split('.') + print 'Running all test modes on test "%s"' % test + sys.argv = [sys.argv[0]] + map(lambda mode: mode+'.'+test, test_modes) + + # Skip requested tests + for i in range(len(sys.argv)): + arg = sys.argv[i] + if arg.startswith('skip:'): + which = arg.split('skip:')[1] + if which.startswith('ALL.'): + ignore, test = which.split('.') + which = map(lambda mode: mode+'.'+test, test_modes) + else: + which = [which] + + print >> sys.stderr, ','.join(which) + for test in which: + print >> sys.stderr, 'will skip "%s"' % test + for m in modules: + try: + exec('m.' + test + ' = RunnerCore("skipme")') + break + except: + pass + sys.argv[i] = None + sys.argv = filter(lambda arg: arg is not None, sys.argv) + # If no tests were specified, run the core suite if len(sys.argv) == 1: sys.argv = [sys.argv[0]] + map(lambda mode: mode, test_modes) @@ -670,6 +732,7 @@ if __name__ == '__main__': ============================================================================== Running the main part of the test suite. Don't forget to run the other parts! + other - tests separate from the main suite sanity - tests for first run, etc., modifies ~/.emscripten benchmark - run before and after each set of changes before pushing to master, verify no regressions @@ -706,55 +769,6 @@ an individual test with ''' time.sleep(2) - # If a test (e.g. test_html) is specified as ALL.test_html, add an entry for each test_mode - if len(sys.argv) == 2 and sys.argv[1].startswith('ALL.'): - ignore, test = sys.argv[1].split('.') - print 'Running all test modes on test "%s"' % test - sys.argv = [sys.argv[0]] + map(lambda mode: mode+'.'+test, test_modes) - - # Extract the JS engine override from the arguments (used by benchmarks) - for i in range(1, len(sys.argv)): - arg = sys.argv[i] - if arg.isupper(): - print 'Interpreting all capital argument "%s" as JS_ENGINE override' % arg - Building.JS_ENGINE_OVERRIDE = eval(arg) - sys.argv[i] = None - sys.argv = filter(lambda arg: arg is not None, sys.argv) - - # Create a list of modules to load tests from - modules = [] - for filename in glob.glob(os.path.join(os.path.dirname(__file__), 'test*.py')): - module_dir, module_file = os.path.split(filename) - module_name, module_ext = os.path.splitext(module_file) - __import__(module_name) - modules.append(sys.modules[module_name]) - - # Skip requested tests - def skipme(self): - return self.skip('requested to be skipped') - - for i in range(len(sys.argv)): - arg = sys.argv[i] - if arg.startswith('skip:'): - which = arg.split('skip:')[1] - if which.startswith('ALL.'): - ignore, test = which.split('.') - which = map(lambda mode: mode+'.'+test, test_modes) - else: - which = [which] - - print >> sys.stderr, ','.join(which) - for test in which: - print >> sys.stderr, 'will skip "%s"' % test - for m in modules: - try: - exec('m.' + test + ' = skipme') - break - except: - pass - sys.argv[i] = None - sys.argv = filter(lambda arg: arg is not None, sys.argv) - # Filter and load tests from the discovered modules loader = unittest.TestLoader() names = sys.argv[1:] @@ -765,10 +779,17 @@ an individual test with except: pass + numFailures = 0 # Keep count of the total number of failing tests. + # Run the discovered tests if not len(suites): print >> sys.stderr, 'No tests found for %s' % str(sys.argv[1:]) + numFailures = 1 else: testRunner = unittest.TextTestRunner(verbosity=2) for suite in suites: - testRunner.run(suite) + results = testRunner.run(suite) + numFailures += len(results.errors) + len(results.failures) + + # Return the number of failures as the process exit code for automating success/failure reporting. + exit(numFailures) diff --git a/tests/sdl_ogl_proc_alias.c b/tests/sdl_ogl_proc_alias.c new file mode 100644 index 00000000..c96da81b --- /dev/null +++ b/tests/sdl_ogl_proc_alias.c @@ -0,0 +1,180 @@ +/******************************************************************* + * * + * Using SDL With OpenGL * + * * + * Tutorial by Kyle Foley (sdw) * + * * + * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL * + * * + *******************************************************************/ + +/* +THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION +AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN. + +THE ORIGINAL AUTHOR IS KYLE FOLEY. + +THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY +OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF +MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, +ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE +RESULTING FROM THE USE, MODIFICATION, OR +REDISTRIBUTION OF THIS SOFTWARE. +*/ + +#include "SDL/SDL.h" +#include "SDL/SDL_image.h" +#include "SDL/SDL_opengl.h" + +#include <stdio.h> +#include <string.h> + +void (*true_glGenTextures)(GLsizei, GLuint*) = NULL; + +void glGenTextures(GLsizei n, GLuint *textures) { + printf("num? %d\n", n); + true_glGenTextures(n + 1, textures); // correct the error, ensures we are gone through +} + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen; + + // Slightly different SDL initialization + if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { + printf("Unable to initialize SDL: %s\n", SDL_GetError()); + return 1; + } + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new* + + screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed* + if ( !screen ) { + printf("Unable to set video mode: %s\n", SDL_GetError()); + return 1; + } + + // Set the OpenGL state after creating the context with SDL_SetVideoMode + + glClearColor( 0, 0, 0, 0 ); + + glEnable( GL_TEXTURE_2D ); // Needed when we're using the fixed-function pipeline. + + glViewport( 0, 0, 640, 480 ); + + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); // just for testing + glLoadIdentity(); + + glOrtho( 0, 640, 480, 0, -1, 1 ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Load the OpenGL texture + + GLuint texture; // Texture object handle + SDL_Surface *surface; // Gives us the information to make the texture + + if ( (surface = IMG_Load("screenshot.png")) ) { + + // Check that the image's width is a power of 2 + if ( (surface->w & (surface->w - 1)) != 0 ) { + printf("warning: image.bmp's width is not a power of 2\n"); + } + + // Also check if the height is a power of 2 + if ( (surface->h & (surface->h - 1)) != 0 ) { + printf("warning: image.bmp's height is not a power of 2\n"); + } + + true_glGenTextures = SDL_GL_GetProcAddress("glGenTextures"); + + // Have OpenGL generate a texture object handle for us + glGenTextures( 0, &texture ); + + // Bind the texture object + glBindTexture( GL_TEXTURE_2D, texture ); + + // Set the texture's stretching properties + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + //SDL_LockSurface(surface); + + // Add some greyness + memset(surface->pixels, 0x66, surface->w*surface->h); + + // Edit the texture object's image data using the information SDL_Surface gives us + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, + GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels ); + + //SDL_UnlockSurface(surface); + } + else { + printf("SDL could not load image.bmp: %s\n", SDL_GetError()); + SDL_Quit(); + return 1; + } + + // Free the SDL_Surface only if it was successfully created + if ( surface ) { + SDL_FreeSurface( surface ); + } + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + // Bind the texture to which subsequent calls refer to + glBindTexture( GL_TEXTURE_2D, texture ); + + glBegin( GL_QUADS ); + glTexCoord2i( 0, 0 ); glVertex3f( 10, 10, 0 ); + glTexCoord2i( 1, 0 ); glVertex3f( 300, 10, 0 ); + glTexCoord2i( 1, 1 ); glVertex3f( 300, 128, 0 ); + glTexCoord2i( 0, 1 ); glVertex3f( 10, 128, 0 ); + + glTexCoord2f( 0, 0.5 ); glVertex3f( 410, 10, 0 ); + glTexCoord2f( 1, 0.5 ); glVertex3f( 600, 10, 0 ); + glTexCoord2f( 1, 1 ); glVertex3f( 630, 200, 0 ); + glTexCoord2f( 0.5, 1 ); glVertex3f( 310, 250, 0 ); + glEnd(); + + glBegin( GL_TRIANGLE_STRIP ); + glTexCoord2i( 0, 0 ); glVertex3f( 100, 300, 0 ); + glTexCoord2i( 1, 0 ); glVertex3f( 300, 300, 0 ); + glTexCoord2i( 1, 1 ); glVertex3f( 300, 400, 0 ); + glTexCoord2i( 0, 1 ); glVertex3f( 500, 410, 0 ); + glEnd(); + + glDisable(GL_TEXTURE_2D); + + glColor3ub(90, 255, 255); + glBegin( GL_QUADS ); + glVertex3f( 10, 410, 0 ); + glVertex3f( 300, 410, 0 ); + glVertex3f( 300, 480, 0 ); + glVertex3f( 10, 470, 0 ); + glEnd(); + + glBegin( GL_QUADS ); + glColor3f(1.0, 0, 1.0); glVertex3f( 410, 410, 0 ); + glColor3f(0, 1.0, 0); glVertex3f( 600, 410, 0 ); + glColor3f(0, 0, 1.0); glVertex3f( 600, 480, 0 ); + glColor3f(1.0, 1.0, 1.0); glVertex3f( 410, 470, 0 ); + glEnd(); + + SDL_GL_SwapBuffers(); + +#if !EMSCRIPTEN + // Wait for 3 seconds to give us a chance to see the image + SDL_Delay(3000); +#endif + + // Now we can delete the OpenGL texture and close down SDL + glDeleteTextures( 1, &texture ); + + SDL_Quit(); + + return 0; +} diff --git a/tests/sockets/test_sockets_echo_server.c b/tests/sockets/test_sockets_echo_server.c index 8a48b878..f01004c3 100644 --- a/tests/sockets/test_sockets_echo_server.c +++ b/tests/sockets/test_sockets_echo_server.c @@ -37,6 +37,11 @@ typedef struct { server_t server; client_t client; +void cleanup() { + if (server.fd) close(server.fd); + if (client.fd) close(client.fd); +} + void main_loop(void *arg) { int res; fd_set fdr; @@ -105,6 +110,9 @@ int main() { struct sockaddr_in addr; int res; + atexit(cleanup); + //signal(SIGTERM, cleanup); + memset(&server, 0, sizeof(server_t)); memset(&client, 0, sizeof(client_t)); diff --git a/tests/sockets/test_sockets_partial_server.c b/tests/sockets/test_sockets_partial_server.c index 57fae84b..21096552 100644 --- a/tests/sockets/test_sockets_partial_server.c +++ b/tests/sockets/test_sockets_partial_server.c @@ -14,18 +14,13 @@ #include <emscripten.h> #endif -int serverfd = -1; -int clientfd = -1; - -// csock.send("\x09\x01\x02\x03\x04\x05\x06\x07\x08\x09") -// csock.send("\x08\x01\x02\x03\x04\x05\x06\x07\x08") -// csock.send("\x07\x01\x02\x03\x04\x05\x06\x07") -// csock.send("\x06\x01\x02\x03\x04\x05\x06") -// csock.send("\x05\x01\x02\x03\x04\x05") -// csock.send("\x04\x01\x02\x03\x04") -// csock.send("\x03\x01\x02\x03") -// csock.send("\x02\x01\x02") -// csock.send("\x01\x01") +int serverfd = 0; +int clientfd = 0; + +void cleanup() { + if (serverfd) close(serverfd); + if (clientfd) close(clientfd); +} void do_send(int sockfd) { static char* buffers[] = { @@ -69,7 +64,7 @@ void iter(void *arg) { FD_ZERO(&fdr); FD_ZERO(&fdw); FD_SET(serverfd, &fdr); - if (clientfd != -1) FD_SET(clientfd, &fdw); + if (clientfd) FD_SET(clientfd, &fdw); res = select(64, &fdr, &fdw, NULL, NULL); if (res == -1) { perror("select failed"); @@ -91,6 +86,9 @@ int main() { struct sockaddr_in addr; int res; + atexit(cleanup); + //signal(SIGTERM, cleanup); + // create the socket serverfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (serverfd == -1) { diff --git a/tests/sockets/webrtc_host.c b/tests/sockets/webrtc_host.c new file mode 100644 index 00000000..770e59e0 --- /dev/null +++ b/tests/sockets/webrtc_host.c @@ -0,0 +1,89 @@ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <assert.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 +#define BUFLEN 16 + +int result = 0; +int sock; +char buf[BUFLEN]; +char expected[] = "emscripten"; +struct sockaddr_in si_host, + si_peer; +struct iovec iov[1]; +struct msghdr hdr; +int done = 0; + +void iter(void* arg) { + int n; + n = recvmsg(sock, &hdr, 0); + + if(0 < n) { + done = 1; + fprintf(stderr, "received %d bytes: %s", n, (char*)hdr.msg_iov[0].iov_base); + + shutdown(sock, SHUT_RDWR); + close(sock); + +#if EMSCRIPTEN + int result = 1; + REPORT_RESULT(); + exit(EXIT_SUCCESS); + emscripten_cancel_main_loop(); +#endif + } else if(EWOULDBLOCK != errno) { + perror("recvmsg failed"); + exit(EXIT_FAILURE); + emscripten_cancel_main_loop(); + } +} + +int main(void) +{ + memset(&si_host, 0, sizeof(struct sockaddr_in)); + memset(&si_peer, 0, sizeof(struct sockaddr_in)); + + si_host.sin_family = AF_INET; + si_host.sin_port = htons(8991); + si_host.sin_addr.s_addr = htonl(INADDR_ANY); + + if(-1 == (sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))) { + perror("cannot create host socket"); + exit(EXIT_FAILURE); + } + + if(-1 == bind(sock, (struct sockaddr*)&si_host, sizeof(struct sockaddr))) { + perror("cannot bind host socket"); + exit(EXIT_FAILURE); + } + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + + memset (&hdr, 0, sizeof (struct msghdr)); + + hdr.msg_name = &si_peer; + hdr.msg_namelen = sizeof(struct sockaddr_in); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else + while (!done) iter(NULL); +#endif + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/tests/sockets/webrtc_peer.c b/tests/sockets/webrtc_peer.c new file mode 100644 index 00000000..d24979e7 --- /dev/null +++ b/tests/sockets/webrtc_peer.c @@ -0,0 +1,81 @@ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <assert.h> +#if EMSCRIPTEN +#include <emscripten.h> +#endif + +#define EXPECTED_BYTES 5 +#define BUFLEN 16 +#define HOST_ADDR "10.0.0.1" + +int result = 0; +int sock; +char buf[16] = "emscripten"; +struct sockaddr_in si_host; +struct iovec iov[1]; +struct msghdr hdr; +int done = 0; + +void iter(void* arg) { + int n; + n = sendmsg(sock, &hdr, 0); + + if(0 < n) { + done = 1; + fprintf(stderr, "sent %d bytes: %s", n, (char*)hdr.msg_iov[0].iov_base); + + shutdown(sock, SHUT_RDWR); + close(sock); + + exit(EXIT_SUCCESS); + emscripten_cancel_main_loop(); + } else if(EWOULDBLOCK != errno) { + perror("sendmsg failed"); + exit(EXIT_FAILURE); + emscripten_cancel_main_loop(); + } +} + +int main(void) +{ + memset(&si_host, 0, sizeof(struct sockaddr_in)); + + si_host.sin_family = AF_INET; + si_host.sin_port = htons(8991); + if(0 == inet_pton(AF_INET, HOST_ADDR, &si_host.sin_addr)) { + perror("inet_aton failed"); + exit(EXIT_FAILURE); + } + + if(-1 == (sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))) { + perror("cannot create socket"); + exit(EXIT_FAILURE); + } + + iov[0].iov_base = buf; + iov[0].iov_len = sizeof(buf); + + memset (&hdr, 0, sizeof (struct msghdr)); + + hdr.msg_name = &si_host; + hdr.msg_namelen = sizeof(struct sockaddr_in); + hdr.msg_iov = iov; + hdr.msg_iovlen = 1; + +#if EMSCRIPTEN + emscripten_set_main_loop(iter, 0, 0); +#else + while (!done) iter(NULL); +#endif + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/tests/test_browser.py b/tests/test_browser.py index 60c030aa..7c387071 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -620,7 +620,7 @@ Press any key to continue.''' def test_sdl_canvas(self): open(os.path.join(self.get_dir(), 'sdl_canvas.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_canvas.c')).read())) - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_sdl_key(self): @@ -787,6 +787,9 @@ Press any key to continue.''' Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-O2', '--minify', '0', '-o', 'sdl_mouse.js', '--pre-js', 'pre.js']).communicate() self.run_browser('page.html', '', '/report_result?600') + def test_glut_touchevents(self): + self.btest('glut_touchevents.c', '1') + def test_sdl_pumpevents(self): # key events should be detected using SDL_PumpEvents open(os.path.join(self.get_dir(), 'pre.js'), 'w').write(''' @@ -843,50 +846,55 @@ Press any key to continue.''' def test_sdl_ogl(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl.c', reference='screenshot-gray-purple.png', reference_slack=1, - args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png'], + args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with gray at the top.') def test_sdl_ogl_defaultmatrixmode(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl_defaultMatrixMode.c', reference='screenshot-gray-purple.png', reference_slack=1, - args=['--minify', '0', '--preload-file', 'screenshot.png'], + args=['--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with gray at the top.') def test_sdl_ogl_p(self): # Immediate mode with pointers shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_ogl_p.c', reference='screenshot-gray.png', reference_slack=1, - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with gray at the top.') + def test_sdl_ogl_proc_alias(self): + shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) + self.btest('sdl_ogl_proc_alias.c', reference='screenshot-gray-purple.png', reference_slack=1, + args=['-O2', '-g2', '-s', 'INLINING_LIMIT=1', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '-s', 'VERBOSE=1']) + def test_sdl_fog_simple(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_simple.c', reference='screenshot-fog-simple.png', - args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png'], + args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_sdl_fog_negative(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_negative.c', reference='screenshot-fog-negative.png', - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_sdl_fog_density(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_density.c', reference='screenshot-fog-density.png', - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_sdl_fog_exp2(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_exp2.c', reference='screenshot-fog-exp2.png', - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_sdl_fog_linear(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('sdl_fog_linear.c', reference='screenshot-fog-linear.png', reference_slack=1, - args=['--preload-file', 'screenshot.png'], + args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], message='You should see an image with fog.') def test_openal_playback(self): @@ -903,7 +911,7 @@ Press any key to continue.''' def test_glfw(self): open(os.path.join(self.get_dir(), 'glfw.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'glfw.c')).read())) - Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html']).communicate() + Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_egl_width_height(self): @@ -1056,30 +1064,26 @@ Press any key to continue.''' server.terminate() def test_glgears(self): - self.btest('hello_world_gles.c', reference='gears.png', + self.btest('hello_world_gles.c', reference='gears.png', reference_slack=1, args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html', message='You should see animating gears.') def test_glgears_animation(self): es2_suffix = ['', '_full', '_full_944'] for full_es2 in [0, 1, 2]: - for emulation in [0, 1]: - if full_es2 and emulation: continue - print full_es2, emulation - Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles%s.c' % es2_suffix[full_es2]), '-o', 'something.html', - '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', - '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] + - (['-s', 'FORCE_GL_EMULATION=1'] if emulation else []) + - (['-s', 'FULL_ES2=1'] if full_es2 else []), - ).communicate() - self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true') - assert ('var GLEmulation' in open(self.in_dir('something.html')).read()) == emulation, "emulation code should be added when asked for" + print full_es2 + Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles%s.c' % es2_suffix[full_es2]), '-o', 'something.html', + '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', + '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] + + (['-s', 'FULL_ES2=1'] if full_es2 else []), + ).communicate() + self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true') def test_fulles2_sdlproc(self): self.btest('full_es2_sdlproc.c', '1', args=['-s', 'GL_TESTING=1', '-DHAVE_BUILTIN_SINCOS', '-s', 'FULL_ES2=1']) def test_glgears_deriv(self): - self.btest('hello_world_gles_deriv.c', reference='gears.png', + self.btest('hello_world_gles_deriv.c', reference='gears.png', reference_slack=1, args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html', message='You should see animating gears.') with open('something.html') as f: @@ -1163,90 +1167,90 @@ Press any key to continue.''' self.btest('glgetattachedshaders.c', '1') def test_sdlglshader(self): - self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1']) + self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1']) def test_gl_ps(self): # pointers and a shader shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'], reference_slack=1) + self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1) def test_gl_ps_packed(self): # packed data that needs to be strided shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'], reference_slack=1) + self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1) def test_gl_ps_strides(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png']) + self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1']) def test_gl_renderers(self): - self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-s', 'GL_UNSAFE_OPTS=0']) + self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) def test_gl_stride(self): - self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0']) + self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1']) def test_matrix_identity(self): - self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840']) + self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840'], args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre(self): - self.btest('cubegeom_pre.c', reference='cubegeom_pre.png') + self.btest('cubegeom_pre.c', reference='cubegeom_pre.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre2(self): - self.btest('cubegeom_pre2.c', reference='cubegeom_pre2.png', args=['-s', 'GL_DEBUG=1']) # some coverage for GL_DEBUG not breaking the build + self.btest('cubegeom_pre2.c', reference='cubegeom_pre2.png', args=['-s', 'GL_DEBUG=1', '-s', 'LEGACY_GL_EMULATION=1']) # some coverage for GL_DEBUG not breaking the build def test_cubegeom_pre3(self): - self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png') + self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom(self): - self.btest('cubegeom.c', args=['-O2', '-g'], reference='cubegeom.png') + self.btest('cubegeom.c', reference='cubegeom.png', args=['-O2', '-g', '-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_glew(self): - self.btest('cubegeom_glew.c', args=['-O2', '--closure', '1'], reference='cubegeom.png') + self.btest('cubegeom_glew.c', reference='cubegeom.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_color(self): - self.btest('cubegeom_color.c', reference='cubegeom_color.png') + self.btest('cubegeom_color.c', reference='cubegeom_color.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal(self): - self.btest('cubegeom_normal.c', reference='cubegeom_normal.png') + self.btest('cubegeom_normal.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap(self): # draw is given a direct pointer to clientside memory, no element array buffer - self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png') + self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap_far(self): # indices do nto start from 0 - self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png') + self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap_far_range(self): # glDrawRangeElements - self.btest('cubegeom_normal_dap_far_range.c', reference='cubegeom_normal.png') + self.btest('cubegeom_normal_dap_far_range.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap_far_glda(self): # use glDrawArrays - self.btest('cubegeom_normal_dap_far_glda.c', reference='cubegeom_normal_dap_far_glda.png') + self.btest('cubegeom_normal_dap_far_glda.c', reference='cubegeom_normal_dap_far_glda.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_normal_dap_far_glda_quad(self): # with quad - self.btest('cubegeom_normal_dap_far_glda_quad.c', reference='cubegeom_normal_dap_far_glda_quad.png') + self.btest('cubegeom_normal_dap_far_glda_quad.c', reference='cubegeom_normal_dap_far_glda_quad.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_mt(self): - self.btest('cubegeom_mt.c', reference='cubegeom_mt.png') # multitexture + self.btest('cubegeom_mt.c', reference='cubegeom_mt.png', args=['-s', 'LEGACY_GL_EMULATION=1']) # multitexture def test_cubegeom_color2(self): - self.btest('cubegeom_color2.c', reference='cubegeom_color2.png') + self.btest('cubegeom_color2.c', reference='cubegeom_color2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_texturematrix(self): - self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png') + self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_fog(self): - self.btest('cubegeom_fog.c', reference='cubegeom_fog.png') + self.btest('cubegeom_fog.c', reference='cubegeom_fog.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre_vao(self): - self.btest('cubegeom_pre_vao.c', reference='cubegeom_pre_vao.png') + self.btest('cubegeom_pre_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre2_vao(self): - self.btest('cubegeom_pre2_vao.c', reference='cubegeom_pre_vao.png') + self.btest('cubegeom_pre2_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cubegeom_pre2_vao2(self): - self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png') + self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_cube_explosion(self): - self.btest('cube_explosion.c', reference='cube_explosion.png') + self.btest('cube_explosion.c', reference='cube_explosion.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_sdl_canvas_blank(self): self.btest('sdl_canvas_blank.c', reference='sdl_canvas_blank.png') @@ -1298,11 +1302,11 @@ Press any key to continue.''' def test_glbegin_points(self): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) - self.btest('glbegin_points.c', reference='glbegin_points.png', args=['--preload-file', 'screenshot.png']) + self.btest('glbegin_points.c', reference='glbegin_points.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1']) def test_s3tc(self): shutil.copyfile(path_from_root('tests', 'screenshot.dds'), os.path.join(self.get_dir(), 'screenshot.dds')) - self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds']) + self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1']) def test_s3tc_crunch(self): shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds') @@ -1313,7 +1317,7 @@ Press any key to continue.''' shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed - self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'pre.js']) + self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'pre.js', '-s', 'LEGACY_GL_EMULATION=1']) def test_s3tc_crunch_split(self): # load several datafiles/outputs of file packager shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds') @@ -1324,14 +1328,20 @@ Press any key to continue.''' shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed - self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js']) + self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js', '-s', 'LEGACY_GL_EMULATION=1']) def test_aniso(self): + if SPIDERMONKEY_ENGINE in JS_ENGINES: + # asm.js-ification check + Popen([PYTHON, EMCC, path_from_root('tests', 'aniso.c'), '-O2', '-g2', '-s', 'LEGACY_GL_EMULATION=1']).communicate() + Settings.ASM_JS = 1 + self.run_generated_code(SPIDERMONKEY_ENGINE, 'a.out.js') + shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds') - self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds']) + self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds', '-s', 'LEGACY_GL_EMULATION=1']) def test_tex_nonbyte(self): - self.btest('tex_nonbyte.c', reference='tex_nonbyte.png') + self.btest('tex_nonbyte.c', reference='tex_nonbyte.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_float_tex(self): self.btest('float_tex.cpp', reference='float_tex.png') @@ -1340,10 +1350,10 @@ Press any key to continue.''' self.btest('gl_subdata.cpp', reference='float_tex.png') def test_perspective(self): - self.btest('perspective.c', reference='perspective.png') + self.btest('perspective.c', reference='perspective.png', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_runtimelink(self): - return self.skip('shared libs are deprecated') + return self.skip('BUILD_AS_SHARED_LIB=2 is deprecated') main, supp = self.setup_runtimelink_test() open(self.in_dir('supp.cpp'), 'w').write(supp) diff --git a/tests/test_core.py b/tests/test_core.py index 31db6ca5..f3ddc4f4 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -808,6 +808,80 @@ nada ''' self.do_run(src, ',0,,2,C!,0,C!,0,,65535,C!,0,') + def test_double_i64_conversion(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2') + + src = r''' + #include <cassert> + #include <inttypes.h> + #include <stdio.h> + + __attribute((noinline)) bool eq(double d, int64_t i) { + int64_t i2 = (int64_t)d; + if (i != i2) { + printf("%.20g converted to int64 returns %lld, not %lld as expected!\n", d, i2, i); + } + return i == i2; + } + + int main() { + assert(eq(0.0, 0)); + assert(eq(-0.0, 0)); + assert(eq(0.1, 0)); + assert(eq(-0.1, 0)); + assert(eq(0.6, 0)); + assert(eq(-0.6, 0)); + assert(eq(1.0, 1)); + assert(eq(-1.0, -1)); + assert(eq(1.1, 1)); + assert(eq(-1.1, -1)); + assert(eq(1.6, 1)); + assert(eq(-1.6, -1)); + assert(eq(4294967295.0, 4294967295LL)); + assert(eq(4294967295.5, 4294967295LL)); + assert(eq(4294967296.0, 4294967296LL)); + assert(eq(4294967296.5, 4294967296LL)); + assert(eq(14294967295.0, 14294967295LL)); + assert(eq(14294967295.5, 14294967295LL)); + assert(eq(14294967296.0, 14294967296LL)); + assert(eq(14294967296.5, 14294967296LL)); + assert(eq(-4294967295.0, -4294967295LL)); + assert(eq(-4294967295.5, -4294967295LL)); + assert(eq(-4294967296.0, -4294967296LL)); + assert(eq(-4294967296.5, -4294967296LL)); + assert(eq(-14294967295.0, -14294967295LL)); + assert(eq(-14294967295.5, -14294967295LL)); + assert(eq(-14294967296.0, -14294967296LL)); + assert(eq(-14294967296.5, -14294967296LL)); + + assert(eq(4294967295.3, 4294967295LL)); + assert(eq(4294967296.3, 4294967296LL)); + assert(eq(14294967295.3, 14294967295LL)); + assert(eq(14294967296.3, 14294967296LL)); + assert(eq(-4294967295.3, -4294967295LL)); + assert(eq(-4294967296.3, -4294967296LL)); + assert(eq(-14294967295.3, -14294967295LL)); + assert(eq(-14294967296.3, -14294967296LL)); + + assert(eq(4294967295.8, 4294967295LL)); + assert(eq(4294967296.8, 4294967296LL)); + assert(eq(14294967295.8, 14294967295LL)); + assert(eq(14294967296.8, 14294967296LL)); + assert(eq(-4294967295.8, -4294967295LL)); + assert(eq(-4294967296.8, -4294967296LL)); + assert(eq(-14294967295.8, -14294967295LL)); + assert(eq(-14294967296.8, -14294967296LL)); + + // The following number is the largest double such that all integers smaller than this can exactly be represented in a double. + assert(eq(9007199254740992.0, 9007199254740992LL /* == 2^53 */)); + assert(eq(-9007199254740992.0, -9007199254740992LL /* == -2^53 */)); + + printf("OK!\n"); + return 0; + } + ''' + self.do_run(src, 'OK!\n'); + def test_negative_zero(self): src = r''' #include <stdio.h> @@ -5451,7 +5525,7 @@ The current type of b is: 9 self.do_run(src, '*16,0,4,8,8,12|20,0,4,4,8,12,12,16|24,0,20,0,4,4,8,12,12,16*\n*0,0,0,1,2,64,68,69,72*\n*2*') def test_runtimelink(self): - return self.skip('shared libs are deprecated') + return self.skip('BUILD_AS_SHARED_LIB=2 is deprecated') if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize printf into puts in the parent, and the child will still look for puts') if Settings.ASM_JS: return self.skip('asm does not support runtime linking') @@ -5470,7 +5544,6 @@ The current type of b is: 9 self.do_run(main, 'supp: 54,2\nmain: 56\nsupp see: 543\nmain see: 76\nok.') def test_dlfcn_basic(self): - return self.skip('shared libs are deprecated') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') Settings.NAMED_GLOBALS = 1 @@ -5525,7 +5598,6 @@ def process(filename): post_build=add_pre_run_and_checks) def test_dlfcn_qsort(self): - return self.skip('shared libs are deprecated') if self.emcc_args is None: return self.skip('requires emcc') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') @@ -5622,7 +5694,6 @@ def process(filename): post_build=add_pre_run_and_checks) def test_dlfcn_data_and_fptr(self): - return self.skip('shared libs are deprecated') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func') @@ -5727,7 +5798,6 @@ def process(filename): post_build=add_pre_run_and_checks) def test_dlfcn_alias(self): - return self.skip('shared libs are deprecated') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') Settings.LINKABLE = 1 @@ -5785,7 +5855,6 @@ def process(filename): Settings.INCLUDE_FULL_LIBRARY = 0 def test_dlfcn_varargs(self): - return self.skip('shared libs are deprecated') if Settings.ASM_JS: return self.skip('TODO: dlopen in asm') Settings.LINKABLE = 1 @@ -9582,15 +9651,15 @@ def process(filename): self.assertIdentical(clean(no_maps_file), clean(out_file)) map_filename = out_filename + '.map' data = json.load(open(map_filename, 'r')) - self.assertIdentical(out_filename, data['file']) - self.assertIdentical(src_filename, data['sources'][0]) - self.assertIdentical(src, data['sourcesContent'][0]) + self.assertPathsIdentical(out_filename, data['file']) + self.assertPathsIdentical(src_filename, data['sources'][0]) + self.assertTextDataIdentical(src, data['sourcesContent'][0]) mappings = json.loads(jsrun.run_js( path_from_root('tools', 'source-maps', 'sourcemap2json.js'), tools.shared.NODE_JS, [map_filename])) seen_lines = set() for m in mappings: - self.assertIdentical(src_filename, m['source']) + self.assertPathsIdentical(src_filename, m['source']) seen_lines.add(m['originalLine']) # ensure that all the 'meaningful' lines in the original code get mapped assert seen_lines.issuperset([6, 7, 11, 12]) @@ -10071,4 +10140,5 @@ for compiler, quantum, embetter, typed_arrays in [ ) locals()[fullname] = make_run(fullname, fullname, compiler, embetter, quantum, typed_arrays) -del T # T is just a shape for the specific subclasses, we don't test it itself
\ No newline at end of file +del T # T is just a shape for the specific subclasses, we don't test it itself + diff --git a/tests/test_other.py b/tests/test_other.py index b3e8a2a1..3b3887d6 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1033,7 +1033,7 @@ int main(int argc, char const *argv[]) self.assertContained('hello from lib', run_js(os.path.join(self.get_dir(), 'a.out.js'))) def test_runtimelink_multi(self): - return self.skip('shared libs are deprecated') + return self.skip('BUILD_AS_SHARED_LIB=2 is deprecated') if Settings.ASM_JS: return self.skip('asm does not support runtime linking yet') if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey due to node limitations') diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 03593674..4f6ee2a9 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -198,3 +198,71 @@ class sockets(BrowserCore): # ]: # with harness: # self.btest(os.path.join('sockets', 'test_enet_client.c'), expected='0', args=['-DSOCKK=9011'] + enet) + + def test_webrtc(self): + host_src = 'webrtc_host.c' + peer_src = 'webrtc_peer.c' + + host_outfile = 'host.html' + peer_outfile = 'peer.html' + + host_filepath = path_from_root('tests', 'sockets', host_src) + temp_host_filepath = os.path.join(self.get_dir(), os.path.basename(host_src)) + with open(host_filepath) as f: host_src = f.read() + with open(temp_host_filepath, 'w') as f: f.write(self.with_report_result(host_src)) + + peer_filepath = path_from_root('tests', 'sockets', peer_src) + temp_peer_filepath = os.path.join(self.get_dir(), os.path.basename(peer_src)) + with open(peer_filepath) as f: peer_src = f.read() + with open(temp_peer_filepath, 'w') as f: f.write(self.with_report_result(peer_src)) + + open(os.path.join(self.get_dir(), 'host_pre.js'), 'w').write(''' + var Module = { + webrtc: { + broker: 'https://mdsw.ch:8080', + session: undefined, + onpeer: function(peer, route) { + window.open('http://localhost:8888/peer.html?' + route); + // iframe = document.createElement("IFRAME"); + // iframe.setAttribute("src", "http://localhost:8888/peer.html?" + route); + // iframe.style.display = "none"; + // document.body.appendChild(iframe); + peer.listen(); + }, + onconnect: function(peer) { + }, + ondisconnect: function(peer) { + }, + onerror: function(error) { + console.error(error); + } + }, + }; + ''') + + open(os.path.join(self.get_dir(), 'peer_pre.js'), 'w').write(''' + var Module = { + webrtc: { + broker: 'https://mdsw.ch:8080', + session: window.location.toString().split('?')[1], + onpeer: function(peer, route) { + peer.connect(Module['webrtc']['session']); + }, + onconnect: function(peer) { + }, + ondisconnect: function(peer) { + // Calling window.close() from this handler hangs my browser, so run it in the next turn + setTimeout(window.close, 0); + }, + onerror: function(error) { + console.error(error); + } + } + }; + ''') + + Popen([PYTHON, EMCC, temp_host_filepath, '-o', host_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'host_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1']).communicate() + Popen([PYTHON, EMCC, temp_peer_filepath, '-o', peer_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'peer_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1']).communicate() + + expected = '1' + self.run_browser(host_outfile, '.', ['/report_result?' + e for e in expected])
\ No newline at end of file diff --git a/tools/find_bigfuncs.py b/tools/find_bigfuncs.py index 6fdec3a9..79136343 100644 --- a/tools/find_bigfuncs.py +++ b/tools/find_bigfuncs.py @@ -1,5 +1,5 @@ ''' -Simple tool to find big functions in an .ll file. +Simple tool to find big functions in a js or ll file ''' import os, sys, re @@ -11,7 +11,7 @@ curr = None data = [] for line in open(filename): i += 1 - if line.startswith('function '): + if line.startswith(('function ', 'define ')): start = i curr = line elif line.startswith('}') and curr: diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index ff6aee67..e61317af 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -801,7 +801,10 @@ function simplifyExpressions(ast) { // HEAP[x >> 2] // very often. We can in some cases do the shift on the variable itself when it is set, // to greatly reduce the number of shift operations. -// TODO: when shifting a variable, if there are other uses, keep an unshifted version too, to prevent slowdowns? +// XXX this optimization is deprecated and currently invalid: does not handle overflows +// or non-aligned (round numbers, x >> 2 is a multiple of 4). Both are ok to assume +// for pointers (undefined behavior otherwise), but invalid in general, and we do +// no sufficiently-well distinguish the cases. function optimizeShiftsInternal(ast, conservative) { var MAX_SHIFTS = 3; traverseGeneratedFunctions(ast, function(fun) { @@ -3001,7 +3004,7 @@ function outline(ast) { // Try to flatten out code as much as possible, to make outlining more feasible. function flatten(func, asmData) { - var minSize = sizeToOutline; + var minSize = extraInfo.sizeToOutline/4; var helperId = 0; function getHelper() { while (1) { @@ -3475,6 +3478,9 @@ function outline(ast) { } } } + function done() { + return asmData.splitCounter >= asmData.maxOutlinings || measureSize(func) <= extraInfo.sizeToOutline; + } while (1) { i--; calcMinIndex(); // TODO: optimize @@ -3530,7 +3536,7 @@ function outline(ast) { if (ret.length > pre) { // we outlined recursively, reset our state here //printErr('successful outline in recursion ' + func[1] + ' due to recursive in level ' + level); - if (measureSize(func) <= extraInfo.sizeToOutline) break; + if (done()) break; end = i-1; sizeSeen = 0; canRestart = true; @@ -3570,7 +3576,7 @@ function outline(ast) { if (newFuncs.length) { ret.push.apply(ret, newFuncs); } - if (measureSize(func) <= extraInfo.sizeToOutline) break; + if (done()) break; sizeSeen = 0; end = i-1; canRestart = true; diff --git a/tools/jsrun.py b/tools/jsrun.py index 27c55350..571e9cee 100644 --- a/tools/jsrun.py +++ b/tools/jsrun.py @@ -15,7 +15,7 @@ def timeout_run(proc, timeout, note='unnamed process', full_output=False): def run_js(filename, engine=None, args=[], check_timeout=False, stdout=PIPE, stderr=None, cwd=None, full_output=False): if type(engine) is not list: engine = [engine] - command = engine + [filename] + (['--'] if 'd8' in engine[0] else []) + args + command = engine + [filename] + (['--'] if 'd8' in engine[0] or 'jsc' in engine[0] else []) + args return timeout_run( Popen( command, diff --git a/tools/response_file.py b/tools/response_file.py index 312cda73..f19cf8af 100644 --- a/tools/response_file.py +++ b/tools/response_file.py @@ -6,8 +6,8 @@ def create_response_file(args, directory): (response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.rsp', dir=directory, text=True) response_fd = os.fdopen(response_fd, "w") #print >> sys.stderr, "Creating response file '%s'" % response_filename - args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args) - response_fd.write(' '.join(args)) + args = map(lambda p: p.replace('\\', '\\\\').replace('"', '\\"'), args) + response_fd.write('"' + '" "'.join(args) + '"') response_fd.close() return response_filename diff --git a/tools/shared.py b/tools/shared.py index 917f548e..0d0f20d4 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -550,6 +550,7 @@ if USE_EMSDK: # allows projects to override them) EMSDK_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', '-Xclang', '-isystem' + path_from_root('system', 'local', 'include'), + '-Xclang', '-isystem' + path_from_root('system', 'include', 'compat'), '-Xclang', '-isystem' + path_from_root('system', 'include', 'libcxx'), '-Xclang', '-isystem' + path_from_root('system', 'include'), '-Xclang', '-isystem' + path_from_root('system', 'include', 'emscripten'), diff --git a/tools/source-maps/sourcemapper.js b/tools/source-maps/sourcemapper.js index fa908900..06c9a227 100755 --- a/tools/source-maps/sourcemapper.js +++ b/tools/source-maps/sourcemapper.js @@ -16,6 +16,38 @@ function countLines(s) { return count; } +// For a minor optimization, only do win32->unix normalization if we are actually on Windows, +// which avoids redundantly scanning files if not needed. +var isWindows = (process.platform === 'win32'); + +var unixPathRe = new RegExp('\\\\', 'g'); +// Returns the given (possibly Windows) path p normalized to unix path separators '/'. +function toUnixPath(p) { + if (isWindows) { + return p.replace(unixPathRe, '/'); + } else { + return p; + } +} + +var unixLineEndRe = new RegExp('\r\n', 'g'); +// Returns the given (possibly Windows) text data t normalized to unix line endings '\n'. +function toUnixLineEnding(t) { + if (isWindows) { + return t.replace(unixLineEndRe, '\n'); + } else { + return t; + } +} + +// If path "p2" is a relative path, joins paths p1 and p2 to form "p1/p2". If p2 is an absolute path, "p2" is returned. +function joinPath(p1, p2) { + if (p2[0] == '/' || (p2.length >= 3 && p2[1] == ':' && (p2[2] == '/' || p2[2] == '\\'))) // Is p2 an absolute path? + return p2; + else + return toUnixPath(path.join(p1, p2)); +} + /* * Extracts the line (not block) comments from the generated function code and * invokes commentHandler with (comment content, line number of comment). This @@ -105,8 +137,7 @@ function generateMap(mappings, sourceRoot, mapFileBaseName, generatedLineOffset) // avoid doing it unnecessarily if (!(originalFileName in seenFiles)) { seenFiles[originalFileName] = true; - var rootedPath = originalFileName[0] === path.sep ? - originalFileName : path.join(sourceRoot, originalFileName); + var rootedPath = joinPath(sourceRoot, originalFileName); try { generator.setSourceContent(originalFileName, fs.readFileSync(rootedPath, 'utf-8')); } catch (e) { @@ -144,15 +175,15 @@ if (require.main === module) { } else { var opts = parseArgs(process.argv.slice(2)); var fileName = opts._[0]; - var sourceRoot = opts.sourceRoot ? opts.sourceRoot : "."; - var mapFileBaseName = opts.mapFileBaseName ? opts.mapFileBaseName : fileName; + var sourceRoot = opts.sourceRoot ? toUnixPath(opts.sourceRoot) : "."; + var mapFileBaseName = toUnixPath(opts.mapFileBaseName ? opts.mapFileBaseName : fileName); var generatedLineOffset = opts.offset ? parseInt(opts.offset, 10) : 0; - var generatedSource = fs.readFileSync(fileName, 'utf-8'); + var generatedSource = toUnixLineEnding(fs.readFileSync(fileName, 'utf-8')); var source = generatedSource; var mappings = getMappings(generatedSource); for (var i = 1, l = opts._.length; i < l; i ++) { - var optimizedSource = fs.readFileSync(opts._[i], 'utf-8') + var optimizedSource = toUnixLineEnding(fs.readFileSync(opts._[i], 'utf-8')) var optimizedMappings = getMappings(optimizedSource); var newMappings = {}; // uglify processes the code between EMSCRIPTEN_START_FUNCS and diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js index 904e56cf..d8ea9446 100644 --- a/tools/test-js-optimizer-asm-outline1-output.js +++ b/tools/test-js-optimizer-asm-outline1-output.js @@ -276,8 +276,29 @@ function vars_w_stack(x, y) { function chain() { var helper$0 = 0, sp = 0; sp = STACKTOP; - STACKTOP = STACKTOP + 240 | 0; + STACKTOP = STACKTOP + 464 | 0; helper$0 = 1; + if (helper$0) { + helper$0 = 0; + if (x == 1) { + print(1); + } else { + helper$0 = 1; + } + } + if (helper$0) { + helper$0 = 0; + if (x == 2) { + print(2); + } else { + helper$0 = 1; + } + } + HEAP32[sp + 8 >> 2] = helper$0; + HEAP32[sp + 48 >> 2] = 0; + HEAP32[sp + 52 >> 2] = 0; + chain$4(sp); + helper$0 = HEAP32[sp + 8 >> 2] | 0; HEAP32[sp + 8 >> 2] = helper$0; HEAP32[sp + 40 >> 2] = 0; HEAP32[sp + 44 >> 2] = 0; @@ -288,6 +309,16 @@ function chain() { HEAP32[sp + 36 >> 2] = 0; chain$2(sp); helper$0 = HEAP32[sp + 8 >> 2] | 0; + HEAP32[sp + 8 >> 2] = helper$0; + HEAP32[sp + 24 >> 2] = 0; + HEAP32[sp + 28 >> 2] = 0; + chain$1(sp); + helper$0 = HEAP32[sp + 8 >> 2] | 0; + HEAP32[sp + 8 >> 2] = helper$0; + HEAP32[sp + 16 >> 2] = 0; + HEAP32[sp + 20 >> 2] = 0; + chain$0(sp); + helper$0 = HEAP32[sp + 8 >> 2] | 0; STACKTOP = sp; } function lin$0(sp) { @@ -500,22 +531,21 @@ function chain$0(sp) { sp = sp | 0; var helper$0 = 0; helper$0 = HEAP32[sp + 8 >> 2] | 0; - if (x == 7) { - print(7); - } else if (x == 8) { - print(8); - } else if (x == 9) { - print(9); - } else if (x == 10) { - print(10); - } else if (x == 11) { - print(11); - } else if (x == 12) { - print(12); - } else if (1) { - print(99); - } else { - helper$0 = 1; + if (helper$0) { + helper$0 = 0; + if (x == 12) { + print(12); + } else { + helper$0 = 1; + } + } + if (helper$0) { + helper$0 = 0; + if (1) { + print(99); + } else { + helper$0 = 1; + } } HEAP32[sp + 8 >> 2] = helper$0; } @@ -523,20 +553,21 @@ function chain$1(sp) { sp = sp | 0; var helper$0 = 0; helper$0 = HEAP32[sp + 8 >> 2] | 0; - if (x == 1) { - print(1); - } else if (x == 2) { - print(2); - } else if (x == 3) { - print(3); - } else if (x == 4) { - print(4); - } else if (x == 5) { - print(5); - } else if (x == 6) { - print(6); - } else { - helper$0 = 1; + if (helper$0) { + helper$0 = 0; + if (x == 10) { + print(10); + } else { + helper$0 = 1; + } + } + if (helper$0) { + helper$0 = 0; + if (x == 11) { + print(11); + } else { + helper$0 = 1; + } } HEAP32[sp + 8 >> 2] = helper$0; } @@ -546,11 +577,19 @@ function chain$2(sp) { helper$0 = HEAP32[sp + 8 >> 2] | 0; if (helper$0) { helper$0 = 0; - HEAP32[sp + 8 >> 2] = helper$0; - HEAP32[sp + 16 >> 2] = 0; - HEAP32[sp + 20 >> 2] = 0; - chain$0(sp); - helper$0 = HEAP32[sp + 8 >> 2] | 0; + if (x == 8) { + print(8); + } else { + helper$0 = 1; + } + } + if (helper$0) { + helper$0 = 0; + if (x == 9) { + print(9); + } else { + helper$0 = 1; + } } HEAP32[sp + 8 >> 2] = helper$0; } @@ -560,11 +599,49 @@ function chain$3(sp) { helper$0 = HEAP32[sp + 8 >> 2] | 0; if (helper$0) { helper$0 = 0; - HEAP32[sp + 8 >> 2] = helper$0; - HEAP32[sp + 24 >> 2] = 0; - HEAP32[sp + 28 >> 2] = 0; - chain$1(sp); - helper$0 = HEAP32[sp + 8 >> 2] | 0; + if (x == 6) { + print(6); + } else { + helper$0 = 1; + } + } + if (helper$0) { + helper$0 = 0; + if (x == 7) { + print(7); + } else { + helper$0 = 1; + } + } + HEAP32[sp + 8 >> 2] = helper$0; +} +function chain$4(sp) { + sp = sp | 0; + var helper$0 = 0; + helper$0 = HEAP32[sp + 8 >> 2] | 0; + if (helper$0) { + helper$0 = 0; + if (x == 3) { + print(3); + } else { + helper$0 = 1; + } + } + if (helper$0) { + helper$0 = 0; + if (x == 4) { + print(4); + } else { + helper$0 = 1; + } + } + if (helper$0) { + helper$0 = 0; + if (x == 5) { + print(5); + } else { + helper$0 = 1; + } } HEAP32[sp + 8 >> 2] = helper$0; } diff --git a/tools/test-js-optimizer-asm-outline2-output.js b/tools/test-js-optimizer-asm-outline2-output.js index 28feb6cb..2658fda0 100644 --- a/tools/test-js-optimizer-asm-outline2-output.js +++ b/tools/test-js-optimizer-asm-outline2-output.js @@ -23,7 +23,7 @@ function linear() { } function _free($mem) { $mem = $mem | 0; - var $5 = 0, $10 = 0, $16 = 0, $21 = 0, $25 = 0, $26 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $194 = 0, sp = 0; + var $5 = 0, $10 = 0, $16 = 0, $21 = 0, $25 = 0, $26 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $194 = 0, sp = 0, helper$0 = 0; sp = STACKTOP; if (($mem | 0) == 0) { STACKTOP = sp; @@ -39,59 +39,71 @@ function _free($mem) { } $16 = $mem + (($10 & -8) - 8) | 0; L621 : do { - if (($10 & 1 | 0) == 0) { - $21 = HEAP32[($mem - 8 | 0) >> 2] | 0; - if (($10 & 3 | 0) == 0) { - return; - } - $25 = $mem + (-8 - $21 | 0) | 0; - $26 = $21 + ($10 & -8) | 0; - if (($mem + (-8 - $21 | 0) | 0) >>> 0 < $5 >>> 0) { - _abort(); - } - if (($25 | 0) == (HEAP32[25] | 0)) { - if ((HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & 3 | 0) != 3) { - $p_0 = $25; - $psize_0 = $26; + helper$0 = 1; + if (helper$0) { + helper$0 = 0; + if (($10 & 1 | 0) == 0) { + $21 = HEAP32[($mem - 8 | 0) >> 2] | 0; + if (($10 & 3 | 0) == 0) { + return; + } + $25 = $mem + (-8 - $21 | 0) | 0; + $26 = $21 + ($10 & -8) | 0; + if (($mem + (-8 - $21 | 0) | 0) >>> 0 < $5 >>> 0) { + _abort(); + } + if (($25 | 0) == (HEAP32[25] | 0)) { + if ((HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & 3 | 0) != 3) { + $p_0 = $25; + $psize_0 = $26; + break; + } + HEAP32[22] = $26; + HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & -2; + HEAP32[$mem + ((-8 - $21 | 0) + 4) >> 2] = $26 | 1; + HEAP32[($mem + (($10 & -8) - 8) | 0) >> 2] = $26; + return; + } + HEAP32[sp + 8 >> 2] = $mem; + HEAP32[sp + 16 >> 2] = $5; + HEAP32[sp + 40 >> 2] = $21; + HEAP32[sp + 48 >> 2] = $25; + HEAP32[sp + 56 >> 2] = $26; + HEAP32[sp + 216 >> 2] = $psize_0; + HEAP32[sp + 224 >> 2] = $p_0; + HEAP32[sp + 696 >> 2] = 0; + HEAP32[sp + 700 >> 2] = 0; + _free$1(sp); + $psize_0 = HEAP32[sp + 216 >> 2] | 0; + $p_0 = HEAP32[sp + 224 >> 2] | 0; + tempValue = HEAP32[sp + 696 >> 2] | 0; + tempInt = HEAP32[sp + 700 >> 2] | 0; + tempDouble = +HEAPF32[sp + 700 >> 2]; + HEAP32[sp + 696 >> 2] = 0; + HEAP32[sp + 700 >> 2] = 0; + if ((tempValue | 0) == 1) { break; } - HEAP32[22] = $26; - HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & -2; - HEAP32[$mem + ((-8 - $21 | 0) + 4) >> 2] = $26 | 1; - HEAP32[($mem + (($10 & -8) - 8) | 0) >> 2] = $26; - return; - } - HEAP32[sp + 8 >> 2] = $mem; - HEAP32[sp + 16 >> 2] = $5; - HEAP32[sp + 40 >> 2] = $21; - HEAP32[sp + 48 >> 2] = $25; - HEAP32[sp + 56 >> 2] = $26; - HEAP32[sp + 216 >> 2] = $psize_0; - HEAP32[sp + 224 >> 2] = $p_0; - HEAP32[sp + 648 >> 2] = 0; - HEAP32[sp + 652 >> 2] = 0; - _free$1(sp); - $psize_0 = HEAP32[sp + 216 >> 2] | 0; - $p_0 = HEAP32[sp + 224 >> 2] | 0; - tempValue = HEAP32[sp + 648 >> 2] | 0; - tempInt = HEAP32[sp + 652 >> 2] | 0; - tempDouble = +HEAPF32[sp + 652 >> 2]; - HEAP32[sp + 648 >> 2] = 0; - HEAP32[sp + 652 >> 2] = 0; - if ((tempValue | 0) == 1) { - break; - } - if ((tempValue | 0) == 2) { - switch (tempInt | 0) { - case 2: - { - break L621; + if ((tempValue | 0) == 2) { + switch (tempInt | 0) { + case 2: + { + break L621; + } } } + } else { + helper$0 = 1; + } + } + if (helper$0) { + helper$0 = 0; + if (1) { + $p_0 = $mem - 8 | 0; + $psize_0 = $10 & -8; + } else { + helper$0 = 1; } - } else { - $p_0 = $mem - 8 | 0; - $psize_0 = $10 & -8; } } while (0); $189 = $p_0; @@ -109,14 +121,14 @@ function _free($mem) { HEAP32[sp + 224 >> 2] = $p_0; HEAP32[sp + 232 >> 2] = $189; HEAP32[sp + 240 >> 2] = $194; - HEAP32[sp + 656 >> 2] = 0; - HEAP32[sp + 660 >> 2] = 0; + HEAP32[sp + 704 >> 2] = 0; + HEAP32[sp + 708 >> 2] = 0; _free$2(sp); - tempValue = HEAP32[sp + 656 >> 2] | 0; - tempInt = HEAP32[sp + 660 >> 2] | 0; - tempDouble = +HEAPF32[sp + 660 >> 2]; - HEAP32[sp + 656 >> 2] = 0; - HEAP32[sp + 660 >> 2] = 0; + tempValue = HEAP32[sp + 704 >> 2] | 0; + tempInt = HEAP32[sp + 708 >> 2] | 0; + tempDouble = +HEAPF32[sp + 708 >> 2]; + HEAP32[sp + 704 >> 2] = 0; + HEAP32[sp + 708 >> 2] = 0; if ((tempValue | 0) == 5) { return; } @@ -153,175 +165,200 @@ function linear$1(sp) { } function _free$0(sp) { sp = sp | 0; - var $194 = 0, $233 = 0, $mem = 0, $10 = 0, $236 = 0, $16 = 0, $_pre_phi305 = 0, $267 = 0, $270 = 0, $273 = 0, $294 = 0, $299 = 0, $R7_1 = 0, $R7_0 = 0, $RP9_0 = 0, $301 = 0, $302 = 0, $305 = 0, $306 = 0, $278 = 0, $320 = 0, $351 = 0, $364 = 0; + var helper$3 = 0, $194 = 0, $233 = 0, $mem = 0, $10 = 0, $236 = 0, $16 = 0, $_pre_phi305 = 0, $267 = 0, $270 = 0, $273 = 0, helper$4 = 0, $294 = 0, $299 = 0, $R7_1 = 0, $R7_0 = 0, $RP9_0 = 0, $301 = 0, $302 = 0, $305 = 0, $306 = 0, $278 = 0, $320 = 0, $351 = 0, $364 = 0; $mem = HEAP32[sp + 8 >> 2] | 0; $10 = HEAP32[sp + 24 >> 2] | 0; $16 = HEAP32[sp + 32 >> 2] | 0; $194 = HEAP32[sp + 240 >> 2] | 0; + helper$3 = HEAP32[sp + 664 >> 2] | 0; OL : do { - if ($194 >>> 0 < 256) { - $233 = HEAP32[$mem + ($10 & -8) >> 2] | 0; - $236 = HEAP32[$mem + ($10 & -8 | 4) >> 2] | 0; - do { - if (($233 | 0) != (120 + ($194 >>> 3 << 1 << 2) | 0 | 0)) { - if ($233 >>> 0 < (HEAP32[24] | 0) >>> 0) { + if (helper$3) { + helper$3 = 0; + if ($194 >>> 0 < 256) { + $233 = HEAP32[$mem + ($10 & -8) >> 2] | 0; + $236 = HEAP32[$mem + ($10 & -8 | 4) >> 2] | 0; + do { + if (($233 | 0) != (120 + ($194 >>> 3 << 1 << 2) | 0 | 0)) { + if ($233 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); + } + if ((HEAP32[$233 + 12 >> 2] | 0) == ($16 | 0)) { + break; + } _abort(); } - if ((HEAP32[$233 + 12 >> 2] | 0) == ($16 | 0)) { - break; - } - _abort(); + } while (0); + if (($236 | 0) == ($233 | 0)) { + HEAP32[20] = HEAP32[20] & (1 << ($194 >>> 3) ^ -1); + HEAP32[sp + 688 >> 2] = 1; + break OL; } - } while (0); - if (($236 | 0) == ($233 | 0)) { - HEAP32[20] = HEAP32[20] & (1 << ($194 >>> 3) ^ -1); - HEAP32[sp + 640 >> 2] = 1; - break OL; - } - do { - if (($236 | 0) == (120 + ($194 >>> 3 << 1 << 2) | 0 | 0)) { - $_pre_phi305 = $236 + 8 | 0; - } else { - if ($236 >>> 0 < (HEAP32[24] | 0) >>> 0) { - _abort(); - } - if ((HEAP32[($236 + 8 | 0) >> 2] | 0) == ($16 | 0)) { + do { + if (($236 | 0) == (120 + ($194 >>> 3 << 1 << 2) | 0 | 0)) { $_pre_phi305 = $236 + 8 | 0; - break; - } - _abort(); - } - } while (0); - HEAP32[$233 + 12 >> 2] = $236; - HEAP32[$_pre_phi305 >> 2] = $233; - } else { - $267 = $mem + (($10 & -8) - 8) | 0; - $270 = HEAP32[$mem + (($10 & -8) + 16) >> 2] | 0; - $273 = HEAP32[$mem + ($10 & -8 | 4) >> 2] | 0; - do { - if (($273 | 0) == ($267 | 0)) { - $294 = HEAP32[($mem + (($10 & -8) + 12) | 0) >> 2] | 0; - if (($294 | 0) == 0) { - $299 = HEAP32[($mem + (($10 & -8) + 8) | 0) >> 2] | 0; - if (($299 | 0) == 0) { - $R7_1 = 0; - break; - } else { - $R7_0 = $299; - $RP9_0 = $mem + (($10 & -8) + 8) | 0; - } } else { - $R7_0 = $294; - $RP9_0 = $mem + (($10 & -8) + 12) | 0; - } - while (1) { - $301 = $R7_0 + 20 | 0; - $302 = HEAP32[$301 >> 2] | 0; - if (($302 | 0) != 0) { - $R7_0 = $302; - $RP9_0 = $301; - continue; + if ($236 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); } - $305 = $R7_0 + 16 | 0; - $306 = HEAP32[$305 >> 2] | 0; - if (($306 | 0) == 0) { + if ((HEAP32[($236 + 8 | 0) >> 2] | 0) == ($16 | 0)) { + $_pre_phi305 = $236 + 8 | 0; break; - } else { - $R7_0 = $306; - $RP9_0 = $305; } - } - if ($RP9_0 >>> 0 < (HEAP32[24] | 0) >>> 0) { _abort(); - } else { - HEAP32[$RP9_0 >> 2] = 0; - $R7_1 = $R7_0; - break; } - } else { - $278 = HEAP32[$mem + ($10 & -8) >> 2] | 0; - if ($278 >>> 0 < (HEAP32[24] | 0) >>> 0) { - _abort(); + } while (0); + HEAP32[$233 + 12 >> 2] = $236; + HEAP32[$_pre_phi305 >> 2] = $233; + } else { + helper$3 = 1; + } + } + if (helper$3) { + helper$3 = 0; + if (1) { + $267 = $mem + (($10 & -8) - 8) | 0; + $270 = HEAP32[$mem + (($10 & -8) + 16) >> 2] | 0; + $273 = HEAP32[$mem + ($10 & -8 | 4) >> 2] | 0; + do { + helper$4 = 1; + if (helper$4) { + helper$4 = 0; + if (($273 | 0) == ($267 | 0)) { + $294 = HEAP32[($mem + (($10 & -8) + 12) | 0) >> 2] | 0; + if (($294 | 0) == 0) { + $299 = HEAP32[($mem + (($10 & -8) + 8) | 0) >> 2] | 0; + if (($299 | 0) == 0) { + $R7_1 = 0; + break; + } else { + $R7_0 = $299; + $RP9_0 = $mem + (($10 & -8) + 8) | 0; + } + } else { + $R7_0 = $294; + $RP9_0 = $mem + (($10 & -8) + 12) | 0; + } + while (1) { + $301 = $R7_0 + 20 | 0; + $302 = HEAP32[$301 >> 2] | 0; + if (($302 | 0) != 0) { + $R7_0 = $302; + $RP9_0 = $301; + continue; + } + $305 = $R7_0 + 16 | 0; + $306 = HEAP32[$305 >> 2] | 0; + if (($306 | 0) == 0) { + break; + } else { + $R7_0 = $306; + $RP9_0 = $305; + } + } + if ($RP9_0 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); + } else { + HEAP32[$RP9_0 >> 2] = 0; + $R7_1 = $R7_0; + break; + } + } else { + helper$4 = 1; + } } - if ((HEAP32[($278 + 12 | 0) >> 2] | 0) != ($267 | 0)) { - _abort(); + if (helper$4) { + helper$4 = 0; + if (1) { + $278 = HEAP32[$mem + ($10 & -8) >> 2] | 0; + if ($278 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); + } + if ((HEAP32[($278 + 12 | 0) >> 2] | 0) != ($267 | 0)) { + _abort(); + } + if ((HEAP32[($273 + 8 | 0) >> 2] | 0) == ($267 | 0)) { + HEAP32[($278 + 12 | 0) >> 2] = $273; + HEAP32[($273 + 8 | 0) >> 2] = $278; + $R7_1 = $273; + break; + } else { + _abort(); + } + } else { + helper$4 = 1; + } } - if ((HEAP32[($273 + 8 | 0) >> 2] | 0) == ($267 | 0)) { - HEAP32[($278 + 12 | 0) >> 2] = $273; - HEAP32[($273 + 8 | 0) >> 2] = $278; - $R7_1 = $273; - break; + } while (0); + if (($270 | 0) == 0) { + HEAP32[sp + 688 >> 2] = 1; + break OL; + } + $320 = 384 + (HEAP32[($mem + (($10 & -8) + 20) | 0) >> 2] << 2) | 0; + do { + if (($267 | 0) == (HEAP32[$320 >> 2] | 0)) { + HEAP32[$320 >> 2] = $R7_1; + if (($R7_1 | 0) != 0) { + break; + } + HEAP32[21] = HEAP32[21] & (1 << HEAP32[($mem + (($10 & -8) + 20) | 0) >> 2] ^ -1); + HEAP32[sp + 688 >> 2] = 2; + HEAP32[sp + 692 >> 2] = 2; + break OL; } else { - _abort(); + if ($270 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); + } + if ((HEAP32[($270 + 16 | 0) >> 2] | 0) == ($267 | 0)) { + HEAP32[($270 + 16 | 0) >> 2] = $R7_1; + } else { + HEAP32[$270 + 20 >> 2] = $R7_1; + } + if (($R7_1 | 0) == 0) { + HEAP32[sp + 688 >> 2] = 2; + HEAP32[sp + 692 >> 2] = 2; + break OL; + } } + } while (0); + if ($R7_1 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); } - } while (0); - if (($270 | 0) == 0) { - HEAP32[sp + 640 >> 2] = 1; - break OL; - } - $320 = 384 + (HEAP32[($mem + (($10 & -8) + 20) | 0) >> 2] << 2) | 0; - do { - if (($267 | 0) == (HEAP32[$320 >> 2] | 0)) { - HEAP32[$320 >> 2] = $R7_1; - if (($R7_1 | 0) != 0) { - break; + HEAP32[$R7_1 + 24 >> 2] = $270; + $351 = HEAP32[$mem + (($10 & -8) + 8) >> 2] | 0; + do { + if (($351 | 0) != 0) { + if ($351 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); + } else { + HEAP32[$R7_1 + 16 >> 2] = $351; + HEAP32[$351 + 24 >> 2] = $R7_1; + break; + } } - HEAP32[21] = HEAP32[21] & (1 << HEAP32[($mem + (($10 & -8) + 20) | 0) >> 2] ^ -1); - HEAP32[sp + 640 >> 2] = 2; - HEAP32[sp + 644 >> 2] = 2; + } while (0); + $364 = HEAP32[$mem + (($10 & -8) + 12) >> 2] | 0; + if (($364 | 0) == 0) { + HEAP32[sp + 688 >> 2] = 1; break OL; - } else { - if ($270 >>> 0 < (HEAP32[24] | 0) >>> 0) { - _abort(); - } - if ((HEAP32[($270 + 16 | 0) >> 2] | 0) == ($267 | 0)) { - HEAP32[($270 + 16 | 0) >> 2] = $R7_1; - } else { - HEAP32[$270 + 20 >> 2] = $R7_1; - } - if (($R7_1 | 0) == 0) { - HEAP32[sp + 640 >> 2] = 2; - HEAP32[sp + 644 >> 2] = 2; - break OL; - } } - } while (0); - if ($R7_1 >>> 0 < (HEAP32[24] | 0) >>> 0) { - _abort(); - } - HEAP32[$R7_1 + 24 >> 2] = $270; - $351 = HEAP32[$mem + (($10 & -8) + 8) >> 2] | 0; - do { - if (($351 | 0) != 0) { - if ($351 >>> 0 < (HEAP32[24] | 0) >>> 0) { - _abort(); - } else { - HEAP32[$R7_1 + 16 >> 2] = $351; - HEAP32[$351 + 24 >> 2] = $R7_1; - break; - } + if ($364 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); + } else { + HEAP32[$R7_1 + 20 >> 2] = $364; + HEAP32[$364 + 24 >> 2] = $R7_1; + HEAP32[sp + 688 >> 2] = 1; + break OL; } - } while (0); - $364 = HEAP32[$mem + (($10 & -8) + 12) >> 2] | 0; - if (($364 | 0) == 0) { - HEAP32[sp + 640 >> 2] = 1; - break OL; - } - if ($364 >>> 0 < (HEAP32[24] | 0) >>> 0) { - _abort(); } else { - HEAP32[$R7_1 + 20 >> 2] = $364; - HEAP32[$364 + 24 >> 2] = $R7_1; - HEAP32[sp + 640 >> 2] = 1; - break OL; + helper$3 = 1; } } } while (0); + HEAP32[sp + 664 >> 2] = helper$3; } function _free$1(sp) { sp = sp | 0; - var $21 = 0, $37 = 0, $mem = 0, $40 = 0, $5 = 0, $25 = 0, $26 = 0, $_pre_phi307 = 0, $69 = 0, $72 = 0, $75 = 0, $95 = 0, $100 = 0, $R_1 = 0, $R_0 = 0, $RP_0 = 0, $102 = 0, $103 = 0, $106 = 0, $107 = 0, $80 = 0, $120 = 0, $151 = 0, $164 = 0, $p_0 = 0, $psize_0 = 0; + var $21 = 0, $37 = 0, $mem = 0, $40 = 0, $5 = 0, $25 = 0, $26 = 0, $_pre_phi307 = 0, $69 = 0, $72 = 0, $75 = 0, helper$1 = 0, $95 = 0, $100 = 0, $R_1 = 0, $R_0 = 0, $RP_0 = 0, $102 = 0, $103 = 0, $106 = 0, $107 = 0, $80 = 0, $120 = 0, $151 = 0, $164 = 0, $p_0 = 0, $psize_0 = 0; $mem = HEAP32[sp + 8 >> 2] | 0; $5 = HEAP32[sp + 16 >> 2] | 0; $21 = HEAP32[sp + 40 >> 2] | 0; @@ -348,7 +385,7 @@ function _free$1(sp) { HEAP32[20] = HEAP32[20] & (1 << ($21 >>> 3) ^ -1); $p_0 = $25; $psize_0 = $26; - HEAP32[sp + 648 >> 2] = 1; + HEAP32[sp + 696 >> 2] = 1; break OL; } do { @@ -369,74 +406,86 @@ function _free$1(sp) { HEAP32[$_pre_phi307 >> 2] = $37; $p_0 = $25; $psize_0 = $26; - HEAP32[sp + 648 >> 2] = 1; + HEAP32[sp + 696 >> 2] = 1; break OL; } $69 = $mem + (-8 - $21 | 0) | 0; $72 = HEAP32[$mem + ((-8 - $21 | 0) + 24) >> 2] | 0; $75 = HEAP32[$mem + ((-8 - $21 | 0) + 12) >> 2] | 0; do { - if (($75 | 0) == ($69 | 0)) { - $95 = HEAP32[($mem + ((-8 - $21 | 0) + 20) | 0) >> 2] | 0; - if (($95 | 0) == 0) { - $100 = HEAP32[($mem + ((-8 - $21 | 0) + 16) | 0) >> 2] | 0; - if (($100 | 0) == 0) { - $R_1 = 0; - break; + helper$1 = 1; + if (helper$1) { + helper$1 = 0; + if (($75 | 0) == ($69 | 0)) { + $95 = HEAP32[($mem + ((-8 - $21 | 0) + 20) | 0) >> 2] | 0; + if (($95 | 0) == 0) { + $100 = HEAP32[($mem + ((-8 - $21 | 0) + 16) | 0) >> 2] | 0; + if (($100 | 0) == 0) { + $R_1 = 0; + break; + } else { + $R_0 = $100; + $RP_0 = $mem + ((-8 - $21 | 0) + 16) | 0; + } + } else { + $R_0 = $95; + $RP_0 = $mem + ((-8 - $21 | 0) + 20) | 0; + } + while (1) { + $102 = $R_0 + 20 | 0; + $103 = HEAP32[$102 >> 2] | 0; + if (($103 | 0) != 0) { + $R_0 = $103; + $RP_0 = $102; + continue; + } + $106 = $R_0 + 16 | 0; + $107 = HEAP32[$106 >> 2] | 0; + if (($107 | 0) == 0) { + break; + } else { + $R_0 = $107; + $RP_0 = $106; + } + } + if ($RP_0 >>> 0 < $5 >>> 0) { + _abort(); } else { - $R_0 = $100; - $RP_0 = $mem + ((-8 - $21 | 0) + 16) | 0; + HEAP32[$RP_0 >> 2] = 0; + $R_1 = $R_0; + break; } } else { - $R_0 = $95; - $RP_0 = $mem + ((-8 - $21 | 0) + 20) | 0; + helper$1 = 1; } - while (1) { - $102 = $R_0 + 20 | 0; - $103 = HEAP32[$102 >> 2] | 0; - if (($103 | 0) != 0) { - $R_0 = $103; - $RP_0 = $102; - continue; + } + if (helper$1) { + helper$1 = 0; + if (1) { + $80 = HEAP32[$mem + ((-8 - $21 | 0) + 8) >> 2] | 0; + if ($80 >>> 0 < $5 >>> 0) { + _abort(); + } + if ((HEAP32[($80 + 12 | 0) >> 2] | 0) != ($69 | 0)) { + _abort(); } - $106 = $R_0 + 16 | 0; - $107 = HEAP32[$106 >> 2] | 0; - if (($107 | 0) == 0) { + if ((HEAP32[($75 + 8 | 0) >> 2] | 0) == ($69 | 0)) { + HEAP32[($80 + 12 | 0) >> 2] = $75; + HEAP32[($75 + 8 | 0) >> 2] = $80; + $R_1 = $75; break; } else { - $R_0 = $107; - $RP_0 = $106; + _abort(); } - } - if ($RP_0 >>> 0 < $5 >>> 0) { - _abort(); } else { - HEAP32[$RP_0 >> 2] = 0; - $R_1 = $R_0; - break; - } - } else { - $80 = HEAP32[$mem + ((-8 - $21 | 0) + 8) >> 2] | 0; - if ($80 >>> 0 < $5 >>> 0) { - _abort(); - } - if ((HEAP32[($80 + 12 | 0) >> 2] | 0) != ($69 | 0)) { - _abort(); - } - if ((HEAP32[($75 + 8 | 0) >> 2] | 0) == ($69 | 0)) { - HEAP32[($80 + 12 | 0) >> 2] = $75; - HEAP32[($75 + 8 | 0) >> 2] = $80; - $R_1 = $75; - break; - } else { - _abort(); + helper$1 = 1; } } } while (0); if (($72 | 0) == 0) { $p_0 = $25; $psize_0 = $26; - HEAP32[sp + 648 >> 2] = 1; + HEAP32[sp + 696 >> 2] = 1; break OL; } $120 = 384 + (HEAP32[($mem + ((-8 - $21 | 0) + 28) | 0) >> 2] << 2) | 0; @@ -449,8 +498,8 @@ function _free$1(sp) { HEAP32[21] = HEAP32[21] & (1 << HEAP32[($mem + ((-8 - $21 | 0) + 28) | 0) >> 2] ^ -1); $p_0 = $25; $psize_0 = $26; - HEAP32[sp + 648 >> 2] = 2; - HEAP32[sp + 652 >> 2] = 2; + HEAP32[sp + 696 >> 2] = 2; + HEAP32[sp + 700 >> 2] = 2; break OL; } else { if ($72 >>> 0 < (HEAP32[24] | 0) >>> 0) { @@ -464,8 +513,8 @@ function _free$1(sp) { if (($R_1 | 0) == 0) { $p_0 = $25; $psize_0 = $26; - HEAP32[sp + 648 >> 2] = 2; - HEAP32[sp + 652 >> 2] = 2; + HEAP32[sp + 696 >> 2] = 2; + HEAP32[sp + 700 >> 2] = 2; break OL; } } @@ -490,7 +539,7 @@ function _free$1(sp) { if (($164 | 0) == 0) { $p_0 = $25; $psize_0 = $26; - HEAP32[sp + 648 >> 2] = 1; + HEAP32[sp + 696 >> 2] = 1; break OL; } if ($164 >>> 0 < (HEAP32[24] | 0) >>> 0) { @@ -500,7 +549,7 @@ function _free$1(sp) { HEAP32[$164 + 24 >> 2] = $R_1; $p_0 = $25; $psize_0 = $26; - HEAP32[sp + 648 >> 2] = 1; + HEAP32[sp + 696 >> 2] = 1; break OL; } } while (0); @@ -509,7 +558,7 @@ function _free$1(sp) { } function _free$2(sp) { sp = sp | 0; - var $194 = 0, $16 = 0, $204 = 0, $psize_0 = 0, $p_0 = 0, $220 = 0, $189 = 0, $227 = 0, $mem = 0, $10 = 0, $psize_1 = 0, $390 = 0, $396 = 0, $F16_0 = 0, $_pre_phi = 0, $404 = 0, $414 = 0, $415 = 0, $I18_0 = 0, $428 = 0, $436 = 0, $443 = 0, $447 = 0, $448 = 0, $463 = 0, $K19_0 = 0, $T_0 = 0, $472 = 0, $473 = 0, label = 0, $486 = 0, $487 = 0, $489 = 0, $501 = 0, $sp_0_in_i = 0, $sp_0_i = 0; + var helper$2 = 0, $194 = 0, $16 = 0, $204 = 0, $psize_0 = 0, $p_0 = 0, $220 = 0, $189 = 0, $227 = 0, helper$3 = 0, $mem = 0, $10 = 0, $psize_1 = 0, $390 = 0, $396 = 0, $F16_0 = 0, $_pre_phi = 0, $404 = 0, $414 = 0, $415 = 0, $I18_0 = 0, $428 = 0, $436 = 0, $443 = 0, $447 = 0, $448 = 0, helper$5 = 0, $463 = 0, $K19_0 = 0, $T_0 = 0, $472 = 0, $473 = 0, label = 0, $486 = 0, $487 = 0, $489 = 0, $501 = 0, $sp_0_in_i = 0, $sp_0_i = 0; $mem = HEAP32[sp + 8 >> 2] | 0; $10 = HEAP32[sp + 24 >> 2] | 0; $16 = HEAP32[sp + 32 >> 2] | 0; @@ -519,73 +568,88 @@ function _free$2(sp) { $194 = HEAP32[sp + 240 >> 2] | 0; OL : do { do { - if (($194 & 2 | 0) == 0) { - if (($16 | 0) == (HEAP32[26] | 0)) { - $204 = (HEAP32[23] | 0) + $psize_0 | 0; - HEAP32[23] = $204; - HEAP32[26] = $p_0; - HEAP32[$p_0 + 4 >> 2] = $204 | 1; - if (($p_0 | 0) == (HEAP32[25] | 0)) { - HEAP32[25] = 0; - HEAP32[22] = 0; - } - if ($204 >>> 0 <= (HEAP32[27] | 0) >>> 0) { - HEAP32[sp + 656 >> 2] = 5; + helper$2 = 1; + if (helper$2) { + helper$2 = 0; + if (($194 & 2 | 0) == 0) { + if (($16 | 0) == (HEAP32[26] | 0)) { + $204 = (HEAP32[23] | 0) + $psize_0 | 0; + HEAP32[23] = $204; + HEAP32[26] = $p_0; + HEAP32[$p_0 + 4 >> 2] = $204 | 1; + if (($p_0 | 0) == (HEAP32[25] | 0)) { + HEAP32[25] = 0; + HEAP32[22] = 0; + } + if ($204 >>> 0 <= (HEAP32[27] | 0) >>> 0) { + HEAP32[sp + 704 >> 2] = 5; + break OL; + } + _sys_trim(0) | 0; + HEAP32[sp + 704 >> 2] = 5; break OL; } - _sys_trim(0) | 0; - HEAP32[sp + 656 >> 2] = 5; - break OL; - } - if (($16 | 0) == (HEAP32[25] | 0)) { - $220 = (HEAP32[22] | 0) + $psize_0 | 0; - HEAP32[22] = $220; - HEAP32[25] = $p_0; - HEAP32[$p_0 + 4 >> 2] = $220 | 1; - HEAP32[$189 + $220 >> 2] = $220; - HEAP32[sp + 656 >> 2] = 5; - break OL; - } - $227 = ($194 & -8) + $psize_0 | 0; - L726 : do { - HEAP32[sp + 8 >> 2] = $mem; - HEAP32[sp + 24 >> 2] = $10; - HEAP32[sp + 32 >> 2] = $16; - HEAP32[sp + 240 >> 2] = $194; - HEAP32[sp + 640 >> 2] = 0; - HEAP32[sp + 644 >> 2] = 0; - _free$0(sp); - tempValue = HEAP32[sp + 640 >> 2] | 0; - tempInt = HEAP32[sp + 644 >> 2] | 0; - tempDouble = +HEAPF32[sp + 644 >> 2]; - HEAP32[sp + 640 >> 2] = 0; - HEAP32[sp + 644 >> 2] = 0; - if ((tempValue | 0) == 1) { - break; + if (($16 | 0) == (HEAP32[25] | 0)) { + $220 = (HEAP32[22] | 0) + $psize_0 | 0; + HEAP32[22] = $220; + HEAP32[25] = $p_0; + HEAP32[$p_0 + 4 >> 2] = $220 | 1; + HEAP32[$189 + $220 >> 2] = $220; + HEAP32[sp + 704 >> 2] = 5; + break OL; } - if ((tempValue | 0) == 2) { - switch (tempInt | 0) { - case 2: - { - break L726; + $227 = ($194 & -8) + $psize_0 | 0; + L726 : do { + helper$3 = 1; + HEAP32[sp + 8 >> 2] = $mem; + HEAP32[sp + 24 >> 2] = $10; + HEAP32[sp + 32 >> 2] = $16; + HEAP32[sp + 240 >> 2] = $194; + HEAP32[sp + 664 >> 2] = helper$3; + HEAP32[sp + 688 >> 2] = 0; + HEAP32[sp + 692 >> 2] = 0; + _free$0(sp); + helper$3 = HEAP32[sp + 664 >> 2] | 0; + tempValue = HEAP32[sp + 688 >> 2] | 0; + tempInt = HEAP32[sp + 692 >> 2] | 0; + tempDouble = +HEAPF32[sp + 692 >> 2]; + HEAP32[sp + 688 >> 2] = 0; + HEAP32[sp + 692 >> 2] = 0; + if ((tempValue | 0) == 1) { + break; + } + if ((tempValue | 0) == 2) { + switch (tempInt | 0) { + case 2: + { + break L726; + } } } + } while (0); + HEAP32[$p_0 + 4 >> 2] = $227 | 1; + HEAP32[$189 + $227 >> 2] = $227; + if (($p_0 | 0) != (HEAP32[25] | 0)) { + $psize_1 = $227; + break; } - } while (0); - HEAP32[$p_0 + 4 >> 2] = $227 | 1; - HEAP32[$189 + $227 >> 2] = $227; - if (($p_0 | 0) != (HEAP32[25] | 0)) { - $psize_1 = $227; - break; + HEAP32[22] = $227; + HEAP32[sp + 704 >> 2] = 5; + break OL; + } else { + helper$2 = 1; + } + } + if (helper$2) { + helper$2 = 0; + if (1) { + HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = $194 & -2; + HEAP32[$p_0 + 4 >> 2] = $psize_0 | 1; + HEAP32[$189 + $psize_0 >> 2] = $psize_0; + $psize_1 = $psize_0; + } else { + helper$2 = 1; } - HEAP32[22] = $227; - HEAP32[sp + 656 >> 2] = 5; - break OL; - } else { - HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = $194 & -2; - HEAP32[$p_0 + 4 >> 2] = $psize_0 | 1; - HEAP32[$189 + $psize_0 >> 2] = $psize_0; - $psize_1 = $psize_0; } } while (0); $390 = $psize_1 >>> 3; @@ -610,7 +674,7 @@ function _free$2(sp) { HEAP32[$F16_0 + 12 >> 2] = $p_0; HEAP32[$p_0 + 8 >> 2] = $F16_0; HEAP32[$p_0 + 12 >> 2] = 120 + ($390 << 1 << 2) | 0; - HEAP32[sp + 656 >> 2] = 5; + HEAP32[sp + 704 >> 2] = 5; break OL; } $414 = $p_0; @@ -635,60 +699,72 @@ function _free$2(sp) { $447 = HEAP32[21] | 0; $448 = 1 << $I18_0; do { - if (($447 & $448 | 0) == 0) { - HEAP32[21] = $447 | $448; - HEAP32[$443 >> 2] = $414; - HEAP32[$p_0 + 24 >> 2] = $443; - HEAP32[$p_0 + 12 >> 2] = $p_0; - HEAP32[$p_0 + 8 >> 2] = $p_0; - } else { - if (($I18_0 | 0) == 31) { - $463 = 0; + helper$5 = 1; + if (helper$5) { + helper$5 = 0; + if (($447 & $448 | 0) == 0) { + HEAP32[21] = $447 | $448; + HEAP32[$443 >> 2] = $414; + HEAP32[$p_0 + 24 >> 2] = $443; + HEAP32[$p_0 + 12 >> 2] = $p_0; + HEAP32[$p_0 + 8 >> 2] = $p_0; } else { - $463 = 25 - ($I18_0 >>> 1) | 0; + helper$5 = 1; } - $K19_0 = $psize_1 << $463; - $T_0 = HEAP32[$443 >> 2] | 0; - while (1) { - if ((HEAP32[$T_0 + 4 >> 2] & -8 | 0) == ($psize_1 | 0)) { - break; - } - $472 = $T_0 + 16 + ($K19_0 >>> 31 << 2) | 0; - $473 = HEAP32[$472 >> 2] | 0; - if (($473 | 0) == 0) { - label = 569; - break; + } + if (helper$5) { + helper$5 = 0; + if (1) { + if (($I18_0 | 0) == 31) { + $463 = 0; } else { - $K19_0 = $K19_0 << 1; - $T_0 = $473; + $463 = 25 - ($I18_0 >>> 1) | 0; } - } - if ((label | 0) == 569) { - if ($472 >>> 0 < (HEAP32[24] | 0) >>> 0) { + $K19_0 = $psize_1 << $463; + $T_0 = HEAP32[$443 >> 2] | 0; + while (1) { + if ((HEAP32[$T_0 + 4 >> 2] & -8 | 0) == ($psize_1 | 0)) { + break; + } + $472 = $T_0 + 16 + ($K19_0 >>> 31 << 2) | 0; + $473 = HEAP32[$472 >> 2] | 0; + if (($473 | 0) == 0) { + label = 569; + break; + } else { + $K19_0 = $K19_0 << 1; + $T_0 = $473; + } + } + if ((label | 0) == 569) { + if ($472 >>> 0 < (HEAP32[24] | 0) >>> 0) { + _abort(); + } else { + HEAP32[$472 >> 2] = $414; + HEAP32[$p_0 + 24 >> 2] = $T_0; + HEAP32[$p_0 + 12 >> 2] = $p_0; + HEAP32[$p_0 + 8 >> 2] = $p_0; + break; + } + } + $486 = $T_0 + 8 | 0; + $487 = HEAP32[$486 >> 2] | 0; + $489 = HEAP32[24] | 0; + if ($T_0 >>> 0 < $489 >>> 0) { + _abort(); + } + if ($487 >>> 0 < $489 >>> 0) { _abort(); } else { - HEAP32[$472 >> 2] = $414; - HEAP32[$p_0 + 24 >> 2] = $T_0; - HEAP32[$p_0 + 12 >> 2] = $p_0; - HEAP32[$p_0 + 8 >> 2] = $p_0; + HEAP32[$487 + 12 >> 2] = $414; + HEAP32[$486 >> 2] = $414; + HEAP32[$p_0 + 8 >> 2] = $487; + HEAP32[$p_0 + 12 >> 2] = $T_0; + HEAP32[$p_0 + 24 >> 2] = 0; break; } - } - $486 = $T_0 + 8 | 0; - $487 = HEAP32[$486 >> 2] | 0; - $489 = HEAP32[24] | 0; - if ($T_0 >>> 0 < $489 >>> 0) { - _abort(); - } - if ($487 >>> 0 < $489 >>> 0) { - _abort(); } else { - HEAP32[$487 + 12 >> 2] = $414; - HEAP32[$486 >> 2] = $414; - HEAP32[$p_0 + 8 >> 2] = $487; - HEAP32[$p_0 + 12 >> 2] = $T_0; - HEAP32[$p_0 + 24 >> 2] = 0; - break; + helper$5 = 1; } } } while (0); @@ -697,7 +773,7 @@ function _free$2(sp) { if (($501 | 0) == 0) { $sp_0_in_i = 536; } else { - HEAP32[sp + 656 >> 2] = 5; + HEAP32[sp + 704 >> 2] = 5; break OL; } while (1) { @@ -710,7 +786,7 @@ function _free$2(sp) { } HEAP32[28] = -1; STACKTOP = sp; - HEAP32[sp + 656 >> 2] = 5; + HEAP32[sp + 704 >> 2] = 5; break OL; } while (0); } |