diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-01-31 17:15:45 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-01-31 17:15:45 -0800 |
commit | ac0972ebf6cb8ff17f1bbbf01526d29fd2d2f420 (patch) | |
tree | 499dd06881cddf43520b40cc62b51276ca411c60 /src | |
parent | 64c779641a2a9587613cc65ad7251890f18e25c3 (diff) | |
parent | 375eb145c8a6c1627a8b93f81d40fd1aa7fc899b (diff) |
Merge branch 'incoming'
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 3 | ||||
-rw-r--r-- | src/determinstic.js | 12 | ||||
-rw-r--r-- | src/headless.js | 2 | ||||
-rw-r--r-- | src/jsifier.js | 13 | ||||
-rw-r--r-- | src/library.js | 172 | ||||
-rw-r--r-- | src/library_browser.js | 4 | ||||
-rw-r--r-- | src/library_egl.js | 31 | ||||
-rw-r--r-- | src/library_gl.js | 38 | ||||
-rw-r--r-- | src/library_sdl.js | 8 | ||||
-rw-r--r-- | src/modules.js | 1 | ||||
-rw-r--r-- | src/parseTools.js | 43 | ||||
-rw-r--r-- | src/postamble.js | 16 | ||||
-rw-r--r-- | src/preamble.js | 17 | ||||
-rw-r--r-- | src/runtime.js | 2 | ||||
-rw-r--r-- | src/settings.js | 5 |
15 files changed, 259 insertions, 108 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 60ef5ba8..1c53b76c 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1517,9 +1517,8 @@ function analyzer(data, sidePass) { for (var i = 0; i < lines.length; i++) { var item = lines[i]; - if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum)) { + if (!finishedInitial && (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum))) { finishedInitial = true; - continue; } if (item.intertype == 'alloca' && finishedInitial) { func.otherStackAllocations = true; diff --git a/src/determinstic.js b/src/determinstic.js index 7bf1143c..91f98ed9 100644 --- a/src/determinstic.js +++ b/src/determinstic.js @@ -2,15 +2,11 @@ var MAGIC = 0; Math.random = function() { MAGIC = Math.pow(MAGIC + 1.8912, 3) % 1; - return MAGIC + 10; + return MAGIC; }; -var TIME = 0; +var TIME = 10000; Date.now = function() { - TIME += 0.05; - return TIME; -}; -performance.now = function() { - TIME += 0.05; - return TIME; + return TIME++; }; +performance.now = Date.now; diff --git a/src/headless.js b/src/headless.js index a528e8af..8e847d27 100644 --- a/src/headless.js +++ b/src/headless.js @@ -1,6 +1,8 @@ //== HEADLESS ==// +// TODO: sync from bananabread headless.js + var window = { location: { toString: function() { diff --git a/src/jsifier.js b/src/jsifier.js index 84a9b5f7..761a5fec 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1394,6 +1394,19 @@ function JSify(data, functionsOnly, givenFunctions) { return inline.apply(null, args); // Warning: inlining does not prevent recalculation of the arguments. They should be simple identifiers } + if (ASM_JS) { + // remove unneeded arguments, which the asm sig can show us. this lets us alias memset with llvm.memset, we just + // drop the final 2 args so things validate properly in asm + var libsig = LibraryManager.library[shortident + '__sig']; + if (libsig) { + assert(!hasVarArgs); + while (libsig.length - 1 < args.length) { + args.pop(); + argsTypes.pop(); + } + } + } + var returnType; if (byPointer || ASM_JS) { returnType = getReturnType(type); diff --git a/src/library.js b/src/library.js index 74ebdc07..5071552a 100644 --- a/src/library.js +++ b/src/library.js @@ -4217,16 +4217,31 @@ LibraryManager.library = { return ret; }, + memcpy__asm: 'true', + memcpy__sig: 'iiii', memcpy: function (dest, src, num) { - // simple version, in general it should not be used - we should pull it in from libc - if (!_memcpy.shown) { - _memcpy.shown = true; - Module.printErr('warning: library.js memcpy should not be running, it is only for testing!'); + dest = dest|0; src = src|0; num = num|0; + if ((dest&3) == (src&3)) { + while (dest & 3 & num) { + {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}}; + dest = (dest+1)|0; + src = (src+1)|0; + num = (num-1)|0; + } + while ((num|0) >= 4) { + {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i32'), 'i32') }}}; + dest = (dest+4)|0; + src = (src+4)|0; + num = (num-4)|0; + } } -#endif - while (num--) { - HEAP8[dest++] = HEAP8[src++]; + while ((num|0) > 0) { + {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}}; + dest = (dest+1)|0; + src = (src+1)|0; + num = (num-1)|0; } + return dest|0; }, wmemcpy: function() { throw 'wmemcpy not implemented' }, @@ -4236,16 +4251,20 @@ LibraryManager.library = { llvm_memcpy_p0i8_p0i8_i32: 'memcpy', llvm_memcpy_p0i8_p0i8_i64: 'memcpy', + memmove__sig: 'viii', + memmove__asm: true, memmove__deps: ['memcpy'], - memmove: function(dest, src, num, align) { - if (src < dest && dest < src + num) { - // Copy backwards in a safe manner - src += num; - dest += num; - while (num--) { - dest--; - src--; - {{{ makeCopyValues('dest', 'src', 1, 'null', null, 1) }}}; + memmove: function(dest, src, num) { + dest = dest|0; src = src|0; num = num|0; + if ((src|0 < (dest|0)) & (dest|0 < ((src + num)|0))) { + // Unlikely case: Copy backwards in a safe manner + src = (src + num)|0; + dest = (dest + num)|0; + while (num|0 > 0) { + dest = (dest - 1)|0; + src = (src - 1)|0; + num = (num - 1)|0; + {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}}; } } else { _memcpy(dest, src, num); @@ -4261,31 +4280,36 @@ LibraryManager.library = { memset__inline: function(ptr, value, num, align) { return makeSetValues(ptr, 0, value, 'null', num, align); }, - memset: function(ptr, value, num, align) { + memset__sig: 'viii', + memset__asm: true, + memset: function(ptr, value, num) { #if USE_TYPED_ARRAYS == 2 - // TODO: make these settings, and in memcpy, {{'s - if (num >= {{{ SEEK_OPTIMAL_ALIGN_MIN }}}) { + ptr = ptr|0; value = value|0; num = num|0; + var stop = 0, value4 = 0, stop4 = 0, unaligned = 0; + stop = (ptr + num)|0; + if (num|0 >= {{{ SEEK_OPTIMAL_ALIGN_MIN }}}) { // This is unaligned, but quite large, so work hard to get to aligned settings - var stop = ptr + num; - while (ptr % 4) { // no need to check for stop, since we have large num - HEAP8[ptr++] = value; - } - if (value < 0) value += 256; // make it unsigned - var ptr4 = ptr >> 2, stop4 = stop >> 2, value4 = value | (value << 8) | (value << 16) | (value << 24); - while (ptr4 < stop4) { - HEAP32[ptr4++] = value4; - } - ptr = ptr4 << 2; - while (ptr < stop) { - HEAP8[ptr++] = value; + unaligned = ptr & 3; + value4 = value | (value << 8) | (value << 16) | (value << 24); + stop4 = stop & ~3; + if (unaligned) { + unaligned = (ptr + 4 - unaligned)|0; + while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num + {{{ makeSetValueAsm('ptr', 0, 'value', 'i8') }}}; + ptr = (ptr+1)|0; + } } - } else { - while (num--) { - HEAP8[ptr++] = value; + while ((ptr|0) < (stop4|0)) { + {{{ makeSetValueAsm('ptr', 0, 'value4', 'i32') }}}; + ptr = (ptr+4)|0; } } + while ((ptr|0) < (stop|0)) { + {{{ makeSetValueAsm('ptr', 0, 'value', 'i8') }}}; + ptr = (ptr+1)|0; + } #else - {{{ makeSetValues('ptr', '0', 'value', 'null', 'num', 'align') }}}; + {{{ makeSetValues('ptr', '0', 'value', 'null', 'num') }}}; #endif }, llvm_memset_i32: 'memset', @@ -4857,13 +4881,25 @@ LibraryManager.library = { #endif }, - llvm_ctlz_i32: function(x) { - for (var i=0; i<32; i++) { - if ( (x & (1 << (31-i))) != 0 ) { - return i; + llvm_ctlz_i32__deps: [function() { + function ctlz(x) { + for (var i = 0; i < 8; i++) { + if (x & (1 << (7-i))) { + return i; } + } + return 8; } - return 32; + return 'var ctlz_i8 = [' + range(256).map(function(x) { return ctlz(x) }).join(',') + '];'; + }], + llvm_ctlz_i32: function(x) { + var ret = ctlz_i8[x >>> 24]; + if (ret < 8) return ret; + var ret = ctlz_i8[(x >> 16)&0xff]; + if (ret < 8) return ret + 8; + var ret = ctlz_i8[(x >> 8)&0xff]; + if (ret < 8) return ret + 16; + return ctlz_i8[x&0xff] + 24; }, llvm_ctlz_i64__deps: ['llvm_ctlz_i32'], @@ -4877,6 +4913,38 @@ LibraryManager.library = { #endif }, + llvm_cttz_i32__deps: [function() { + function cttz(x) { + for (var i = 0; i < 8; i++) { + if (x & (1 << i)) { + return i; + } + } + return 8; + } + return 'var cttz_i8 = [' + range(256).map(function(x) { return cttz(x) }).join(',') + '];'; + }], + llvm_cttz_i32: function(x) { + var ret = cttz_i8[x & 0xff]; + if (ret < 8) return ret; + var ret = cttz_i8[(x >> 8)&0xff]; + if (ret < 8) return ret + 8; + var ret = cttz_i8[(x >> 16)&0xff]; + if (ret < 8) return ret + 16; + return cttz_i8[x >>> 24] + 24; + }, + + llvm_cttz_i64__deps: ['llvm_cttz_i32'], + llvm_cttz_i64: function(l, h) { + var ret = _llvm_cttz_i32(l); + if (ret == 32) ret += _llvm_cttz_i32(h); +#if USE_TYPED_ARRAYS == 2 + {{{ makeStructuralReturn(['ret', '0']) }}}; +#else + return ret; +#endif + }, + llvm_trap: function() { throw 'trap! ' + new Error().stack; }, @@ -5548,11 +5616,11 @@ LibraryManager.library = { // ========================================================================== __utsname_struct_layout: Runtime.generateStructInfo([ - 'sysname', - 'nodename', - 'release', - 'version', - 'machine'], '%struct.utsname'), + 'sysname', + 'nodename', + 'release', + 'version', + 'machine'], '%struct.utsname'), uname__deps: ['__utsname_struct_layout'], uname: function(name) { // int uname(struct utsname *name); @@ -5983,14 +6051,13 @@ LibraryManager.library = { return 0; }, - // TODO: Implement remaining functions. // http://pubs.opengroup.org/onlinepubs/000095399/basedefs/sys/time.h.html gettimeofday: function(ptr) { // %struct.timeval = type { i32, i32 } - var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] }); + {{{ (LibraryManager.structs.gettimeofday = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] }), null) }}} var now = Date.now(); - {{{ makeSetValue('ptr', 'indexes[0]', 'Math.floor(now/1000)', 'i32') }}} // seconds - {{{ makeSetValue('ptr', 'indexes[1]', 'Math.floor((now-1000*Math.floor(now/1000))*1000)', 'i32') }}} // microseconds + {{{ makeSetValue('ptr', LibraryManager.structs.gettimeofday[0], 'Math.floor(now/1000)', 'i32') }}}; // seconds + {{{ makeSetValue('ptr', LibraryManager.structs.gettimeofday[1], 'Math.floor((now-1000*Math.floor(now/1000))*1000)', 'i32') }}}; // microseconds return 0; }, @@ -6809,10 +6876,11 @@ LibraryManager.library = { nextFd: 1, fds: {}, sockaddr_in_layout: Runtime.generateStructInfo([ - ['i16', 'sin_family'], + ['i32', 'sin_family'], ['i16', 'sin_port'], ['i32', 'sin_addr'], - ['i64', 'sin_zero'], + ['i32', 'sin_zero'], + ['i16', 'sin_zero_b'], ]), msghdr_layout: Runtime.generateStructInfo([ ['*', 'msg_name'], @@ -6974,7 +7042,7 @@ LibraryManager.library = { if (!info) return -1; if (info.inQueue.length == 0) { ___setErrNo(ERRNO_CODES.EAGAIN); // no data, and all sockets are nonblocking, so this is the right behavior - return 0; // should this be -1 like the spec says? + return -1; } var buffer = info.inQueue.shift(); #if SOCKET_DEBUG diff --git a/src/library_browser.js b/src/library_browser.js index 0bc6d130..d16fbc0b 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -98,7 +98,9 @@ mergeInto(LibraryManager.library, { b = bb.getBlob(); } var url = Browser.URLObject.createObjectURL(b); +#if ASSERTIONS assert(typeof url == 'string', 'createObjectURL must return a url as a string'); +#endif var img = new Image(); img.onload = function() { assert(img.complete, 'Image ' + name + ' could not be decoded'); @@ -144,7 +146,9 @@ mergeInto(LibraryManager.library, { return fail(); } var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this! +#if ASSERTIONS assert(typeof url == 'string', 'createObjectURL must return a url as a string'); +#endif var audio = new Audio(); audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926 audio.onerror = function(event) { diff --git a/src/library_egl.js b/src/library_egl.js index 1c35ddf4..a9eb37dd 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -71,6 +71,17 @@ var LibraryEGL = { return 0; } }, + + // EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); + eglTerminate: function(display) { + if (display != 62000 /* Magic ID for Emscripten 'default display' */) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + // TODO: Tear down EGL here. Currently a no-op since we don't need to actually do anything here for the browser. + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }, // EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); eglGetConfigs: function(display, configs, config_size, numConfigs) { @@ -228,6 +239,22 @@ var LibraryEGL = { return 62004; // Magic ID for Emscripten EGLContext }, + // EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx); + eglDestroyContext: function(display, context) { + if (display != 62000 /* Magic ID for Emscripten 'default display' */) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + + if (context != 62004 /* Magic ID for Emscripten EGLContext */) { + EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); + return 0; + } + + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }, + // EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); eglQuerySurface: function(display, surface, attribute, value) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { @@ -336,6 +363,7 @@ var LibraryEGL = { return EGL.eglErrorCode; }, + // EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); eglQueryString: function(display, name) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -412,7 +440,8 @@ var LibraryEGL = { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); return 1; }, - + + // EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); eglSwapBuffers: function() { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); }, diff --git a/src/library_gl.js b/src/library_gl.js index c153a181..0566b3a0 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -725,22 +725,22 @@ var LibraryGL = { }, glVertexAttrib1fv: function(index, v) { - v = {{{ makeHEAPView('F32', 'v', 'v+1*4') }}}; + v = {{{ makeHEAPView('F32', 'v', 'v+' + (1*4)) }}}; Module.ctx.vertexAttrib1fv(index, v); }, glVertexAttrib2fv: function(index, v) { - v = {{{ makeHEAPView('F32', 'v', 'v+2*4') }}}; + v = {{{ makeHEAPView('F32', 'v', 'v+' + (2*4)) }}}; Module.ctx.vertexAttrib2fv(index, v); }, glVertexAttrib3fv: function(index, v) { - v = {{{ makeHEAPView('F32', 'v', 'v+3*4') }}}; + v = {{{ makeHEAPView('F32', 'v', 'v+' + (3*4)) }}}; Module.ctx.vertexAttrib3fv(index, v); }, glVertexAttrib4fv: function(index, v) { - v = {{{ makeHEAPView('F32', 'v', 'v+4*4') }}}; + v = {{{ makeHEAPView('F32', 'v', 'v+' + (4*4)) }}}; Module.ctx.vertexAttrib4fv(index, v); }, @@ -2380,7 +2380,7 @@ var LibraryGL = { glLoadMatrixd: function(matrix) { GL.immediate.matricesModified = true; - GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+16*8') }}}, GL.immediate.matrix[GL.immediate.currentMatrix]); + GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]); }, glLoadMatrixf: function(matrix) { @@ -2388,37 +2388,37 @@ var LibraryGL = { if (GL.debug) Module.printErr('glLoadMatrixf receiving: ' + Array.prototype.slice.call(HEAPF32.subarray(matrix >> 2, (matrix >> 2) + 16))); #endif GL.immediate.matricesModified = true; - GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+16*4') }}}, GL.immediate.matrix[GL.immediate.currentMatrix]); + GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]); }, glLoadTransposeMatrixd: function(matrix) { GL.immediate.matricesModified = true; - GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+16*8') }}}, GL.immediate.matrix[GL.immediate.currentMatrix]); + GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]); GL.immediate.matrix.lib.mat4.transpose(GL.immediate.matrix[GL.immediate.currentMatrix]); }, glLoadTransposeMatrixf: function(matrix) { GL.immediate.matricesModified = true; - GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+16*4') }}}, GL.immediate.matrix[GL.immediate.currentMatrix]); + GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]); GL.immediate.matrix.lib.mat4.transpose(GL.immediate.matrix[GL.immediate.currentMatrix]); }, glMultMatrixd: function(matrix) { GL.immediate.matricesModified = true; GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix], - {{{ makeHEAPView('F64', 'matrix', 'matrix+16*8') }}}); + {{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}); }, glMultMatrixf: function(matrix) { GL.immediate.matricesModified = true; GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix], - {{{ makeHEAPView('F32', 'matrix', 'matrix+16*4') }}}); + {{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}); }, glMultTransposeMatrixd: function(matrix) { GL.immediate.matricesModified = true; var colMajor = GL.immediate.matrix.lib.mat4.create(); - GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+16*8') }}}, colMajor); + GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, colMajor); GL.immediate.matrix.lib.mat4.transpose(colMajor); GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix], colMajor); }, @@ -2426,7 +2426,7 @@ var LibraryGL = { glMultTransposeMatrixf: function(matrix) { GL.immediate.matricesModified = true; var colMajor = GL.immediate.matrix.lib.mat4.create(); - GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+16*4') }}}, colMajor); + GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, colMajor); GL.immediate.matrix.lib.mat4.transpose(colMajor); GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix], colMajor); }, @@ -2481,9 +2481,9 @@ var LibraryGL = { var inVec = new Float32Array(4); var outVec = new Float32Array(4); - GL.immediate.matrix.lib.mat4.multiplyVec4({{{ makeHEAPView('F64', 'model', 'model+16*8') }}}, + GL.immediate.matrix.lib.mat4.multiplyVec4({{{ makeHEAPView('F64', 'model', 'model+' + (16*8)) }}}, [objX, objY, objZ, 1.0], outVec); - GL.immediate.matrix.lib.mat4.multiplyVec4({{{ makeHEAPView('F64', 'proj', 'proj+16*8') }}}, + GL.immediate.matrix.lib.mat4.multiplyVec4({{{ makeHEAPView('F64', 'proj', 'proj+' + (16*8)) }}}, outVec, inVec); if (inVec[3] == 0.0) { return 0 /* GL_FALSE */; @@ -2496,8 +2496,8 @@ var LibraryGL = { inVec[1] = inVec[1] * 0.5 + 0.5; inVec[2] = inVec[2] * 0.5 + 0.5; // Map x, y to viewport - inVec[0] = inVec[0] * {{{ makeGetValue('view', '2*4', 'i32') }}} + {{{ makeGetValue('view', '0*4', 'i32') }}}; - inVec[1] = inVec[1] * {{{ makeGetValue('view', '3*4', 'i32') }}} + {{{ makeGetValue('view', '1*4', 'i32') }}}; + inVec[0] = inVec[0] * {{{ makeGetValue('view', 2*4, 'i32') }}} + {{{ makeGetValue('view', 0*4, 'i32') }}}; + inVec[1] = inVec[1] * {{{ makeGetValue('view', 3*4, 'i32') }}} + {{{ makeGetValue('view', 1*4, 'i32') }}}; {{{ makeSetValue('winX', '0', 'inVec[0]', 'double') }}}; {{{ makeSetValue('winY', '0', 'inVec[1]', 'double') }}}; @@ -2508,9 +2508,9 @@ var LibraryGL = { gluUnProject: function(winX, winY, winZ, model, proj, view, objX, objY, objZ) { var result = GL.immediate.matrix.lib.mat4.unproject([winX, winY, winZ], - {{{ makeHEAPView('F64', 'model', 'model+16*8') }}}, - {{{ makeHEAPView('F64', 'proj', 'proj+16*8') }}}, - {{{ makeHEAPView('32', 'view', 'view+4*4') }}}); + {{{ makeHEAPView('F64', 'model', 'model+' + (16*8)) }}}, + {{{ makeHEAPView('F64', 'proj', 'proj+' + (16*8)) }}}, + {{{ makeHEAPView('32', 'view', 'view+' + (4*4)) }}}); if (result === null) { return 0 /* GL_FALSE */; diff --git a/src/library_sdl.js b/src/library_sdl.js index 712ec290..cfab6410 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -483,7 +483,7 @@ var LibrarySDL = { // correct. SDL.buttonState |= 1 << event.button; } else if (event.type == 'mouseup') { - SDL.buttonState = 0; + SDL.buttonState &= ~(1 << event.button); } // fall through case 'mousemove': { @@ -883,7 +883,7 @@ var LibrarySDL = { SDL_GetMouseState: function(x, y) { if (x) {{{ makeSetValue('x', '0', 'SDL.mouseX', 'i32') }}}; if (y) {{{ makeSetValue('y', '0', 'SDL.mouseY', 'i32') }}}; - return 0; + return SDL.buttonState; }, SDL_WarpMouse: function(x, y) { @@ -1260,9 +1260,9 @@ var LibrarySDL = { // Get the audio element associated with the ID var info = SDL.audios[id]; - if (!info) return 0; + if (!info) return -1; var audio = info.audio; - if (!audio) return 0; + if (!audio) return -1; // If the user asks us to allocate a channel automatically, get the first // free one. diff --git a/src/modules.js b/src/modules.js index f33f302b..695abbe7 100644 --- a/src/modules.js +++ b/src/modules.js @@ -347,6 +347,7 @@ var Functions = { var LibraryManager = { library: null, + structs: {}, loaded: false, load: function() { diff --git a/src/parseTools.js b/src/parseTools.js index 3410c4c9..f5e2f33f 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -6,11 +6,10 @@ // Does simple 'macro' substitution, using Django-like syntax, // {{{ code }}} will be replaced with |eval(code)|. function processMacros(text) { - return text.replace(/{{{[^}]+}}}/g, function(str) { + return text.replace(/{{{([^}]|}(?!}))+}}}/g, function(str) { str = str.substr(3, str.length-6); var ret = eval(str); - if (ret !== undefined) ret = ret.toString(); - return ret; + return ret ? ret.toString() : ''; }); } @@ -1080,6 +1079,8 @@ function makeSetTempDouble(i, type, value) { return makeGetTempDouble(i, type, true) + '=' + asmEnsureFloat(value, type); } +var asmPrintCounter = 0; + // See makeSetValue function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe, forceAsm) { if (UNALIGNED_MEMORY) align = 1; @@ -1118,9 +1119,9 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } } else { if (type == 'float') { - ret += 'copyTempFloat(' + getFastValue(ptr, '+', pos) + '),' + makeGetTempDouble(0, 'float'); + ret += 'copyTempFloat(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + '),' + makeGetTempDouble(0, 'float'); } else { - ret += 'copyTempDouble(' + getFastValue(ptr, '+', pos) + '),' + makeGetTempDouble(0, 'double'); + ret += 'copyTempDouble(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + '),' + makeGetTempDouble(0, 'double'); } } ret += ')'; @@ -1130,14 +1131,19 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP && !noSafe) { - if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"'; - if (type[0] === '#') type = type.substr(1); - return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; + var printType = type; + if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; + if (printType[0] === '#') printType = printType.substr(1); + return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type); } else { var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; - if (ASM_JS && phase == 'funcs') { + if (ASM_JS && (phase == 'funcs' || forceAsm)) { ret = asmCoercion(ret, type); } + if (ASM_HEAP_LOG) { + ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret, + 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int')); + } return ret; } } @@ -1175,7 +1181,7 @@ function indexizeFunctions(value, type) { //! 'null' means, in the context of SAFE_HEAP, that we should accept all types; //! which means we should write to all slabs, ignore type differences if any on reads, etc. //! @param noNeedFirst Whether to ignore the offset in the pointer itself. -function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) { +function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign, forceAsm) { if (UNALIGNED_MEMORY && !forcedAlign) align = 1; sep = sep || ';'; if (isStructType(type)) { @@ -1233,16 +1239,19 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, value = indexizeFunctions(value, type); var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP && !noSafe) { - if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"'; - if (type[0] === '#') type = type.substr(1); - return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + type + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; + var printType = type; + if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; + if (printType[0] === '#') printType = printType.substr(1); + return 'SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; } else { - return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type) + ']=' + value }).join(sep); - //return '(print("set:"+(' + value + ')+":"+(' + getHeapOffset(offset, type) + ')),' + - // makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type) + ']=' + value }).join('; ') + ')'; + return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep); } } +function makeSetValueAsm(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) { + return makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign, true); +} + var SEEK_OPTIMAL_ALIGN_MIN = 20; var UNROLL_LOOP_MAX = 8; @@ -1264,7 +1273,7 @@ function makeSetValues(ptr, pos, value, type, num, align) { // If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset // TODO: optimize the case of numeric num but non-numeric value if (!isNumber(num) || !isNumber(value) || (align < 4 && parseInt(num) >= SEEK_OPTIMAL_ALIGN_MIN)) { - return '_memset(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + ', ' + asmCoercion(value, 'i32') + ', ' + asmCoercion(num, 'i32') + ', ' + align + ')'; + return '_memset(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + ', ' + asmCoercion(value, 'i32') + ', ' + asmCoercion(num, 'i32') + ')'; } num = parseInt(num); value = parseInt(value); diff --git a/src/postamble.js b/src/postamble.js index 5f541733..00205abc 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -17,18 +17,30 @@ Module.callMain = function callMain(args) { argv.push(0); argv = allocate(argv, 'i32', ALLOC_STATIC); +#if BENCHMARK + var start = Date.now(); +#endif + + var ret; + #if CATCH_EXIT_CODE var initialStackTop = STACKTOP; try { - return Module['_main'](argc, argv, 0); + ret = Module['_main'](argc, argv, 0); } catch(e) { if (e.name == "ExitStatus") return e.status; throw e; } finally { STACKTOP = initialStackTop; } #else - return Module['_main'](argc, argv, 0); + ret = Module['_main'](argc, argv, 0); #endif + +#if BENCHMARK + Module.realPrint('main() took ' + (Date.now() - start) + ' milliseconds'); +#endif + + return ret; } {{GLOBAL_VARS}} diff --git a/src/preamble.js b/src/preamble.js index 52e6a7ca..aab50e9a 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -6,6 +6,11 @@ {{RUNTIME}} +#if BENCHMARK +Module.realPrint = Module.print; +Module.print = Module.printErr = function(){}; +#endif + #if SAFE_HEAP //======================================== // Debugging tools - Heap @@ -30,8 +35,8 @@ function SAFE_HEAP_ACCESS(dest, type, store, ignore) { // When using typed arrays, reads over the top of TOTAL_MEMORY will fail silently, so we must // correct that by growing TOTAL_MEMORY as needed. Without typed arrays, memory is a normal // JS array so it will work (potentially slowly, depending on the engine). - assert(dest < STATICTOP); - assert(STATICTOP <= TOTAL_MEMORY); + assert(ignore || dest < STATICTOP); + assert(ignore || STATICTOP <= TOTAL_MEMORY); #endif #if USE_TYPED_ARRAYS == 2 @@ -473,6 +478,14 @@ Module['ALLOC_STACK'] = ALLOC_STACK; Module['ALLOC_STATIC'] = ALLOC_STATIC; Module['ALLOC_NONE'] = ALLOC_NONE; +// Simple unoptimized memset - necessary during startup +var _memset = function(ptr, value, num) { + var stop = ptr + num; + while (ptr < stop) { + {{{ makeSetValue('ptr++', 0, 'value', 'i8', null, true) }}}; + } +} + // allocate(): This is for internal use. You can use it yourself as well, but the interface // is a little tricky (see docs right below). The reason is that it is optimized // for multiple syntaxes to save space in generated code. So you should diff --git a/src/runtime.js b/src/runtime.js index 43bd7de1..5fce4651 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -55,7 +55,7 @@ var RuntimeGenerator = { if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return ''; var ret = ''; if (SAFE_HEAP) { - ret += 'for (var i = __stackBase__; i < STACKTOP; i++) SAFE_HEAP_CLEAR(i);'; + ret += 'var i = __stackBase__; while ((i|0) < (STACKTOP|0)) { SAFE_HEAP_CLEAR(i|0); i = (i+1)|0 }'; } return ret += 'STACKTOP = __stackBase__'; }, diff --git a/src/settings.js b/src/settings.js index ccf2a25b..26b649e0 100644 --- a/src/settings.js +++ b/src/settings.js @@ -132,6 +132,8 @@ var SAFE_HEAP = 0; // Check each write to the heap, for example, this will give // that 3 is the option you usually want here. var SAFE_HEAP_LOG = 0; // Log out all SAFE_HEAP operations +var ASM_HEAP_LOG = 0; // Simple heap logging, like SAFE_HEAP_LOG but cheaper, and in asm.js + var LABEL_DEBUG = 0; // 1: Print out functions as we enter them // 2: Also print out each label as we enter it var LABEL_FUNCTION_FILTERS = []; // Filters for function label debug. @@ -317,6 +319,9 @@ var HEADLES |