diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rwxr-xr-x | emcc | 8 | ||||
-rw-r--r-- | src/library.js | 18 | ||||
-rw-r--r-- | src/library_browser.js | 1 | ||||
-rw-r--r-- | src/library_gl.js | 2 | ||||
-rw-r--r-- | src/parseTools.js | 10 | ||||
-rw-r--r-- | tests/cases/funcptr.ll | 27 | ||||
-rw-r--r-- | tests/cases/funcptr.txt | 1 | ||||
-rwxr-xr-x | tests/runner.py | 82 | ||||
-rw-r--r-- | tests/sdl_mouse.c | 10 | ||||
-rwxr-xr-x | tools/bindings_generator.py | 29 | ||||
-rw-r--r-- | tools/shared.py | 30 |
12 files changed, 185 insertions, 34 deletions
@@ -22,3 +22,4 @@ under the licensing terms detailed in LICENSE. * Brian Anderson <banderson@mozilla.com> * Jon Bardin <diclophis@gmail.com> * Jukka Jylänki <jujjyl@gmail.com> +* Aleksander Guryanov <caiiiycuk@gmail.com> @@ -548,9 +548,11 @@ try: settings_changes = [] for i in range(len(newargs)): if newargs[i] == '-s': - assert '=' in newargs[i+1], 'Incorrect syntax for -s (use -s OPT=VAL): ' + newargs[i+1] - settings_changes.append(newargs[i+1]) - newargs[i] = newargs[i+1] = '' + if i+1 < len(newargs) and '=' in newargs[i+1]: # -s OPT=VALUE is for us, -s by itself is a linker option + settings_changes.append(newargs[i+1]) + newargs[i] = newargs[i+1] = '' + else: + print >> sys.stderr, 'emcc: warning: treating -s as linker option and not as -s OPT=VALUE for js compilation' elif newargs[i].startswith('--typed-arrays'): assert '=' not in newargs[i], 'Invalid typed arrays parameter (do not use "=")' settings_changes.append('USE_TYPED_ARRAYS=' + newargs[i+1]) diff --git a/src/library.js b/src/library.js index f406f02a..8d68251f 100644 --- a/src/library.js +++ b/src/library.js @@ -4199,6 +4199,24 @@ LibraryManager.library = { return newStr; }, + strndup__deps: ['strdup'], + strndup: function(ptr, size) { + var len = String_len(ptr); + + if (size >= len) { + return _strdup(ptr); + } + + if (size < 0) { + size = 0; + } + + var newStr = _malloc(size + 1); + {{{ makeCopyValues('newStr', 'ptr', 'size', 'null', null, 1) }}}; + {{{ makeSetValue('newStr', 'size', '0', 'i8') }}}; + return newStr; + }, + strpbrk: function(ptr1, ptr2) { var searchSet = Runtime.set.apply(null, String_copy(ptr2)); while ({{{ makeGetValue('ptr1', 0, 'i8') }}}) { diff --git a/src/library_browser.js b/src/library_browser.js index d49c4103..e9860742 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -77,6 +77,7 @@ mergeInto(LibraryManager.library, { } if (setInModule) { Module.ctx = ctx; + Module.useWebGL = useWebGL; Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() }); } return ctx; diff --git a/src/library_gl.js b/src/library_gl.js index 3eba76d0..2be48ba1 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -1517,6 +1517,8 @@ var LibraryGL = { Module.printErr('WARNING: using emscripten GL immediate mode emulation. This is very limited in what it supports'); GL.immediate.initted = true; + if (!Module.useWebGL) return; // a 2D canvas may be currently used TODO: make sure we are actually called in that case + this.matrixStack['m'] = []; this.matrixStack['p'] = []; for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) { diff --git a/src/parseTools.js b/src/parseTools.js index 81fa61d9..158e6340 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -169,7 +169,15 @@ function isFunctionDef(token, out) { function isFunctionType(type, out) { type = type.replace(/"[^"]+"/g, '".."'); - var parts = type.split(' '); + var parts; + // hackish, but quick splitting of function def parts. this must be fast as it happens a lot + if (type[0] != '[') { + parts = type.split(' '); + } else { + var index = type.search(']'); + index += type.substr(index).search(' '); + parts = [type.substr(0, index), type.substr(index+1)]; + } if (pointingLevels(type) !== 1) return false; var text = removeAllPointing(parts.slice(1).join(' ')); if (!text) return false; diff --git a/tests/cases/funcptr.ll b/tests/cases/funcptr.ll new file mode 100644 index 00000000..07e2bf91 --- /dev/null +++ b/tests/cases/funcptr.ll @@ -0,0 +1,27 @@ +; ModuleID = 'tests/hello_world.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@.str = private unnamed_addr constant [17 x i8] c"hello %d world!\0A\00", align 1 ; [#uses=1 type=[17 x i8]*] + +; [#uses=0] +define i32 @main() { +entry: + %retval = alloca i32, align 4 ; [#uses=1 type=i32*] + store i32 0, i32* %retval + %access_virt_barray = bitcast i32 0 to [64 x i16]* (i32*, i32)** + store [64 x i16]* (i32*, i32)* @access_virt_barray, [64 x i16]* (i32*, i32)** %access_virt_barray, align 4 + %wakaptr = bitcast [64 x i16]* (i32*, i32)** %access_virt_barray to i32* + %waka = load i32* %wakaptr + %waka2 = icmp eq i32 %waka, 0 + %waka3 = zext i1 %waka2 to i32 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([17 x i8]* @.str, i32 0, i32 0), i32 %waka3) ; [#uses=0 type=i32] + ret i32 1 +} + +define [64 x i16]* @access_virt_barray(i32*, i32) { + ret void +} + +; [#uses=1] +declare i32 @printf(i8*, ...) diff --git a/tests/cases/funcptr.txt b/tests/cases/funcptr.txt new file mode 100644 index 00000000..1030830d --- /dev/null +++ b/tests/cases/funcptr.txt @@ -0,0 +1 @@ +hello 0 world! diff --git a/tests/runner.py b/tests/runner.py index 8e2e7b28..ce19aadb 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -1393,6 +1393,48 @@ m_divisor is 1091269979 ''' self.do_run(src, '4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\n', ['wowie', 'too', '74']) + def test_strndup(self): + src = ''' + //--------------- + //- http://pubs.opengroup.org/onlinepubs/9699919799/functions/strndup.html + //--------------- + + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + + int main(int argc, char **argv) { + const char* source = "strndup - duplicate a specific number of bytes from a string"; + + char* strdup_val = strndup(source, 0); + printf("1:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, 7); + printf("2:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, 1000); + printf("3:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, 60); + printf("4:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, 19); + printf("5:%s\\n", strdup_val); + free(strdup_val); + + strdup_val = strndup(source, -1); + printf("6:%s\\n", strdup_val); + free(strdup_val); + + return 0; + } + ''' + self.do_run(src, '1:\n2:strndup\n3:strndup - duplicate a specific number of bytes from a string\n4:strndup - duplicate a specific number of bytes from a string\n5:strndup - duplicate\n6:\n') + def test_errar(self): src = r''' #include <stdio.h> @@ -5493,6 +5535,7 @@ def process(filename): int value; public: Parent(int val); + Parent(Parent *p, Parent *q); // overload constructor int getVal() { return value; }; // inline should work just fine here, unlike Way 1 before void mulVal(int mul); }; @@ -5530,6 +5573,7 @@ def process(filename): #include "header.h" Parent::Parent(int val) : value(val) { printf("Parent:%d\\n", val); } + Parent::Parent(Parent *p, Parent *q) : value(p->value + q->value) { printf("Parent:%d\\n", value); } void Parent::mulVal(int mul) { value *= mul; } #include "bindingtest.cpp" @@ -6988,6 +7032,37 @@ fscanfed: 10 - hello output = Popen(['python', EMCONFIG, 'sys.argv[1]'], stdout=PIPE, stderr=PIPE).communicate()[0] assert output == invalid + def test_link_s(self): + # -s OPT=VALUE can conflict with -s as a linker option. We warn and ignore + open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' + extern "C" { + void something(); + } + + int main() { + something(); + return 0; + } + ''') + open(os.path.join(self.get_dir(), 'supp.cpp'), 'w').write(r''' + #include <stdio.h> + + extern "C" { + void something() { + printf("yello\n"); + } + } + ''') + Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-o', 'main.o']).communicate() + Popen(['python', EMCC, os.path.join(self.get_dir(), 'supp.cpp'), '-o', 'supp.o']).communicate() + + output = Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.o'), '-s', os.path.join(self.get_dir(), 'supp.o'), '-s', 'SAFE_HEAP=1'], stderr=PIPE).communicate() + self.assertContained('emcc: warning: treating -s as linker option', output[1]) + output = run_js('a.out.js') + assert 'yello' in output, 'code works' + code = open('a.out.js').read() + assert 'SAFE_HEAP' in code, 'valid -s option had an effect' + elif 'browser' in str(sys.argv): # Browser tests. @@ -8111,9 +8186,10 @@ elif 'sanity' in str(sys.argv): assert os.path.exists(EMCC_CACHE) assert os.path.exists(os.path.join(EMCC_CACHE, libname + '.bc')) if libname == 'libcxx': - assert os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size > 3500000, 'libc++ is big' - assert os.stat(basebc_name).st_size > 3500000, 'libc++ is indeed big' - assert os.stat(dcebc_name).st_size < 2000000, 'Dead code elimination must remove most of libc++' + print os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size, os.stat(basebc_name).st_size, os.stat(dcebc_name).st_size + assert os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size > 2000000, 'libc++ is big' + assert os.stat(basebc_name).st_size > 2000000, 'libc++ is indeed big' + assert os.stat(dcebc_name).st_size < 1500000, 'Dead code elimination must remove most of libc++' finally: if emcc_debug: os.environ['EMCC_DEBUG'] = emcc_debug diff --git a/tests/sdl_mouse.c b/tests/sdl_mouse.c index 8af87c8c..0c10198a 100644 --- a/tests/sdl_mouse.c +++ b/tests/sdl_mouse.c @@ -43,6 +43,8 @@ void one() { } } +void main_2(); + int main() { SDL_Init(SDL_INIT_VIDEO); SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE); @@ -50,6 +52,12 @@ int main() { SDL_Rect rect = { 0, 0, 600, 450 }; SDL_FillRect(screen, &rect, 0x2244ffff); + emscripten_async_call(main_2, 3000); // avoid startup delays and intermittent errors + + return 0; +} + +void main_2() { emscripten_run_script("window.simulateMouseEvent(10, 20, -1)"); // move from 0,0 to 10,20 emscripten_run_script("window.simulateMouseEvent(10, 20, 0)"); // click emscripten_run_script("window.simulateMouseEvent(10, 20, 0)"); // click some more, but this one should be ignored through PeepEvent @@ -57,7 +65,5 @@ int main() { emscripten_run_script("window.simulateMouseEvent(30, 77, 1)"); // trigger the end emscripten_set_main_loop(one, 0); - - return 0; } diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py index 3fbff13d..0c7c814f 100755 --- a/tools/bindings_generator.py +++ b/tools/bindings_generator.py @@ -671,25 +671,22 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge has_string_convs = False - # We can assume that NULL is passed for null pointers, so object arguments can always - # have .ptr done on them - justargs_fixed = justargs(args)[:] - for i in range(len(args)): - arg = args[i] - clean = clean_type(arg['type']) - if clean in classes: - justargs_fixed[i] += '.ptr' - elif arg['type'].replace(' ', '').endswith('char*'): - justargs_fixed[i] = 'ensureString(' + justargs_fixed[i] + ')' - has_string_convs = True - calls = '' - if has_string_convs: - calls += 'var stack = Runtime.stackSave();\n'; - calls += 'try {\n' #print 'js loopin', params, '|', len(args)#, args for args in params: + # We can assume that NULL is passed for null pointers, so object arguments can always + # have .ptr done on them + justargs_fixed = justargs(args)[:] + for i in range(len(args)): + arg = args[i] + clean = clean_type(arg['type']) + if clean in classes: + justargs_fixed[i] += '.ptr' + elif arg['type'].replace(' ', '').endswith('char*'): + justargs_fixed[i] = 'ensureString(' + justargs_fixed[i] + ')' + has_string_convs = True + i = len(args) if args != params[0]: calls += ' else ' @@ -715,7 +712,7 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge calls += '\n' if has_string_convs: - calls += '} finally { Runtime.stackRestore(stack) }\n'; + calls = 'var stack = Runtime.stackSave();\ntry {\n' + calls + '} finally { Runtime.stackRestore(stack) }\n'; print 'Maekin:', classname, generating_classname, mname, mname_suffixed if constructor: diff --git a/tools/shared.py b/tools/shared.py index 30de8685..f71bec72 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -37,9 +37,10 @@ This command will now exit. When you are done editing those paths, re-run it. ''' % (EM_CONFIG, CONFIG_FILE) sys.exit(0) try: - exec(open(CONFIG_FILE, 'r').read() if CONFIG_FILE else EM_CONFIG) + config_text = open(CONFIG_FILE, 'r').read() if CONFIG_FILE else EM_CONFIG + exec(config_text) except Exception, e: - print >> sys.stderr, 'Error in evaluating %s (at %s): %s' % (EM_CONFIG, CONFIG_FILE, str(e)) + print >> sys.stderr, 'Error in evaluating %s (at %s): %s, text: %s' % (EM_CONFIG, CONFIG_FILE, str(e), config_text) sys.exit(1) # Check that basic stuff we need (a JS engine to compile, Node.js, and Clang and LLVM) @@ -172,6 +173,12 @@ try: except: CLOSURE_COMPILER = path_from_root('third_party', 'closure-compiler', 'compiler.jar') +try: + JAVA +except: + print >> sys.stderr, 'JAVA not defined in ~/.emscripten, using "java"' + JAVA = 'java' + # Additional compiler options try: @@ -504,13 +511,18 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e if configure: # Useful in debugging sometimes to comment this out (and the lines below up to and including the |link| call) Building.configure(configure + configure_args, stdout=open(os.path.join(project_dir, 'configure_'), 'w'), stderr=open(os.path.join(project_dir, 'configure_err'), 'w'), env=env) - Building.make(make + make_args, stdout=open(os.path.join(project_dir, 'make_'), 'w'), - stderr=open(os.path.join(project_dir, 'make_err'), 'w'), env=env) - if cache is not None: - cache[cache_name] = [] - for f in generated_libs: - basename = os.path.basename(f) - cache[cache_name].append((basename, open(f, 'rb').read())) + for i in range(2): # workaround for some build systems that need to be run twice to succeed (e.g. poppler) + Building.make(make + make_args, stdout=open(os.path.join(project_dir, 'make_' + str(i)), 'w'), + stderr=open(os.path.join(project_dir, 'make_err' + str(i)), 'w'), env=env) + try: + if cache is not None: + cache[cache_name] = [] + for f in generated_libs: + basename = os.path.basename(f) + cache[cache_name].append((basename, open(f, 'rb').read())) + break + except: + if i > 0: raise Exception('could not build library ' + name) if old_dir: os.chdir(old_dir) return generated_libs |