summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemcc21
-rw-r--r--emscripten-version.txt2
-rwxr-xr-xemscripten.py1
-rw-r--r--src/emscripten-source-map.min.js3
-rw-r--r--src/library.js18
-rw-r--r--src/library_gl.js47
-rw-r--r--src/library_sdl.js2
-rw-r--r--src/preamble.js9
-rw-r--r--system/include/emscripten/emscripten.h26
-rw-r--r--tests/cases/floatundefinvoke_fastcomp.ll30
-rw-r--r--tests/cases/floatundefinvoke_fastcomp.txt3
-rw-r--r--tests/core/test_exceptions_white_list_empty.out0
-rw-r--r--tests/core/test_set_align.c50
-rw-r--r--tests/core/test_set_align.out8
-rw-r--r--tests/gl_teximage.c120
-rw-r--r--tests/test_browser.py3
-rw-r--r--tests/test_core.py95
-rw-r--r--tests/test_other.py20
-rw-r--r--tests/test_sanity.py2
-rw-r--r--tools/js-optimizer.js21
-rw-r--r--tools/js_optimizer.py28
-rw-r--r--tools/shared.py2
-rw-r--r--tools/test-js-optimizer-asm-pre-output.js14
-rw-r--r--tools/test-js-optimizer-asm-pre.js13
25 files changed, 459 insertions, 80 deletions
diff --git a/AUTHORS b/AUTHORS
index dc848d34..2ff3bd94 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -141,4 +141,5 @@ a license to everyone to use it as detailed in LICENSE.)
* Markus Henschel <markus.henschel@yager.de>
* Ophir Lojkine <ophir.lojkine@eleves.ec-nantes.fr>
* Ryan Sturgell <ryan.sturgell@gmail.com> (copyright owned by Google, Inc.)
+* Jason Green <jason@transgaming.com> (copyright owned by TransGaming, Inc.)
diff --git a/emcc b/emcc
index 1a645965..e55990df 100755
--- a/emcc
+++ b/emcc
@@ -64,6 +64,7 @@ DYNAMICLIB_ENDINGS = ('.dylib', '.so', '.dll')
STATICLIB_ENDINGS = ('.a',)
ASSEMBLY_ENDINGS = ('.ll',)
HEADER_ENDINGS = ('.h', '.hxx', '.hpp', '.hh', '.H', '.HXX', '.HPP', '.HH')
+SUPPORTED_LINKER_FLAGS = ('--start-group', '-(', '--end-group', '-)')
LIB_PREFIXES = ('', 'lib')
@@ -1177,7 +1178,12 @@ try:
# (4, a), (4.25, b), (4.5, c), (4.75, d)
link_flags_to_add = arg.split(',')[1:]
for flag_index, flag in enumerate(link_flags_to_add):
- link_flags.append((i + float(flag_index) / len(link_flags_to_add), flag))
+ # Only keep flags that shared.Building.link knows how to deal with.
+ # We currently can't handle flags with options (like
+ # -Wl,-rpath,/bin:/lib, where /bin:/lib is an option for the -rpath
+ # flag).
+ if flag in SUPPORTED_LINKER_FLAGS:
+ link_flags.append((i + float(flag_index) / len(link_flags_to_add), flag))
newargs[i] = ''
original_input_files = input_files[:]
@@ -1263,10 +1269,10 @@ try:
assert shared.Settings.TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 1, 'fastcomp requires asmjs-unknown-emscripten'
assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2'
assert not split_js_file, '--split-js is deprecated and not supported in fastcomp'
- assert shared.Settings.MAX_SETJMPS == 20, 'changing MAX_SETJMPS is not supported in fastcomp yet'
assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)'
assert not shared.Settings.RUNTIME_TYPE_INFO, 'RUNTIME_TYPE_INFO is not supported in fastcomp'
assert not shared.Settings.CORRUPTION_CHECK, 'CORRUPTION_CHECK is not supported in asm.js mode, which is what fastcomp can emit (you can use non-asm.js mode in non-fastcomp)'
+ assert not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE, 'Linking modules is not supported in fastcomp'
except Exception, e:
logging.error('Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend')
raise e
@@ -1283,8 +1289,8 @@ try:
fastcomp_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt']
if shared.Settings.DISABLE_EXCEPTION_CATCHING != 1:
fastcomp_opts += ['-enable-emscripten-cxx-exceptions']
- if len(shared.Settings.EXCEPTION_CATCHING_WHITELIST) > 0:
- fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST)]
+ if shared.Settings.DISABLE_EXCEPTION_CATCHING == 2:
+ fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST or ['fake'])]
if shared.Settings.ASM_JS:
assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above'
@@ -1788,8 +1794,11 @@ try:
if emit_symbol_map: js_optimizer_queue += ['symbolMap='+target+'.symbols']
if debug_level == 0: js_optimizer_queue += ['minifyWhitespace']
- if closure and shared.Settings.ASM_JS:
- js_optimizer_queue += ['closure']
+ if shared.Settings.ASM_JS:
+ if closure:
+ js_optimizer_queue += ['closure']
+ elif debug_level <= 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE:
+ js_optimizer_queue += ['cleanup']
if not shared.Settings.SIDE_MODULE: js_optimizer_queue += ['last'] # side modules are not finalized until after relocation
diff --git a/emscripten-version.txt b/emscripten-version.txt
index 18abf253..ca3ca78e 100644
--- a/emscripten-version.txt
+++ b/emscripten-version.txt
@@ -1,2 +1,2 @@
-1.18.3
+1.18.4
diff --git a/emscripten.py b/emscripten.py
index 9abaf60c..98877a8e 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -761,6 +761,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
if settings['ALIASING_FUNCTION_POINTERS'] == 0:
backend_args += ['-emscripten-no-aliasing-function-pointers']
backend_args += ['-O' + str(settings['OPT_LEVEL'])]
+ backend_args += ['-emscripten-max-setjmps=%d' % settings['MAX_SETJMPS']]
if DEBUG:
logging.debug('emscript: llvm backend: ' + ' '.join(backend_args))
t = time.time()
diff --git a/src/emscripten-source-map.min.js b/src/emscripten-source-map.min.js
index 9151400f..44cb1d84 100644
--- a/src/emscripten-source-map.min.js
+++ b/src/emscripten-source-map.min.js
@@ -4,7 +4,7 @@ var emscripten_sourcemap_xmlHttp = undefined;
function emscripten_sourceMapLoaded() {
if (emscripten_sourcemap_xmlHttp.readyState === 4) {
Module['removeRunDependency']('sourcemap');
- if (emscripten_sourcemap_xmlHttp.status === 200) {
+ if (emscripten_sourcemap_xmlHttp.status === 200 || emscripten_sourcemap_xmlHttp.status === 0) {
emscripten_source_map = new window.sourceMap.SourceMapConsumer(emscripten_sourcemap_xmlHttp.responseText);
console.log('Source map data loaded.');
} else {
@@ -20,6 +20,7 @@ function emscripten_loadSourceMap() {
emscripten_sourcemap_xmlHttp = new XMLHttpRequest();
emscripten_sourcemap_xmlHttp.onreadystatechange = emscripten_sourceMapLoaded;
emscripten_sourcemap_xmlHttp.open("GET", url, true);
+ emscripten_sourcemap_xmlHttp.responseType = "text";
emscripten_sourcemap_xmlHttp.send(null);
}
diff --git a/src/library.js b/src/library.js
index 9dd2aedc..fb1a8998 100644
--- a/src/library.js
+++ b/src/library.js
@@ -5923,15 +5923,15 @@ LibraryManager.library = {
var i = 0;
setjmpId = (setjmpId+1)|0;
{{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}};
- while ((i|0) < {{{ 2*MAX_SETJMPS }}}) {
- if ({{{ makeGetValueAsm('table', '(i<<2)', 'i32') }}} == 0) {
- {{{ makeSetValueAsm('table', '(i<<2)', 'setjmpId', 'i32') }}};
- {{{ makeSetValueAsm('table', '(i<<2)+4', 'label', 'i32') }}};
+ while ((i|0) < {{{ MAX_SETJMPS }}}) {
+ if ({{{ makeGetValueAsm('table', '(i<<3)', 'i32') }}} == 0) {
+ {{{ makeSetValueAsm('table', '(i<<3)', 'setjmpId', 'i32') }}};
+ {{{ makeSetValueAsm('table', '(i<<3)+4', 'label', 'i32') }}};
// prepare next slot
- {{{ makeSetValueAsm('table', '(i<<2)+8', '0', 'i32') }}};
+ {{{ makeSetValueAsm('table', '(i<<3)+8', '0', 'i32') }}};
return 0;
}
- i = (i+2)|0;
+ i = i+1|0;
}
{{{ makePrintChars('too many setjmps in a function call, build with a higher value for MAX_SETJMPS') }}};
abort(0);
@@ -5945,12 +5945,12 @@ LibraryManager.library = {
table = table|0;
var i = 0, curr = 0;
while ((i|0) < {{{ MAX_SETJMPS }}}) {
- curr = {{{ makeGetValueAsm('table', '(i<<2)', 'i32') }}};
+ curr = {{{ makeGetValueAsm('table', '(i<<3)', 'i32') }}};
if ((curr|0) == 0) break;
if ((curr|0) == (id|0)) {
- return {{{ makeGetValueAsm('table', '(i<<2)+4', 'i32') }}};
+ return {{{ makeGetValueAsm('table', '(i<<3)+4', 'i32') }}};
}
- i = (i+2)|0;
+ i = i+1|0;
}
return 0;
},
diff --git a/src/library_gl.js b/src/library_gl.js
index 851b01b1..2659a9d9 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -431,21 +431,42 @@ var LibraryGL = {
sizePerPixel = 2;
break;
default:
- throw 'Invalid format (' + format + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
break;
case 0x1403 /* GL_UNSIGNED_SHORT */:
if (format == 0x1902 /* GL_DEPTH_COMPONENT */) {
sizePerPixel = 2;
} else {
- throw 'Invalid format (' + format + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
break;
case 0x1405 /* GL_UNSIGNED_INT */:
if (format == 0x1902 /* GL_DEPTH_COMPONENT */) {
sizePerPixel = 4;
} else {
- throw 'Invalid format (' + format + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
break;
case 0x84FA /* UNSIGNED_INT_24_8_WEBGL */:
@@ -468,12 +489,26 @@ var LibraryGL = {
sizePerPixel = 4*4;
break;
default:
- throw 'Invalid format (' + format + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
internalFormat = GLctx.RGBA;
break;
default:
- throw 'Invalid type (' + type + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
var bytes = GL.computeImageSize(width, height, sizePerPixel, GL.unpackAlignment);
if (type == 0x1401 /* GL_UNSIGNED_BYTE */) {
@@ -488,7 +523,7 @@ var LibraryGL = {
return {
pixels: pixels,
internalFormat: internalFormat
- }
+ };
},
#if GL_FFP_ONLY
diff --git a/src/library_sdl.js b/src/library_sdl.js
index fd8c6860..a01b3c6c 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -2332,7 +2332,7 @@ var LibrarySDL = {
return 0;
}
- var arrayBuffer = bytes.buffer || bytes;
+ var arrayBuffer = bytes ? bytes.buffer || bytes : bytes;
// To allow user code to work around browser bugs with audio playback on <audio> elements an Web Audio, enable
// the user code to hook in a callback to decide on a file basis whether each file should use Web Audio or <audio> for decoding and playback.
diff --git a/src/preamble.js b/src/preamble.js
index f46119c7..58b442ab 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -352,6 +352,13 @@ var cwrap, ccall;
// C calling interface. A convenient way to call C functions (in C files, or
// defined with extern "C").
//
+ // Note: ccall/cwrap use the C stack for temporary values. If you pass a string
+ // then it is only alive until the call is complete. If the code being
+ // called saves the pointer to be used later, it may point to invalid
+ // data. If you need a string to live forever, you can create it (and
+ // must later delete it manually!) using malloc and writeStringToMemory,
+ // for example.
+ //
// Note: LLVM optimizations can inline and remove functions, after which you will not be
// able to call them. Closure can also do so. To avoid that, add your function to
// the exports using something like
@@ -389,7 +396,7 @@ var cwrap, ccall;
return ret;
}
- var sourceRegex = /^function \((.*)\)\s*{\s*([^]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;
+ var sourceRegex = /^function\s\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;
function parseJSFunc(jsfunc) {
// Match the body and the return value of a javascript function source
var parsed = jsfunc.toString().match(sourceRegex).slice(1);
diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h
index 66017a8d..8a08aabb 100644
--- a/system/include/emscripten/emscripten.h
+++ b/system/include/emscripten/emscripten.h
@@ -18,6 +18,32 @@ extern "C" {
#include <SDL/SDL.h> /* for SDL_Delay in async_call */
#endif
+
+/* Typedefs */
+
+/*
+ * Unaligned types, helpful to force LLVM to emit unaligned
+ * loads/stores in places in your code where SAFE_HEAP found
+ * an unaligned operation. (It's better to avoid unaligned
+ * operations, but if you are reading from a packed stream of
+ * bytes or such, these types may be useful.)
+ */
+
+typedef short __attribute__((aligned(1))) emscripten_align1_short;
+
+typedef int __attribute__((aligned(2))) emscripten_align2_int;
+typedef int __attribute__((aligned(1))) emscripten_align1_int;
+
+typedef float __attribute__((aligned(2))) emscripten_align2_float;
+typedef float __attribute__((aligned(1))) emscripten_align1_float;
+
+typedef double __attribute__((aligned(4))) emscripten_align4_double;
+typedef double __attribute__((aligned(2))) emscripten_align2_double;
+typedef double __attribute__((aligned(1))) emscripten_align1_double;
+
+
+/* Functions */
+
/*
* Convenient syntax for inline assembly/js. Allows stuff like
*
diff --git a/tests/cases/floatundefinvoke_fastcomp.ll b/tests/cases/floatundefinvoke_fastcomp.ll
new file mode 100644
index 00000000..215506ef
--- /dev/null
+++ b/tests/cases/floatundefinvoke_fastcomp.ll
@@ -0,0 +1,30 @@
+; ModuleID = 'a.o'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:128-n32-S128"
+target triple = "asmjs-unknown-emscripten"
+
+@.str = private unnamed_addr constant [11 x i8] c"float: %f\0A\00", align 1
+
+define void @_Z10printFloatf(float %f) #0 {
+entry:
+ %conv = fpext float %f to double
+ %call = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([11 x i8]* @.str, i32 0, i32 0), double %conv)
+ ret void
+}
+
+define i32 @main() #1 {
+entry:
+ tail call void @_Z10printFloatf(float 1.000000e+00)
+ call void @emscripten_preinvoke()
+ call void @_Z10printFloatf(float undef)
+ %last = call i32 @emscripten_postinvoke()
+ %lastf = sitofp i32 %last to float
+ tail call void @_Z10printFloatf(float %lastf)
+ ret i32 1
+}
+
+declare void @emscripten_preinvoke()
+declare i32 @emscripten_postinvoke()
+declare i32 @printf(i8* nocapture, ...) #1
+
+attributes #0 = { noinline nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
diff --git a/tests/cases/floatundefinvoke_fastcomp.txt b/tests/cases/floatundefinvoke_fastcomp.txt
new file mode 100644
index 00000000..5e19391e
--- /dev/null
+++ b/tests/cases/floatundefinvoke_fastcomp.txt
@@ -0,0 +1,3 @@
+float: 1.000000
+float: 0.000000
+float: 0.000000
diff --git a/tests/core/test_exceptions_white_list_empty.out b/tests/core/test_exceptions_white_list_empty.out
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/test_exceptions_white_list_empty.out
diff --git a/tests/core/test_set_align.c b/tests/core/test_set_align.c
new file mode 100644
index 00000000..26158ef4
--- /dev/null
+++ b/tests/core/test_set_align.c
@@ -0,0 +1,50 @@
+
+#include <stdio.h>
+#include <emscripten.h>
+
+volatile char data[16];
+
+__attribute__((noinline)) void *get_aligned(int align)
+{
+ char *ptr = (char*)(((int)(data + 7)) & ~7); // Make 8-byte aligned
+ ptr += align; // Now 'align' aligned
+ return (void*)ptr;
+}
+
+int main()
+{
+ emscripten_align4_double *d4 = (emscripten_align4_double*)get_aligned(4);
+ *d4 = 17.0;
+ printf("addr: %d, value: %f\n", ((int)d4) % 8, *d4);
+
+ emscripten_align2_double *d2 = (emscripten_align2_double*)get_aligned(2);
+ *d2 = 18.0;
+ printf("addr: %d, value: %f\n", ((int)d2) % 8, *d2);
+
+ emscripten_align1_double *d1 = (emscripten_align1_double*)get_aligned(1);
+ *d1 = 19.0;
+ printf("addr: %d, value: %f\n", ((int)d1) % 8, *d1);
+
+ emscripten_align2_float *f2 = (emscripten_align2_float*)get_aligned(2);
+ *f2 = 20.0;
+ printf("addr: %d, value: %f\n", ((int)f2) % 4, *f2);
+
+ emscripten_align1_float *f1 = (emscripten_align1_float*)get_aligned(1);
+ *f1 = 21.0;
+ printf("addr: %d, value: %f\n", ((int)f1) % 4, *f1);
+
+ emscripten_align2_int *i2 = (emscripten_align2_int*)get_aligned(2);
+ *i2 = 22;
+ printf("addr: %d, value: %d\n", ((int)i2) % 4, *i2);
+
+ emscripten_align1_int *i1 = (emscripten_align1_int*)get_aligned(1);
+ *i1 = 23;
+ printf("addr: %d, value: %d\n", ((int)i1) % 4, *i1);
+
+ emscripten_align1_short *s1 = (emscripten_align1_short*)get_aligned(1);
+ *s1 = 24;
+ printf("addr: %d, value: %d\n", ((int)s1) % 4, (int)*s1);
+
+ return 0;
+}
+
diff --git a/tests/core/test_set_align.out b/tests/core/test_set_align.out
new file mode 100644
index 00000000..55e377b0
--- /dev/null
+++ b/tests/core/test_set_align.out
@@ -0,0 +1,8 @@
+addr: 4, value: 17.000000
+addr: 2, value: 18.000000
+addr: 1, value: 19.000000
+addr: 2, value: 20.000000
+addr: 1, value: 21.000000
+addr: 2, value: 22
+addr: 1, value: 23
+addr: 1, value: 24
diff --git a/tests/gl_teximage.c b/tests/gl_teximage.c
new file mode 100644
index 00000000..9cafce9c
--- /dev/null
+++ b/tests/gl_teximage.c
@@ -0,0 +1,120 @@
+/*
+ * GLES2 test for glTexImage2D parameters
+ *
+ * Original author: Jason Green <jason@transgaming.com>
+ *
+ */
+#include "GLES2/gl2.h"
+#include "SDL/SDL.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <emscripten.h>
+#include <unistd.h>
+
+typedef enum {
+ TEST_STATUS_SUCCESS = 0,
+ TEST_STATUS_FAILURE = 1
+} TestStatus;
+
+/* Report success or failure (1 or 0) to Emscripten's test harness. Also, exit
+ * with the given error code. */
+static void exit_with_status(TestStatus code)
+{
+#ifdef REPORT_RESULT
+ int result = (code == TEST_STATUS_SUCCESS) ? 1 : 0;
+ REPORT_RESULT();
+#endif
+
+ exit(code);
+}
+
+/* Loop over all glGetError() results until GL reports GL_NO_ERROR */
+static void clear_gl_errors()
+{
+ GLenum err;
+ do {
+ err = glGetError();
+ } while (err != GL_NO_ERROR);
+}
+
+int main(int argc, char *argv[])
+{
+ TestStatus passed = TEST_STATUS_SUCCESS;
+ SDL_Surface *screen;
+
+ if (SDL_Init(SDL_INIT_VIDEO) != 0) {
+ printf("SDL_Init failed with %s\n", SDL_GetError());
+ exit_with_status(TEST_STATUS_FAILURE);
+ }
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ screen = SDL_SetVideoMode(640, 480, 16, SDL_OPENGL);
+ if (!screen) {
+ printf("SDL_SetVideoMode failed with %s\n", SDL_GetError());
+ exit_with_status(TEST_STATUS_FAILURE);
+ }
+
+ GLuint texture;
+ glGenTextures(1, &texture);
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ // Allocate space for a 32x32 image with 4 bytes per pixel.
+ // No need to fill it with any useful information, as these tests are
+ // only designed to make sure glTexImage2D doesn't crash on unsupported
+ // formats.
+ void* pixels = malloc(4 * 32 * 32);
+ if (pixels == NULL) {
+ printf("Unable to allocate pixel data\n");
+ exit_with_status(TEST_STATUS_FAILURE);
+ }
+
+ // First, try 0xffff for the internal format - should fail
+ glTexImage2D(GL_TEXTURE_2D, 0, 0xffff, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ GLenum err = glGetError();
+ if (err == GL_NO_ERROR) {
+ printf("internal format == 0xffff succeeded, but should have failed\n");
+ passed = TEST_STATUS_FAILURE;
+ }
+ clear_gl_errors();
+
+ // Try 0xffff for the format - should fail
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, 0xffff, GL_UNSIGNED_BYTE, pixels);
+ err = glGetError();
+ if (err == GL_NO_ERROR) {
+ printf("format == 0xffff succeeded, but should have failed\n");
+ passed = TEST_STATUS_FAILURE;
+ }
+ clear_gl_errors();
+
+ // Try 0xffff for the type - should fail
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, 0xffff, pixels);
+ err = glGetError();
+ if (err == GL_NO_ERROR) {
+ printf("type == 0xffff succeeded, but should have failed\n");
+ passed = TEST_STATUS_FAILURE;
+ }
+ clear_gl_errors();
+
+ // Try GL_RGBA/GL_UNSIGNED_BYTE - should succeed
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ err = glGetError();
+ if (err != GL_NO_ERROR) {
+ printf("GL_RGBA/GL_UNSIGNED_BYTE failed with %x, but should have succeeded\n", err);
+ passed = TEST_STATUS_FAILURE;
+ }
+ clear_gl_errors();
+
+ // Clean up objects
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &texture);
+ free(pixels);
+
+ // 'screen' is freed implicitly by SDL_Quit()
+ SDL_Quit();
+
+ exit_with_status(passed);
+}
diff --git a/tests/test_browser.py b/tests/test_browser.py
index aedc926a..c8e07b25 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -1425,6 +1425,9 @@ keydown(100);keyup(100); // trigger the end
def test_sdlglshader(self):
self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1'])
+ def test_gl_glteximage(self):
+ self.btest('gl_teximage.c', '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'))
diff --git a/tests/test_core.py b/tests/test_core.py
index 7c317894..505a051b 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -1166,7 +1166,6 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
def test_longjmp_repeat(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '0': Settings.MAX_SETJMPS = 1 # todo: do this more strict thing in fastcomp too
test_path = path_from_root('tests', 'core', 'test_longjmp_repeat')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
@@ -1190,8 +1189,6 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
def test_setjmp_many(self):
- if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp: make MAX_SETJMPS take effect')
-
src = r'''
#include <stdio.h>
#include <setjmp.h>
@@ -1203,9 +1200,42 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
return 0;
}
'''
- for num in [Settings.MAX_SETJMPS, Settings.MAX_SETJMPS+1]:
- print num
- self.do_run(src.replace('NUM', str(num)), '0\n' * num if num <= Settings.MAX_SETJMPS or not Settings.ASM_JS else 'build with a higher value for MAX_SETJMPS')
+ for maxx in [Settings.MAX_SETJMPS/2, Settings.MAX_SETJMPS, 2*Settings.MAX_SETJMPS]:
+ Settings.MAX_SETJMPS = maxx
+ for num in [maxx, maxx+1]:
+ print maxx, num
+ self.do_run(src.replace('NUM', str(num)), '0\n' * num if num <= Settings.MAX_SETJMPS or not Settings.ASM_JS else 'build with a higher value for MAX_SETJMPS')
+
+ def test_setjmp_many_2(self):
+ if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('non-fastcomp do not hit the limit.')
+
+ src = r'''
+#include <setjmp.h>
+#include <stdio.h>
+
+jmp_buf env;
+
+void luaWork(int d){
+ int x;
+ printf("d is at %d\n", d);
+
+ longjmp(env, 1);
+}
+
+int main()
+{
+ const int ITERATIONS=25;
+ for(int i = 0; i < ITERATIONS; i++){
+ if(!setjmp(env)){
+ luaWork(i);
+ }
+ }
+ return 0;
+}
+'''
+
+ self.do_run(src, r'''d is at 19
+too many setjmps in a function call, build with a higher value for MAX_SETJMPS''')
def test_exceptions(self):
if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
@@ -1317,6 +1347,33 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
test_path = path_from_root('tests', 'core', 'test_exceptions_white_list')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
+ size = len(open('src.cpp.o.js').read())
+ shutil.copyfile('src.cpp.o.js', 'orig.js')
+
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
+ # check that an empty whitelist works properly (as in, same as exceptions disabled)
+ empty_output = path_from_root('tests', 'core', 'test_exceptions_white_list_empty.out')
+
+ Settings.EXCEPTION_CATCHING_WHITELIST = []
+ self.do_run_from_file(src, empty_output)
+ empty_size = len(open('src.cpp.o.js').read())
+ shutil.copyfile('src.cpp.o.js', 'empty.js')
+
+ Settings.EXCEPTION_CATCHING_WHITELIST = ['fake']
+ self.do_run_from_file(src, empty_output)
+ fake_size = len(open('src.cpp.o.js').read())
+ shutil.copyfile('src.cpp.o.js', 'fake.js')
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 1
+ self.do_run_from_file(src, empty_output)
+ disabled_size = len(open('src.cpp.o.js').read())
+ shutil.copyfile('src.cpp.o.js', 'disabled.js')
+
+ assert size - empty_size > 2000, [empty_size, size] # big change when we disable entirely
+ assert size - fake_size > 2000, [fake_size, size]
+ assert empty_size == fake_size, [empty_size, fake_size]
+ assert empty_size - disabled_size < 100, [empty_size, disabled_size] # full disable removes a tiny bit more
+ assert fake_size - disabled_size < 100, [disabled_size, fake_size]
def test_exceptions_white_list_2(self):
Settings.DISABLE_EXCEPTION_CATCHING = 2
@@ -1923,6 +1980,15 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
+ def test_set_align(self):
+ if self.run_name == 'slow2asm': return self.skip('FIXME in slow2asm')
+
+ Settings.SAFE_HEAP = 1
+
+ test_path = path_from_root('tests', 'core', 'test_set_align')
+ src, output = (test_path + s for s in ('.c', '.out'))
+ self.do_run_from_file(src, output)
+
def test_emscripten_api(self):
#if Settings.MICRO_OPTS or Settings.RELOOP or Building.LLVM_OPTS: return self.skip('FIXME')
@@ -2038,10 +2104,10 @@ def process(filename):
if self.emcc_args and '-O2' in self.emcc_args:
# Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized)
- code_start = 'var TOTAL_MEMORY = '
+ code_start = 'var TOTAL_MEMORY'
fail = fail[fail.find(code_start):]
win = win[win.find(code_start):]
- assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller'
+ assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller' + str([len(fail), len(win)])
def test_ssr(self): # struct self-ref
src = '''
@@ -3214,7 +3280,7 @@ def process(filename):
break
else:
raise Exception('Could not find symbol table!')
- table = table[table.find('{'):table.rfind('}')+1]
+ table = table[table.find('{'):table.find('}')+1]
# ensure there aren't too many globals; we don't want unnamed_addr
assert table.count(',') <= 4
@@ -4664,8 +4730,7 @@ int main(void) {
if self.emcc_args is None: self.emcc_args = [] # dlmalloc auto-inclusion is only done if we use emcc
self.banned_js_engines = [NODE_JS] # slower, and fail on 64-bit
- Settings.CORRECT_SIGNS = 2
- Settings.CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]
+ Settings.CORRECT_SIGNS = 1
Settings.TOTAL_MEMORY = 128*1024*1024 # needed with typed arrays
src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
@@ -5424,9 +5489,6 @@ def process(filename):
### Integration tests
def test_ccall(self):
- if self.emcc_args is not None and '-O2' in self.emcc_args:
- self.emcc_args += ['--closure', '1'] # Use closure here, to test we export things right
-
post = '''
def process(filename):
src = \'\'\'
@@ -5470,6 +5532,11 @@ def process(filename):
self.do_run_from_file(src, output, post_build=post)
+ if self.emcc_args is not None and '-O2' in self.emcc_args:
+ print 'with closure'
+ self.emcc_args += ['--closure', '1']
+ self.do_run_from_file(src, output, post_build=post)
+
def test_pgo(self):
if Settings.ASM_JS: return self.skip('PGO does not work in asm mode')
diff --git a/tests/test_other.py b/tests/test_other.py
index 5553a7b1..03859a4e 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -203,6 +203,10 @@ Options that are modified or new in %s include:
(['--typed-arrays', '1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
(['--typed-arrays', '2'], lambda generated: 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 selected'),
(['--llvm-opts', '1'], lambda generated: '_puts(' in generated, 'llvm opts requested'),
+ ([], lambda generated: '// The Module object' in generated, 'without opts, comments in shell code'),
+ (['-O2'], lambda generated: '// The Module object' not in generated, 'with opts, no comments in shell code'),
+ (['-O2', '-g2'], lambda generated: '// The Module object' not in generated, 'with -g2, no comments in shell code'),
+ (['-O2', '-g3'], lambda generated: '// The Module object' in generated, 'with -g3, yes comments in shell code'),
]:
print params, text
self.clear()
@@ -1090,22 +1094,30 @@ This pointer might make sense in another type signature: i: 0
Building.emar('cr', lib_b, [b + '.o', c + '.o']) # libB.a with b.c.o,c.c.o
args = ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1', main, '-o', 'a.out.js']
- libs = [lib_a, lib_b]
+ libs_list = [lib_a, lib_b]
# lib_a does not satisfy any symbols from main, so it will not be included,
# and there will be an unresolved symbol.
- output = Popen([PYTHON, EMCC] + args + libs, stdout=PIPE, stderr=PIPE).communicate()
+ output = Popen([PYTHON, EMCC] + args + libs_list, stdout=PIPE, stderr=PIPE).communicate()
self.assertContained('error: unresolved symbol: x', output[1])
# -Wl,--start-group and -Wl,--end-group around the libs will cause a rescan
# of lib_a after lib_b adds undefined symbol "x", so a.c.o will now be
# included (and the link will succeed).
- libs = ['-Wl,--start-group'] + libs + ['-Wl,--end-group']
+ libs = ['-Wl,--start-group'] + libs_list + ['-Wl,--end-group']
output = Popen([PYTHON, EMCC] + args + libs, stdout=PIPE, stderr=PIPE).communicate()
out_js = os.path.join(self.get_dir(), 'a.out.js')
assert os.path.exists(out_js), '\n'.join(output)
self.assertContained('result: 42', run_js(out_js))
+ # -( and -) should also work.
+ args = ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1', main, '-o', 'a2.out.js']
+ libs = ['-Wl,-('] + libs_list + ['-Wl,-)']
+ output = Popen([PYTHON, EMCC] + args + libs, stdout=PIPE, stderr=PIPE).communicate()
+ out_js = os.path.join(self.get_dir(), 'a2.out.js')
+ assert os.path.exists(out_js), '\n'.join(output)
+ self.assertContained('result: 42', run_js(out_js))
+
def test_redundant_link(self):
lib = "int mult() { return 1; }"
lib_name = os.path.join(self.get_dir(), 'libA.c')
@@ -2210,7 +2222,7 @@ void wakaw::Cm::RasterBase<wakaw::watwat::Polocator?>(unsigned int*, unsigned in
test_js_closure_0 = open(path_from_root('tests', 'Module-exports', 'test.js')).read()
# Check that test.js compiled with --closure 0 contains "module['exports'] = Module;"
- assert "module['exports'] = Module;" in test_js_closure_0
+ assert ("module['exports'] = Module;" in test_js_closure_0) or ('module["exports"]=Module' in test_js_closure_0)
# Check that main.js (which requires test.js) completes successfully when run in node.js
# in order to check that the exports are indeed functioning correctly.
diff --git a/tests/test_sanity.py b/tests/test_sanity.py
index 3d3da523..3ebd49b6 100644
--- a/tests/test_sanity.py
+++ b/tests/test_sanity.py
@@ -240,7 +240,7 @@ class sanity(RunnerCore):
os.chmod(path_from_root('tests', 'fake', 'bin', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
os.chmod(path_from_root('tests', 'fake', 'bin', 'clang++'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
try_delete(SANITY_FILE)
- output = self.check_working(EMCC, 'did not see a source tree above LLVM_DIR, could not verify version numbers match')
+ output = self.check_working(EMCC, 'did not see a source tree above the LLVM root directory')
VERSION_WARNING = 'Emscripten, llvm and clang versions do not match, this is dangerous'
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 2004efda..5b01dae0 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -136,6 +136,7 @@ var CONTROL_FLOW = set('do', 'while', 'for', 'if', 'switch');
var NAME_OR_NUM = set('name', 'num');
var ASSOCIATIVE_BINARIES = set('+', '*', '|', '&', '^');
var ALTER_FLOW = set('break', 'continue', 'return');
+var BITWISE = set('|', '&', '^');
var BREAK_CAPTURERS = set('do', 'while', 'for', 'switch');
var CONTINUE_CAPTURERS = LOOP;
@@ -387,14 +388,18 @@ function simplifyExpressions(ast) {
return innerNode;
}
}
- } else if (type === 'binary' && node[1] === '&' && node[3][0] === 'num') {
- // Rewrite (X < Y) & 1 to (X < Y)|0. (Subsequent passes will eliminate
- // the |0 if possible.)
- var input = node[2];
- var amount = node[3][1];
- if (input[0] === 'binary' && (input[1] in COMPARE_OPS) && amount == 1) {
- node[1] = '|';
- node[3][1] = 0;
+ } else if (type === 'binary' && (node[1] in BITWISE)) {
+ for (var i = 2; i <= 3; i++) {
+ var subNode = node[i];
+ if (subNode[0] === 'binary' && subNode[1] === '&' && subNode[3][0] === 'num' && subNode[3][1] == 1) {
+ // Rewrite (X < Y) & 1 to X < Y , when it is going into a bitwise operator. We could
+ // remove even more (just replace &1 with |0, then subsequent passes could remove the |0)
+ // but v8 issue #2513 means the code would then run very slowly in chrome.
+ var input = subNode[2];
+ if (input[0] === 'binary' && (input[1] in COMPARE_OPS)) {
+ node[i] = input;
+ }
+ }
}
}
});
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index d0284528..e06c2d2f 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -137,6 +137,10 @@ def run_on_js(filename, passes, js_engine, jcache, source_map=False, extra_info=
if closure:
passes = filter(lambda p: p != 'closure', passes) # we will do it manually
+ cleanup = 'cleanup' in passes
+ if cleanup:
+ passes = filter(lambda p: p != 'cleanup', passes) # we will do it manually
+
if not know_generated and jcache:
# JCache cannot be used without metadata, since it might reorder stuff, and that's dangerous since only generated can be reordered
# This means jcache does not work after closure compiler runs, for example. But you won't get much benefit from jcache with closure
@@ -291,23 +295,29 @@ EMSCRIPTEN_FUNCS();
for filename in filenames: temp_files.note(filename)
- if closure:
- # run closure on the shell code, everything but what we js-optimize
+ if closure or cleanup:
+ # run on the shell code, everything but what we js-optimize
start_asm = '// EMSCRIPTEN_START_ASM\n'
end_asm = '// EMSCRIPTEN_END_ASM\n'
- closure_sep = 'wakaUnknownBefore(); var asm=wakaUnknownAfter(global,env,buffer)\n'
+ cl_sep = 'wakaUnknownBefore(); var asm=wakaUnknownAfter(global,env,buffer)\n'
- closuree = temp_files.get('.closure.js').name
- c = open(closuree, 'w')
+ cle = temp_files.get('.cl.js').name
+ c = open(cle, 'w')
pre_1, pre_2 = pre.split(start_asm)
post_1, post_2 = post.split(end_asm)
c.write(pre_1)
- c.write(closure_sep)
+ c.write(cl_sep)
c.write(post_2)
c.close()
- closured = shared.Building.closure_compiler(closuree, pretty='minifyWhitespace' not in passes)
- temp_files.note(closured)
- coutput = open(closured).read()
+ if closure:
+ if DEBUG: print >> sys.stderr, 'running closure on shell code'
+ cld = shared.Building.closure_compiler(cle, pretty='minifyWhitespace' not in passes)
+ else:
+ if DEBUG: print >> sys.stderr, 'running cleanup on shell code'
+ cld = cle + '.js'
+ subprocess.Popen(js_engine + [JS_OPTIMIZER, cle, 'noPrintMetadata'] + (['minifyWhitespace'] if 'minifyWhitespace' in passes else []), stdout=open(cld, 'w')).communicate()
+ temp_files.note(cld)
+ coutput = open(cld).read()
coutput = coutput.replace('wakaUnknownBefore();', '')
after = 'wakaUnknownAfter'
start = coutput.find(after)
diff --git a/tools/shared.py b/tools/shared.py
index 3ce23a4c..7aaa4136 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -326,7 +326,7 @@ def check_fastcomp():
break
d = os.path.dirname(d)
if not seen:
- logging.warning('did not see a source tree above LLVM_DIR, could not verify version numbers match')
+ logging.warning('did not see a source tree above the LLVM root directory (guessing based on directory of %s), could not verify version numbers match' % LLVM_COMPILER)
return True
except Exception, e:
logging.warning('could not check fastcomp: %s' % str(e))
diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js
index 5281b87c..da3ebb4f 100644
--- a/tools/test-js-optimizer-asm-pre-output.js
+++ b/tools/test-js-optimizer-asm-pre-output.js
@@ -106,15 +106,11 @@ function sign_extension_simplification() {
}
}
function compare_result_simplification() {
- HEAP32[$4] = HEAP32[$5] < HEAP32[$6];
- HEAP32[$4] = HEAP32[$5] > HEAP32[$6];
- HEAP32[$4] = HEAP32[$5] <= HEAP32[$6];
- HEAP32[$4] = HEAP32[$5] <= HEAP32[$6];
- HEAP32[$4] = HEAP32[$5] == HEAP32[$6];
- HEAP32[$4] = HEAP32[$5] === HEAP32[$6];
- HEAP32[$4] = HEAP32[$5] != HEAP32[$6];
- HEAP32[$4] = HEAP32[$5] !== HEAP32[$6];
- var x = HEAP32[$5] != HEAP32[$6] | 0;
+ f((a > b & 1) + 1 | 0);
+ f(a > b | z);
+ f(a > b | c > d);
+ HEAP32[$4] = HEAP32[$5] < HEAP32[$6] & 1;
+ var x = HEAP32[$5] != HEAP32[$6] & 1;
}
function tempDoublePtr($45, $14, $28, $42) {
$45 = $45 | 0;
diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js
index d48d736e..08d8c2d4 100644
--- a/tools/test-js-optimizer-asm-pre.js
+++ b/tools/test-js-optimizer-asm-pre.js
@@ -113,16 +113,11 @@ function sign_extension_simplification() {
}
}
function compare_result_simplification() {
- // Eliminate these '&1's.
+ f(((a > b)&1) + 1 | 0);
+ f(((a > b)&1) | z);
+ f(((a > b)&1) | (c > d & 1));
+ // Don't eliminate these '&1's.
HEAP32[$4] = (HEAP32[$5] < HEAP32[$6]) & 1;
- HEAP32[$4] = (HEAP32[$5] > HEAP32[$6]) & 1;
- HEAP32[$4] = (HEAP32[$5] <= HEAP32[$6]) & 1;
- HEAP32[$4] = (HEAP32[$5] <= HEAP32[$6]) & 1;
- HEAP32[$4] = (HEAP32[$5] == HEAP32[$6]) & 1;
- HEAP32[$4] = (HEAP32[$5] === HEAP32[$6]) & 1;
- HEAP32[$4] = (HEAP32[$5] != HEAP32[$6]) & 1;
- HEAP32[$4] = (HEAP32[$5] !== HEAP32[$6]) & 1;
- // Convert the &1 to |0 here, since we don't get an implicit coersion.
var x = (HEAP32[$5] != HEAP32[$6]) & 1;
}
function tempDoublePtr($45, $14, $28, $42) {