aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js3
-rw-r--r--src/determinstic.js12
-rw-r--r--src/headless.js2
-rw-r--r--src/jsifier.js13
-rw-r--r--src/library.js172
-rw-r--r--src/library_browser.js4
-rw-r--r--src/library_egl.js31
-rw-r--r--src/library_gl.js38
-rw-r--r--src/library_sdl.js8
-rw-r--r--src/modules.js1
-rw-r--r--src/parseTools.js43
-rw-r--r--src/postamble.js16
-rw-r--r--src/preamble.js17
-rw-r--r--src/runtime.js2
-rw-r--r--src/settings.js5
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 HEADLESS = 0; // If 1, will include shim code that tries to 'fake' a browser
// very partial - it is hard to fake a whole browser! - so
// keep your expectations low for this to work.
+var BENCHMARK = 0; // If 1, will just time how long main() takes to execute, and not
+ // print out anything at all whatsover. This is useful for benchmarking.
+
var ASM_JS = 0; // If 1, generate code in asm.js format. XXX This is highly experimental,
// and will not work on most codebases yet. It is NOT recommended that you
// try this yet.