diff options
-rw-r--r-- | src/analyzer.js | 2 | ||||
-rw-r--r-- | src/intertyper.js | 2 | ||||
-rw-r--r-- | src/jsifier.js | 14 | ||||
-rw-r--r-- | src/library.js | 69 | ||||
-rw-r--r-- | src/library_gc.js | 13 | ||||
-rw-r--r-- | src/modules.js | 2 | ||||
-rw-r--r-- | src/settings.js | 1 | ||||
-rw-r--r-- | src/utility.js | 2 | ||||
-rw-r--r-- | system/include/gc.h | 10 | ||||
-rw-r--r-- | system/include/net/netinet/in.h | 20 | ||||
-rw-r--r-- | system/include/sys/poll.h | 1 | ||||
-rw-r--r-- | system/include/sys/socket.h | 5 | ||||
-rwxr-xr-x | tests/runner.py | 60 | ||||
-rw-r--r-- | third_party/closure-compiler/README | 12 | ||||
-rw-r--r-- | third_party/closure-compiler/compiler.jar | bin | 5427247 -> 5856710 bytes |
15 files changed, 167 insertions, 46 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index c09739e9..014579f4 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -690,6 +690,8 @@ function analyzer(data, sidePass) { var subType = check[2]; addTypeInternal(subType, data); // needed for anonymous structure definitions (see below) + // Huge structural types are represented very inefficiently, both here and in generated JS. Best to avoid them - for example static char x[10*1024*1024]; is bad, while static char *x = malloc(10*1024*1024) is fine. + if (num >= 10*1024*1024) warnOnce('warning: very large fixed-size structural type: ' + type + ' - can you reduce it? (compilation may be slow)'); Types.types[nonPointing] = { name_: nonPointing, fields: range(num).map(function() { return subType }), diff --git a/src/intertyper.js b/src/intertyper.js index b1bd2ba8..8e7bb418 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -674,7 +674,7 @@ function intertyper(data, sidePass, baseLineNums) { // Inline assembly is just JavaScript that we paste into the code item.intertype = 'value'; if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1); - item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2); + item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly return { forward: null, ret: [item], item: item }; } if (item.ident.substr(-2) == '()') { diff --git a/src/jsifier.js b/src/jsifier.js index 6d3fe781..2791c65b 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -332,7 +332,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (item.ident.substr(0, 5) == '__ZTV') { js += '\n' + makePointer('[0]', null, BUILD_AS_SHARED_LIB ? 'ALLOC_NORMAL' : 'ALLOC_STATIC', ['void*']) + ';'; } - if (item.ident in EXPORTED_GLOBALS) { + if (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS)) { js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; } if (BUILD_AS_SHARED_LIB == 2 && !item.private_) { @@ -442,7 +442,7 @@ function JSify(data, functionsOnly, givenFunctions) { } var text = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); text += isFunction ? snippet : 'var ' + ident + '=' + snippet + ';'; - if (ident in EXPORTED_FUNCTIONS) { + if (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS)) { text += '\nModule["' + ident + '"] = ' + ident + ';'; } return text; @@ -702,7 +702,7 @@ function JSify(data, functionsOnly, givenFunctions) { func.JS += '\n//FUNCTION_END_MARKER_OF_SOURCE_FILE_' + associatedSourceFile + '\n'; } - if (func.ident in EXPORTED_FUNCTIONS) { + if (EXPORT_ALL || (func.ident in EXPORTED_FUNCTIONS)) { func.JS += 'Module["' + func.ident + '"] = ' + func.ident + ';'; } @@ -1069,12 +1069,12 @@ function JSify(data, functionsOnly, givenFunctions) { var param1 = finalizeLLVMParameter(item.params[0]); var param2 = finalizeLLVMParameter(item.params[1]); switch (item.op) { - case 'add': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue+' + param2, type) + ',tempValue)'; - case 'sub': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue-' + param2, type) + ',tempValue)'; - case 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type) + ',tempValue)'; + case 'add': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue+' + param2, type, null, null, null, null, ',') + ',tempValue)'; + case 'sub': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue-' + param2, type, null, null, null, null, ',') + ',tempValue)'; + case 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type, null, null, null, null, ',') + ',tempValue)'; case 'cmpxchg': { var param3 = finalizeLLVMParameter(item.params[2]); - return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' && (' + makeSetValue(param1, 0, param3, type) + ')),tempValue)'; + return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' && (' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ')),tempValue)'; } default: throw 'unhandled atomic op: ' + item.op; } diff --git a/src/library.js b/src/library.js index a281fc10..837ed71d 100644 --- a/src/library.js +++ b/src/library.js @@ -2457,20 +2457,22 @@ LibraryManager.library = { var argIndex = 0; var next; - next = 1; mainLoop: - for (var formatIndex = 0; formatIndex < format.length; formatIndex++) { + for (var formatIndex = 0; formatIndex < format.length;) { + if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') { + var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; + {{{ makeSetValue('argPtr', 0, 'soFar', 'i32') }}}; + formatIndex += 2; + continue; + } + // remove whitespace while (1) { next = get(); if (next == 0) return fields; if (!(next in __scanString.whiteSpace)) break; - } - unget(next); - - if (next <= 0) return fields; - var next = get(); - if (next <= 0) return fields; // End of input. + } + unget(); if (format[formatIndex] === '%') { formatIndex++; @@ -2504,6 +2506,7 @@ LibraryManager.library = { // Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later if (type == 'f') { var last = 0; + next = get(); while (next > 0) { buffer.push(String.fromCharCode(next)); if (__isFloat(buffer.join(''))) { @@ -2511,12 +2514,12 @@ LibraryManager.library = { } next = get(); } - unget(next); - while (buffer.length > last) { - unget(buffer.pop().charCodeAt(0)); + for (var i = 0; i < buffer.length - last + 1; i++) { + unget(); } + buffer.length = last; + } else { next = get(); - } else if (type != 'n') { var first = true; while ((curr < max_ || isNaN(max_)) && next > 0) { if (!(next in __scanString.whiteSpace) && // stop on whitespace @@ -2530,13 +2533,14 @@ LibraryManager.library = { buffer.push(String.fromCharCode(next)); next = get(); curr++; + first = false; } else { break; } - first = false; } + unget(); } - if (buffer.length === 0 && type != 'n') return 0; // Failure. + if (buffer.length === 0) return 0; // Failure. var text = buffer.join(''); var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; argIndex += Runtime.getNativeFieldSize('void*'); @@ -2566,31 +2570,26 @@ LibraryManager.library = { {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}} } break; - case 'n': - {{{ makeSetValue('argPtr', 0, 'soFar-1', 'i32') }}} - break; } - if (type != 'n') fields++; - if (next <= 0) break mainLoop; // End of input. + fields++; } else if (format[formatIndex] in __scanString.whiteSpace) { + next = get(); while (next in __scanString.whiteSpace) { - next = get(); if (next <= 0) break mainLoop; // End of input. + next = get(); } unget(next); + formatIndex++; } else { // Not a specifier. + next = get(); if (format[formatIndex].charCodeAt(0) !== next) { unget(next); break mainLoop; } + formatIndex++; } } - // 'n' is special in that it needs no input. so it can be at the end, even with nothing left to read - if (format[formatIndex-1] == '%' && format[formatIndex] == 'n') { - var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; - {{{ makeSetValue('argPtr', 0, 'soFar-1', 'i32') }}} - } return fields; }, // Performs prtinf-style formatting. @@ -3455,8 +3454,9 @@ LibraryManager.library = { // int fscanf(FILE *restrict stream, const char *restrict format, ... ); // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html if (FS.streams[stream]) { - var get = function() { return _fgetc(stream); }; - var unget = function(c) { return _ungetc(c, stream); }; + var stack = []; + var get = function() { var ret = _fgetc(stream); stack.push(ret); return ret }; + var unget = function(c) { return _ungetc(stack.pop(), stream) }; return __scanString(format, get, unget, varargs); } else { return -1; @@ -4745,6 +4745,10 @@ LibraryManager.library = { return 32; }, + llvm_trap: function() { + throw 'trap! ' + new Error().stack; + }, + __assert_fail: function(condition, file, line) { ABORT = true; throw 'Assertion failed: ' + Pointer_stringify(condition);//JSON.stringify(arguments)//condition; @@ -6465,6 +6469,17 @@ LibraryManager.library = { _pthread_key_create.keys[key] = value; }, + pthread_cleanup_push: function(routine, arg) { + __ATEXIT__.push({ func: function() { FUNCTION_TABLE[routine](arg) } }) + _pthread_cleanup_push.level = __ATEXIT__.length; + }, + + pthread_cleanup_pop: function() { + assert(_pthread_cleanup_push.level == __ATEXIT__.length, 'cannot pop if something else added meanwhile!'); + __ATEXIT__.pop(); + _pthread_cleanup_push.level = __ATEXIT__.length; + }, + // ========================================================================== // malloc.h // ========================================================================== diff --git a/src/library_gc.js b/src/library_gc.js index bf0a6aff..a06e2f01 100644 --- a/src/library_gc.js +++ b/src/library_gc.js @@ -16,6 +16,11 @@ if (GC_SUPPORT) { init: function() { assert(!GC.initted); GC.initted = true; + + _GC_finalize_on_demand = _malloc(4); setValue(_GC_finalize_on_demand, 0, 'i32') + _GC_java_finalization = _malloc(4); setValue(_GC_java_finalization, 0, 'i32'); + _GC_finalizer_notifier = _malloc(4); setValue(_GC_finalizer_notifier, 0, 'i32'); + if (ENVIRONMENT_IS_WEB) { setInterval(function() { GC.maybeCollect(); @@ -159,7 +164,13 @@ if (GC_SUPPORT) { GC_FORCE_COLLECT__deps: ['$GC'], GC_FORCE_COLLECT: function() { GC.collect(); - } + }, + + GC_finalize_on_demand: 0, + GC_java_finalization: 0, + GC_finalizer_notifier: 0, + + GC_enable_incremental: function(){}, }; mergeInto(LibraryManager.library, LibraryGC); diff --git a/src/modules.js b/src/modules.js index 781bed45..06677936 100644 --- a/src/modules.js +++ b/src/modules.js @@ -5,7 +5,7 @@ var LLVM = { LINKAGES: set('private', 'linker_private', 'linker_private_weak', 'linker_private_weak_def_auto', 'internal', 'available_externally', 'linkonce', 'common', 'weak', 'appending', 'extern_weak', 'linkonce_odr', - 'weak_odr', 'externally_visible', 'dllimport', 'dllexport', 'unnamed_addr'), + 'weak_odr', 'externally_visible', 'dllimport', 'dllexport', 'unnamed_addr', 'thread_local'), VISIBILITIES: set('default', 'hidden', 'protected'), PARAM_ATTR: set('noalias', 'signext', 'zeroext', 'inreg', 'sret', 'nocapture', 'nest'), FUNC_ATTR: set('hidden', 'nounwind', 'define', 'inlinehint', '{'), diff --git a/src/settings.js b/src/settings.js index 9cdb496b..5dc1e2eb 100644 --- a/src/settings.js +++ b/src/settings.js @@ -196,6 +196,7 @@ var PGO = 0; // Profile-guided optimization. var PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage example. +var EXPORT_ALL = 0; // If true, we export all the symbols var EXPORTED_FUNCTIONS = ['_main', '_malloc', '_free']; // Functions that are explicitly exported, so they are guaranteed to // be accessible outside of the generated code even after running closure compiler. // Note the necessary prefix of "_". diff --git a/src/utility.js b/src/utility.js index 632ee08c..f3ece90b 100644 --- a/src/utility.js +++ b/src/utility.js @@ -184,7 +184,7 @@ function dprint() { text = text(); // Allows deferred calculation, so dprints don't slow us down when not needed } text = DPRINT_INDENT + '// ' + text; - print(text); + printErr(text); } var PROF_ORIGIN = Date.now(); diff --git a/system/include/gc.h b/system/include/gc.h index 996bc9ec..e0419dcb 100644 --- a/system/include/gc.h +++ b/system/include/gc.h @@ -8,7 +8,7 @@ extern "C" { #endif -void __attribute__((used)) __GC_KEEPALIVE__() { +static void __attribute__((used)) __GC_KEEPALIVE__() { // Force inclusion of necessary dlmalloc functions static int times = 1; void *x = malloc(times); @@ -44,6 +44,14 @@ void GC_MAYBE_COLLECT(); /* Forces a GC. Mainly useful for testing, but call it if you know a good time to GC in your app. */ void GC_FORCE_COLLECT(); +typedef void (*GC_finalization_proc)(void *func, void *arg); +extern void (*GC_finalizer_notifier)(); + +extern int GC_finalize_on_demand; +extern int GC_java_finalization; + +void GC_enable_incremental(); + #ifdef __cplusplus } #endif diff --git a/system/include/net/netinet/in.h b/system/include/net/netinet/in.h index 2e4e4e57..2ac98dfe 100644 --- a/system/include/net/netinet/in.h +++ b/system/include/net/netinet/in.h @@ -48,6 +48,26 @@ struct ip_mreq { struct in_addr imr_interface; }; +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define IP_MSFILTER 41 +#define MCAST_JOIN_GROUP 42 +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_LEAVE_GROUP 45 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 +#define MCAST_MSFILTER 48 +#define IP_MULTICAST_ALL 49 +#define IP_UNICAST_IF 50 + #ifdef __cplusplus } #endif diff --git a/system/include/sys/poll.h b/system/include/sys/poll.h index 55e85237..7521ed0e 100644 --- a/system/include/sys/poll.h +++ b/system/include/sys/poll.h @@ -11,6 +11,7 @@ extern "C" { #define POLLNVAL 4 #define POLLERR 8 #define POLLHUP 16 +#define POLLPRI 32 struct pollfd { int fd; diff --git a/system/include/sys/socket.h b/system/include/sys/socket.h index efbbe6f0..c50a3786 100644 --- a/system/include/sys/socket.h +++ b/system/include/sys/socket.h @@ -28,6 +28,11 @@ extern "C" { #define SO_LINGER 70 #define SO_NOSIGPIPE 80 #define SO_KEEPALIVE 90 +#define SO_OOBINLINE 100 +#define SO_NO_CHECK 110 +#define SO_PRIORITY 120 +#define SO_LINGER 130 +#define SO_BSDCOMPAT 140 #define SHUT_RD 1 #define SHUT_RDWR 2 diff --git a/tests/runner.py b/tests/runner.py index 99af7109..6404a211 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -4560,7 +4560,22 @@ Pass: 0.000012 0.000012''') self.do_run(src, '3\n123,1073741823,1125899906842620\n' + '3\n-123,-1073741823,-1125899906842620\n') - + + def test_sscanf_4(self): + src = r''' + #include <stdio.h> + + int main() + { + char pYear[16], pMonth[16], pDay[16], pDate[64]; + printf("%d\n", sscanf("Nov 19 2012", "%s%s%s", pMonth, pDay, pYear)); + printf("day %s, month %s, year %s \n", pDay, pMonth, pYear); + return(0); + } + ''' + + self.do_run(src, '3\nday 19, month Nov, year 2012'); + def test_langinfo(self): src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read() expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read() @@ -7680,6 +7695,22 @@ f.close() Popen(['python', EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate() self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + def test_unaligned_memory_2(self): + open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r''' + #include <string> + #include <stdio.h> + + int main( int argc, char ** argv ) + { + std::string testString( "Hello, World!" ); + + printf( "testString = %s\n", testString.c_str() ); + return 0; + } + ''') + Popen(['python', EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate() + self.assertContained('testString = Hello, World!', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + def test_l_link(self): # Linking with -lLIBNAME and -L/DIRNAME should work @@ -8126,6 +8157,33 @@ f.close() output = Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.cpp')], stderr=PIPE).communicate() self.assertNotContained('Unresolved symbol: _something\n', output[1]) + def test_toobig(self): + open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' + #include <stdio.h> + + #define BYTES 100*1024*1024 + + int main(int argc, char **argv) { + if (argc == 100) { + static char buf[BYTES]; + static char buf2[BYTES]; + for (int i = 0; i < BYTES; i++) { + buf[i] = i*i; + buf2[i] = i/3; + } + for (int i = 0; i < BYTES; i++) { + buf[i] = buf2[i/2]; + buf2[i] = buf[i/3]; + } + printf("%d\n", buf[10] + buf2[20]); + } + return 0; + } + ''') + output = Popen(['python', EMCC, os.path.join(self.get_dir(), 'main.cpp')], stderr=PIPE).communicate()[1] + assert 'Emscripten failed' in output, output + assert 'warning: very large fixed-size structural type' in output, output + def test_prepost(self): open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(''' #include <stdio.h> diff --git a/third_party/closure-compiler/README b/third_party/closure-compiler/README index 77ab89db..270cfc27 100644 --- a/third_party/closure-compiler/README +++ b/third_party/closure-compiler/README @@ -171,7 +171,7 @@ lib/args4j.jar Args4j URL: https://args4j.dev.java.net/ -Version: 2.0.12 +Version: 2.0.16 License: MIT Description: @@ -187,7 +187,7 @@ lib/guava.jar Guava Libraries URL: http://code.google.com/p/guava-libraries/ -Version: r08 +Version: 13.0.1 License: Apache License 2.0 Description: Google's core Java libraries. @@ -230,7 +230,7 @@ lib/junit.jar JUnit URL: http://sourceforge.net/projects/junit/ -Version: 4.8.2 +Version: 4.10 License: Common Public License 1.0 Description: A framework for writing and running automated tests in Java. @@ -244,7 +244,7 @@ lib/protobuf-java.jar Protocol Buffers URL: http://code.google.com/p/protobuf/ -Version: 2.3.0 +Version: 2.4.1 License: New BSD License Description: Supporting libraries for protocol buffers, @@ -281,9 +281,9 @@ Local Modifications: None --- Code in: -tools/maven-ant-tasks-2.1.1.jar +tools/maven-ant-tasks-2.1.3.jar URL: http://maven.apache.org -Version 2.1.1 +Version 2.1.3 License: Apache License 2.0 Description: Maven Ant tasks are used to manage dependencies and to install/deploy to diff --git a/third_party/closure-compiler/compiler.jar b/third_party/closure-compiler/compiler.jar Binary files differindex da191b01..e23352ff 100644 --- a/third_party/closure-compiler/compiler.jar +++ b/third_party/closure-compiler/compiler.jar |