diff options
51 files changed, 14437 insertions, 132 deletions
@@ -444,25 +444,17 @@ try: extra_files_to_link = [] if not LEAVE_INPUTS_RAW: - # Check if we need to include dlmalloc. Note that we assume a single symbol is enough to know if we have/do not have dlmalloc. If you + # Check if we need to include some libraries that we compile. (We implement libc ourselves in js, but + # compile a malloc implementation and stdlibc++.) + # Note that we assume a single symbol is enough to know if we have/do not have dlmalloc etc. If you # include just a few symbols but want the rest, this will not work. - need_dlmalloc = False - has_dlmalloc = False - for input_file in input_files: - symbols = shared.Building.llvm_nm(in_temp(unsuffixed_basename(input_file) + '.o')) - for malloc_def in ['malloc', 'free', 'calloc', 'memalign', 'realloc', 'valloc', 'pvalloc', 'mallinfo', 'mallopt', 'malloc_trim', 'malloc_stats', 'malloc_usable_size', 'malloc_footprint', 'malloc_max_footprint', 'independent_calloc', 'independent_comalloc', '_Znwj', '_Znaj', '_Znam', '_Znwm']: - if malloc_def in symbols.undefs: - need_dlmalloc = True - if malloc_def in symbols.defs: - has_dlmalloc = True - if need_dlmalloc and not has_dlmalloc: - # We need to build and link dlmalloc in - if DEBUG: print >> sys.stderr, 'emcc: including dlmalloc' - Popen([shared.EMCC, shared.path_from_root('src', 'dlmalloc.c'), '-g', '-o', in_temp('dlmalloc.o')], stdout=PIPE, stderr=PIPE).communicate() - if llvm_opt_level > 0: - shared.Building.llvm_opt(in_temp('dlmalloc.o'), LLVM_INTERNAL_OPT_LEVEL, safe=llvm_opt_level < 2) - extra_files_to_link.append(in_temp('dlmalloc.o')) + # dlmalloc + def create_dlmalloc(): + print >> sys.stderr, 'emcc: building dlmalloc for cache' + Popen([shared.EMCC, shared.path_from_root('src', 'dlmalloc.c'), '-g', '-o', in_temp('dlmalloc.o')], stdout=PIPE, stderr=PIPE).communicate() + return in_temp('dlmalloc.o') + def fix_dlmalloc(): # dlmalloc needs some sign correction. # If we are in mode 0, switch to 2. We will add our lines try: if shared.Settings.CORRECT_SIGNS == 0: raise Exception('we need to change to 2') @@ -472,6 +464,38 @@ try: shared.Settings.CORRECT_SIGNS_LINES = [shared.path_from_root('src', 'dlmalloc.c') + ':' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]] # If we are in mode 1, we are correcting everything anyhow. If we are in mode 3, we will be corrected # so all is well anyhow too. + dlmalloc_symbols = set(['malloc', 'free', 'calloc', 'memalign', 'realloc', 'valloc', 'pvalloc', 'mallinfo', 'mallopt', 'malloc_trim', 'malloc_stats', 'malloc_usable_size', 'malloc_footprint', 'malloc_max_footprint', 'independent_calloc', 'independent_comalloc', '_Znwj', '_Znaj', '_Znam', '_Znwm']) + + # libcxx + def create_libcxx(): + print >> sys.stderr, 'emcc: building libcxx for cache' + shared.Building.build_library('libcxx', shared.EMSCRIPTEN_TEMP_DIR, shared.EMSCRIPTEN_TEMP_DIR, ['libcxx.bc'], configure=None, copy_project=True, source_dir=shared.path_from_root('system', 'lib', 'libcxx')) + return os.path.join(shared.EMSCRIPTEN_TEMP_DIR, 'libcxx', 'libcxx.bc') + def fix_libcxx(): + # libcxx probably needs sign correction. # If we are in mode 0, switch to 2. We will add our lines + shared.Settings.CORRECT_SIGNS = 1 + print >> sys.stderr, 'emcc: warning: using libcxx turns on CORRECT_SIGNS' + libcxx_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libcxx', 'symbols')).readlines()) + libcxx_symbols = filter(lambda symbol: symbol not in dlmalloc_symbols, libcxx_symbols) + libcxx_symbols = set(libcxx_symbols) + + for name, create, fix, library_symbols in [('dlmalloc', create_dlmalloc, fix_dlmalloc, dlmalloc_symbols), + ('libcxx', create_libcxx, fix_libcxx, libcxx_symbols)]: + need = False + has = False + for input_file in input_files: + symbols = shared.Building.llvm_nm(in_temp(unsuffixed_basename(input_file) + '.o')) + for library_symbol in library_symbols: + if library_symbol in symbols.undefs: + need = True + if library_symbol in symbols.defs: + has = True + if need and not has: + # We need to build and link the library in + if DEBUG: print >> sys.stderr, 'emcc: including %s' % name + extra_files_to_link.append(shared.Cache.get(name, create)) + if fix: + fix() # First, combine the bitcode files if there are several if len(input_files) + len(extra_files_to_link) > 1: @@ -488,6 +512,11 @@ try: if llvm_opt_level > 0 and not LEAVE_INPUTS_RAW: if DEBUG: print >> sys.stderr, 'emcc: LLVM opts' shared.Building.llvm_opt(in_temp(target_basename + '.bc'), LLVM_INTERNAL_OPT_LEVEL, safe=llvm_opt_level < 2) + else: + # If possible, remove dead functions etc., this potentially saves a lot in the size of the generated code (and the time to compile it) + if not shared.Settings.BUILD_AS_SHARED_LIB: + if DEBUG: print >> sys.stderr, 'emcc: LLVM dead globals elimination' + shared.Building.llvm_opt(in_temp(target_basename + '.bc'), ['-internalize', '-globaldce']) # Emscripten try: @@ -507,6 +536,7 @@ try: if not LEAVE_INPUTS_RAW: final = in_temp(target_basename + '.bc') + if DEBUG: save_intermediate('bc', 'bc') final = shared.Building.llvm_dis(final, final + '.ll') if DEBUG: save_intermediate('ll', 'll') else: diff --git a/src/intertyper.js b/src/intertyper.js index 7bc23653..6b46cdbb 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -366,6 +366,8 @@ function intertyper(data, sidePass, baseLineNums) { return '/dev/null'; if (tokensLength >= 3 && token0Text == 'invoke') return 'Invoke'; + if (tokensLength >= 3 && token0Text == 'atomicrmw' || token0Text == 'cmpxchg') + return 'Atomic'; } else { // Already intertyped if (item.parentSlot) @@ -739,6 +741,21 @@ function intertyper(data, sidePass, baseLineNums) { return result.ret; } }); + substrate.addActor('Atomic', { + processItem: function(item) { + item.intertype = 'atomic'; + if (item.tokens[0].text == 'atomicrmw') { + item.op = item.tokens[1].text; + item.tokens.splice(1, 1); + } else { + assert(item.tokens[0].text == 'cmpxchg') + item.op = 'cmpxchg'; + } + var last = getTokenIndexByText(item.tokens, ';'); + item.params = splitTokenList(item.tokens.slice(1, last)).map(parseLLVMSegment); + this.forwardItem(item, 'Reintegrator'); + } + }); // 'landingpad' - just a stub implementation substrate.addActor('Landingpad', { processItem: function(item) { diff --git a/src/jsifier.js b/src/jsifier.js index db6936f6..69a64d1a 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -944,6 +944,20 @@ function JSify(data, functionsOnly, givenFunctions) { + ' } else { ' + getPhiSetsForLabel(phiSets, item.unwindLabel) + makeBranch(item.unwindLabel, item.currLabelId) + ' }'; return ret; }); + makeFuncLineActor('atomic', function(item) { + var type = item.params[0].type; + 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 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type) + ',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)'; + } + default: throw 'unhandled atomic op: ' + item.op; + } + }); makeFuncLineActor('landingpad', function(item) { // Just a stub return '{ f0: ' + makeGetValue('_llvm_eh_exception.buf', '0', 'void*') + diff --git a/src/library.js b/src/library.js index 2aace0fb..5a429131 100644 --- a/src/library.js +++ b/src/library.js @@ -3683,6 +3683,32 @@ LibraryManager.library = { } }, + mbtowc: function(pwc, pmb, maxx) { + // XXX doesn't really handle multibyte at all + if (!pmb) return 0; + maxx = Math.min({{{ cDefine('_NL_CTYPE_MB_CUR_MAX') }}}, maxx); + var i; + for (i = 0; i < maxx; i++) { + var curr = {{{ makeGetValue('pmb', 0, 'i8') }}}; + if (pwc) { + {{{ makeSetValue('pwc', '0', 'curr', 'i8') }}}; + {{{ makeSetValue('pwc', '1', '0', 'i8') }}}; + pwc += 2; + } + pmb++; + if (!curr) break; + } + return i; + }, + + wcrtomb: function(s, wc, ps) { + // XXX doesn't really handle multibyte at all + if (s) { + {{{ makeSetValue('s', '0', 'wc', 'i8') }}}; + } + return 1; + }, + // ========================================================================== // string.h // ========================================================================== @@ -4465,57 +4491,6 @@ LibraryManager.library = { llvm_lifetime_end: function() {}, // ========================================================================== - // iostream.h - // ========================================================================== - - // libc++ - - $libcxx__postset: 'try { __ZNSt3__14coutE = 1 } catch(e){}; try { __ZNSt3__14cerrE = 2 } catch(e){};', - $libcxx: {}, - - _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPKv__deps: ['fputs', '$libcxx'], - _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPKv: function(stream, str) { - _fputs(str, _stdout); // XXX stderr etc. - }, - - _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEi__deps: ['fputs', '$libcxx'], - _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEi: function(stream, num) { - _fputs(allocate(intArrayFromString(num.toString()), 'i8', ALLOC_STACK), _stdout); - }, - - _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPFRS3_S4_E__deps: ['fputc', '$libcxx'], - _ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEPFRS3_S4_E: function(stream, x) { - _fputc('\n'.charCodeAt(0), _stdout); - }, - - // glibc - - _ZNSt8ios_base4InitC1Ev: function() { - // need valid 'file descriptors' for glibc - //__ZSt4cout = 1; - //__ZSt4cerr = 2; - }, - _ZNSt8ios_base4InitD1Ev: '_ZNSt8ios_base4InitC1Ev', - _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_: 0, // endl - _ZNSolsEd__deps: ['putchar'], - _ZNSolsEd: function(undefined_stream, data) { - _putchar('\n'.charCodeAt(0)); - }, - _ZNSolsEPFRSoS_E: '_ZNSolsEd', - _ZNSolsEi__deps: ['putchar'], - _ZNSolsEi: function(undefined_stream, data) { - var str = String(data); - for (var i = 0; i < str.length; i++) { - _putchar(str.charCodeAt(i)); - } - }, - _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc__deps: ['fputs', 'stdout'], - _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc: function(undefined_stream, data) { - _fputs(data, {{{ makeGetValue('_stdout', '0', 'void*') }}}); - }, - _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i: '_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc', - - // ========================================================================== // math.h // ========================================================================== @@ -5265,6 +5240,14 @@ LibraryManager.library = { // locale.h // ========================================================================== + newlocale: function(mask, locale, base) { + return 0; + }, + + uselocale: function(locale) { + return 0; + }, + setlocale: function(category, locale) { if (!_setlocale.ret) _setlocale.ret = allocate([0], 'i8', ALLOC_NORMAL); return _setlocale.ret; diff --git a/src/settings.js b/src/settings.js index 587e2f16..1d62cbbf 100644 --- a/src/settings.js +++ b/src/settings.js @@ -200,7 +200,7 @@ var RUNTIME_TYPE_INFO = 0; // Whether to expose type info to the script at run t // to more easily perform operations from handwritten JS on // objects with structures etc. -var FAKE_X86_FP80 = 0; // Replaces x86_fp80 with double. This loses precision. It is better, +var FAKE_X86_FP80 = 1; // Replaces x86_fp80 with double. This loses precision. It is better, // if you can, to get the original source code to build without x86_fp80 // (which is nonportable anyhow). diff --git a/system/include/libc/locale.h b/system/include/libc/locale.h index 532faaa5..b75bed7a 100644 --- a/system/include/libc/locale.h +++ b/system/include/libc/locale.h @@ -21,6 +21,15 @@ #define LC_TIME 5 #define LC_MESSAGES 6 +/* XXX Emscripten: add masks */ +#define LC_ALL_MASK (1 << LC_ALL) +#define LC_COLLATE_MASK (1 << LC_COLLATE) +#define LC_CTYPE_MASK (1 << LC_CTYPE) +#define LC_MONETARY_MASK (1 << LC_MONETARY) +#define LC_NUMERIC_MASK (1 << LC_NUMERIC) +#define LC_TIME_MASK (1 << LC_TIME) +#define LC_MESSAGES_MASK (1 << LC_MESSAGES) + _BEGIN_STD_C struct lconv diff --git a/system/include/libc/pthread.h b/system/include/libc/pthread.h index 63bb6dfa..1185fcc1 100644 --- a/system/include/libc/pthread.h +++ b/system/include/libc/pthread.h @@ -31,7 +31,7 @@ extern "C" { #include <sys/types.h> #include <time.h> -#include <sys/sched.h> +#include <sched.h> /* XXX Emscripten: removed sys/ */ /* Register Fork Handlers */ int _EXFUN(pthread_atfork,(void (*prepare)(void), void (*parent)(void), @@ -46,7 +46,7 @@ int _EXFUN(pthread_mutexattr_getpshared, int _EXFUN(pthread_mutexattr_setpshared, (pthread_mutexattr_t *__attr, int __pshared)); -#if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) +#if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) || defined(EMSCRIPTEN) /* Single UNIX Specification 2 Mutex Attributes types */ diff --git a/system/include/libc/sys/types.h b/system/include/libc/sys/types.h index 5cb126a7..734004e7 100644 --- a/system/include/libc/sys/types.h +++ b/system/include/libc/sys/types.h @@ -300,7 +300,7 @@ typedef __uint32_t pthread_t; /* identify a thread */ #define PTHREAD_CREATE_DETACHED 0 #define PTHREAD_CREATE_JOINABLE 1 -#if defined(__XMK__) || defined(__rtems__) +#if defined(__XMK__) || defined(__rtems__) || defined(EMSCRIPTEN) /* The following defines are part of the X/Open System Interface (XSI). */ /* This type of mutex does not detect deadlock. A thread attempting to relock this mutex without first unlocking diff --git a/system/include/libc/time.h b/system/include/libc/time.h index 3f167556..83993942 100644 --- a/system/include/libc/time.h +++ b/system/include/libc/time.h @@ -229,7 +229,7 @@ extern "C" { #endif -#if defined(_POSIX_MONOTONIC_CLOCK) +#if defined(_POSIX_MONOTONIC_CLOCK) || defined(EMSCRIPTEN) /* The identifier for the system-wide monotonic clock, which is defined * as a clock whose value cannot be set via clock_settime() and which diff --git a/system/include/libcxx/__locale b/system/include/libcxx/__locale index b1c0dd7c..f63815c3 100644 --- a/system/include/libcxx/__locale +++ b/system/include/libcxx/__locale @@ -8,8 +8,6 @@ // //===----------------------------------------------------------------------===// -//class locale; // XXX Emscripten - #ifndef _LIBCPP___LOCALE #define _LIBCPP___LOCALE @@ -24,7 +22,7 @@ #if _WIN32 # include <support/win32/locale.h> #else // _WIN32 -/* XXX EMSCRIPTEN # include <xlocale.h> */ +# include <xlocale.h> #endif // _WIN32 #pragma GCC system_header @@ -44,7 +42,6 @@ public: class id; typedef int category; - /* XXX Emscripten static const category // values assigned here are for exposition only none = 0, collate = LC_COLLATE_MASK, @@ -54,7 +51,6 @@ public: time = LC_TIME_MASK, messages = LC_MESSAGES_MASK, all = collate | ctype | monetary | numeric | time | messages; - */ // construct/copy/destroy: locale() _NOEXCEPT; @@ -335,9 +331,9 @@ public: static const mask xdigit = _HEX; static const mask blank = _BLANK; #else // __GLIBC__ || _WIN32 -#if __APPLE__ +#if defined(__APPLE__) || defined(EMSCRIPTEN) typedef __uint32_t mask; -#elif defined(__FreeBSD__) or defined(EMSCRIPTEN) +#elif __FreeBSD__ typedef unsigned long mask; #endif static const mask space = _CTYPE_S; diff --git a/system/include/libcxx/exception b/system/include/libcxx/exception index f05855b4..f418575c 100644 --- a/system/include/libcxx/exception +++ b/system/include/libcxx/exception @@ -89,7 +89,7 @@ class _LIBCPP_EXCEPTION_ABI exception { public: _LIBCPP_INLINE_VISIBILITY exception() _NOEXCEPT {} - virtual ~exception() _NOEXCEPT{} + virtual ~exception() _NOEXCEPT; virtual const char* what() const _NOEXCEPT; }; @@ -105,19 +105,19 @@ public: typedef void (*unexpected_handler)(); _LIBCPP_VISIBLE unexpected_handler set_unexpected(unexpected_handler) _NOEXCEPT; _LIBCPP_VISIBLE unexpected_handler get_unexpected() _NOEXCEPT; -_LIBCPP_VISIBLE void unexpected(); /* XXX Emscripten: remove _ATTRIBUTE(noreturn), here and two places below */ +_ATTRIBUTE(noreturn) _LIBCPP_VISIBLE void unexpected(); typedef void (*terminate_handler)(); _LIBCPP_VISIBLE terminate_handler set_terminate(terminate_handler) _NOEXCEPT; _LIBCPP_VISIBLE terminate_handler get_terminate() _NOEXCEPT; -_LIBCPP_VISIBLE void terminate() _NOEXCEPT; +_ATTRIBUTE(noreturn) _LIBCPP_VISIBLE void terminate() _NOEXCEPT; _LIBCPP_VISIBLE bool uncaught_exception() _NOEXCEPT; class exception_ptr; exception_ptr current_exception() _NOEXCEPT; -void rethrow_exception(exception_ptr); +_ATTRIBUTE(noreturn) void rethrow_exception(exception_ptr); class _LIBCPP_VISIBLE exception_ptr { @@ -141,7 +141,7 @@ public: {return !(__x == __y);} friend exception_ptr current_exception() _NOEXCEPT; - friend void rethrow_exception(exception_ptr); + _ATTRIBUTE(noreturn) friend void rethrow_exception(exception_ptr); }; template<class _E> @@ -172,7 +172,7 @@ public: virtual ~nested_exception() _NOEXCEPT; // access functions - void rethrow_nested() const; + _ATTRIBUTE(noreturn) void rethrow_nested() const; _LIBCPP_INLINE_VISIBILITY exception_ptr nested_ptr() const _NOEXCEPT {return __ptr_;} }; @@ -185,6 +185,7 @@ struct __nested }; template <class _Tp> +_ATTRIBUTE(noreturn) void #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES throw_with_nested(_Tp&& __t, typename enable_if< @@ -203,6 +204,7 @@ throw_with_nested (_Tp& __t, typename enable_if< } template <class _Tp> +_ATTRIBUTE(noreturn) void #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES throw_with_nested(_Tp&& __t, typename enable_if< diff --git a/system/include/libcxx/ios b/system/include/libcxx/ios index 29bda558..e2f2b6fd 100644 --- a/system/include/libcxx/ios +++ b/system/include/libcxx/ios @@ -317,7 +317,7 @@ public: _LIBCPP_INLINE_VISIBILITY bool bad() const; _LIBCPP_INLINE_VISIBILITY iostate exceptions() const; - _LIBCPP_INLINE_VISIBILITY void exceptions(iostate except); /* XXX Emscripten: renammed __except to except because it is a reserved keyword */ + _LIBCPP_INLINE_VISIBILITY void exceptions(iostate __except); void __set_badbit_and_consider_rethrow(); void __set_failbit_and_consider_rethrow(); @@ -553,9 +553,9 @@ ios_base::exceptions() const inline _LIBCPP_INLINE_VISIBILITY void -ios_base::exceptions(iostate except) /* XXX Emscripten: renammed __except to except because it is a reserved keyword */ +ios_base::exceptions(iostate __except) { - __exceptions_ = except; /* XXX Emscripten: renammed __except to except because it is a reserved keyword */ + __exceptions_ = __except; clear(__rdstate_); } @@ -584,7 +584,7 @@ public: _LIBCPP_ALWAYS_INLINE bool bad() const {return ios_base::bad();} _LIBCPP_ALWAYS_INLINE iostate exceptions() const {return ios_base::exceptions();} - _LIBCPP_ALWAYS_INLINE void exceptions(iostate except) {ios_base::exceptions(except);} /* XXX Emscripten: renammed __except to except because it is a reserved keyword */ + _LIBCPP_ALWAYS_INLINE void exceptions(iostate __except) {ios_base::exceptions(__except);} // 27.5.4.1 Constructor/destructor: _LIBCPP_INLINE_VISIBILITY diff --git a/system/include/libcxx/locale b/system/include/libcxx/locale index 153038ee..e9a18e32 100644 --- a/system/include/libcxx/locale +++ b/system/include/libcxx/locale @@ -189,7 +189,7 @@ template <class charT> class messages_byname; #if _WIN32 #include <support/win32/support.h> // vasprintf #else // _WIN32 -// XXX Emscripten #include <nl_types.h> +#include <nl_types.h> #endif // !_WIN32 #pragma GCC system_header @@ -800,7 +800,6 @@ template <class _CharT, class _InputIterator> locale::id num_get<_CharT, _InputIterator>::id; -/* XXX Emscripten template <class _Tp> _Tp __num_get_signed_integral(const char* __a, const char* __a_end, @@ -1308,8 +1307,6 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e, return __b; } -*/ - extern template class num_get<char>; extern template cla |