summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog137
-rwxr-xr-xemcc139
-rw-r--r--src/analyzer.js10
-rw-r--r--src/compiler.js4
-rw-r--r--src/fastLong.js17
-rw-r--r--src/jsifier.js37
-rw-r--r--src/library.js66
-rw-r--r--src/modules.js2
-rw-r--r--src/parseTools.js13
-rw-r--r--src/settings.js13
-rw-r--r--system/lib/libc.symbols162
-rw-r--r--system/lib/libc/musl/memcpy.c29
-rw-r--r--system/lib/libc/musl/readme.txt1
-rw-r--r--system/lib/libc/musl/src/internal/libc.c22
-rw-r--r--system/lib/libc/musl/src/internal/libc.h71
-rw-r--r--system/lib/libc/musl/src/multibyte/btowc.c7
-rw-r--r--system/lib/libc/musl/src/multibyte/internal.c38
-rw-r--r--system/lib/libc/musl/src/multibyte/internal.h22
-rw-r--r--system/lib/libc/musl/src/multibyte/mblen.c17
-rw-r--r--system/lib/libc/musl/src/multibyte/mbrlen.c18
-rw-r--r--system/lib/libc/musl/src/multibyte/mbrtowc.c57
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsinit.c17
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsnrtowcs.c65
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsrtowcs.c100
-rw-r--r--system/lib/libc/musl/src/multibyte/mbstowcs.c7
-rw-r--r--system/lib/libc/musl/src/multibyte/mbtowc.c53
-rw-r--r--system/lib/libc/musl/src/multibyte/wcrtomb.c38
-rw-r--r--system/lib/libc/musl/src/multibyte/wcsnrtombs.c52
-rw-r--r--system/lib/libc/musl/src/multibyte/wcsrtombs.c58
-rw-r--r--system/lib/libc/musl/src/multibyte/wcstombs.c7
-rw-r--r--system/lib/libc/musl/src/multibyte/wctob.c8
-rw-r--r--system/lib/libc/musl/src/multibyte/wctomb.c18
-rw-r--r--system/lib/libc/musl/src/string/wcpcpy.c6
-rw-r--r--system/lib/libc/musl/src/string/wcpncpy.c6
-rw-r--r--system/lib/libc/musl/src/string/wcscasecmp.c7
-rw-r--r--system/lib/libc/musl/src/string/wcscasecmp_l.c6
-rw-r--r--system/lib/libc/musl/src/string/wcscat.c7
-rw-r--r--system/lib/libc/musl/src/string/wcschr.c8
-rw-r--r--system/lib/libc/musl/src/string/wcscmp.c7
-rw-r--r--system/lib/libc/musl/src/string/wcscpy.c8
-rw-r--r--system/lib/libc/musl/src/string/wcscspn.c10
-rw-r--r--system/lib/libc/musl/src/string/wcsdup.c11
-rw-r--r--system/lib/libc/musl/src/string/wcslen.c8
-rw-r--r--system/lib/libc/musl/src/string/wcsncasecmp.c9
-rw-r--r--system/lib/libc/musl/src/string/wcsncasecmp_l.c6
-rw-r--r--system/lib/libc/musl/src/string/wcsncat.c10
-rw-r--r--system/lib/libc/musl/src/string/wcsncmp.c7
-rw-r--r--system/lib/libc/musl/src/string/wcsncpy.c9
-rw-r--r--system/lib/libc/musl/src/string/wcsnlen.c8
-rw-r--r--system/lib/libc/musl/src/string/wcspbrk.c7
-rw-r--r--system/lib/libc/musl/src/string/wcsrchr.c8
-rw-r--r--system/lib/libc/musl/src/string/wcsspn.c8
-rw-r--r--system/lib/libc/musl/src/string/wcsstr.c108
-rw-r--r--system/lib/libc/musl/src/string/wcstok.c12
-rw-r--r--system/lib/libc/musl/src/string/wcswcs.c6
-rw-r--r--system/lib/libc/musl/src/string/wmemchr.c8
-rw-r--r--system/lib/libc/musl/src/string/wmemcmp.c8
-rw-r--r--system/lib/libc/musl/src/string/wmemcpy.c9
-rw-r--r--system/lib/libc/musl/src/string/wmemmove.c12
-rw-r--r--system/lib/libc/musl/src/string/wmemset.c9
-rw-r--r--system/lib/libcextra.symbols48
-rwxr-xr-xtests/runner.py165
-rw-r--r--tools/find_bigfuncs.py23
-rw-r--r--tools/shared.py6
64 files changed, 1483 insertions, 392 deletions
diff --git a/ChangeLog b/ChangeLog
deleted file mode 100644
index b60921cd..00000000
--- a/ChangeLog
+++ /dev/null
@@ -1,137 +0,0 @@
-2011-??-??: Version 2.0
-
- * Bundled headers
- * TODO: try to not need all the -h in tests/runner.py, and for user scripts too
-
-2011-07-31: Version 1.5
-
- * eSpeak text-to-speech demo
- * Filesystem emulation API
- * Parse metadata type info for easier interaction with llvm structures
- * Bindings generator improvements
- * Many library improvements and fixes
- * Various bug fixes
-
-2011-07-10: Version 1.4
-
- * Compiling and loading of dynamic libraries
- * Automatic bindings generation using CppHeaderParser
- * Much improved emscripten.py
- * Many library improvements and fixes
- * Various bug fixes
-
-2011-06-22: Version 1.3
-
- * Optional typed arrays with single shared buffer (TA2)
- * Optional support for nonportable optimizations with TA2
- * Relooper optimizations
- * Reading from stdin on the web opens window.prompt
- * Various bug fixes
-
-2011-05-29: Version 1.2
-
- * Doom demo
- * Major SDL improvements: color palettes, input events, audio
- * Various improvements for CHECK_* and CORRECT_*, and new AUTO_OPTIMIZE
- * Experimental work towards supporting OpenGL in WebGL
- * Various bug fixes
-
-2011-05-01: Version 1.1
-
- * Much improved Bullet demo (llvm opts, quantum = 1, CubicVR.js)
- * QUANTUM == 1 a.k.a memory compression option
- * Dead function elimination tool
- * Various performance improvements in generated code
- * Various bug fixes
-
-2011-04-09: Version 1.0
-
- * Poppler test and web demo
- * Optimize compiler memory usage very significantly
- * Support for LLVM 2.9
- * Better interaction with closure compiler
- * Finish docs/paper.pdf
- * Many bug fixes
-
-2011-03-05: Version 0.9
-
- * OpenJPEG test and web demo
- * Line number debugging info and autodebugger tool
- * CORRECT_ROUNDINGS option
- * Line-specific CORRECT_* options
- * 20% faster compilation
- * Generate strict mode JavaScript
- * Many bug fixes, additional tests and library implementations
-
-2011-02-06: Version 0.8
-
- * Freetype web demo (2011-02-08, right after 0.8)
- * Freetype and zlib tests (including the entire build procedure)
- * File emulation
- * CHECK_OVERFLOWS & CORRECT_OVERFLOWS options to handle numerical size issues
- * CHECK_SIGNS option to find whether GUARD_SIGNS is necessary
- * Improvements to usage of llvm optimizations, and testing
- * Many bug fixes, additional tests and library implementations
-
-2010-12-18: Version 0.7
-
- * Python web demo
- * Support for essentially all LLVM optimizations
- * Proper support for C bitfields
- * Many bug fixes, additional tests and library implementations
-
-2010-11-25: Version 0.6
-
- * Web demos: Lua and Bullet/WebGL
- * SAFE_HEAP checks for invalid reads/writes, nonportable .ll
- * Basic C++ exceptions support (|catch(...)|)
- * Optimize compilation of very large projects (memory and speed)
- * Support for frontend-optimized .ll input, plus tests
- * Integration (combining scripts with compiled C++) tools and tests
- * Many bug fixes, additional tests and library implementations
-
-2010-11-02: Version 0.5
-
- * Much faster compilation, in particular of large projects
- * Bullet physics library test
- * GCC name demangling test
- * Module-ization of generated code (optional)
- * Name demangler and namespace generator tools
- * Many code cleanups, bug fixes, additional tests and library implementations
-
-2010-10-17: Version 0.4
-
- * Much faster optimized code, now 10X the speed of our unoptimized code
- * Support for the recently-released LLVM 2.8
- * Support for typed arrays
- * Integration with the Closure Compiler
- * Benchmarking framework in test runner
- * Many code cleanups, bug fixes, and additional tests
-
-2010-10-05: Version 0.3
-
- * Much faster compilation (but still slow with relooper)
- * Clang support
- * Optional memory alignment that precisely matches C/C++
- * Proper memory management, including stack and (optional) dlmalloc
- * Rewritten relooper; no emulated blocks in any test
- * Initial support for SDL
- * Raytracing test + web demo
- * Many code cleanups, bug fixes, additional tests and library implementations
-
-2010-09-11: Version 0.2
-
- * sauer (cubescript) test passes (without RELOOPing), + web demo
- * ES_SIZEOF - safe&portable sizeof replacement
- * emscripten.py tool for easy compiling
- * Better debugging support, using SAFE_HEAP and LABEL_DEBUG, using internal preprocessor
- * Compiler can now run all tests in both SpiderMonkey and V8
- * Various compiler optimizations (still barely scratched the surface though)
- * Many code cleanups, bug fixes, additional tests and library implementations
-
-2010-08-28: Version 0.1
-
- * All tests pass, including fannkuch and fasta, but constglobalstructs
- * Relooping of Fannkuch is complete, fasta has one left
- * Emscriptened Fannkuch is 19X slower than gcc -O0, 37X than gcc -O2
-
diff --git a/emcc b/emcc
index 5d22129a..fed7e997 100755
--- a/emcc
+++ b/emcc
@@ -1108,10 +1108,45 @@ try:
# 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.
+ def read_symbols(path, exclude=None):
+ symbols = map(lambda line: line.strip().split(' ')[1], open(path).readlines())
+ if exclude:
+ symbols = filter(lambda symbol: symbol not in exclude, symbols)
+ return set(symbols)
+
+ # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not
+ # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible.
+ libc_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libc.symbols'))
+ libcextra_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcextra.symbols'))
+ libcxx_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxx', 'symbols'), exclude=libc_symbols)
+ libcxxabi_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols'), exclude=libc_symbols)
+
+ def build_libc(lib_filename, files):
+ o_s = []
+ prev_cxx = os.environ.get('EMMAKEN_CXX')
+ if prev_cxx: os.environ['EMMAKEN_CXX'] = ''
+ musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal')
+ for src in files:
+ o = in_temp(os.path.basename(src) + '.o')
+ execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes], stdout=stdout, stderr=stderr)
+ o_s.append(o)
+ if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx
+ shared.Building.link(o_s, in_temp(lib_filename))
+ return in_temp(lib_filename)
+
+ def build_libcxx(src_dirname, lib_filename, files):
+ o_s = []
+ for src in files:
+ o = in_temp(src + '.o')
+ srcfile = shared.path_from_root(src_dirname, src)
+ execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'], stdout=stdout, stderr=stderr)
+ o_s.append(o)
+ shared.Building.link(o_s, in_temp(lib_filename))
+ return in_temp(lib_filename)
+
# libc
def create_libc():
if DEBUG: print >> sys.stderr, 'emcc: building libc for cache'
- o_s = []
libc_files = [
'dlmalloc.c',
os.path.join('libcxx', 'new.cpp'),
@@ -1126,17 +1161,7 @@ try:
os.path.join('libc', 'gen', 'vwarnx.c'),
os.path.join('libc', 'stdlib', 'strtod.c'),
];
-
- prev_cxx = os.environ.get('EMMAKEN_CXX')
- if prev_cxx: os.environ['EMMAKEN_CXX'] = ''
- for src in libc_files:
- o = in_temp(os.path.basename(src) + '.o')
- execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o], stdout=stdout, stderr=stderr)
- o_s.append(o)
- if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx
-
- shared.Building.link(o_s, in_temp('libc.bc'))
- return in_temp('libc.bc')
+ return build_libc('libc.bc', libc_files)
def fix_libc(need):
# libc needs some sign correction. # If we are in mode 0, switch to 2. We will add our lines
@@ -1148,14 +1173,70 @@ 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.
- # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not
- # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible.
- libc_symbols = open(shared.path_from_root('system', 'lib', 'libc.symbols')).read().split('\n')
+
+ # libcextra
+ def create_libcextra():
+ if DEBUG: print >> sys.stderr, 'emcc: building libcextra for cache'
+ musl_files = [
+ ['multibyte', [
+ 'btowc.c',
+ 'mblen.c',
+ 'mbrlen.c',
+ 'mbrtowc.c',
+ 'mbsinit.c',
+ 'mbsnrtowcs.c',
+ 'mbsrtowcs.c',
+ 'mbstowcs.c',
+ 'mbtowc.c',
+ 'wcrtomb.c',
+ 'wcsnrtombs.c',
+ 'wcsrtombs.c',
+ 'wcstombs.c',
+ 'wctob.c',
+ 'wctomb.c',
+ ]],
+ ['string', [
+ 'wcpcpy.c',
+ 'wcpncpy.c',
+ 'wcscasecmp.c',
+ # 'wcscasecmp_l.c', # XXX: alltypes.h issue
+ 'wcscat.c',
+ 'wcschr.c',
+ 'wcscmp.c',
+ 'wcscpy.c',
+ 'wcscspn.c',
+ 'wcsdup.c',
+ 'wcslen.c',
+ 'wcsncasecmp.c',
+ # 'wcsncasecmp_l.c', # XXX: alltypes.h issue
+ 'wcsncat.c',
+ 'wcsncmp.c',
+ 'wcsncpy.c',
+ 'wcsnlen.c',
+ 'wcspbrk.c',
+ 'wcsrchr.c',
+ 'wcsspn.c',
+ 'wcsstr.c',
+ 'wcstok.c',
+ 'wcswcs.c',
+ 'wmemchr.c',
+ 'wmemcmp.c',
+ 'wmemcpy.c',
+ 'wmemmove.c',
+ 'wmemset.c',
+ ]]
+ ]
+ libcextra_files = []
+ for directory, sources in musl_files:
+ libcextra_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources]
+ return build_libc('libcextra.bc', libcextra_files)
+
+ def fix_libcextra(need):
+ pass
# libcxx
def create_libcxx():
if DEBUG: print >> sys.stderr, 'emcc: building libcxx for cache'
- os = []
libcxx_files = [
'algorithm.cpp',
'condition_variable.cpp',
@@ -1180,50 +1261,34 @@ try:
'regex.cpp',
'strstream.cpp'
]
- for src in libcxx_files:
- o = in_temp(src + '.o')
- srcfile = shared.path_from_root('system', 'lib', 'libcxx', src)
- execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'], stdout=stdout, stderr=stderr)
- os.append(o)
- shared.Building.link(os, in_temp('libcxx.bc'))
- return in_temp('libcxx.bc')
+ return build_libcxx(os.path.join('system', 'lib', 'libcxx'), 'libcxx.bc', libcxx_files)
+
def fix_libcxx(need):
assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++ with QUANTUM_SIZE == 1'
# libcxx might need corrections, so turn them all on. TODO: check which are actually needed
shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1
#print >> sys.stderr, 'emcc: info: using libcxx turns on CORRECT_* options'
- 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 libc_symbols, libcxx_symbols)
- libcxx_symbols = set(libcxx_symbols)
# libcxxabi - just for dynamic_cast for now
def create_libcxxabi():
if DEBUG: print >> sys.stderr, 'emcc: building libcxxabi for cache'
- os = []
libcxxabi_files = [
'typeinfo.cpp',
'private_typeinfo.cpp'
]
- for src in libcxxabi_files:
- o = in_temp(src + '.o')
- srcfile = shared.path_from_root('system', 'lib', 'libcxxabi', 'src', src)
- execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'], stdout=stdout, stderr=stderr)
- os.append(o)
- shared.Building.link(os, in_temp('libcxxabi.bc'))
- return in_temp('libcxxabi.bc')
+ return build_libcxx(os.path.join('system', 'lib', 'libcxxabi', 'src'), 'libcxxabi.bc', libcxxabi_files)
+
def fix_libcxxabi(need):
assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++abi with QUANTUM_SIZE == 1'
#print >> sys.stderr, 'emcc: info: using libcxxabi, this may need CORRECT_* options'
#shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1
- libcxxabi_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols')).readlines())
- libcxxabi_symbols = filter(lambda symbol: symbol not in libc_symbols, libcxxabi_symbols)
- libcxxabi_symbols = set(libcxxabi_symbols)
# If we have libcxx, we must force inclusion of libc, since libcxx uses new internally. Note: this is kind of hacky
# Settings this in the environment will avoid checking dependencies and make building big projects a little faster
force = os.environ.get('EMCC_FORCE_STDLIBS')
has = need = None
for name, create, fix, library_symbols in [('libcxx', create_libcxx, fix_libcxx, libcxx_symbols),
+ ('libcextra', create_libcextra, fix_libcextra, libcextra_symbols),
('libcxxabi', create_libcxxabi, fix_libcxxabi, libcxxabi_symbols),
('libc', create_libc, fix_libc, libc_symbols)]:
if not force:
diff --git a/src/analyzer.js b/src/analyzer.js
index 3278139b..7fbdf24d 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -660,10 +660,12 @@ function analyzer(data, sidePass) {
assert(PRECISE_I64_MATH, 'Must have precise i64 math for non-constant 64-bit shifts');
Types.preciseI64MathUsed = 1;
value.intertype = 'value';
- value.ident = 'var ' + value.assignTo + '$0 = _bitshift64' + value.op[0].toUpperCase() + value.op.substr(1) + '(' +
- asmCoercion(sourceElements[0].ident, 'i32') + ',' +
- asmCoercion(sourceElements[1].ident, 'i32') + ',' +
- asmCoercion(value.params[1].ident + '$0', 'i32') + ');' +
+ value.ident = 'var ' + value.assignTo + '$0 = ' +
+ asmCoercion('_bitshift64' + value.op[0].toUpperCase() + value.op.substr(1) + '(' +
+ asmCoercion(sourceElements[0].ident, 'i32') + ',' +
+ asmCoercion(sourceElements[1].ident, 'i32') + ',' +
+ asmCoercion(value.params[1].ident + '$0', 'i32') + ')', 'i32'
+ ) + ';' +
'var ' + value.assignTo + '$1 = tempRet0;';
value.assignTo = null;
i++;
diff --git a/src/compiler.js b/src/compiler.js
index 9c19aeb0..313fd5f7 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -168,6 +168,10 @@ if (SAFE_HEAP >= 2) {
EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS);
EXPORTED_GLOBALS = set(EXPORTED_GLOBALS);
EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST);
+
+DEAD_FUNCTIONS.forEach(function(dead) {
+ DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push(dead.substr(1));
+});
DEAD_FUNCTIONS = numberedSet(DEAD_FUNCTIONS);
RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG;
diff --git a/src/fastLong.js b/src/fastLong.js
index 95f398db..d1ce5d39 100644
--- a/src/fastLong.js
+++ b/src/fastLong.js
@@ -22,13 +22,13 @@ function ___divdi3($a$0, $a$1, $b$0, $b$1) {
$1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1;
$2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1;
$2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1;
- $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1);
+ $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0;
$4$1 = tempRet0;
- $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1);
+ $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0;
$7$0 = $2$0 ^ $1$0;
$7$1 = $2$1 ^ $1$1;
$8$0 = ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, 0) | 0;
- $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1);
+ $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1) | 0;
return (tempRet0 = tempRet0, $10$0) | 0;
}
function ___remdi3($a$0, $a$1, $b$0, $b$1) {
@@ -44,11 +44,11 @@ function ___remdi3($a$0, $a$1, $b$0, $b$1) {
$1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1;
$2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1;
$2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1;
- $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1);
+ $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0;
$4$1 = tempRet0;
- $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1);
+ $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0;
___udivmoddi4($4$0, $4$1, $6$0, tempRet0, $rem);
- $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1);
+ $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1) | 0;
$10$1 = tempRet0;
STACKTOP = __stackBase__;
return (tempRet0 = $10$1, $10$0) | 0;
@@ -245,7 +245,7 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) {
} else {
$d_sroa_0_0_insert_insert99$0 = 0 | $b$0 & -1;
$d_sroa_0_0_insert_insert99$1 = $d_sroa_1_4_extract_shift$0 | $b$1 & 0;
- $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0, $d_sroa_0_0_insert_insert99$1, -1, -1);
+ $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0, $d_sroa_0_0_insert_insert99$1, -1, -1) | 0;
$137$1 = tempRet0;
$q_sroa_1_1198 = $q_sroa_1_1_ph;
$q_sroa_0_1199 = $q_sroa_0_1_ph;
@@ -262,7 +262,7 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) {
$150$1 = tempRet0;
$151$0 = $150$1 >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1;
$152 = $151$0 & 1;
- $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1);
+ $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1) | 0;
$r_sroa_0_0_extract_trunc = $154$0;
$r_sroa_1_4_extract_trunc = tempRet0;
$155 = $sr_1202 - 1 | 0;
@@ -296,3 +296,4 @@ function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) {
return (tempRet0 = $_0$1, $_0$0) | 0;
}
// =======================================================================
+
diff --git a/src/jsifier.js b/src/jsifier.js
index a01b2655..aab21eea 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -484,17 +484,12 @@ function JSify(data, functionsOnly, givenFunctions) {
if (BUILD_AS_SHARED_LIB) {
// Shared libraries reuse the runtime of their parents.
item.JS = '';
- } else if (LibraryManager.library.hasOwnProperty(shortident)) {
- item.JS = addFromLibrary(shortident);
- } else if (!LibraryManager.library.hasOwnProperty(shortident + '__inline')) {
- if (!(item.ident in DEAD_FUNCTIONS) && !UNRESOLVED_AS_DEAD) {
- item.JS = 'var ' + item.ident + '; // stub for ' + item.ident;
- if (ASM_JS) {
- error('Unresolved symbol: ' + item.ident + ', this must be corrected for asm.js validation to succeed. Consider adding it to DEAD_FUNCTIONS.');
- } else if (WARN_ON_UNDEFINED_SYMBOLS) {
- warn('Unresolved symbol: ' + item.ident);
- }
+ } else {
+ if (!LibraryManager.library.hasOwnProperty(shortident) && !LibraryManager.library.hasOwnProperty(shortident + '__inline')) {
+ if (ASSERTIONS) printErr('warning: missing function: ' + shortident);
+ LibraryManager.library[shortident] = new Function("Module['printErr']('missing function: " + shortident + "'); abort(-1);");
}
+ item.JS = addFromLibrary(shortident);
}
return ret;
}
@@ -713,6 +708,7 @@ function JSify(data, functionsOnly, givenFunctions) {
} else {
ret += 'var setjmpLabel = 0;\n';
ret += 'var setjmpTable = ' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n';
+ ret += makeSetValue('setjmpTable', '0', '0', 'i32') + ';'; // initialize first entry to 0
}
}
ret += indent + 'while(1) ';
@@ -1370,7 +1366,7 @@ function JSify(data, functionsOnly, givenFunctions) {
args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) });
if (ASM_JS) {
- if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced) {
+ if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || funcData.setjmpTable) {
args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) });
} else {
args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) });
@@ -1438,30 +1434,25 @@ function JSify(data, functionsOnly, givenFunctions) {
returnType = getReturnType(type);
}
- if (callIdent in DEAD_FUNCTIONS) {
- var ret = 'abort(' + DEAD_FUNCTIONS[callIdent] + ')';
- if (ASM_JS) ret = asmCoercion(ret, returnType);
- return ret;
- }
-
if (byPointer) {
var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs);
if (ASM_JS) {
assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out)
- if (!byPointerForced) {
+ if (!byPointerForced && !funcData.setjmpTable) {
+ // normal asm function pointer call
callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py
} else {
- // This is a forced call, through an invoke_*.
+ // This is a call through an invoke_*, either a forced one, or a setjmp-required one
// note: no need to update argsTypes at this point
- Functions.unimplementedFunctions[callIdent] = sig;
- args.unshift(byPointerForced ? Functions.getIndex(callIdent) : callIdent);
+ if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig;
+ args.unshift(byPointerForced ? Functions.getIndex(callIdent) : asmCoercion(callIdent, 'i32'));
callIdent = 'invoke_' + sig;
}
} else if (SAFE_DYNCALLS) {
assert(!ASM_JS, 'cannot emit safe dyncalls in asm');
callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)';
}
- if (!byPointerForced) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
+ if (!ASM_JS || (!byPointerForced && !funcData.setjmpTable)) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
}
var ret = callIdent + '(' + args.join(', ') + ')';
@@ -1475,7 +1466,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (ASM_JS && funcData.setjmpTable) {
// check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to -111 to handle it.
// otherwise, just return - the call to us must also have been an invoke, so the setjmp propagates that way
- ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = _testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable); if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n';
+ ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n';
}
return ret;
diff --git a/src/library.js b/src/library.js
index cd416599..5bbf4204 100644
--- a/src/library.js
+++ b/src/library.js
@@ -4168,32 +4168,6 @@ 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;
- },
-
arc4random: 'rand',
// ==========================================================================
@@ -4243,8 +4217,6 @@ LibraryManager.library = {
return ret|0;
},
- wmemcpy: function() { throw 'wmemcpy not implemented' },
-
llvm_memcpy_i32: 'memcpy',
llvm_memcpy_i64: 'memcpy',
llvm_memcpy_p0i8_p0i8_i32: 'memcpy',
@@ -4274,8 +4246,6 @@ LibraryManager.library = {
llvm_memmove_p0i8_p0i8_i32: 'memmove',
llvm_memmove_p0i8_p0i8_i64: 'memmove',
- wmemmove: function() { throw 'wmemmove not implemented' },
-
memset__inline: function(ptr, value, num, align) {
return makeSetValues(ptr, 0, value, 'null', num, align);
},
@@ -4316,32 +4286,18 @@ LibraryManager.library = {
llvm_memset_p0i8_i32: 'memset',
llvm_memset_p0i8_i64: 'memset',
- wmemset: function() { throw 'wmemset not implemented' },
-
strlen__sig: 'ii',
strlen__asm: true,
strlen: function(ptr) {
ptr = ptr|0;
var curr = 0;
curr = ptr;
- while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}|0 != 0) {
+ while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}) {
curr = (curr + 1)|0;
}
return (curr - ptr)|0;
},
- // TODO: Implement when we have real unicode support.
- mblen: function() {
- return 1;
- },
-
- wcslen: function() { throw 'wcslen not implemented' },
- mbrlen: function() { throw 'mbrlen not implemented' },
- mbsrtowcs: function() { throw 'mbsrtowcs not implemented' },
- wcsnrtombs: function() { throw 'wcsnrtombs not implemented' },
- mbsnrtowcs: function() { throw 'mbsnrtowcs not implemented' },
- mbrtowc: function() { throw 'mbrtowc not implemented' },
-
strspn: function(pstr, pset) {
var str = pstr, set, strcurr, setcurr;
while (1) {
@@ -4382,7 +4338,7 @@ LibraryManager.library = {
do {
{{{ makeCopyValues('(pdest+i)|0', '(psrc+i)|0', 1, 'i8', null, 1) }}};
i = (i+1)|0;
- } while (({{{ makeGetValue('psrc', 'i-1', 'i8') }}})|0 != 0);
+ } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}});
return pdest|0;
},
@@ -4437,11 +4393,11 @@ LibraryManager.library = {
strcat: function(pdest, psrc) {
pdest = pdest|0; psrc = psrc|0;
var i = 0;
- pdest = (pdest + _strlen(pdest))|0;
+ pdest = (pdest + (_strlen(pdest)|0))|0;
do {
{{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}};
i = (i+1)|0;
- } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}} != 0);
+ } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}});
return pdest|0;
},
@@ -4501,8 +4457,8 @@ LibraryManager.library = {
px = px|0; py = py|0; n = n|0;
var i = 0, x = 0, y = 0;
while ((i>>>0) < (n>>>0)) {
- x = _tolower({{{ makeGetValueAsm('px', 'i', 'i8', 0, 1) }}});
- y = _tolower({{{ makeGetValueAsm('py', 'i', 'i8', 0, 1) }}});
+ x = _tolower({{{ makeGetValueAsm('px', 'i', 'i8', 0, 1) }}})|0;
+ y = _tolower({{{ makeGetValueAsm('py', 'i', 'i8', 0, 1) }}})|0;
if (((x|0) == (y|0)) & ((x|0) == 0)) return 0;
if ((x|0) == 0) return -1;
if ((y|0) == 0) return 1;
@@ -5355,6 +5311,8 @@ LibraryManager.library = {
llvm_objectsize_i32: function() { return -1 }, // TODO: support this
+ llvm_dbg_declare__inline: function() { throw 'llvm_debug_declare' }, // avoid warning
+
// ==========================================================================
// llvm-mono integration
// ==========================================================================
@@ -6220,6 +6178,7 @@ LibraryManager.library = {
saveSetjmp__asm: true,
saveSetjmp__sig: 'iii',
+ saveSetjmp__deps: ['putchar'],
saveSetjmp: function(env, label, table) {
// Not particularly fast: slow table lookup of setjmpId to label. But setjmp
// prevents relooping anyhow, so slowness is to be expected. And typical case
@@ -6233,7 +6192,7 @@ LibraryManager.library = {
#endif
setjmpId = (setjmpId+1)|0;
{{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}};
- while ((i|0) < {{{ MAX_SETJMPS }}}) {
+ while ((i|0) < {{{ 2*MAX_SETJMPS }}}) {
if ({{{ makeGetValueAsm('table', 'i*4', 'i32') }}} == 0) {
{{{ makeSetValueAsm('table', 'i*4', 'setjmpId', 'i32') }}};
{{{ makeSetValueAsm('table', 'i*4+4', 'label', 'i32') }}};
@@ -6243,7 +6202,8 @@ LibraryManager.library = {
}
i = (i+2)|0;
}
- abort(987); // if you hit this, adjust MAX_SETJMPS
+ {{{ makePrintChars('too many setjmps in a function call, build with a higher value for MAX_SETJMPS') }}};
+ abort(0);
return 0;
},
@@ -6270,7 +6230,7 @@ LibraryManager.library = {
setjmp__inline: function(env) {
// Save the label
#if ASM_JS
- return '_saveSetjmp(' + env + ', label, setjmpTable)';
+ return '_saveSetjmp(' + env + ', label, setjmpTable)|0';
#else
return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32', undefined, undefined, undefined, undefined, ',') + ', 0)';
#endif
diff --git a/src/modules.js b/src/modules.js
index 7a769846..ce162ac1 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -291,7 +291,7 @@ var Functions = {
var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig'] : 'x';
assert(sig, ident);
if (!tables[sig]) tables[sig] = emptyTable(sig); // TODO: make them compact
- tables[sig][this.indexedFunctions[ident]] = ident in DEAD_FUNCTIONS ? '0' : ident;
+ tables[sig][this.indexedFunctions[ident]] = ident;
}
var generated = false;
var wrapped = {};
diff --git a/src/parseTools.js b/src/parseTools.js
index 2eb456f1..f4ce12d5 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -2000,7 +2000,7 @@ function processMathop(item) {
}
function preciseCall(name) {
Types.preciseI64MathUsed = true;
- return finish([name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']);
+ return finish([asmCoercion(name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'i32'), 'tempRet0']);
}
function i64PreciseLib(type) {
return preciseCall('_i64' + type[0].toUpperCase() + type.substr(1));
@@ -2363,3 +2363,14 @@ function getTypeFromHeap(suffix) {
}
}
+// Generates code that prints without printf(), but just putchar (so can be directly inline in asm.js)
+function makePrintChars(s, sep) {
+ sep = sep || ';';
+ var ret = '';
+ for (var i = 0; i < s.length; i++) {
+ ret += '_putchar(' + s.charCodeAt(i) + ')' + sep;
+ }
+ ret += '_putchar(10)';
+ return ret;
+}
+
diff --git a/src/settings.js b/src/settings.js
index 7cd0c02e..c878be92 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -55,7 +55,7 @@ var ALLOW_MEMORY_GROWTH = 0; // If false, we abort with an error if we try to al
// that case we must be careful about optimizations, in particular the
// eliminator). Note that memory growth is only supported with typed
// arrays.
-var MAX_SETJMPS = 10; // size of setjmp table allocated in each function invocation (that has setjmp)
+var MAX_SETJMPS = 20; // size of setjmp table allocated in each function invocation (that has setjmp)
// Code embetterments
var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables
@@ -342,19 +342,10 @@ var PGO = 0; // Enables profile-guided optimization in the form of runtime check
// calling PGOMonitor.dump());
var DEAD_FUNCTIONS = []; // Functions on this list are not converted to JS, and calls to
// them are turned into abort()s. This is potentially useful for
- // (1) reducing code size, if you know some function will never
- // be called (see PGO), and also (2) ASM.js requires all declared
- // functions to have a corresponding implementation (even if the
- // function is never called) and will emit an error during linking if no
- // implementation can be found; with this option, asm.js validation will
- // succeed for that function and calls to it.
+ // reducing code size.
// If a dead function is actually called, you will get a runtime
// error.
// TODO: options to lazily load such functions
-var UNRESOLVED_AS_DEAD = 0; // Handle all unresolved functions as if they were in the
- // list of dead functions. This is a quick way to turn
- // all unresolved references into runtime aborts (and not
- // get compile-time warnings or errors on them).
var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i32, using ?:
diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols
index 96e995cf..1b126abf 100644
--- a/system/lib/libc.symbols
+++ b/system/lib/libc.symbols
@@ -1,81 +1,81 @@
-_ZNKSt20bad_array_new_length4whatEv
-_ZNKSt9bad_alloc4whatEv
-_ZNSt20bad_array_new_lengthC1Ev
-_ZNSt20bad_array_new_lengthC2Ev
-_ZNSt20bad_array_new_lengthD0Ev
-_ZNSt20bad_array_new_lengthD1Ev
-_ZNSt20bad_array_new_lengthD2Ev
-_ZNSt9bad_allocC1Ev
-_ZNSt9bad_allocC2Ev
-_ZNSt9bad_allocD0Ev
-_ZNSt9bad_allocD1Ev
-_ZNSt9bad_allocD2Ev
-_ZSt15get_new_handlerv
-_ZSt15set_new_handlerPFvvE
-_ZSt17__throw_bad_allocv
-_ZSt7nothrow
-_ZTISt20bad_array_new_length
-_ZTISt9bad_alloc
-_ZTSSt20bad_array_new_length
-_ZTSSt9bad_alloc
-_ZTVSt20bad_array_new_length
-_ZTVSt9bad_alloc
-_ZdaPv
-_ZdaPvRKSt9nothrow_t
-_ZdlPv
-_ZdlPvRKSt9nothrow_t
-_Znaj
-_ZnajRKSt9nothrow_t
-_Znwj
-_ZnwjRKSt9nothrow_t
-_err
-_errx
-_verr
-_verrx
-_vwarn
-_vwarnx
-_warn
-_warnx
-atof
-bulk_free
-calloc
-err
-errx
-free
-getopt
-getopt_long
-getopt_long_only
-independent_calloc
-independent_comalloc
-mallinfo
-malloc
-malloc_footprint
-malloc_footprint_limit
-malloc_max_footprint
-malloc_set_footprint_limit
-malloc_stats
-malloc_trim
-malloc_usable_size
-mallopt
-memalign
-optarg
-opterr
-optind
-optopt
-optreset
-posix_memalign
-pvalloc
-realloc
-realloc_in_place
-strtod
-strtod_l
-strtof
-strtold
-strtold_l
-valloc
-verr
-verrx
-vwarn
-vwarnx
-warn1
-warnx
+ T _ZNKSt20bad_array_new_length4whatEv
+ T _ZNKSt9bad_alloc4whatEv
+ T _ZNSt20bad_array_new_lengthC1Ev
+ T _ZNSt20bad_array_new_lengthC2Ev
+ T _ZNSt20bad_array_new_lengthD0Ev
+ ? _ZNSt20bad_array_new_lengthD1Ev
+ T _ZNSt20bad_array_new_lengthD2Ev
+ T _ZNSt9bad_allocC1Ev
+ T _ZNSt9bad_allocC2Ev
+ T _ZNSt9bad_allocD0Ev
+ T _ZNSt9bad_allocD1Ev
+ T _ZNSt9bad_allocD2Ev
+ T _ZSt15get_new_handlerv
+ T _ZSt15set_new_handlerPFvvE
+ T _ZSt17__throw_bad_allocv
+ D _ZSt7nothrow
+ D _ZTISt20bad_array_new_length
+ D _ZTISt9bad_alloc
+ D _ZTSSt20bad_array_new_length
+ D _ZTSSt9bad_alloc
+ D _ZTVSt20bad_array_new_length
+ D _ZTVSt9bad_alloc
+ W _ZdaPv
+ W _ZdaPvRKSt9nothrow_t
+ W _ZdlPv
+ W _ZdlPvRKSt9nothrow_t
+ W _Znaj
+ W _ZnajRKSt9nothrow_t
+ W _Znwj
+ W _ZnwjRKSt9nothrow_t
+ T _err
+ T _errx
+ T _verr
+ T _verrx
+ T _vwarn
+ T _vwarnx
+ T _warn
+ T _warnx
+ T atof
+ W bulk_free
+ W calloc
+ W err
+ W errx
+ W free
+ T getopt
+ T getopt_long
+ T getopt_long_only
+ W independent_calloc
+ W independent_comalloc
+ W mallinfo
+ W malloc
+ W malloc_footprint
+ W malloc_footprint_limit
+ W malloc_max_footprint
+ W malloc_set_footprint_limit
+ W malloc_stats
+ W malloc_trim
+ T malloc_usable_size
+ W mallopt
+ W memalign
+ C optarg
+ D opterr
+ D optind
+ D optopt
+ C optreset
+ W posix_memalign
+ W pvalloc
+ W realloc
+ W realloc_in_place
+ T strtod
+ T strtod_l
+ T strtof
+ T strtold
+ T strtold_l
+ W valloc
+ W verr
+ W verrx
+ W vwarn
+ W vwarnx
+ W warn1
+ W warnx
diff --git a/system/lib/libc/musl/memcpy.c b/system/lib/libc/musl/memcpy.c
deleted file mode 100644
index 8e98302f..00000000
--- a/system/lib/libc/musl/memcpy.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#define SS (sizeof(size_t))
-#define ALIGN (sizeof(size_t)-1)
-#define ONES ((size_t)-1/UCHAR_MAX)
-
-void *memcpy(void *restrict dest, const void *restrict src, size_t n)
-{
- unsigned char *d = dest;
- const unsigned char *s = src;
-
- if (((uintptr_t)d & ALIGN) != ((uintptr_t)s & ALIGN))
- goto misaligned;
-
- for (; ((uintptr_t)d & ALIGN) && n; n--) *d++ = *s++;
- if (n) {
- size_t *wd = (void *)d;
- const size_t *ws = (const void *)s;
-
- for (; n>=SS; n-=SS) *wd++ = *ws++;
- d = (void *)wd;
- s = (const void *)ws;
-misaligned:
- for (; n; n--) *d++ = *s++;
- }
- return dest;
-}
diff --git a/system/lib/libc/musl/readme.txt b/system/lib/libc/musl/readme.txt
new file mode 100644
index 00000000..0df3429d
--- /dev/null
+++ b/system/lib/libc/musl/readme.txt
@@ -0,0 +1 @@
+These sources were downloaded from the musl-0.9.10 release on April 14, 2003.
diff --git a/system/lib/libc/musl/src/internal/libc.c b/system/lib/libc/musl/src/internal/libc.c
new file mode 100644
index 00000000..942f6b44
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/libc.c
@@ -0,0 +1,22 @@
+#include "libc.h"
+
+#ifdef USE_LIBC_ACCESSOR
+struct __libc *__libc_loc()
+{
+ static struct __libc __libc;
+ return &__libc;
+}
+#else
+struct __libc __libc;
+#endif
+
+#ifdef BROKEN_VISIBILITY
+__asm__(".hidden __libc");
+#endif
+
+size_t __hwcap;
+size_t __sysinfo;
+char *__progname=0, *__progname_full=0;
+
+weak_alias(__progname, program_invocation_short_name);
+weak_alias(__progname_full, program_invocation_name);
diff --git a/system/lib/libc/musl/src/internal/libc.h b/system/lib/libc/musl/src/internal/libc.h
new file mode 100644
index 00000000..c9416f07
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/libc.h
@@ -0,0 +1,71 @@
+#ifndef LIBC_H
+#define LIBC_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+struct __libc {
+ void *main_thread;
+ int threaded;
+ int secure;
+ size_t *auxv;
+ int (*atexit)(void (*)(void));
+ void (*fini)(void);
+ void (*ldso_fini)(void);
+ volatile int threads_minus_1;
+ int canceldisable;
+ FILE *ofl_head;
+ int ofl_lock[2];
+ size_t tls_size;
+};
+
+extern size_t __hwcap;
+
+#if !defined(__PIC__) || (100*__GNUC__+__GNUC_MINOR__ >= 303 && !defined(__PCC__))
+
+#ifdef __PIC__
+#if __GNUC__ < 4
+#define BROKEN_VISIBILITY 1
+#endif
+#define ATTR_LIBC_VISIBILITY __attribute__((visibility("hidden")))
+#else
+#define ATTR_LIBC_VISIBILITY
+#endif
+
+extern struct __libc __libc ATTR_LIBC_VISIBILITY;
+#define libc __libc
+
+#else
+
+#define USE_LIBC_ACCESSOR
+#define ATTR_LIBC_VISIBILITY
+extern struct __libc *__libc_loc(void) __attribute__((const));
+#define libc (*__libc_loc())
+
+#endif
+
+
+/* Designed to avoid any overhead in non-threaded processes */
+void __lock(volatile int *) ATTR_LIBC_VISIBILITY;
+void __unlock(volatile int *) ATTR_LIBC_VISIBILITY;
+int __lockfile(FILE *) ATTR_LIBC_VISIBILITY;
+void __unlockfile(FILE *) ATTR_LIBC_VISIBILITY;
+#define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1))
+#define UNLOCK(x) (libc.threads_minus_1 ? (__unlock(x),1) : ((void)(x),1))
+
+void __synccall(void (*)(void *), void *);
+int __setxid(int, int, int, int);
+
+extern char **__environ;
+
+#undef weak_alias
+#define weak_alias(old, new) \
+ extern __typeof(old) new __attribute__((weak, alias(#old)))
+
+#undef LFS64_2
+#define LFS64_2(x, y) weak_alias(x, y)
+
+#undef LFS64
+#define LFS64(x) LFS64_2(x, x##64)
+
+#endif
diff --git a/system/lib/libc/musl/src/multibyte/btowc.c b/system/lib/libc/musl/src/multibyte/btowc.c
new file mode 100644
index 00000000..9d2c3b16
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/btowc.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <wchar.h>
+
+wint_t btowc(int c)
+{
+ return c<128U ? c : EOF;
+}
diff --git a/system/lib/libc/musl/src/multibyte/internal.c b/system/lib/libc/musl/src/multibyte/internal.c
new file mode 100644
index 00000000..ab22806e
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/internal.c
@@ -0,0 +1,38 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <inttypes.h>
+
+#include "internal.h"
+
+#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) )
+#define D(x) C((x+16))
+#define E(x) ( ( x==0 ? R(0xa0,0xc0) : \
+ x==0xd ? R(0x80,0xa0) : \
+ R(0x80,0xc0) ) \
+ | ( R(0x80,0xc0) >> 6 ) \
+ | x )
+#define F(x) ( ( x>=5 ? 0 : \
+ x==0 ? R(0x90,0xc0) : \
+ x==4 ? R(0x80,0xa0) : \
+ R(0x80,0xc0) ) \
+ | ( R(0x80,0xc0) >> 6 ) \
+ | ( R(0x80,0xc0) >> 12 ) \
+ | x )
+
+const uint32_t bittab[] = {
+ C(0x2),C(0x3),C(0x4),C(0x5),C(0x6),C(0x7),
+ C(0x8),C(0x9),C(0xa),C(0xb),C(0xc),C(0xd),C(0xe),C(0xf),
+ D(0x0),D(0x1),D(0x2),D(0x3),D(0x4),D(0x5),D(0x6),D(0x7),
+ D(0x8),D(0x9),D(0xa),D(0xb),D(0xc),D(0xd),D(0xe),D(0xf),
+ E(0x0),E(0x1),E(0x2),E(0x3),E(0x4),E(0x5),E(0x6),E(0x7),
+ E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf),
+ F(0x0),F(0x1),F(0x2),F(0x3),F(0x4)
+};
+
+#ifdef BROKEN_VISIBILITY
+__asm__(".hidden __fsmu8");
+#endif
diff --git a/system/lib/libc/musl/src/multibyte/internal.h b/system/lib/libc/musl/src/multibyte/internal.h
new file mode 100644
index 00000000..25ba240e
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/internal.h
@@ -0,0 +1,22 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#define bittab __fsmu8
+
+#include "libc.h"
+
+extern const uint32_t bittab[] ATTR_LIBC_VISIBILITY;
+
+/* Upper 6 state bits are a negative integer offset to bound-check next byte */
+/* equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f */
+#define OOB(c,b) (((((b)>>3)-0x10)|(((b)>>3)+((int32_t)(c)>>26))) & ~7)
+
+/* Interval [a,b). Either a must be 80 or b must be c0, lower 3 bits clear. */
+#define R(a,b) ((uint32_t)((a==0x80 ? 0x40-b : -a) << 23))
+#define FAILSTATE R(0x80,0x80)
+
+#define SA 0xc2u
+#define SB 0xf4u
diff --git a/system/lib/libc/musl/src/multibyte/mblen.c b/system/lib/libc/musl/src/multibyte/mblen.c
new file mode 100644
index 00000000..26d35649
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mblen.c
@@ -0,0 +1,17 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int mblen(const char *s, size_t n)
+{
+ return mbtowc(0, s, n);
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbrlen.c b/system/lib/libc/musl/src/multibyte/mbrlen.c
new file mode 100644
index 00000000..c9714ef8
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbrlen.c
@@ -0,0 +1,18 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbrlen(const char *restrict s, size_t n, mbstate_t *restrict st)
+{
+ static unsigned internal;
+ return mbrtowc(0, s, n, st ? st : (mbstate_t *)&internal);
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbrtowc.c b/system/lib/libc/musl/src/multibyte/mbrtowc.c
new file mode 100644
index 00000000..db803661
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbrtowc.c
@@ -0,0 +1,57 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st)
+{
+ static unsigned internal_state;
+ unsigned c;
+ const unsigned char *s = (const void *)src;
+ const unsigned N = n;
+
+ if (!st) st = (void *)&internal_state;
+ c = *(unsigned *)st;
+
+ if (!s) {
+ if (c) goto ilseq;
+ return 0;
+ } else if (!wc) wc = (void *)&wc;
+
+ if (!n) return -2;
+ if (!c) {
+ if (*s < 0x80) return !!(*wc = *s);
+ if (*s-SA > SB-SA) goto ilseq;
+ c = bittab[*s++-SA]; n--;
+ }
+
+ if (n) {
+ if (OOB(c,*s)) goto ilseq;
+loop:
+ c = c<<6 | *s++-0x80; n--;
+ if (!(c&(1U<<31))) {
+ *(unsigned *)st = 0;
+ *wc = c;
+ return N-n;
+ }
+ if (n) {
+ if (*s-0x80u >= 0x40) goto ilseq;
+ goto loop;
+ }
+ }
+
+ *(unsigned *)st = c;
+ return -2;
+ilseq:
+ *(unsigned *)st = 0;
+ errno = EILSEQ;
+ return -1;
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbsinit.c b/system/lib/libc/musl/src/multibyte/mbsinit.c
new file mode 100644
index 00000000..c0e7e494
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbsinit.c
@@ -0,0 +1,17 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int mbsinit(const mbstate_t *st)
+{
+ return !st || !*(unsigned *)st;
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c
new file mode 100644
index 00000000..33457f95
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c
@@ -0,0 +1,65 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "internal.h"
+
+size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st)
+{
+ size_t l, cnt=0, n2;
+ wchar_t *ws, wbuf[256];
+ const char *s = *src;
+
+ if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf;
+ else ws = wcs;
+
+ /* making sure output buffer size is at most n/4 will ensure
+ * that mbsrtowcs never reads more than n input bytes. thus
+ * we can use mbsrtowcs as long as it's practical.. */
+
+ while ( s && wn && ( (n2=n/4)>=wn || n2>32 ) ) {
+ if (n2>=wn) n2=wn;
+ n -= n2;
+ l = mbsrtowcs(ws, &s, n2, st);
+ if (!(l+1)) {
+ cnt = l;
+ wn = 0;
+ break;
+ }
+ if (ws != wbuf) {
+ ws += l;
+ wn -= l;
+ }
+ cnt += l;
+ }
+ if (s) while (wn && n) {
+ l = mbrtowc(ws, s, n, st);
+ if (l+2<=2) {
+ if (!(l+1)) {
+ cnt = l;
+ break;
+ }
+ if (!l) {
+ s = 0;
+ break;
+ }
+ /* have to roll back partial character */
+ *(unsigned *)st = 0;
+ break;
+ }
+ s += l; n -= l;
+ /* safe - this loop runs fewer than sizeof(wbuf)/8 times */
+ ws++; wn--;
+ cnt++;
+ }
+ if (wcs) *src = s;
+ return cnt;
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbsrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c
new file mode 100644
index 00000000..75a493c4
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c
@@ -0,0 +1,100 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st)
+{
+ const unsigned char *s = (const void *)*src;
+ size_t wn0 = wn;
+ unsigned c = 0;
+
+ if (st && (c = *(unsigned *)st)) {
+ if (ws) {
+ *(unsigned *)st = 0;
+ goto resume;
+ } else {
+ goto resume0;
+ }
+ }
+
+ if (!ws) for (;;) {
+ if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
+ while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
+ s += 4;
+ wn -= 4;
+ }
+ }
+ if (*s-1u < 0x7f) {
+ s++;
+ wn--;
+ continue;
+ }
+ if (*s-SA > SB-SA) break;
+ c = bittab[*s++-SA];
+resume0:
+ if (OOB(c,*s)) { s--; break; }
+ s++;
+ if (c&(1U<<25)) {
+ if (*s-0x80u >= 0x40) { s-=2; break; }
+ s++;
+ if (c&(1U<<19)) {
+ if (*s-0x80u >= 0x40) { s-=3; break; }
+ s++;
+ }
+ }
+ wn--;
+ c = 0;
+ } else for (;;) {
+ if (!wn) return wn0;
+ if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
+ while (wn>=4 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
+ *ws++ = *s++;
+ *ws++ = *s++;
+ *ws++ = *s++;
+ *ws++ = *s++;
+ wn -= 4;
+ }
+ }
+ if (*s-1u < 0x7f) {
+ *ws++ = *s++;
+ wn--;
+ continue;
+ }
+ if (*s-SA > SB-SA) break;
+ c = bittab[*s++-SA];
+resume:
+ if (OOB(c,*s)) { s--; break; }
+ c = (c<<6) | *s++-0x80;
+ if (c&(1U<<31)) {
+ if (*s-0x80u >= 0x40) { s-=2; break; }
+ c = (c<<6) | *s++-0x80;
+ if (c&(1U<<31)) {
+ if (*s-0x80u >= 0x40) { s-=3; break; }
+ c = (c<<6) | *s++-0x80;
+ }
+ }
+ *ws++ = c;
+ wn--;
+ c = 0;
+ }
+
+ if (!c && !*s) {
+ if (ws) {
+ *ws = 0;
+ *src = 0;
+ }
+ return wn0-wn;
+ }
+ errno = EILSEQ;
+ if (ws) *src = (const void *)s;
+ return -1;
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbstowcs.c b/system/lib/libc/musl/src/multibyte/mbstowcs.c
new file mode 100644
index 00000000..dc0d4594
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbstowcs.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+#include <wchar.h>
+
+size_t mbstowcs(wchar_t *restrict ws, const char *restrict s, size_t wn)
+{
+ return mbsrtowcs(ws, (void*)&s, wn, 0);
+}
diff --git a/system/lib/libc/musl/src/multibyte/mbtowc.c b/system/lib/libc/musl/src/multibyte/mbtowc.c
new file mode 100644
index 00000000..ec9e54ad
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/mbtowc.c
@@ -0,0 +1,53 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+#include <stdio.h>
+int mbtowc(wchar_t *restrict wc, const char *restrict src, size_t n)
+{
+ unsigned c;
+ const unsigned char *s = (const void *)src;
+
+ if (!s) return 0;
+ if (!n) goto ilseq;
+ if (!wc) wc = (void *)&wc;
+
+ if (*s < 0x80) return !!(*wc = *s);
+ if (*s-SA > SB-SA) goto ilseq;
+ c = bittab[*s++-SA];
+
+ /* Avoid excessive checks against n: If shifting the state n-1
+ * times does not clear the high bit, then the value of n is
+ * insufficient to read a character */
+ if (n<4 && ((c<<(6*n-6)) & (1U<<31))) goto ilseq;
+
+ if (OOB(c,*s)) goto ilseq;
+ c = c<<6 | *s++-0x80;
+ if (!(c&(1U<<31))) {
+ *wc = c;
+ return 2;
+ }
+
+ if (*s-0x80u >= 0x40) goto ilseq;
+ c = c<<6 | *s++-0x80;
+ if (!(c&(1U<<31))) {
+ *wc = c;
+ return 3;
+ }
+
+ if (*s-0x80u >= 0x40) goto ilseq;
+ *wc = c<<6 | *s++-0x80;
+ return 4;
+
+ilseq:
+ errno = EILSEQ;
+ return -1;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wcrtomb.c b/system/lib/libc/musl/src/multibyte/wcrtomb.c
new file mode 100644
index 00000000..250649f5
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wcrtomb.c
@@ -0,0 +1,38 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st)
+{
+ if (!s) return 1;
+ if ((unsigned)wc < 0x80) {
+ *s = wc;
+ return 1;
+ } else if ((unsigned)wc < 0x800) {
+ *s++ = 0xc0 | (wc>>6);
+ *s = 0x80 | (wc&0x3f);
+ return 2;
+ } else if ((unsigned)wc < 0xd800 || (unsigned)wc-0xe000 < 0x2000) {
+ *s++ = 0xe0 | (wc>>12);
+ *s++ = 0x80 | ((wc>>6)&0x3f);
+ *s = 0x80 | (wc&0x3f);
+ return 3;
+ } else if ((unsigned)wc-0x10000 < 0x100000) {
+ *s++ = 0xf0 | (wc>>18);
+ *s++ = 0x80 | ((wc>>12)&0x3f);
+ *s++ = 0x80 | ((wc>>6)&0x3f);
+ *s = 0x80 | (wc&0x3f);
+ return 4;
+ }
+ errno = EILSEQ;
+ return -1;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wcsnrtombs.c b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c
new file mode 100644
index 00000000..a2e308b3
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c
@@ -0,0 +1,52 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict wcs, size_t wn, size_t n, mbstate_t *restrict st)
+{
+ size_t l, cnt=0, n2;
+ char *s, buf[256];
+ const wchar_t *ws = *wcs;
+
+ if (!dst) s = buf, n = sizeof buf;
+ else s = dst;
+
+ while ( ws && n && ( (n2=wn)>=n || n2>32 ) ) {
+ if (n2>=n) n2=n;
+ wn -= n2;
+ l = wcsrtombs(s, &ws, n2, 0);
+ if (!(l+1)) {
+ cnt = l;
+ n = 0;
+ break;
+ }
+ if (s != buf) {
+ s += l;
+ n -= l;
+ }
+ cnt += l;
+ }
+ if (ws) while (n && wn) {
+ l = wcrtomb(s, *ws, 0);
+ if ((l+1)<=1) {
+ if (!l) ws = 0;
+ else cnt = l;
+ break;
+ }
+ ws++; wn--;
+ /* safe - this loop runs fewer than sizeof(buf) times */
+ s+=l; n-=l;
+ cnt++;
+ }
+ if (dst) *wcs = ws;
+ return cnt;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wcsrtombs.c b/system/lib/libc/musl/src/multibyte/wcsrtombs.c
new file mode 100644
index 00000000..d48a65e7
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wcsrtombs.c
@@ -0,0 +1,58 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstate_t *restrict st)
+{
+ const wchar_t *ws2;
+ char buf[4];
+ size_t N = n, l;
+ if (!s) {
+ for (n=0, ws2=*ws; *ws2; ws2++) {
+ if (*ws2 >= 0x80u) {
+ l = wcrtomb(buf, *ws2, 0);
+ if (!(l+1)) return -1;
+ n += l;
+ } else n++;
+ }
+ return n;
+ }
+ while (n>=4 && **ws) {
+ if (**ws >= 0x80u) {
+ l = wcrtomb(s, **ws, 0);
+ if (!(l+1)) return -1;
+ s += l;
+ n -= l;
+ } else {
+ *s++ = **ws;
+ n--;
+ }
+ (*ws)++;
+ }
+ while (n && **ws) {
+ if (**ws >= 0x80u) {
+ l = wcrtomb(buf, **ws, 0);
+ if (!(l+1)) return -1;
+ if (l>n) return N-n;
+ wcrtomb(s, **ws, 0);
+ s += l;
+ n -= l;
+ } else {
+ *s++ = **ws;
+ n--;
+ }
+ (*ws)++;
+ }
+ if (n) *s = 0;
+ *ws = 0;
+ return N-n;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wcstombs.c b/system/lib/libc/musl/src/multibyte/wcstombs.c
new file mode 100644
index 00000000..ab152874
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wcstombs.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+#include <wchar.h>
+
+size_t wcstombs(char *restrict s, const wchar_t *restrict ws, size_t n)
+{
+ return wcsrtombs(s, &(const wchar_t *){ws}, n, 0);
+}
diff --git a/system/lib/libc/musl/src/multibyte/wctob.c b/system/lib/libc/musl/src/multibyte/wctob.c
new file mode 100644
index 00000000..d6353ee1
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wctob.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include <wchar.h>
+
+int wctob(wint_t c)
+{
+ if (c < 128U) return c;
+ return EOF;
+}
diff --git a/system/lib/libc/musl/src/multibyte/wctomb.c b/system/lib/libc/musl/src/multibyte/wctomb.c
new file mode 100644
index 00000000..6910ef37
--- /dev/null
+++ b/system/lib/libc/musl/src/multibyte/wctomb.c
@@ -0,0 +1,18 @@
+/*
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int wctomb(char *s, wchar_t wc)
+{
+ if (!s) return 0;
+ return wcrtomb(s, wc, 0);
+}
diff --git a/system/lib/libc/musl/src/string/wcpcpy.c b/system/lib/libc/musl/src/string/wcpcpy.c
new file mode 100644
index 00000000..ef401343
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcpcpy.c
@@ -0,0 +1,6 @@
+#include <wchar.h>
+
+wchar_t *wcpcpy(wchar_t *restrict d, const wchar_t *restrict s)
+{
+ return wcscpy(d, s) + wcslen(s);
+}
diff --git a/system/lib/libc/musl/src/string/wcpncpy.c b/system/lib/libc/musl/src/string/wcpncpy.c
new file mode 100644
index 00000000..b667f6d6
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcpncpy.c
@@ -0,0 +1,6 @@
+#include <wchar.h>
+
+wchar_t *wcpncpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n)
+{
+ return wcsncpy(d, s, n) + wcsnlen(s, n);
+}
diff --git a/system/lib/libc/musl/src/string/wcscasecmp.c b/system/lib/libc/musl/src/string/wcscasecmp.c
new file mode 100644
index 00000000..3edeec7d
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcscasecmp.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+#include <wctype.h>
+
+int wcscasecmp(const wchar_t *l, const wchar_t *r)
+{
+ return wcsncasecmp(l, r, -1);
+}
diff --git a/system/lib/libc/musl/src/string/wcscasecmp_l.c b/system/lib/libc/musl/src/string/wcscasecmp_l.c
new file mode 100644
index 00000000..065dd0aa
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcscasecmp_l.c
@@ -0,0 +1,6 @@
+#include <wchar.h>
+
+int wcscasecmp_l(const wchar_t *l, const wchar_t *r, locale_t locale)
+{
+ return wcscasecmp(l, r);
+}
diff --git a/system/lib/libc/musl/src/string/wcscat.c b/system/lib/libc/musl/src/string/wcscat.c
new file mode 100644
index 00000000..d4f00ebd
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcscat.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+wchar_t *wcscat(wchar_t *restrict dest, const wchar_t *restrict src)
+{
+ wcscpy(dest + wcslen(dest), src);
+ return dest;
+}
diff --git a/system/lib/libc/musl/src/string/wcschr.c b/system/lib/libc/musl/src/string/wcschr.c
new file mode 100644
index 00000000..8dfc2f31
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcschr.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+wchar_t *wcschr(const wchar_t *s, wchar_t c)
+{
+ if (!c) return (wchar_t *)s + wcslen(s);
+ for (; *s && *s != c; s++);
+ return *s ? (wchar_t *)s : 0;
+}
diff --git a/system/lib/libc/musl/src/string/wcscmp.c b/system/lib/libc/musl/src/string/wcscmp.c
new file mode 100644
index 00000000..26eeee70
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcscmp.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+int wcscmp(const wchar_t *l, const wchar_t *r)
+{
+ for (; *l==*r && *l && *r; l++, r++);
+ return *l - *r;
+}
diff --git a/system/lib/libc/musl/src/string/wcscpy.c b/system/lib/libc/musl/src/string/wcscpy.c
new file mode 100644
index 00000000..625bf53d
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcscpy.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+wchar_t *wcscpy(wchar_t *restrict d, const wchar_t *restrict s)
+{
+ wchar_t *a = d;
+ while ((*d++ = *s++));
+ return a;
+}
diff --git a/system/lib/libc/musl/src/string/wcscspn.c b/system/lib/libc/musl/src/string/wcscspn.c
new file mode 100644
index 00000000..c4e52722
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcscspn.c
@@ -0,0 +1,10 @@
+#include <wchar.h>
+
+size_t wcscspn(const wchar_t *s, const wchar_t *c)
+{
+ const wchar_t *a;
+ if (!c[0]) return wcslen(s);
+ if (!c[1]) return (s=wcschr(a=s, *c)) ? s-a : wcslen(a);
+ for (a=s; *s && !wcschr(c, *s); s++);
+ return s-a;
+}
diff --git a/system/lib/libc/musl/src/string/wcsdup.c b/system/lib/libc/musl/src/string/wcsdup.c
new file mode 100644
index 00000000..dd49c1b6
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsdup.c
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+#include <wchar.h>
+#include "libc.h"
+
+wchar_t *wcsdup(const wchar_t *s)
+{
+ size_t l = wcslen(s);
+ wchar_t *d = malloc((l+1)*sizeof(wchar_t));
+ if (!d) return NULL;
+ return wmemcpy(d, s, l+1);
+}
diff --git a/system/lib/libc/musl/src/string/wcslen.c b/system/lib/libc/musl/src/string/wcslen.c
new file mode 100644
index 00000000..1b7b6655
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcslen.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+size_t wcslen(const wchar_t *s)
+{
+ const wchar_t *a;
+ for (a=s; *s; s++);
+ return s-a;
+}
diff --git a/system/lib/libc/musl/src/string/wcsncasecmp.c b/system/lib/libc/musl/src/string/wcsncasecmp.c
new file mode 100644
index 00000000..8fefe799
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsncasecmp.c
@@ -0,0 +1,9 @@
+#include <wchar.h>
+#include <wctype.h>
+
+int wcsncasecmp(const wchar_t *l, const wchar_t *r, size_t n)
+{
+ if (!n--) return 0;
+ for (; *l && *r && n && (*l == *r || towlower(*l) == towlower(*r)); l++, r++, n--);
+ return towlower(*l) - towlower(*r);
+}
diff --git a/system/lib/libc/musl/src/string/wcsncasecmp_l.c b/system/lib/libc/musl/src/string/wcsncasecmp_l.c
new file mode 100644
index 00000000..63872481
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsncasecmp_l.c
@@ -0,0 +1,6 @@
+#include <wchar.h>
+
+int wcsncasecmp_l(const wchar_t *l, const wchar_t *r, size_t n, locale_t locale)
+{
+ return wcsncasecmp(l, r, n);
+}
diff --git a/system/lib/libc/musl/src/string/wcsncat.c b/system/lib/libc/musl/src/string/wcsncat.c
new file mode 100644
index 00000000..8563f1a2
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsncat.c
@@ -0,0 +1,10 @@
+#include <wchar.h>
+
+wchar_t *wcsncat(wchar_t *restrict d, const wchar_t *restrict s, size_t n)
+{
+ wchar_t *a = d;
+ d += wcslen(d);
+ while (n && *s) n--, *d++ = *s++;
+ *d++ = 0;
+ return a;
+}
diff --git a/system/lib/libc/musl/src/string/wcsncmp.c b/system/lib/libc/musl/src/string/wcsncmp.c
new file mode 100644
index 00000000..4ab32a92
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsncmp.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n)
+{
+ for (; n && *l==*r && *l && *r; n--, l++, r++);
+ return n ? *l - *r : 0;
+}
diff --git a/system/lib/libc/musl/src/string/wcsncpy.c b/system/lib/libc/musl/src/string/wcsncpy.c
new file mode 100644
index 00000000..4bede04d
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsncpy.c
@@ -0,0 +1,9 @@
+#include <wchar.h>
+
+wchar_t *wcsncpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n)
+{
+ wchar_t *a = d;
+ while (n && *s) n--, *d++ = *s++;
+ wmemset(d, 0, n);
+ return a;
+}
diff --git a/system/lib/libc/musl/src/string/wcsnlen.c b/system/lib/libc/musl/src/string/wcsnlen.c
new file mode 100644
index 00000000..a7763373
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsnlen.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+size_t wcsnlen(const wchar_t *s, size_t n)
+{
+ const wchar_t *z = wmemchr(s, 0, n);
+ if (z) n = z-s;
+ return n;
+}
diff --git a/system/lib/libc/musl/src/string/wcspbrk.c b/system/lib/libc/musl/src/string/wcspbrk.c
new file mode 100644
index 00000000..0c72c197
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcspbrk.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+wchar_t *wcspbrk(const wchar_t *s, const wchar_t *b)
+{
+ s += wcscspn(s, b);
+ return *s ? (wchar_t *)s : NULL;
+}
diff --git a/system/lib/libc/musl/src/string/wcsrchr.c b/system/lib/libc/musl/src/string/wcsrchr.c
new file mode 100644
index 00000000..8961b9e2
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsrchr.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+wchar_t *wcsrchr(const wchar_t *s, wchar_t c)
+{
+ const wchar_t *p;
+ for (p=s+wcslen(s); p>=s && *p!=c; p--);
+ return p>=s ? (wchar_t *)p : 0;
+}
diff --git a/system/lib/libc/musl/src/string/wcsspn.c b/system/lib/libc/musl/src/string/wcsspn.c
new file mode 100644
index 00000000..4320d8f6
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsspn.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+size_t wcsspn(const wchar_t *s, const wchar_t *c)
+{
+ const wchar_t *a;
+ for (a=s; *s && wcschr(c, *s); s++);
+ return s-a;
+}
diff --git a/system/lib/libc/musl/src/string/wcsstr.c b/system/lib/libc/musl/src/string/wcsstr.c
new file mode 100644
index 00000000..037d0965
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcsstr.c
@@ -0,0 +1,108 @@
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n)
+{
+ const wchar_t *z;
+ size_t l, ip, jp, k, p, ms, p0, mem, mem0;
+
+ /* Computing length of needle */
+ for (l=0; n[l] && h[l]; l++);
+ if (n[l]) return 0; /* hit the end of h */
+
+ /* Compute maximal suffix */
+ ip = -1; jp = 0; k = p = 1;
+ while (jp+k<l) {
+ if (n[ip+k] == n[jp+k]) {
+ if (k == p) {
+ jp += p;
+ k = 1;
+ } else k++;
+ } else if (n[ip+k] > n[jp+k]) {
+ jp += k;
+ k = 1;
+ p = jp - ip;
+ } else {
+ ip = jp++;
+ k = p = 1;
+ }
+ }
+ ms = ip;
+ p0 = p;
+
+ /* And with the opposite comparison */
+ ip = -1; jp = 0; k = p = 1;
+ while (jp+k<l) {
+ if (n[ip+k] == n[jp+k]) {
+ if (k == p) {
+ jp += p;
+ k = 1;
+ } else k++;
+ } else if (n[ip+k] < n[jp+k]) {
+ jp += k;
+ k = 1;
+ p = jp - ip;
+ } else {
+ ip = jp++;
+ k = p = 1;
+ }
+ }
+ if (ip+1 > ms+1) ms = ip;
+ else p = p0;
+
+ /* Periodic needle? */
+ if (wmemcmp(n, n+p, ms+1)) {
+ mem0 = 0;
+ p = MAX(ms, l-ms-1) + 1;
+ } else mem0 = l-p;
+ mem = 0;
+
+ /* Initialize incremental end-of-haystack pointer */
+ z = h;
+
+ /* Search loop */
+ for (;;) {
+ /* Update incremental end-of-haystack pointer */
+ if (z-h < l) {
+ /* Fast estimate for MIN(l,63) */
+ size_t grow = l | 63;
+ const wchar_t *z2 = wmemchr(z, 0, grow);
+ if (z2) {
+ z = z2;
+ if (z-h < l) return 0;
+ } else z += grow;
+ }
+
+ /* Compare right half */
+ for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
+ if (n[k]) {
+ h += k-ms;
+ mem = 0;
+ continue;
+ }
+ /* Compare left half */
+ for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
+ if (k == mem) return (wchar_t *)h;
+ h += p;
+ mem = mem0;
+ }
+}
+
+wchar_t *wcsstr(const wchar_t *restrict h, const wchar_t *restrict n)
+{
+ /* Return immediately on empty needle or haystack */
+ if (!n[0]) return (wchar_t *)h;
+ if (!h[0]) return 0;
+
+ /* Use faster algorithms for short needles */
+ h = wcschr(h, *n);
+ if (!h || !n[1]) return (wchar_t *)h;
+ if (!h[1]) return 0;
+
+ return twoway_wcsstr(h, n);
+}
diff --git a/system/lib/libc/musl/src/string/wcstok.c b/system/lib/libc/musl/src/string/wcstok.c
new file mode 100644
index 00000000..ecc80331
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcstok.c
@@ -0,0 +1,12 @@
+#include <wchar.h>
+
+wchar_t *wcstok(wchar_t *restrict s, const wchar_t *restrict sep, wchar_t **restrict p)
+{
+ if (!s && !(s = *p)) return NULL;
+ s += wcsspn(s, sep);
+ if (!*s) return *p = 0;
+ *p = s + wcscspn(s, sep);
+ if (**p) *(*p)++ = 0;
+ else *p = 0;
+ return s;
+}
diff --git a/system/lib/libc/musl/src/string/wcswcs.c b/system/lib/libc/musl/src/string/wcswcs.c
new file mode 100644
index 00000000..9cfe4ac4
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wcswcs.c
@@ -0,0 +1,6 @@
+#include <wchar.h>
+
+wchar_t *wcswcs(const wchar_t *haystack, const wchar_t *needle)
+{
+ return wcsstr(haystack, needle);
+}
diff --git a/system/lib/libc/musl/src/string/wmemchr.c b/system/lib/libc/musl/src/string/wmemchr.c
new file mode 100644
index 00000000..37d69629
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wmemchr.c
@@ -0,0 +1,8 @@
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n)
+{
+ for (; n && *s != c; n--, s++);
+ return n ? (wchar_t *)s : 0;
+}
diff --git a/system/lib/libc/musl/src/string/wmemcmp.c b/system/lib/libc/musl/src/string/wmemcmp.c
new file mode 100644
index 00000000..6788a383
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wmemcmp.c
@@ -0,0 +1,8 @@
+#include <string.h>
+#include <wchar.h>
+
+int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n)
+{
+ for (; n && *l==*r; n--, l++, r++);
+ return n ? *l-*r : 0;
+}
diff --git a/system/lib/libc/musl/src/string/wmemcpy.c b/system/lib/libc/musl/src/string/wmemcpy.c
new file mode 100644
index 00000000..55a8e1d8
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wmemcpy.c
@@ -0,0 +1,9 @@
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *wmemcpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n)
+{
+ wchar_t *a = d;
+ while (n--) *d++ = *s++;
+ return a;
+}
diff --git a/system/lib/libc/musl/src/string/wmemmove.c b/system/lib/libc/musl/src/string/wmemmove.c
new file mode 100644
index 00000000..cde4feec
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wmemmove.c
@@ -0,0 +1,12 @@
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *wmemmove(wchar_t *d, const wchar_t *s, size_t n)
+{
+ wchar_t *d0 = d;
+ if ((size_t)(d-s) < n)
+ while (n--) d[n] = s[n];
+ else
+ while (n--) *d++ = *s++;
+ return d0;
+}
diff --git a/system/lib/libc/musl/src/string/wmemset.c b/system/lib/libc/musl/src/string/wmemset.c
new file mode 100644
index 00000000..1a2a8618
--- /dev/null
+++ b/system/lib/libc/musl/src/string/wmemset.c
@@ -0,0 +1,9 @@
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n)
+{
+ wchar_t *ret = d;
+ while (n--) *d++ = c;
+ return ret;
+}
diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols
new file mode 100644
index 00000000..97805c96
--- /dev/null
+++ b/system/lib/libcextra.symbols
@@ -0,0 +1,48 @@
+ U __errno
+ U __fsmu8
+ T btowc
+ U malloc
+ T mblen
+ T mbrlen
+ d mbrlen.internal
+ T mbrtowc
+ d mbrtowc.internal_state
+ T mbsinit
+ T mbsnrtowcs
+ T mbsrtowcs
+ T mbstowcs
+ T mbtowc
+ U towlower
+ t twoway_wcsstr
+ T wcpcpy
+ T wcpncpy
+ T wcrtomb
+ T wcscasecmp
+ T wcscat
+ T wcschr
+ T wcscmp
+ T wcscpy
+ T wcscspn
+ T wcsdup
+ T wcslen
+ T wcsncasecmp
+ T wcsncat
+ T wcsncmp
+ T wcsncpy
+ T wcsnlen
+ T wcsnrtombs
+ T wcspbrk
+ T wcsrchr
+ T wcsrtombs
+ T wcsspn
+ T wcsstr
+ T wcstok
+ T wcstombs
+ T wcswcs
+ T wctob
+ T wctomb
+ T wmemchr
+ T wmemcmp
+ T wmemcpy
+ T wmemmove
+ T wmemset
diff --git a/tests/runner.py b/tests/runner.py
index 811d32a5..5602fd94 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -2309,6 +2309,23 @@ cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too'
'''
self.do_run(src, 'Assertion failed: 1 == false')
+ def test_libcextra(self):
+ if self.emcc_args is None: return self.skip('needs emcc for libcextra')
+ src = r'''
+ #include <stdio.h>
+ #include <wchar.h>
+
+ int main()
+ {
+ const wchar_t* wstr = L"Hello";
+
+ printf("wcslen: %d\n", wcslen(wstr));
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'wcslen: 5')
+
def test_longjmp(self):
src = r'''
#include <stdio.h>
@@ -2489,6 +2506,145 @@ Calling longjmp the second time!
Exception execution path of first function! 1
''')
+ def test_longjmp_funcptr(self):
+ src = r'''
+ #include <stdio.h>
+ #include <setjmp.h>
+
+ static jmp_buf buf;
+
+ void (*fp)() = NULL;
+
+ void second(void) {
+ printf("second\n"); // prints
+ longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
+ }
+
+ void first(void) {
+ fp();
+ printf("first\n"); // does not print
+ }
+
+ int main(int argc, char **argv) {
+ fp = argc == 200 ? NULL : second;
+
+ volatile int x = 0;
+ if ( ! setjmp(buf) ) {
+ x++;
+ first(); // when executed, setjmp returns 0
+ } else { // when longjmp jumps back, setjmp returns 1
+ printf("main: %d\n", x); // prints
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'second\nmain: 1\n')
+
+ def test_longjmp_repeat(self):
+ Settings.MAX_SETJMPS = 1
+
+ src = r'''
+ #include <stdio.h>
+ #include <setjmp.h>
+
+ static jmp_buf buf;
+
+ int main() {
+ volatile int x = 0;
+ printf("setjmp:%d\n", setjmp(buf));
+ x++;
+ printf("x:%d\n", x);
+ if (x < 4) longjmp(buf, x*2);
+ return 0;
+ }
+ '''
+ self.do_run(src, '''setjmp:0
+x:1
+setjmp:2
+x:2
+setjmp:4
+x:3
+setjmp:6
+x:4
+''')
+
+ def test_longjmp_stacked(self):
+ src = r'''
+ #include <stdio.h>
+ #include <setjmp.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ int bottom, top;
+
+ int run(int y) {
+ // confuse stack
+ char *s = (char*)alloca(100);
+ memset(s, 1, 100);
+ s[y] = y;
+ s[y/2] = y*2;
+ volatile int x = s[y];
+ top = (int)alloca(4);
+ if (x <= 2) return x;
+ jmp_buf buf;
+ printf("setjmp of %d\n", x);
+ if (setjmp(buf) == 0) {
+ printf("going\n");
+ x += run(x/2);
+ longjmp(buf, 1);
+ }
+ printf("back\n");
+ return x/2;
+ }
+
+ int main(int argc, char **argv) {
+ int sum = 0;
+ for (int i = 0; i < argc*2; i++) {
+ bottom = (int)alloca(4);
+ sum += run(10);
+ // scorch the earth
+ if (bottom < top) {
+ memset((void*)bottom, 1, top - bottom);
+ } else {
+ memset((void*)top, 1, bottom - top);
+ }
+ }
+ printf("%d\n", sum);
+ return sum;
+ }
+ '''
+ self.do_run(src, '''setjmp of 10
+going
+setjmp of 5
+going
+back
+back
+setjmp of 10
+going
+setjmp of 5
+going
+back
+back
+12
+''')
+
+ def test_setjmp_many(self):
+ src = r'''
+ #include <stdio.h>
+ #include <setjmp.h>
+
+ int main(int argc) {
+ jmp_buf buf;
+ for (int i = 0; i < NUM; i++) printf("%d\n", setjmp(buf));
+ if (argc-- == 1131) longjmp(buf, 11);
+ 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')
+
def test_exceptions(self):
if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
@@ -8015,11 +8171,12 @@ def process(filename):
# Kill off the dead function, still works and it is not emitted
Settings.DEAD_FUNCTIONS = ['_unused']
js = test('*9*')
- assert 'function _unused(' not in js
+ assert 'function _unused($' not in js # no compiled code
+ assert 'function _unused(' in js # lib-generated stub
Settings.DEAD_FUNCTIONS = []
# Run the same code with argc that uses the dead function, see abort
- test(('abort', 'is not a function'), args=['a', 'b'], no_build=True)
+ test(('missing function: unused'), args=['a', 'b'], no_build=True)
# Normal stuff
run_all('normal', r'''
@@ -8094,7 +8251,7 @@ def process(filename):
before = len(open('normal.js').read())
after = len(open('pgoed.js').read())
- assert after < 0.66 * before, [before, after] # expect a big size reduction
+ assert after < 0.90 * before, [before, after] # expect a size reduction
# with response in settings element itself
@@ -10201,7 +10358,7 @@ f.close()
(1, 0, 3, 2), (1, 1, 3, 4)
]:
print asm, linkable, chunks, js_chunks
- output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1', '-s', 'LINKABLE=%d' % linkable, '-s', 'ASM_JS=%d' % asm, '-s', 'UNRESOLVED_AS_DEAD=1'] + (['-O2'] if asm else []), stdout=PIPE, stderr=PIPE).communicate()
+ output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1', '-s', 'LINKABLE=%d' % linkable, '-s', 'ASM_JS=%d' % asm] + (['-O2'] if asm else []), stdout=PIPE, stderr=PIPE).communicate()
ok = False
for c in range(chunks, chunks+2):
ok = ok or ('phase 2 working on %d chunks' % c in err)
diff --git a/tools/find_bigfuncs.py b/tools/find_bigfuncs.py
new file mode 100644
index 00000000..ebff8b6e
--- /dev/null
+++ b/tools/find_bigfuncs.py
@@ -0,0 +1,23 @@
+'''
+Simple tool to find big functions in an .ll file. Anything over i64 is of interest.
+'''
+
+import os, sys, re
+
+filename = sys.argv[1]
+i = 0
+maxx = -1
+maxxest = '?'
+start = -1
+curr = '?'
+for line in open(filename):
+ i += 1
+ if line.startswith('function '):
+ start = i
+ curr = line
+ elif line.startswith('}'):
+ size = i - start
+ if size > maxx:
+ maxx = size
+ maxxest = curr
+print maxx, 'lines in', maxxest
diff --git a/tools/shared.py b/tools/shared.py
index 6b5ad835..33b0273e 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -111,7 +111,7 @@ else:
config_file = config_file.replace('{{{ EMSCRIPTEN_ROOT }}}', __rootpath__)
llvm_root = '/usr/bin'
try:
- llvm_root = os.path.dirname(Popen(['which', 'clang'], stdout=PIPE).communicate()[0].replace('\n', ''))
+ llvm_root = os.path.dirname(Popen(['which', 'llvm-dis'], stdout=PIPE).communicate()[0].replace('\n', ''))
except:
pass
config_file = config_file.replace('{{{ LLVM_ROOT }}}', llvm_root)
@@ -199,7 +199,7 @@ def check_node_version():
# we re-check sanity when the settings are changed)
# We also re-check sanity and clear the cache when the version changes
-EMSCRIPTEN_VERSION = '1.3.6'
+EMSCRIPTEN_VERSION = '1.3.7'
def check_sanity(force=False):
try:
@@ -401,7 +401,7 @@ except:
# Force a simple, standard target as much as possible: target 32-bit linux, and disable various flags that hint at other platforms
COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__i386', '-Ui386',
'-U__SSE__', '-U__SSE_MATH__', '-U__SSE2__', '-U__SSE2_MATH__', '-U__MMX__',
- '-DEMSCRIPTEN', '-U__STRICT_ANSI__',
+ '-DEMSCRIPTEN', '-D__EMSCRIPTEN__', '-U__STRICT_ANSI__',
'-target', 'i386-pc-linux-gnu', '-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno']
USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK')